@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.js CHANGED
@@ -649,8 +649,9 @@ var AxBaseAI = class {
649
649
  this.tracer = options.tracer;
650
650
  this.modelInfo = modelInfo;
651
651
  this.models = models;
652
+ this.id = crypto.randomUUID();
652
653
  const model = this.models?.find((v) => v.key === defaults.model)?.model ?? defaults.model;
653
- const embedModel = this.models?.find((v) => v.key === defaults.embedModel)?.model ?? defaults.embedModel;
654
+ const embedModel = defaults.embedModel;
654
655
  this.defaults = { model, embedModel };
655
656
  if (!defaults.model || typeof defaults.model !== "string" || defaults.model === "") {
656
657
  throw new Error("No model defined");
@@ -668,6 +669,7 @@ var AxBaseAI = class {
668
669
  defaults;
669
670
  apiURL;
670
671
  name;
672
+ id;
671
673
  headers;
672
674
  supportFor;
673
675
  // Add private metrics tracking properties
@@ -702,6 +704,9 @@ var AxBaseAI = class {
702
704
  setName(name) {
703
705
  this.name = name;
704
706
  }
707
+ getId() {
708
+ return this.id;
709
+ }
705
710
  setAPIURL(apiURL) {
706
711
  this.apiURL = apiURL;
707
712
  }
@@ -747,8 +752,7 @@ var AxBaseAI = class {
747
752
  }
748
753
  const mi = getModelInfo({
749
754
  model: this.defaults.embedModel,
750
- modelInfo: this.modelInfo,
751
- models: this.models
755
+ modelInfo: this.modelInfo
752
756
  });
753
757
  return {
754
758
  ...mi,
@@ -954,7 +958,7 @@ var AxBaseAI = class {
954
958
  }
955
959
  }
956
960
  async _embed1(req, options) {
957
- const embedModel = req.embedModel ? this.models?.find((v) => v.key === req.embedModel)?.model ?? req.embedModel : this.defaults.embedModel;
961
+ const embedModel = req.embedModel ?? this.defaults.embedModel;
958
962
  if (!embedModel) {
959
963
  throw new Error("No embed model defined");
960
964
  }
@@ -965,7 +969,7 @@ var AxBaseAI = class {
965
969
  kind: SpanKind.SERVER,
966
970
  attributes: {
967
971
  [axSpanAttributes.LLM_SYSTEM]: this.name,
968
- [axSpanAttributes.LLM_REQUEST_MODEL]: req.embedModel ?? this.defaults.embedModel
972
+ [axSpanAttributes.LLM_REQUEST_MODEL]: embedModel
969
973
  }
970
974
  },
971
975
  async (span) => {
@@ -1144,13 +1148,13 @@ var AxAIAnthropicModel = /* @__PURE__ */ ((AxAIAnthropicModel2) => {
1144
1148
  AxAIAnthropicModel2["ClaudeInstant12"] = "claude-instant-1.2";
1145
1149
  return AxAIAnthropicModel2;
1146
1150
  })(AxAIAnthropicModel || {});
1147
- var AxAIAnthropicVertexModel = /* @__PURE__ */ ((AxAIAnthropicVertexModel2) => {
1148
- AxAIAnthropicVertexModel2["Claude35Haiku"] = "claude-3-5-haiku";
1149
- AxAIAnthropicVertexModel2["Claude35Sonnet"] = "claude-3-5-sonnet";
1150
- AxAIAnthropicVertexModel2["Claude35SonnetV2"] = "claude-3-5-sonnet-v2";
1151
- AxAIAnthropicVertexModel2["Claude3Haiku"] = "claude-3-haiku";
1152
- AxAIAnthropicVertexModel2["Claude3Opus"] = "claude-3-opus";
1153
- return AxAIAnthropicVertexModel2;
1151
+ var AxAIAnthropicVertexModel = /* @__PURE__ */ ((AxAIAnthropicVertexModel3) => {
1152
+ AxAIAnthropicVertexModel3["Claude35Haiku"] = "claude-3-5-haiku";
1153
+ AxAIAnthropicVertexModel3["Claude35Sonnet"] = "claude-3-5-sonnet";
1154
+ AxAIAnthropicVertexModel3["Claude35SonnetV2"] = "claude-3-5-sonnet-v2";
1155
+ AxAIAnthropicVertexModel3["Claude3Haiku"] = "claude-3-haiku";
1156
+ AxAIAnthropicVertexModel3["Claude3Opus"] = "claude-3-opus";
1157
+ return AxAIAnthropicVertexModel3;
1154
1158
  })(AxAIAnthropicVertexModel || {});
1155
1159
 
1156
1160
  // ai/anthropic/info.ts
@@ -1954,26 +1958,22 @@ function createMessages2(req) {
1954
1958
  }
1955
1959
  });
1956
1960
  }
1957
- var AxAIOpenAI = class extends AxBaseAI {
1961
+ var AxAIOpenAIBase = class extends AxBaseAI {
1958
1962
  constructor({
1959
1963
  apiKey,
1960
1964
  config,
1961
1965
  options,
1962
1966
  apiURL,
1963
- modelInfo = axModelInfoOpenAI,
1967
+ modelInfo,
1964
1968
  models
1965
1969
  }) {
1966
1970
  if (!apiKey || apiKey === "") {
1967
1971
  throw new Error("OpenAI API key not set");
1968
1972
  }
1969
- const _config = {
1970
- ...axAIOpenAIDefaultConfig(),
1971
- ...config
1972
- };
1973
1973
  const aiImpl = new AxAIOpenAIImpl(
1974
- _config,
1974
+ config,
1975
1975
  options?.streamingUsage ?? true,
1976
- config?.dimensions
1976
+ config.dimensions
1977
1977
  );
1978
1978
  super(aiImpl, {
1979
1979
  name: "OpenAI",
@@ -1981,8 +1981,8 @@ var AxAIOpenAI = class extends AxBaseAI {
1981
1981
  headers: async () => ({ Authorization: `Bearer ${apiKey}` }),
1982
1982
  modelInfo,
1983
1983
  defaults: {
1984
- model: _config.model,
1985
- embedModel: _config.embedModel
1984
+ model: config.model,
1985
+ embedModel: config.embedModel
1986
1986
  },
1987
1987
  options,
1988
1988
  supportFor: () => {
@@ -1995,10 +1995,33 @@ var AxAIOpenAI = class extends AxBaseAI {
1995
1995
  var isReasoningModel = (model) => ["o1-mini" /* O1Mini */, "o1" /* O1 */, "o3-mini" /* O3Mini */].includes(
1996
1996
  model
1997
1997
  );
1998
+ var AxAIOpenAI = class extends AxAIOpenAIBase {
1999
+ constructor({
2000
+ apiKey,
2001
+ config,
2002
+ options,
2003
+ models
2004
+ }) {
2005
+ if (!apiKey || apiKey === "") {
2006
+ throw new Error("OpenAI API key not set");
2007
+ }
2008
+ super({
2009
+ apiKey,
2010
+ config: {
2011
+ ...axAIOpenAIDefaultConfig(),
2012
+ ...config
2013
+ },
2014
+ options,
2015
+ modelInfo: axModelInfoOpenAI,
2016
+ models
2017
+ });
2018
+ super.setName("OpenAI");
2019
+ }
2020
+ };
1998
2021
 
1999
2022
  // ai/azure-openai/api.ts
2000
2023
  var axAIAzureOpenAIDefaultConfig = axAIOpenAIDefaultConfig;
2001
- var AxAIAzureOpenAI = class extends AxAIOpenAI {
2024
+ var AxAIAzureOpenAI = class extends AxAIOpenAIBase {
2002
2025
  constructor({
2003
2026
  apiKey,
2004
2027
  resourceName,
@@ -2021,7 +2044,13 @@ var AxAIAzureOpenAI = class extends AxAIOpenAI {
2021
2044
  ...axAIAzureOpenAIDefaultConfig(),
2022
2045
  ...config
2023
2046
  };
2024
- super({ apiKey, config: _config, options, models });
2047
+ super({
2048
+ apiKey,
2049
+ config: _config,
2050
+ options,
2051
+ models,
2052
+ modelInfo: axModelInfoOpenAI
2053
+ });
2025
2054
  const host = resourceName.includes("://") ? resourceName : `https://${resourceName}.openai.azure.com/`;
2026
2055
  super.setName("Azure OpenAI");
2027
2056
  super.setAPIURL(
@@ -2384,7 +2413,7 @@ var axAIDeepSeekDefaultConfig = () => structuredClone({
2384
2413
  model: "deepseek-chat" /* DeepSeekChat */,
2385
2414
  ...axBaseAIDefaultConfig()
2386
2415
  });
2387
- var AxAIDeepSeek = class extends AxAIOpenAI {
2416
+ var AxAIDeepSeek = class extends AxAIOpenAIBase {
2388
2417
  constructor({
2389
2418
  apiKey,
2390
2419
  config,
@@ -2948,7 +2977,7 @@ var axAIGroqDefaultConfig = () => structuredClone({
2948
2977
  model: "llama-3.3-70b-versatile" /* Llama33_70B */,
2949
2978
  ...axBaseAIDefaultConfig()
2950
2979
  });
2951
- var AxAIGroq = class extends AxAIOpenAI {
2980
+ var AxAIGroq = class extends AxAIOpenAIBase {
2952
2981
  constructor({
2953
2982
  apiKey,
2954
2983
  config,
@@ -3193,7 +3222,7 @@ var axAIMistralDefaultConfig = () => structuredClone({
3193
3222
  model: "mistral-small-latest" /* MistralSmall */,
3194
3223
  ...axBaseAIDefaultConfig()
3195
3224
  });
3196
- var AxAIMistral = class extends AxAIOpenAI {
3225
+ var AxAIMistral = class extends AxAIOpenAIBase {
3197
3226
  constructor({
3198
3227
  apiKey,
3199
3228
  config,
@@ -3225,7 +3254,7 @@ var axAIOllamaDefaultConfig = () => structuredClone({
3225
3254
  model: "nous-hermes2",
3226
3255
  embedModel: "all-minilm"
3227
3256
  });
3228
- var AxAIOllama = class extends AxAIOpenAI {
3257
+ var AxAIOllama = class extends AxAIOpenAIBase {
3229
3258
  constructor({
3230
3259
  apiKey = "not-set",
3231
3260
  url = "http://localhost:11434/v1",
@@ -3242,7 +3271,8 @@ var AxAIOllama = class extends AxAIOpenAI {
3242
3271
  options,
3243
3272
  config: _config,
3244
3273
  apiURL: url,
3245
- models
3274
+ models,
3275
+ modelInfo: []
3246
3276
  });
3247
3277
  super.setName("Ollama");
3248
3278
  }
@@ -3479,7 +3509,7 @@ var axAITogetherDefaultConfig = () => structuredClone({
3479
3509
  model: "mistralai/Mixtral-8x7B-Instruct-v0.1",
3480
3510
  ...axBaseAIDefaultConfig()
3481
3511
  });
3482
- var AxAITogether = class extends AxAIOpenAI {
3512
+ var AxAITogether = class extends AxAIOpenAIBase {
3483
3513
  constructor({
3484
3514
  apiKey,
3485
3515
  config,
@@ -3553,6 +3583,9 @@ var AxAI = class {
3553
3583
  getName() {
3554
3584
  return this.ai.getName();
3555
3585
  }
3586
+ getId() {
3587
+ return this.ai.getId();
3588
+ }
3556
3589
  getModelInfo() {
3557
3590
  return this.ai.getModelInfo();
3558
3591
  }
@@ -6154,6 +6187,10 @@ var AxBalancer = class _AxBalancer {
6154
6187
  currentServiceIndex = 0;
6155
6188
  currentService;
6156
6189
  debug;
6190
+ initialBackoffMs;
6191
+ maxBackoffMs;
6192
+ maxRetries;
6193
+ serviceFailures = /* @__PURE__ */ new Map();
6157
6194
  constructor(services, options) {
6158
6195
  if (services.length === 0) {
6159
6196
  throw new Error("No AI services provided.");
@@ -6167,6 +6204,9 @@ var AxBalancer = class _AxBalancer {
6167
6204
  }
6168
6205
  this.currentService = cs;
6169
6206
  this.debug = options?.debug ?? true;
6207
+ this.initialBackoffMs = options?.initialBackoffMs ?? 1e3;
6208
+ this.maxBackoffMs = options?.maxBackoffMs ?? 32e3;
6209
+ this.maxRetries = options?.maxRetries ?? 3;
6170
6210
  }
6171
6211
  /**
6172
6212
  * Service comparator that respects the input order of services.
@@ -6183,7 +6223,7 @@ var AxBalancer = class _AxBalancer {
6183
6223
  return aTotalCost - bTotalCost;
6184
6224
  };
6185
6225
  getModelList() {
6186
- throw new Error("Method not implemented.");
6226
+ return this.currentService.getModelList();
6187
6227
  }
6188
6228
  getNextService() {
6189
6229
  const cs = this.services[++this.currentServiceIndex];
@@ -6204,6 +6244,9 @@ var AxBalancer = class _AxBalancer {
6204
6244
  getName() {
6205
6245
  return this.currentService.getName();
6206
6246
  }
6247
+ getId() {
6248
+ return this.currentService.getId();
6249
+ }
6207
6250
  getModelInfo() {
6208
6251
  return this.currentService.getModelInfo();
6209
6252
  }
@@ -6216,11 +6259,56 @@ var AxBalancer = class _AxBalancer {
6216
6259
  getMetrics() {
6217
6260
  return this.currentService.getMetrics();
6218
6261
  }
6262
+ canRetryService() {
6263
+ const failure = this.serviceFailures.get(this.currentService.getId());
6264
+ if (!failure) return true;
6265
+ const { retries, lastFailureTime } = failure;
6266
+ const timeSinceLastFailure = Date.now() - lastFailureTime;
6267
+ const backoffMs = Math.min(
6268
+ this.initialBackoffMs * Math.pow(2, retries),
6269
+ this.maxBackoffMs
6270
+ );
6271
+ return timeSinceLastFailure >= backoffMs;
6272
+ }
6273
+ handleFailure() {
6274
+ const failure = this.serviceFailures.get(this.currentService.getId());
6275
+ const retries = (failure?.retries ?? 0) + 1;
6276
+ this.serviceFailures.set(this.currentService.getId(), {
6277
+ retries,
6278
+ lastFailureTime: Date.now()
6279
+ });
6280
+ if (this.debug) {
6281
+ console.warn(
6282
+ `AxBalancer: Service ${this.currentService.getName()} failed (retry ${retries}/${this.maxRetries})`
6283
+ );
6284
+ }
6285
+ if (retries >= this.maxRetries) {
6286
+ const gotNextService = this.getNextService();
6287
+ if (this.debug) {
6288
+ console.warn(
6289
+ `AxBalancer: Switching to service ${this.currentService.getName()}`
6290
+ );
6291
+ }
6292
+ return gotNextService;
6293
+ }
6294
+ return true;
6295
+ }
6296
+ handleSuccess() {
6297
+ this.serviceFailures.delete(this.currentService.getId());
6298
+ }
6219
6299
  async chat(req, options) {
6220
6300
  this.reset();
6221
6301
  while (true) {
6302
+ if (!this.canRetryService()) {
6303
+ if (!this.getNextService()) {
6304
+ throw new Error("All services exhausted");
6305
+ }
6306
+ continue;
6307
+ }
6222
6308
  try {
6223
- return await this.currentService.chat(req, options);
6309
+ const response = await this.currentService.chat(req, options);
6310
+ this.handleSuccess();
6311
+ return response;
6224
6312
  } catch (e) {
6225
6313
  if (!(e instanceof AxAIServiceError)) {
6226
6314
  throw e;
@@ -6241,38 +6329,29 @@ var AxBalancer = class _AxBalancer {
6241
6329
  default:
6242
6330
  throw e;
6243
6331
  }
6244
- if (this.debug) {
6245
- console.warn(
6246
- `AxBalancer: Service ${this.currentService.getName()} failed`,
6247
- e
6248
- );
6249
- }
6250
- if (!this.getNextService()) {
6332
+ if (!this.handleFailure()) {
6251
6333
  throw e;
6252
6334
  }
6253
- if (this.debug) {
6254
- console.warn(
6255
- `AxBalancer: Switching to service ${this.currentService.getName()}`
6256
- );
6257
- }
6258
6335
  }
6259
6336
  }
6260
6337
  }
6261
6338
  async embed(req, options) {
6262
6339
  this.reset();
6263
6340
  while (true) {
6341
+ if (!this.canRetryService()) {
6342
+ if (!this.getNextService()) {
6343
+ throw new Error("All services exhausted");
6344
+ }
6345
+ continue;
6346
+ }
6264
6347
  try {
6265
- return await this.currentService.embed(req, options);
6348
+ const response = await this.currentService.embed(req, options);
6349
+ this.handleSuccess();
6350
+ return response;
6266
6351
  } catch (e) {
6267
- if (this.debug) {
6268
- console.warn(`Service ${this.currentService.getName()} failed`);
6269
- }
6270
- if (!this.getNextService()) {
6352
+ if (!this.handleFailure()) {
6271
6353
  throw e;
6272
6354
  }
6273
- if (this.debug) {
6274
- console.warn(`Switching to service ${this.currentService.getName()}`);
6275
- }
6276
6355
  }
6277
6356
  }
6278
6357
  }
@@ -7765,6 +7844,7 @@ var AxEmbeddingAdapter = class {
7765
7844
  var AxMockAIService = class {
7766
7845
  constructor(config = {}) {
7767
7846
  this.config = config;
7847
+ this.config.id = this.config.id ?? crypto.randomUUID();
7768
7848
  }
7769
7849
  options = {};
7770
7850
  metrics = {
@@ -7780,6 +7860,9 @@ var AxMockAIService = class {
7780
7860
  getName() {
7781
7861
  return this.config.name ?? "mock-ai-service";
7782
7862
  }
7863
+ getId() {
7864
+ return this.config.id ?? "mock-ai-service-id";
7865
+ }
7783
7866
  getModelInfo() {
7784
7867
  return {
7785
7868
  name: "mock-model",
@@ -7935,6 +8018,7 @@ export {
7935
8018
  AxAIMistralModel,
7936
8019
  AxAIOllama,
7937
8020
  AxAIOpenAI,
8021
+ AxAIOpenAIBase,
7938
8022
  AxAIOpenAIEmbedModel,
7939
8023
  AxAIOpenAIModel,
7940
8024
  AxAIReka,