@ax-llm/ax 10.0.45 → 10.0.47

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
@@ -182,7 +182,6 @@ var AxSpanKindValues = /* @__PURE__ */ ((AxSpanKindValues2) => {
182
182
  })(AxSpanKindValues || {});
183
183
 
184
184
  // util/apicall.ts
185
- var import_path = __toESM(require("path"), 1);
186
185
  var import_web3 = require("stream/web");
187
186
  var import_api = require("@opentelemetry/api");
188
187
 
@@ -310,7 +309,6 @@ var defaultRetryConfig = {
310
309
  maxRetries: 3,
311
310
  initialDelayMs: 1e3,
312
311
  maxDelayMs: 6e4,
313
- // Increased to 60 seconds
314
312
  backoffFactor: 2,
315
313
  retryableStatusCodes: [500, 408, 429, 502, 503, 504]
316
314
  };
@@ -321,18 +319,19 @@ var AxAIServiceError = class extends Error {
321
319
  super(message);
322
320
  this.url = url;
323
321
  this.requestBody = requestBody;
324
- this.context = context;
325
322
  this.name = "AxAIServiceError";
326
323
  this.timestamp = (/* @__PURE__ */ new Date()).toISOString();
327
324
  this.errorId = crypto.randomUUID();
325
+ this.context = context;
328
326
  }
329
327
  timestamp;
330
328
  errorId;
329
+ context;
331
330
  toString() {
332
331
  return `${this.name} [${this.errorId}]: ${this.message}
333
332
  Timestamp: ${this.timestamp}
334
333
  URL: ${this.url}${this.requestBody ? `
335
- Request Body: ${JSON.stringify(this.requestBody, null, 2)}` : ""}${this.context ? `
334
+ Request Body: ${JSON.stringify(this.requestBody, null, 2)}` : ""}${Object.keys(this.context).length ? `
336
335
  Context: ${JSON.stringify(this.context, null, 2)}` : ""}`;
337
336
  }
338
337
  toJSON() {
@@ -420,14 +419,31 @@ function updateRetryMetrics(metrics) {
420
419
  metrics.retryCount++;
421
420
  metrics.lastRetryTime = Date.now();
422
421
  }
422
+ function shouldRetry(error, status, attempt, config) {
423
+ if (attempt >= config.maxRetries) return false;
424
+ if (status && config.retryableStatusCodes.includes(status)) return true;
425
+ return error instanceof AxAIServiceNetworkError && !(error instanceof AxAIServiceAuthenticationError);
426
+ }
423
427
  var apiCall = async (api, json) => {
424
428
  const retryConfig = { ...defaultRetryConfig, ...api.retry };
425
429
  const timeoutMs = api.timeout ?? defaultTimeoutMs;
426
430
  const metrics = createRequestMetrics();
431
+ let timeoutId;
427
432
  const baseUrl = new URL(process.env["PROXY"] ?? api.url);
428
- const apiPath = import_path.default.join(baseUrl.pathname, api.name ?? "/", baseUrl.search);
433
+ const apiPath = [baseUrl.pathname, api.name].filter(Boolean).join("/").replace(/\/+/g, "/");
429
434
  const apiUrl = new URL(apiPath, baseUrl);
430
435
  const requestId = crypto.randomUUID();
436
+ if (api.validateRequest) {
437
+ const isValid = await api.validateRequest(json);
438
+ if (!isValid) {
439
+ throw new AxAIServiceResponseError(
440
+ "Invalid request data",
441
+ apiUrl.href,
442
+ json,
443
+ { validation: "request" }
444
+ );
445
+ }
446
+ }
431
447
  if (api.span?.isRecording()) {
432
448
  api.span.setAttributes({
433
449
  "http.request.method": api.put ? "PUT" : "POST",
@@ -439,7 +455,7 @@ var apiCall = async (api, json) => {
439
455
  let attempt = 0;
440
456
  while (true) {
441
457
  const controller = new AbortController();
442
- let timeoutId = setTimeout(() => {
458
+ timeoutId = setTimeout(() => {
443
459
  controller.abort("Request timeout");
444
460
  }, timeoutMs);
445
461
  try {
@@ -458,7 +474,7 @@ var apiCall = async (api, json) => {
458
474
  if (res.status === 401 || res.status === 403) {
459
475
  throw new AxAIServiceAuthenticationError(apiUrl.href, json, { metrics });
460
476
  }
461
- if (res.status >= 400 && attempt < retryConfig.maxRetries && retryConfig.retryableStatusCodes.includes(res.status)) {
477
+ if (res.status >= 400 && shouldRetry(new Error(), res.status, attempt, retryConfig)) {
462
478
  const delay = calculateRetryDelay(attempt, retryConfig);
463
479
  attempt++;
464
480
  updateRetryMetrics(metrics);
@@ -472,7 +488,7 @@ var apiCall = async (api, json) => {
472
488
  "metrics.lastRetryTime": metrics.lastRetryTime
473
489
  });
474
490
  }
475
- clearTimeout(timeoutId);
491
+ await new Promise((resolve) => setTimeout(resolve, delay));
476
492
  continue;
477
493
  }
478
494
  if (res.status >= 400) {
@@ -486,6 +502,17 @@ var apiCall = async (api, json) => {
486
502
  }
487
503
  if (!api.stream) {
488
504
  const resJson = await res.json();
505
+ if (api.validateResponse) {
506
+ const isValid = await api.validateResponse(resJson);
507
+ if (!isValid) {
508
+ throw new AxAIServiceResponseError(
509
+ "Invalid response data",
510
+ apiUrl.href,
511
+ json,
512
+ { validation: "response" }
513
+ );
514
+ }
515
+ }
489
516
  if (api.span?.isRecording()) {
490
517
  api.span.setAttributes({
491
518
  "response.time": Date.now() - metrics.startTime,
@@ -504,7 +531,7 @@ var apiCall = async (api, json) => {
504
531
  }
505
532
  let lastChunk;
506
533
  let chunkCount = 0;
507
- const trackingStream = new TransformStream({
534
+ const trackingStream = new import_web3.TransformStream({
508
535
  transform(chunk, controller2) {
509
536
  lastChunk = chunk;
510
537
  chunkCount++;
@@ -512,7 +539,7 @@ var apiCall = async (api, json) => {
512
539
  metrics.lastChunkTime = Date.now();
513
540
  controller2.enqueue(chunk);
514
541
  },
515
- flush(controller2) {
542
+ flush() {
516
543
  if (api.span?.isRecording()) {
517
544
  api.span.setAttributes({
518
545
  "stream.chunks": chunkCount,
@@ -520,10 +547,10 @@ var apiCall = async (api, json) => {
520
547
  "response.retries": metrics.retryCount
521
548
  });
522
549
  }
523
- controller2.terminate();
524
550
  }
525
551
  });
526
- const wrappedStream = new import_web3.ReadableStream({
552
+ let closed = false;
553
+ return new import_web3.ReadableStream({
527
554
  start(controller2) {
528
555
  const reader = res.body.pipeThrough(new textDecoderStream()).pipeThrough(new SSEParser()).pipeThrough(trackingStream).getReader();
529
556
  async function read() {
@@ -531,11 +558,14 @@ var apiCall = async (api, json) => {
531
558
  while (true) {
532
559
  const { done, value } = await reader.read();
533
560
  if (done) {
534
- controller2.close();
561
+ if (!closed) {
562
+ closed = true;
563
+ controller2.close();
564
+ }
535
565
  break;
536
- } else {
537
- controller2.enqueue(value);
538
566
  }
567
+ if (closed) break;
568
+ controller2.enqueue(value);
539
569
  }
540
570
  } catch (e) {
541
571
  const error = e;
@@ -552,26 +582,42 @@ var apiCall = async (api, json) => {
552
582
  { streamMetrics }
553
583
  )
554
584
  );
555
- } else {
585
+ } else if (error instanceof TypeError && error.message.includes("cancelled")) {
556
586
  controller2.error(
557
- new AxAIServiceResponseError(
558
- `Stream processing error: ${error.message}`,
587
+ new AxAIServiceStreamTerminatedError(
559
588
  apiUrl.href,
560
589
  json,
561
- { streamMetrics }
590
+ lastChunk,
591
+ {
592
+ streamMetrics,
593
+ cancelReason: "Stream cancelled by client"
594
+ }
562
595
  )
563
596
  );
597
+ } else {
598
+ controller2.error(
599
+ new AxAIServiceNetworkError(error, apiUrl.href, json, {
600
+ streamMetrics
601
+ })
602
+ );
564
603
  }
604
+ throw error;
565
605
  } finally {
606
+ clearTimeout(timeoutId);
566
607
  reader.releaseLock();
608
+ if (api.span?.isRecording()) {
609
+ api.span.end();
610
+ }
567
611
  }
568
612
  }
569
613
  read();
614
+ },
615
+ // When the consumer cancels the stream, set our flag to stop processing further.
616
+ cancel() {
617
+ closed = true;
570
618
  }
571
619
  });
572
- return wrappedStream;
573
620
  } catch (error) {
574
- clearTimeout(timeoutId);
575
621
  if (error instanceof Error && error.name === "AbortError") {
576
622
  throw new AxAIServiceTimeoutError(apiUrl.href, timeoutMs, json, {
577
623
  metrics
@@ -584,7 +630,7 @@ var apiCall = async (api, json) => {
584
630
  "error.retries": metrics.retryCount
585
631
  });
586
632
  }
587
- if (error instanceof AxAIServiceNetworkError && attempt < retryConfig.maxRetries) {
633
+ if (error instanceof AxAIServiceNetworkError && shouldRetry(error, void 0, attempt, retryConfig)) {
588
634
  const delay = calculateRetryDelay(attempt, retryConfig);
589
635
  attempt++;
590
636
  updateRetryMetrics(metrics);
@@ -598,12 +644,20 @@ var apiCall = async (api, json) => {
598
644
  "metrics.lastRetryTime": metrics.lastRetryTime
599
645
  });
600
646
  }
647
+ await new Promise((resolve) => setTimeout(resolve, delay));
601
648
  continue;
602
649
  }
603
650
  if (error instanceof AxAIServiceError) {
604
651
  error.context["metrics"] = metrics;
605
652
  }
606
653
  throw error;
654
+ } finally {
655
+ if (timeoutId !== void 0) {
656
+ clearTimeout(timeoutId);
657
+ }
658
+ if (api.span?.isRecording()) {
659
+ api.span.end();
660
+ }
607
661
  }
608
662
  }
609
663
  };
@@ -1158,8 +1212,6 @@ var import_google_auth_library = require("google-auth-library");
1158
1212
  var GoogleVertexAuth = class {
1159
1213
  auth;
1160
1214
  client;
1161
- currentToken;
1162
- tokenExpiry;
1163
1215
  constructor(config = {}) {
1164
1216
  this.auth = new import_google_auth_library.GoogleAuth({
1165
1217
  scopes: ["https://www.googleapis.com/auth/cloud-platform"],
@@ -1173,36 +1225,12 @@ var GoogleVertexAuth = class {
1173
1225
  return this.client;
1174
1226
  }
1175
1227
  async getAccessToken() {
1176
- if (this.currentToken && this.tokenExpiry && Date.now() < this.tokenExpiry) {
1177
- return this.currentToken;
1178
- }
1179
1228
  const client = await this.getAuthenticatedClient();
1180
- const tokenResponse = await client.getAccessToken();
1181
- this.currentToken = tokenResponse.token;
1182
- const expiry = this.getExpiry(tokenResponse);
1183
- const tenMinutes = 10 * 60 * 1e3;
1184
- this.tokenExpiry = expiry - tenMinutes;
1185
- return this.currentToken;
1186
- }
1187
- /**
1188
- * Get the expiry date from the token response.
1189
- */
1190
- getExpiry(tokenResponse) {
1191
- const oneHour = 3600 * 1e3;
1192
- let expiry = Date.now() + oneHour;
1193
- let responseExpiry = tokenResponse.res?.data?.expiry_date;
1194
- if (responseExpiry) {
1195
- if (typeof responseExpiry === "number") {
1196
- expiry = responseExpiry;
1197
- } else if (responseExpiry instanceof Date) {
1198
- expiry = responseExpiry.getTime();
1199
- } else if (typeof responseExpiry === "string") {
1200
- expiry = new Date(responseExpiry).getTime();
1201
- } else {
1202
- console.warn("Unknown expiry type", responseExpiry);
1203
- }
1229
+ const response = await client.getAccessToken();
1230
+ if (!response.token) {
1231
+ throw new Error("Failed to obtain access token");
1204
1232
  }
1205
- return expiry;
1233
+ return response.token;
1206
1234
  }
1207
1235
  };
1208
1236
 
@@ -1679,8 +1707,9 @@ function mapFinishReason(stopReason) {
1679
1707
 
1680
1708
  // ai/openai/types.ts
1681
1709
  var AxAIOpenAIModel = /* @__PURE__ */ ((AxAIOpenAIModel2) => {
1682
- AxAIOpenAIModel2["O1Preview"] = "o1-preview";
1710
+ AxAIOpenAIModel2["O1"] = "o1";
1683
1711
  AxAIOpenAIModel2["O1Mini"] = "o1-mini";
1712
+ AxAIOpenAIModel2["O3Mini"] = "o3-mini";
1684
1713
  AxAIOpenAIModel2["GPT4"] = "gpt-4";
1685
1714
  AxAIOpenAIModel2["GPT4O"] = "gpt-4o";
1686
1715
  AxAIOpenAIModel2["GPT4OMini"] = "gpt-4o-mini";
@@ -1703,7 +1732,7 @@ var AxAIOpenAIEmbedModel = /* @__PURE__ */ ((AxAIOpenAIEmbedModel2) => {
1703
1732
  // ai/openai/info.ts
1704
1733
  var axModelInfoOpenAI = [
1705
1734
  {
1706
- name: "o1-preview" /* O1Preview */,
1735
+ name: "o1" /* O1 */,
1707
1736
  currency: "usd",
1708
1737
  promptTokenCostPer1M: 15,
1709
1738
  completionTokenCostPer1M: 60
@@ -1711,8 +1740,14 @@ var axModelInfoOpenAI = [
1711
1740
  {
1712
1741
  name: "o1-mini" /* O1Mini */,
1713
1742
  currency: "usd",
1714
- promptTokenCostPer1M: 3,
1715
- completionTokenCostPer1M: 12
1743
+ promptTokenCostPer1M: 1.1,
1744
+ completionTokenCostPer1M: 14.4
1745
+ },
1746
+ {
1747
+ name: "o3-mini" /* O3Mini */,
1748
+ currency: "usd",
1749
+ promptTokenCostPer1M: 1.1,
1750
+ completionTokenCostPer1M: 4.4
1716
1751
  },
1717
1752
  {
1718
1753
  name: "gpt-4" /* GPT4 */,
@@ -1812,16 +1847,12 @@ var AxAIOpenAIImpl = class {
1812
1847
  parameters: v.parameters
1813
1848
  }
1814
1849
  }));
1815
- if (tools && isO1Model(model)) {
1816
- throw new Error("Functions are not supported for O1 models");
1817
- }
1818
1850
  const toolsChoice = !req.functionCall && req.functions && req.functions.length > 0 ? "auto" : req.functionCall;
1819
1851
  const messages = createMessages2(req);
1820
1852
  const frequencyPenalty = req.modelConfig?.frequencyPenalty ?? this.config.frequencyPenalty;
1821
1853
  const stream = req.modelConfig?.stream ?? this.config.stream;
1822
- if (stream && isO1Model(model)) {
1823
- throw new Error("Streaming is not supported for O1 models");
1824
- }
1854
+ const reasoningEffort = isReasoningModel(model) ? this.config.reasoningEffort : void 0;
1855
+ const store = this.config.store;
1825
1856
  const reqValue = {
1826
1857
  model,
1827
1858
  messages,
@@ -1836,7 +1867,9 @@ var AxAIOpenAIImpl = class {
1836
1867
  presence_penalty: req.modelConfig?.presencePenalty ?? this.config.presencePenalty,
1837
1868
  logit_bias: this.config.logitBias,
1838
1869
  ...frequencyPenalty ? { frequency_penalty: frequencyPenalty } : {},
1839
- ...stream && this.streamingUsage ? { stream: true, stream_options: { include_usage: true } } : {}
1870
+ ...stream && this.streamingUsage ? { stream: true, stream_options: { include_usage: true } } : {},
1871
+ ...reasoningEffort ? { reasoning_effort: reasoningEffort } : {},
1872
+ ...store ? { store } : {}
1840
1873
  };
1841
1874
  return [apiConfig, reqValue];
1842
1875
  }
@@ -1962,12 +1995,6 @@ var mapFinishReason2 = (finishReason) => {
1962
1995
  };
1963
1996
  function createMessages2(req) {
1964
1997
  return req.chatPrompt.map((msg) => {
1965
- if (msg.role === "system" && isO1Model(req.model)) {
1966
- msg = {
1967
- role: "user",
1968
- content: msg.content
1969
- };
1970
- }
1971
1998
  switch (msg.role) {
1972
1999
  case "system":
1973
2000
  return { role: "system", content: msg.content };
@@ -2057,14 +2084,14 @@ var AxAIOpenAI = class extends AxBaseAI {
2057
2084
  embedModel: _config.embedModel
2058
2085
  },
2059
2086
  options,
2060
- supportFor: (model) => {
2061
- return isO1Model(model) ? { functions: false, streaming: false } : { functions: true, streaming: true };
2087
+ supportFor: () => {
2088
+ return { functions: true, streaming: true };
2062
2089
  },
2063
2090
  modelMap
2064
2091
  });
2065
2092
  }
2066
2093
  };
2067
- var isO1Model = (model) => ["o1-mini" /* O1Mini */, "o1-preview" /* O1Preview */].includes(
2094
+ var isReasoningModel = (model) => ["o1-mini" /* O1Mini */, "o1" /* O1 */, "o3-mini" /* O3Mini */].includes(
2068
2095
  model
2069
2096
  );
2070
2097
 
@@ -5309,8 +5336,10 @@ function* streamValues(sig, values, xstate, content, final = false) {
5309
5336
  const v = content.substring(s);
5310
5337
  const v1 = v.replace(/[\s\n\t]+$/, "");
5311
5338
  const v2 = pos === 0 ? v1.trimStart() : v1;
5312
- yield { [fieldName]: v2 };
5313
- xstate.streamedIndex[fieldName] = pos + v1.length;
5339
+ if (v2.length > 0) {
5340
+ yield { [fieldName]: v2 };
5341
+ xstate.streamedIndex[fieldName] = pos + v1.length;
5342
+ }
5314
5343
  return;
5315
5344
  }
5316
5345
  }
@@ -5319,7 +5348,7 @@ function* streamValues(sig, values, xstate, content, final = false) {
5319
5348
  if (Array.isArray(value)) {
5320
5349
  const s = xstate.streamedIndex[key] ?? 0;
5321
5350
  const v = value.slice(s);
5322
- if (v) {
5351
+ if (v && v.length > 0) {
5323
5352
  yield { [key]: v };
5324
5353
  xstate.streamedIndex[key] = s + 1;
5325
5354
  }
@@ -5415,7 +5444,7 @@ var extractBlock = (input) => {
5415
5444
  // dsp/jsonschema.ts
5416
5445
  var validateJSONSchema = (schema) => {
5417
5446
  const errors = [];
5418
- const validateSchemaObject = (schema2, path2 = "") => {
5447
+ const validateSchemaObject = (schema2, path = "") => {
5419
5448
  const validTypes = [
5420
5449
  "array",
5421
5450
  "integer",
@@ -5426,31 +5455,31 @@ var validateJSONSchema = (schema) => {
5426
5455
  "object"
5427
5456
  ];
5428
5457
  if (!validTypes.includes(schema2.type)) {
5429
- errors.push(`Invalid type '${schema2.type}' at ${path2 || "root"}`);
5458
+ errors.push(`Invalid type '${schema2.type}' at ${path || "root"}`);
5430
5459
  return;
5431
5460
  }
5432
5461
  if (schema2.type === "object" && schema2.properties) {
5433
5462
  if (typeof schema2.properties !== "object" || Array.isArray(schema2.properties)) {
5434
- errors.push(`Invalid properties object at ${path2 || "root"}`);
5463
+ errors.push(`Invalid properties object at ${path || "root"}`);
5435
5464
  } else {
5436
5465
  for (const key in schema2.properties) {
5437
5466
  const value = schema2.properties[key];
5438
5467
  if (typeof value !== "object") {
5439
- errors.push(`Invalid schema object at ${path2}${key}`);
5468
+ errors.push(`Invalid schema object at ${path}${key}`);
5440
5469
  continue;
5441
5470
  }
5442
- validateSchemaObject(value, `${path2}${key}.`);
5471
+ validateSchemaObject(value, `${path}${key}.`);
5443
5472
  }
5444
5473
  }
5445
5474
  if (schema2.required && !Array.isArray(schema2.required)) {
5446
- errors.push(`'required' should be an array at ${path2 || "root"}`);
5475
+ errors.push(`'required' should be an array at ${path || "root"}`);
5447
5476
  }
5448
5477
  }
5449
5478
  if (schema2.type === "array" && schema2.items) {
5450
5479
  if (typeof schema2.items !== "object") {
5451
- errors.push(`Invalid items schema at ${path2 || "root"}`);
5480
+ errors.push(`Invalid items schema at ${path || "root"}`);
5452
5481
  } else {
5453
- validateSchemaObject(schema2.items, `${path2}items.`);
5482
+ validateSchemaObject(schema2.items, `${path}items.`);
5454
5483
  }
5455
5484
  }
5456
5485
  };
@@ -5834,6 +5863,7 @@ var AxGen = class extends AxProgramWithSignature {
5834
5863
  const e1 = e;
5835
5864
  errorFields = e1.getFixingInstructions();
5836
5865
  err = e;
5866
+ } else if (e instanceof AxAIServiceStreamTerminatedError) {
5837
5867
  } else {
5838
5868
  throw e;
5839
5869
  }
@@ -6097,6 +6127,7 @@ var AxBalancer = class _AxBalancer {
6097
6127
  services;
6098
6128
  currentServiceIndex = 0;
6099
6129
  currentService;
6130
+ debug;
6100
6131
  constructor(services, options) {
6101
6132
  if (services.length === 0) {
6102
6133
  throw new Error("No AI services provided.");
@@ -6109,6 +6140,7 @@ var AxBalancer = class _AxBalancer {
6109
6140
  throw new Error("Error initializing the AI services.");
6110
6141
  }
6111
6142
  this.currentService = cs;
6143
+ this.debug = options?.debug ?? true;
6112
6144
  }
6113
6145
  /**
6114
6146
  * Service comparator that respects the input order of services.
@@ -6183,16 +6215,20 @@ var AxBalancer = class _AxBalancer {
6183
6215
  default:
6184
6216
  throw e;
6185
6217
  }
6186
- console.warn(
6187
- `AxBalancer: Service ${this.currentService.getName()} failed`,
6188
- e
6189
- );
6218
+ if (this.debug) {
6219
+ console.warn(
6220
+ `AxBalancer: Service ${this.currentService.getName()} failed`,
6221
+ e
6222
+ );
6223
+ }
6190
6224
  if (!this.getNextService()) {
6191
6225
  throw e;
6192
6226
  }
6193
- console.warn(
6194
- `AxBalancer: Switching to service ${this.currentService.getName()}`
6195
- );
6227
+ if (this.debug) {
6228
+ console.warn(
6229
+ `AxBalancer: Switching to service ${this.currentService.getName()}`
6230
+ );
6231
+ }
6196
6232
  }
6197
6233
  }
6198
6234
  }
@@ -6202,11 +6238,15 @@ var AxBalancer = class _AxBalancer {
6202
6238
  try {
6203
6239
  return await this.currentService.embed(req, options);
6204
6240
  } catch (e) {
6205
- console.warn(`Service ${this.currentService.getName()} failed`);
6241
+ if (this.debug) {
6242
+ console.warn(`Service ${this.currentService.getName()} failed`);
6243
+ }
6206
6244
  if (!this.getNextService()) {
6207
6245
  throw e;
6208
6246
  }
6209
- console.warn(`Switching to service ${this.currentService.getName()}`);
6247
+ if (this.debug) {
6248
+ console.warn(`Switching to service ${this.currentService.getName()}`);
6249
+ }
6210
6250
  }
6211
6251
  }
6212
6252
  }