@axlsdk/axl 0.17.9 → 0.18.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/dist/index.js CHANGED
@@ -142,27 +142,180 @@ function sleep2(ms, signal) {
142
142
  );
143
143
  });
144
144
  }
145
- async function fetchWithRetry(input, init, maxRetries = MAX_RETRIES) {
146
- for (let attempt = 0; ; attempt++) {
147
- const res = await fetch(input, init);
148
- if (res.ok || !RETRYABLE_STATUS_CODES.has(res.status) || attempt >= maxRetries) {
149
- return res;
150
- }
151
- if (init?.signal?.aborted) {
152
- return res;
153
- }
154
- const retryAfter = res.headers.get("retry-after");
155
- let delay;
156
- if (retryAfter && !isNaN(Number(retryAfter))) {
157
- delay = Number(retryAfter) * 1e3;
158
- } else {
159
- delay = BASE_DELAY_MS * 2 ** attempt;
145
+ async function fetchWithRetry(input, init, opts) {
146
+ const maxRetries = opts?.maxRetries ?? MAX_RETRIES;
147
+ const governor = opts?.governor;
148
+ let acquired = false;
149
+ if (governor) {
150
+ await governor.acquire(init?.signal ?? void 0);
151
+ acquired = true;
152
+ }
153
+ try {
154
+ for (let attempt = 0; ; attempt++) {
155
+ const res = await fetch(input, init);
156
+ governor?.observe(res);
157
+ if (res.ok || !RETRYABLE_STATUS_CODES.has(res.status) || attempt >= maxRetries) {
158
+ return res;
159
+ }
160
+ if (init?.signal?.aborted) {
161
+ return res;
162
+ }
163
+ const retryAfter = res.headers.get("retry-after");
164
+ let delay;
165
+ if (retryAfter && !isNaN(Number(retryAfter))) {
166
+ delay = Number(retryAfter) * 1e3;
167
+ } else {
168
+ delay = BASE_DELAY_MS * 2 ** attempt;
169
+ }
170
+ delay *= 0.75 + Math.random() * 0.5;
171
+ await sleep2(delay, init?.signal ?? void 0);
160
172
  }
161
- delay *= 0.75 + Math.random() * 0.5;
162
- await sleep2(delay, init?.signal ?? void 0);
173
+ } finally {
174
+ if (acquired) governor.release();
163
175
  }
164
176
  }
165
177
 
178
+ // src/providers/rate-limiter.ts
179
+ function abortError() {
180
+ return Object.assign(new Error("The operation was aborted"), { name: "AbortError" });
181
+ }
182
+ var RateLimiter = class {
183
+ maxConcurrent;
184
+ minIntervalMs;
185
+ acquireTimeoutMs;
186
+ active = 0;
187
+ // `-Infinity` (not 0) so the FIRST grant is always immediate regardless of the
188
+ // wall clock: `Date.now() - (-Infinity) === Infinity`, which always satisfies
189
+ // `minIntervalMs`. Initializing to 0 would (only under a mocked/near-zero clock)
190
+ // wrongly delay the first grant by a full interval, since the limiter has never
191
+ // actually granted anything yet.
192
+ lastGrantAt = Number.NEGATIVE_INFINITY;
193
+ queue = [];
194
+ spacingTimer;
195
+ warnedQueued = false;
196
+ constructor(config = {}) {
197
+ const mc = config.maxConcurrent;
198
+ if (mc == null) {
199
+ this.maxConcurrent = Infinity;
200
+ } else if (!Number.isFinite(mc) || mc < 1) {
201
+ console.warn(
202
+ `[axl] RateLimiter: ignoring invalid maxConcurrent (${mc}); expected an integer >= 1. No concurrency cap applied.`
203
+ );
204
+ this.maxConcurrent = Infinity;
205
+ } else {
206
+ this.maxConcurrent = Math.floor(mc);
207
+ if (this.maxConcurrent < 2) {
208
+ console.warn(
209
+ `[axl] RateLimiter: maxConcurrent=${this.maxConcurrent} serializes every request to this provider. Nested same-provider calls still complete (permits aren't held across a nested ask), but throughput is a floor, not a guarantee.`
210
+ );
211
+ }
212
+ }
213
+ this.minIntervalMs = config.minIntervalMs != null && Number.isFinite(config.minIntervalMs) && config.minIntervalMs > 0 ? config.minIntervalMs : 0;
214
+ this.acquireTimeoutMs = config.acquireTimeoutMs != null && Number.isFinite(config.acquireTimeoutMs) && config.acquireTimeoutMs > 0 ? config.acquireTimeoutMs : void 0;
215
+ }
216
+ /**
217
+ * Acquire a permit. Resolves when one is granted (respecting `maxConcurrent`
218
+ * and `minIntervalMs`). The caller MUST pair every resolved `acquire()` with
219
+ * exactly one {@link release}.
220
+ *
221
+ * Abort handling:
222
+ * - Pre-aborted signal ⇒ rejects immediately, no permit taken.
223
+ * - Aborted while queued ⇒ spliced out of the queue, no counter change, rejects.
224
+ * - (Once granted, the abort listener is removed — the holder owns the permit
225
+ * and releases it via `fetchWithRetry`'s `finally`.)
226
+ *
227
+ * With `acquireTimeoutMs`, a waiter that sits in the queue too long rejects.
228
+ */
229
+ acquire(signal) {
230
+ if (signal?.aborted) return Promise.reject(abortError());
231
+ return new Promise((resolve2, reject) => {
232
+ const waiter = { resolve: resolve2, reject, signal };
233
+ if (signal) {
234
+ waiter.onAbort = () => this.settleWaiter(waiter, abortError());
235
+ signal.addEventListener("abort", waiter.onAbort, { once: true });
236
+ }
237
+ if (this.acquireTimeoutMs != null) {
238
+ waiter.timer = setTimeout(
239
+ () => this.settleWaiter(
240
+ waiter,
241
+ new Error(`RateLimiter.acquire timed out after ${this.acquireTimeoutMs}ms`)
242
+ ),
243
+ this.acquireTimeoutMs
244
+ );
245
+ }
246
+ this.queue.push(waiter);
247
+ this.pump();
248
+ if (!waiter.granted && !this.warnedQueued) {
249
+ this.warnedQueued = true;
250
+ console.warn(
251
+ `[axl] RateLimiter: request queued (maxConcurrent=${this.maxConcurrent}${this.minIntervalMs ? `, minIntervalMs=${this.minIntervalMs}` : ""}). This is expected backpressure; lower fan-out or raise the cap if throughput suffers.`
252
+ );
253
+ }
254
+ });
255
+ }
256
+ /** Release a previously acquired permit and wake the next waiter. */
257
+ release() {
258
+ if (this.active === 0) {
259
+ console.warn(
260
+ "[axl] RateLimiter.release() called with no active permits \u2014 likely a double-release bug."
261
+ );
262
+ return;
263
+ }
264
+ this.active--;
265
+ this.pump();
266
+ }
267
+ /** v1 no-op seam for a future adaptive (rate-limit-header-driven) pacing follow-up. */
268
+ observe(_res) {
269
+ }
270
+ /** Drain the queue: grant head waiters while a permit is free and spacing allows. */
271
+ pump() {
272
+ while (this.queue.length > 0 && this.active < this.maxConcurrent) {
273
+ if (this.minIntervalMs > 0) {
274
+ const waitMs = this.minIntervalMs - (Date.now() - this.lastGrantAt);
275
+ if (waitMs > 0) {
276
+ if (!this.spacingTimer) {
277
+ this.spacingTimer = setTimeout(() => {
278
+ this.spacingTimer = void 0;
279
+ this.pump();
280
+ }, waitMs);
281
+ }
282
+ return;
283
+ }
284
+ }
285
+ const waiter = this.queue.shift();
286
+ this.grant(waiter);
287
+ }
288
+ }
289
+ grant(waiter) {
290
+ waiter.settled = true;
291
+ waiter.granted = true;
292
+ this.active++;
293
+ this.lastGrantAt = Date.now();
294
+ this.clearWaiterTimers(waiter);
295
+ waiter.resolve();
296
+ }
297
+ /** Reject a still-queued waiter (abort or timeout) and remove it cleanly. */
298
+ settleWaiter(waiter, err) {
299
+ if (waiter.settled) return;
300
+ waiter.settled = true;
301
+ const idx = this.queue.indexOf(waiter);
302
+ if (idx !== -1) this.queue.splice(idx, 1);
303
+ this.clearWaiterTimers(waiter);
304
+ waiter.reject(err);
305
+ this.pump();
306
+ }
307
+ clearWaiterTimers(waiter) {
308
+ if (waiter.timer) {
309
+ clearTimeout(waiter.timer);
310
+ waiter.timer = void 0;
311
+ }
312
+ if (waiter.signal && waiter.onAbort) {
313
+ waiter.signal.removeEventListener("abort", waiter.onAbort);
314
+ waiter.onAbort = void 0;
315
+ }
316
+ }
317
+ };
318
+
166
319
  // src/providers/openai.ts
167
320
  var OPENAI_PRICING = {
168
321
  // gpt-4o era — cache reads at 50% of input rate
@@ -190,7 +343,10 @@ var OPENAI_PRICING = {
190
343
  "gpt-5.2": [175e-8, 14e-6, 0.1],
191
344
  "gpt-5.3": [175e-8, 14e-6, 0.1],
192
345
  "gpt-5.4": [25e-7, 15e-6, 0.1],
193
- "gpt-5.4-pro": [3e-5, 18e-5, 0.1]
346
+ "gpt-5.4-pro": [3e-5, 18e-5, 0.1],
347
+ // gpt-5.5 era (flagship released 2026-04) — cache reads at 10% of input rate
348
+ "gpt-5.5": [5e-6, 3e-5, 0.1],
349
+ "gpt-5.5-pro": [3e-5, 18e-5, 0.1]
194
350
  };
195
351
  var PRICING_KEYS_BY_LENGTH = Object.keys(OPENAI_PRICING).sort((a, b) => b.length - a.length);
196
352
  function estimateOpenAICost(model, promptTokens, completionTokens, cachedTokens) {
@@ -239,9 +395,11 @@ var OpenAIProvider = class {
239
395
  name = "openai";
240
396
  baseUrl;
241
397
  apiKey;
398
+ governor;
242
399
  constructor(options = {}) {
243
400
  this.apiKey = options.apiKey ?? process.env.OPENAI_API_KEY ?? "";
244
401
  this.baseUrl = (options.baseUrl ?? process.env.OPENAI_BASE_URL ?? "https://api.openai.com/v1").replace(/\/$/, "");
402
+ this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
245
403
  if (!this.apiKey) {
246
404
  throw new Error("OpenAI API key is required. Set OPENAI_API_KEY or pass apiKey in options.");
247
405
  }
@@ -251,15 +409,19 @@ var OpenAIProvider = class {
251
409
  // ---------------------------------------------------------------------------
252
410
  async chat(messages, options) {
253
411
  const body = this.buildRequestBody(messages, options, false);
254
- const res = await fetchWithRetry(`${this.baseUrl}/chat/completions`, {
255
- method: "POST",
256
- headers: {
257
- "Content-Type": "application/json",
258
- Authorization: `Bearer ${this.apiKey}`
412
+ const res = await fetchWithRetry(
413
+ `${this.baseUrl}/chat/completions`,
414
+ {
415
+ method: "POST",
416
+ headers: {
417
+ "Content-Type": "application/json",
418
+ Authorization: `Bearer ${this.apiKey}`
419
+ },
420
+ body: JSON.stringify(body),
421
+ signal: options.signal
259
422
  },
260
- body: JSON.stringify(body),
261
- signal: options.signal
262
- });
423
+ { governor: this.governor }
424
+ );
263
425
  if (!res.ok) {
264
426
  const errorBody = await res.text();
265
427
  const message = this.extractErrorMessage(errorBody, res.status);
@@ -299,15 +461,19 @@ var OpenAIProvider = class {
299
461
  // ---------------------------------------------------------------------------
300
462
  async *stream(messages, options) {
301
463
  const body = this.buildRequestBody(messages, options, true);
302
- const res = await fetchWithRetry(`${this.baseUrl}/chat/completions`, {
303
- method: "POST",
304
- headers: {
305
- "Content-Type": "application/json",
306
- Authorization: `Bearer ${this.apiKey}`
464
+ const res = await fetchWithRetry(
465
+ `${this.baseUrl}/chat/completions`,
466
+ {
467
+ method: "POST",
468
+ headers: {
469
+ "Content-Type": "application/json",
470
+ Authorization: `Bearer ${this.apiKey}`
471
+ },
472
+ body: JSON.stringify(body),
473
+ signal: options.signal
307
474
  },
308
- body: JSON.stringify(body),
309
- signal: options.signal
310
- });
475
+ { governor: this.governor }
476
+ );
311
477
  if (!res.ok) {
312
478
  const errorBody = await res.text();
313
479
  const message = this.extractErrorMessage(errorBody, res.status);
@@ -480,9 +646,11 @@ var OpenAIResponsesProvider = class {
480
646
  name = "openai-responses";
481
647
  baseUrl;
482
648
  apiKey;
649
+ governor;
483
650
  constructor(options = {}) {
484
651
  this.apiKey = options.apiKey ?? process.env.OPENAI_API_KEY ?? "";
485
652
  this.baseUrl = (options.baseUrl ?? process.env.OPENAI_BASE_URL ?? "https://api.openai.com/v1").replace(/\/$/, "");
653
+ this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
486
654
  if (!this.apiKey) {
487
655
  throw new Error("OpenAI API key is required. Set OPENAI_API_KEY or pass apiKey in options.");
488
656
  }
@@ -492,15 +660,19 @@ var OpenAIResponsesProvider = class {
492
660
  // ---------------------------------------------------------------------------
493
661
  async chat(messages, options) {
494
662
  const body = this.buildRequestBody(messages, options, false);
495
- const res = await fetchWithRetry(`${this.baseUrl}/responses`, {
496
- method: "POST",
497
- headers: {
498
- "Content-Type": "application/json",
499
- Authorization: `Bearer ${this.apiKey}`
663
+ const res = await fetchWithRetry(
664
+ `${this.baseUrl}/responses`,
665
+ {
666
+ method: "POST",
667
+ headers: {
668
+ "Content-Type": "application/json",
669
+ Authorization: `Bearer ${this.apiKey}`
670
+ },
671
+ body: JSON.stringify(body),
672
+ signal: options.signal
500
673
  },
501
- body: JSON.stringify(body),
502
- signal: options.signal
503
- });
674
+ { governor: this.governor }
675
+ );
504
676
  if (!res.ok) {
505
677
  const errorBody = await res.text();
506
678
  const message = this.extractErrorMessage(errorBody, res.status);
@@ -514,15 +686,19 @@ var OpenAIResponsesProvider = class {
514
686
  // ---------------------------------------------------------------------------
515
687
  async *stream(messages, options) {
516
688
  const body = this.buildRequestBody(messages, options, true);
517
- const res = await fetchWithRetry(`${this.baseUrl}/responses`, {
518
- method: "POST",
519
- headers: {
520
- "Content-Type": "application/json",
521
- Authorization: `Bearer ${this.apiKey}`
689
+ const res = await fetchWithRetry(
690
+ `${this.baseUrl}/responses`,
691
+ {
692
+ method: "POST",
693
+ headers: {
694
+ "Content-Type": "application/json",
695
+ Authorization: `Bearer ${this.apiKey}`
696
+ },
697
+ body: JSON.stringify(body),
698
+ signal: options.signal
522
699
  },
523
- body: JSON.stringify(body),
524
- signal: options.signal
525
- });
700
+ { governor: this.governor }
701
+ );
526
702
  if (!res.ok) {
527
703
  const errorBody = await res.text();
528
704
  const message = this.extractErrorMessage(errorBody, res.status);
@@ -839,6 +1015,7 @@ var OpenAIResponsesProvider = class {
839
1015
  // src/providers/anthropic.ts
840
1016
  var ANTHROPIC_API_VERSION = "2023-06-01";
841
1017
  var ANTHROPIC_PRICING = {
1018
+ "claude-opus-4-8": [5e-6, 25e-6],
842
1019
  "claude-opus-4-7": [5e-6, 25e-6],
843
1020
  "claude-opus-4-6": [5e-6, 25e-6],
844
1021
  "claude-sonnet-4-6": [3e-6, 15e-6],
@@ -884,16 +1061,16 @@ var THINKING_BUDGETS = {
884
1061
  max: 3e4
885
1062
  };
886
1063
  function supportsAdaptiveThinking(model) {
887
- return model.startsWith("claude-opus-4-7") || model.startsWith("claude-opus-4-6") || model.startsWith("claude-sonnet-4-6");
1064
+ return model.startsWith("claude-opus-4-8") || model.startsWith("claude-opus-4-7") || model.startsWith("claude-opus-4-6") || model.startsWith("claude-sonnet-4-6");
888
1065
  }
889
1066
  function supportsMaxEffort(model) {
890
- return model.startsWith("claude-opus-4-7") || model.startsWith("claude-opus-4-6");
1067
+ return model.startsWith("claude-opus-4-8") || model.startsWith("claude-opus-4-7") || model.startsWith("claude-opus-4-6");
891
1068
  }
892
1069
  function supportsXhigh2(model) {
893
- return model.startsWith("claude-opus-4-7");
1070
+ return model.startsWith("claude-opus-4-8") || model.startsWith("claude-opus-4-7");
894
1071
  }
895
1072
  function supportsEffort(model) {
896
- return model.startsWith("claude-opus-4-7") || model.startsWith("claude-opus-4-6") || model.startsWith("claude-sonnet-4-6") || model.startsWith("claude-opus-4-5");
1073
+ return model.startsWith("claude-opus-4-8") || model.startsWith("claude-opus-4-7") || model.startsWith("claude-opus-4-6") || model.startsWith("claude-sonnet-4-6") || model.startsWith("claude-opus-4-5");
897
1074
  }
898
1075
  function clampAnthropicEffort(model, effort) {
899
1076
  if (effort === "max" && !supportsMaxEffort(model)) return "high";
@@ -905,9 +1082,11 @@ var AnthropicProvider = class {
905
1082
  baseUrl;
906
1083
  apiKey;
907
1084
  currentModel;
1085
+ governor;
908
1086
  constructor(options = {}) {
909
1087
  this.apiKey = options.apiKey ?? process.env.ANTHROPIC_API_KEY ?? "";
910
1088
  this.baseUrl = (options.baseUrl ?? "https://api.anthropic.com/v1").replace(/\/$/, "");
1089
+ this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
911
1090
  if (!this.apiKey) {
912
1091
  throw new Error(
913
1092
  "Anthropic API key is required. Set ANTHROPIC_API_KEY or pass apiKey in options."
@@ -920,12 +1099,16 @@ var AnthropicProvider = class {
920
1099
  async chat(messages, options) {
921
1100
  this.currentModel = options.model;
922
1101
  const body = this.buildRequestBody(messages, options, false);
923
- const res = await fetchWithRetry(`${this.baseUrl}/messages`, {
924
- method: "POST",
925
- headers: this.buildHeaders(),
926
- body: JSON.stringify(body),
927
- signal: options.signal
928
- });
1102
+ const res = await fetchWithRetry(
1103
+ `${this.baseUrl}/messages`,
1104
+ {
1105
+ method: "POST",
1106
+ headers: this.buildHeaders(),
1107
+ body: JSON.stringify(body),
1108
+ signal: options.signal
1109
+ },
1110
+ { governor: this.governor }
1111
+ );
929
1112
  if (!res.ok) {
930
1113
  const errorBody = await res.text();
931
1114
  const message = this.extractErrorMessage(errorBody, res.status);
@@ -939,12 +1122,16 @@ var AnthropicProvider = class {
939
1122
  // ---------------------------------------------------------------------------
940
1123
  async *stream(messages, options) {
941
1124
  const body = this.buildRequestBody(messages, options, true);
942
- const res = await fetchWithRetry(`${this.baseUrl}/messages`, {
943
- method: "POST",
944
- headers: this.buildHeaders(),
945
- body: JSON.stringify(body),
946
- signal: options.signal
947
- });
1125
+ const res = await fetchWithRetry(
1126
+ `${this.baseUrl}/messages`,
1127
+ {
1128
+ method: "POST",
1129
+ headers: this.buildHeaders(),
1130
+ body: JSON.stringify(body),
1131
+ signal: options.signal
1132
+ },
1133
+ { governor: this.governor }
1134
+ );
948
1135
  if (!res.ok) {
949
1136
  const errorBody = await res.text();
950
1137
  const message = this.extractErrorMessage(errorBody, res.status);
@@ -1431,12 +1618,14 @@ var GeminiProvider = class {
1431
1618
  baseUrl;
1432
1619
  apiKey;
1433
1620
  callCounter = 0;
1621
+ governor;
1434
1622
  constructor(options = {}) {
1435
1623
  this.apiKey = options.apiKey ?? process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY ?? "";
1436
1624
  this.baseUrl = (options.baseUrl ?? "https://generativelanguage.googleapis.com/v1beta").replace(
1437
1625
  /\/$/,
1438
1626
  ""
1439
1627
  );
1628
+ this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
1440
1629
  if (!this.apiKey) {
1441
1630
  throw new Error("Google API key is required. Set GOOGLE_API_KEY or pass apiKey in options.");
1442
1631
  }
@@ -1446,12 +1635,16 @@ var GeminiProvider = class {
1446
1635
  // ---------------------------------------------------------------------------
1447
1636
  async chat(messages, options) {
1448
1637
  const body = this.buildRequestBody(messages, options);
1449
- const res = await fetchWithRetry(`${this.baseUrl}/models/${options.model}:generateContent`, {
1450
- method: "POST",
1451
- headers: this.buildHeaders(),
1452
- body: JSON.stringify(body),
1453
- signal: options.signal
1454
- });
1638
+ const res = await fetchWithRetry(
1639
+ `${this.baseUrl}/models/${options.model}:generateContent`,
1640
+ {
1641
+ method: "POST",
1642
+ headers: this.buildHeaders(),
1643
+ body: JSON.stringify(body),
1644
+ signal: options.signal
1645
+ },
1646
+ { governor: this.governor }
1647
+ );
1455
1648
  if (!res.ok) {
1456
1649
  const errorBody = await res.text();
1457
1650
  const message = this.extractErrorMessage(errorBody, res.status);
@@ -1472,7 +1665,8 @@ var GeminiProvider = class {
1472
1665
  headers: this.buildHeaders(),
1473
1666
  body: JSON.stringify(body),
1474
1667
  signal: options.signal
1475
- }
1668
+ },
1669
+ { governor: this.governor }
1476
1670
  );
1477
1671
  if (!res.ok) {
1478
1672
  const errorBody = await res.text();
@@ -1851,19 +2045,39 @@ var GeminiProvider = class {
1851
2045
  var builtinFactories = {
1852
2046
  openai: (config) => {
1853
2047
  const opts = config.providers?.openai ?? {};
1854
- return new OpenAIProvider({ apiKey: opts.apiKey, baseUrl: opts.baseUrl });
2048
+ return new OpenAIProvider({
2049
+ apiKey: opts.apiKey,
2050
+ baseUrl: opts.baseUrl,
2051
+ rateLimit: opts.rateLimit
2052
+ });
1855
2053
  },
2054
+ // NB: each adapter builds its OWN RateLimiter from its config — caps are
2055
+ // per-adapter-instance, not pooled. Configuring `openai` AND using both
2056
+ // `openai:` and `openai-responses:` yields two independent governors against
2057
+ // the same key (effective concurrency = the sum). Documented in providers.md.
1856
2058
  "openai-responses": (config) => {
1857
2059
  const opts = config.providers?.["openai-responses"] ?? config.providers?.openai ?? {};
1858
- return new OpenAIResponsesProvider({ apiKey: opts.apiKey, baseUrl: opts.baseUrl });
2060
+ return new OpenAIResponsesProvider({
2061
+ apiKey: opts.apiKey,
2062
+ baseUrl: opts.baseUrl,
2063
+ rateLimit: opts.rateLimit
2064
+ });
1859
2065
  },
1860
2066
  anthropic: (config) => {
1861
2067
  const opts = config.providers?.anthropic ?? {};
1862
- return new AnthropicProvider({ apiKey: opts.apiKey, baseUrl: opts.baseUrl });
2068
+ return new AnthropicProvider({
2069
+ apiKey: opts.apiKey,
2070
+ baseUrl: opts.baseUrl,
2071
+ rateLimit: opts.rateLimit
2072
+ });
1863
2073
  },
1864
2074
  google: (config) => {
1865
2075
  const opts = config.providers?.google ?? {};
1866
- return new GeminiProvider({ apiKey: opts.apiKey, baseUrl: opts.baseUrl });
2076
+ return new GeminiProvider({
2077
+ apiKey: opts.apiKey,
2078
+ baseUrl: opts.baseUrl,
2079
+ rateLimit: opts.rateLimit
2080
+ });
1867
2081
  }
1868
2082
  };
1869
2083
  var ProviderRegistry = class {
@@ -8596,14 +8810,11 @@ var AxlRuntime = class extends EventEmitter2 {
8596
8810
  captureTraces: options?.captureTraces
8597
8811
  });
8598
8812
  } else {
8599
- result = await this.eval(
8600
- entry.config,
8601
- {
8602
- onProgress: options?.onProgress,
8603
- signal: options?.signal,
8604
- captureTraces: options?.captureTraces
8605
- }
8606
- );
8813
+ result = await this.eval(entry.config, {
8814
+ onProgress: options?.onProgress,
8815
+ signal: options?.signal,
8816
+ captureTraces: options?.captureTraces
8817
+ });
8607
8818
  }
8608
8819
  const resultObj = result;
8609
8820
  if (options?.metadata) {
@@ -10542,6 +10753,7 @@ export {
10542
10753
  QuorumNotMet,
10543
10754
  REDACTED,
10544
10755
  REDACTION_RULES,
10756
+ RateLimiter,
10545
10757
  RedisStore,
10546
10758
  SQLiteStore,
10547
10759
  Session,