@ax-llm/ax 11.0.0 → 11.0.2

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
  }
@@ -5959,6 +5992,7 @@ var AxAgent = class {
5959
5992
  program;
5960
5993
  functions;
5961
5994
  agents;
5995
+ disableSmartModelRouting;
5962
5996
  name;
5963
5997
  description;
5964
5998
  subAgentList;
@@ -5974,6 +6008,7 @@ var AxAgent = class {
5974
6008
  this.ai = ai;
5975
6009
  this.agents = agents;
5976
6010
  this.functions = functions;
6011
+ this.disableSmartModelRouting = options?.disableSmartModelRouting;
5977
6012
  this.signature = new AxSignature(signature);
5978
6013
  this.signature.setDescription(description);
5979
6014
  if (!name || name.length < 5) {
@@ -6000,7 +6035,7 @@ var AxAgent = class {
6000
6035
  func: () => this.forward
6001
6036
  };
6002
6037
  const mm = ai?.getModelList();
6003
- if (mm) {
6038
+ if (mm && !this.disableSmartModelRouting) {
6004
6039
  this.func.parameters = addModelParameter(this.func.parameters, mm);
6005
6040
  }
6006
6041
  }
@@ -6040,11 +6075,16 @@ var AxAgent = class {
6040
6075
  func: wrappedFunc
6041
6076
  };
6042
6077
  }
6078
+ getFeatures() {
6079
+ return {
6080
+ canConfigureSmartModelRouting: this.ai !== void 0
6081
+ };
6082
+ }
6043
6083
  init(parentAi, options) {
6044
6084
  const ai = this.ai ?? parentAi;
6045
6085
  const mm = ai?.getModelList();
6046
6086
  const agentFuncs = this.agents?.map((a) => a.getFunction())?.map(
6047
- (f) => mm ? { ...f, parameters: addModelParameter(f.parameters, mm) } : f
6087
+ (f) => mm && !this.disableSmartModelRouting && this.agents?.find((a) => a.getFunction().name === f.name)?.getFeatures().canConfigureSmartModelRouting ? { ...f, parameters: addModelParameter(f.parameters, mm) } : f
6048
6088
  );
6049
6089
  const functions = [
6050
6090
  ...options?.functions ?? this.functions ?? [],
@@ -6154,6 +6194,10 @@ var AxBalancer = class _AxBalancer {
6154
6194
  currentServiceIndex = 0;
6155
6195
  currentService;
6156
6196
  debug;
6197
+ initialBackoffMs;
6198
+ maxBackoffMs;
6199
+ maxRetries;
6200
+ serviceFailures = /* @__PURE__ */ new Map();
6157
6201
  constructor(services, options) {
6158
6202
  if (services.length === 0) {
6159
6203
  throw new Error("No AI services provided.");
@@ -6167,6 +6211,9 @@ var AxBalancer = class _AxBalancer {
6167
6211
  }
6168
6212
  this.currentService = cs;
6169
6213
  this.debug = options?.debug ?? true;
6214
+ this.initialBackoffMs = options?.initialBackoffMs ?? 1e3;
6215
+ this.maxBackoffMs = options?.maxBackoffMs ?? 32e3;
6216
+ this.maxRetries = options?.maxRetries ?? 3;
6170
6217
  }
6171
6218
  /**
6172
6219
  * Service comparator that respects the input order of services.
@@ -6183,7 +6230,7 @@ var AxBalancer = class _AxBalancer {
6183
6230
  return aTotalCost - bTotalCost;
6184
6231
  };
6185
6232
  getModelList() {
6186
- throw new Error("Method not implemented.");
6233
+ return this.currentService.getModelList();
6187
6234
  }
6188
6235
  getNextService() {
6189
6236
  const cs = this.services[++this.currentServiceIndex];
@@ -6204,6 +6251,9 @@ var AxBalancer = class _AxBalancer {
6204
6251
  getName() {
6205
6252
  return this.currentService.getName();
6206
6253
  }
6254
+ getId() {
6255
+ return this.currentService.getId();
6256
+ }
6207
6257
  getModelInfo() {
6208
6258
  return this.currentService.getModelInfo();
6209
6259
  }
@@ -6216,11 +6266,56 @@ var AxBalancer = class _AxBalancer {
6216
6266
  getMetrics() {
6217
6267
  return this.currentService.getMetrics();
6218
6268
  }
6269
+ canRetryService() {
6270
+ const failure = this.serviceFailures.get(this.currentService.getId());
6271
+ if (!failure) return true;
6272
+ const { retries, lastFailureTime } = failure;
6273
+ const timeSinceLastFailure = Date.now() - lastFailureTime;
6274
+ const backoffMs = Math.min(
6275
+ this.initialBackoffMs * Math.pow(2, retries),
6276
+ this.maxBackoffMs
6277
+ );
6278
+ return timeSinceLastFailure >= backoffMs;
6279
+ }
6280
+ handleFailure() {
6281
+ const failure = this.serviceFailures.get(this.currentService.getId());
6282
+ const retries = (failure?.retries ?? 0) + 1;
6283
+ this.serviceFailures.set(this.currentService.getId(), {
6284
+ retries,
6285
+ lastFailureTime: Date.now()
6286
+ });
6287
+ if (this.debug) {
6288
+ console.warn(
6289
+ `AxBalancer: Service ${this.currentService.getName()} failed (retry ${retries}/${this.maxRetries})`
6290
+ );
6291
+ }
6292
+ if (retries >= this.maxRetries) {
6293
+ const gotNextService = this.getNextService();
6294
+ if (this.debug) {
6295
+ console.warn(
6296
+ `AxBalancer: Switching to service ${this.currentService.getName()}`
6297
+ );
6298
+ }
6299
+ return gotNextService;
6300
+ }
6301
+ return true;
6302
+ }
6303
+ handleSuccess() {
6304
+ this.serviceFailures.delete(this.currentService.getId());
6305
+ }
6219
6306
  async chat(req, options) {
6220
6307
  this.reset();
6221
6308
  while (true) {
6309
+ if (!this.canRetryService()) {
6310
+ if (!this.getNextService()) {
6311
+ throw new Error("All services exhausted");
6312
+ }
6313
+ continue;
6314
+ }
6222
6315
  try {
6223
- return await this.currentService.chat(req, options);
6316
+ const response = await this.currentService.chat(req, options);
6317
+ this.handleSuccess();
6318
+ return response;
6224
6319
  } catch (e) {
6225
6320
  if (!(e instanceof AxAIServiceError)) {
6226
6321
  throw e;
@@ -6241,38 +6336,29 @@ var AxBalancer = class _AxBalancer {
6241
6336
  default:
6242
6337
  throw e;
6243
6338
  }
6244
- if (this.debug) {
6245
- console.warn(
6246
- `AxBalancer: Service ${this.currentService.getName()} failed`,
6247
- e
6248
- );
6249
- }
6250
- if (!this.getNextService()) {
6339
+ if (!this.handleFailure()) {
6251
6340
  throw e;
6252
6341
  }
6253
- if (this.debug) {
6254
- console.warn(
6255
- `AxBalancer: Switching to service ${this.currentService.getName()}`
6256
- );
6257
- }
6258
6342
  }
6259
6343
  }
6260
6344
  }
6261
6345
  async embed(req, options) {
6262
6346
  this.reset();
6263
6347
  while (true) {
6348
+ if (!this.canRetryService()) {
6349
+ if (!this.getNextService()) {
6350
+ throw new Error("All services exhausted");
6351
+ }
6352
+ continue;
6353
+ }
6264
6354
  try {
6265
- return await this.currentService.embed(req, options);
6355
+ const response = await this.currentService.embed(req, options);
6356
+ this.handleSuccess();
6357
+ return response;
6266
6358
  } catch (e) {
6267
- if (this.debug) {
6268
- console.warn(`Service ${this.currentService.getName()} failed`);
6269
- }
6270
- if (!this.getNextService()) {
6359
+ if (!this.handleFailure()) {
6271
6360
  throw e;
6272
6361
  }
6273
- if (this.debug) {
6274
- console.warn(`Switching to service ${this.currentService.getName()}`);
6275
- }
6276
6362
  }
6277
6363
  }
6278
6364
  }
@@ -7765,6 +7851,7 @@ var AxEmbeddingAdapter = class {
7765
7851
  var AxMockAIService = class {
7766
7852
  constructor(config = {}) {
7767
7853
  this.config = config;
7854
+ this.config.id = this.config.id ?? crypto.randomUUID();
7768
7855
  }
7769
7856
  options = {};
7770
7857
  metrics = {
@@ -7780,6 +7867,9 @@ var AxMockAIService = class {
7780
7867
  getName() {
7781
7868
  return this.config.name ?? "mock-ai-service";
7782
7869
  }
7870
+ getId() {
7871
+ return this.config.id ?? "mock-ai-service-id";
7872
+ }
7783
7873
  getModelInfo() {
7784
7874
  return {
7785
7875
  name: "mock-model",
@@ -7935,6 +8025,7 @@ export {
7935
8025
  AxAIMistralModel,
7936
8026
  AxAIOllama,
7937
8027
  AxAIOpenAI,
8028
+ AxAIOpenAIBase,
7938
8029
  AxAIOpenAIEmbedModel,
7939
8030
  AxAIOpenAIModel,
7940
8031
  AxAIReka,