@absolutejs/ai 0.0.21 → 0.0.22

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/ai/index.js CHANGED
@@ -1,15 +1,236 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // src/ai/providers/instrumentation.ts
5
- var instrumentAIProvider = (provider, providerName) => ({
6
- stream: (params) => {
7
- if (!params.onUsage && !params.onSpan) {
8
- return provider.stream(params);
9
- }
10
- return tapStream(provider.stream(params), params, providerName);
4
+ // src/ai/errors/providerError.ts
5
+ var PROVIDER_STATUS_PAGES = {
6
+ anthropic: "https://status.anthropic.com",
7
+ gemini: "https://status.cloud.google.com",
8
+ google: "https://status.cloud.google.com",
9
+ openai: "https://status.openai.com"
10
+ };
11
+ var RETRYABLE_STATUSES = new Set([
12
+ 408,
13
+ 409,
14
+ 425,
15
+ 429,
16
+ 500,
17
+ 502,
18
+ 503,
19
+ 504,
20
+ 529
21
+ ]);
22
+ var CONNECTION_ERROR_PATTERNS = [
23
+ "econnreset",
24
+ "econnrefused",
25
+ "etimedout",
26
+ "enotfound",
27
+ "eai_again",
28
+ "socket hang up",
29
+ "fetch failed",
30
+ "network",
31
+ "terminated",
32
+ "timed out",
33
+ "timeout",
34
+ "and not retryable",
35
+ "no response body"
36
+ ];
37
+ var isAbortError = (err) => err instanceof Error && (err.name === "AbortError" || /\babort(ed)?\b/i.test(err.message));
38
+ var providerStatusPage = (provider) => PROVIDER_STATUS_PAGES[provider] ?? null;
39
+
40
+ class ProviderError extends Error {
41
+ provider;
42
+ status;
43
+ type;
44
+ retryable;
45
+ statusPageUrl;
46
+ constructor(init) {
47
+ super(init.message, init.cause === undefined ? undefined : { cause: init.cause });
48
+ this.name = "ProviderError";
49
+ this.provider = init.provider;
50
+ this.status = init.status ?? null;
51
+ this.type = init.type ?? null;
52
+ this.retryable = init.retryable;
53
+ this.statusPageUrl = providerStatusPage(init.provider);
54
+ }
55
+ static fromResponse(provider, status, body, type) {
56
+ return new ProviderError({
57
+ message: `${capitalize(provider)} API error ${status}: ${body}`,
58
+ provider,
59
+ retryable: RETRYABLE_STATUSES.has(status),
60
+ status,
61
+ type: type ?? null
62
+ });
63
+ }
64
+ static from(err, provider) {
65
+ if (err instanceof ProviderError)
66
+ return err;
67
+ if (isAbortError(err))
68
+ throw err;
69
+ const rawMessage = err instanceof Error ? err.message : String(err ?? "");
70
+ const lower = rawMessage.toLowerCase();
71
+ const statusMatch = lower.match(/api error\s+(\d{3})/);
72
+ const status = statusMatch ? Number(statusMatch[1]) : null;
73
+ const retryable = status !== null && RETRYABLE_STATUSES.has(status) || status === null && CONNECTION_ERROR_PATTERNS.some((pattern) => lower.includes(pattern));
74
+ return new ProviderError({
75
+ cause: err,
76
+ message: rawMessage || `${capitalize(provider)} request failed`,
77
+ provider,
78
+ retryable,
79
+ status
80
+ });
11
81
  }
82
+ }
83
+ var capitalize = (value) => value.charAt(0).toUpperCase() + value.slice(1);
84
+
85
+ // src/ai/resilience.ts
86
+ var DEFAULT_CONFIG = {
87
+ baseDelayMs: 500,
88
+ failureThreshold: 4,
89
+ maxDelayMs: 8000,
90
+ maxRetries: 2,
91
+ openMs: 30000
92
+ };
93
+ var config = { ...DEFAULT_CONFIG };
94
+ var configureProviderResilience = (partial) => {
95
+ config = { ...config, ...partial };
96
+ };
97
+ var health = new Map;
98
+ var recordFor = (provider) => {
99
+ const existing = health.get(provider);
100
+ if (existing)
101
+ return existing;
102
+ const fresh = {
103
+ consecutiveFailures: 0,
104
+ lastError: null,
105
+ lastFailureAt: null,
106
+ lastSuccessAt: null,
107
+ nextProbeAt: null,
108
+ state: "closed"
109
+ };
110
+ health.set(provider, fresh);
111
+ return fresh;
112
+ };
113
+ var noteSuccess = (provider) => {
114
+ const record = recordFor(provider);
115
+ record.state = "closed";
116
+ record.consecutiveFailures = 0;
117
+ record.nextProbeAt = null;
118
+ record.lastError = null;
119
+ record.lastSuccessAt = Date.now();
120
+ };
121
+ var noteFailure = (provider, error) => {
122
+ const record = recordFor(provider);
123
+ record.consecutiveFailures += 1;
124
+ record.lastFailureAt = Date.now();
125
+ record.lastError = {
126
+ message: error.message,
127
+ status: error.status,
128
+ type: error.type
129
+ };
130
+ if (record.consecutiveFailures >= config.failureThreshold) {
131
+ record.state = "open";
132
+ record.nextProbeAt = Date.now() + config.openMs;
133
+ }
134
+ };
135
+ var snapshot = (provider, record) => ({
136
+ consecutiveFailures: record.consecutiveFailures,
137
+ healthy: record.state === "closed",
138
+ lastError: record.lastError,
139
+ lastFailureAt: record.lastFailureAt,
140
+ lastSuccessAt: record.lastSuccessAt,
141
+ nextRetryAt: record.nextProbeAt,
142
+ provider,
143
+ state: record.state,
144
+ statusPageUrl: providerStatusPage(provider)
12
145
  });
146
+ function getProviderHealth(provider) {
147
+ if (provider !== undefined)
148
+ return snapshot(provider, recordFor(provider));
149
+ return [...health.entries()].map(([name, record]) => snapshot(name, record));
150
+ }
151
+ var backoffDelay = (attempt) => {
152
+ const exponential = config.baseDelayMs * 2 ** attempt;
153
+ const capped = Math.min(exponential, config.maxDelayMs);
154
+ return Math.round(capped / 2 + Math.random() * capped / 2);
155
+ };
156
+ var sleep = (ms, signal) => new Promise((resolve, reject) => {
157
+ if (signal?.aborted) {
158
+ reject(signal.reason ?? new Error("aborted"));
159
+ return;
160
+ }
161
+ const timer = setTimeout(() => {
162
+ signal?.removeEventListener("abort", onAbort);
163
+ resolve();
164
+ }, ms);
165
+ const onAbort = () => {
166
+ clearTimeout(timer);
167
+ reject(signal?.reason ?? new Error("aborted"));
168
+ };
169
+ signal?.addEventListener("abort", onAbort, { once: true });
170
+ });
171
+ var circuitOpen = (provider) => {
172
+ const record = recordFor(provider);
173
+ if (record.state !== "open")
174
+ return null;
175
+ if (record.nextProbeAt !== null && Date.now() >= record.nextProbeAt) {
176
+ record.state = "half-open";
177
+ return null;
178
+ }
179
+ const detail = record.lastError?.message ?? "recent failures";
180
+ return new ProviderError({
181
+ message: `${provider} is temporarily unavailable (circuit open after ${record.consecutiveFailures} failures): ${detail}`,
182
+ provider,
183
+ retryable: true,
184
+ status: record.lastError?.status ?? null,
185
+ type: record.lastError?.type ?? null
186
+ });
187
+ };
188
+ var withResilience = (provider, providerName = "unknown") => {
189
+ const attempt = async function* (params, attemptNo) {
190
+ let yielded = false;
191
+ try {
192
+ for await (const chunk of provider.stream(params)) {
193
+ yielded = true;
194
+ yield chunk;
195
+ }
196
+ noteSuccess(providerName);
197
+ } catch (err) {
198
+ const providerError = ProviderError.from(err, providerName);
199
+ const canRetry = !yielded && providerError.retryable && attemptNo < config.maxRetries && !params.signal?.aborted;
200
+ if (canRetry) {
201
+ await sleep(backoffDelay(attemptNo), params.signal);
202
+ yield* attempt(params, attemptNo + 1);
203
+ return;
204
+ }
205
+ noteFailure(providerName, providerError);
206
+ throw providerError;
207
+ }
208
+ };
209
+ return {
210
+ stream: (params) => {
211
+ const tripped = circuitOpen(providerName);
212
+ if (tripped) {
213
+ return async function* () {
214
+ throw tripped;
215
+ }();
216
+ }
217
+ return attempt(params, 0);
218
+ }
219
+ };
220
+ };
221
+
222
+ // src/ai/providers/instrumentation.ts
223
+ var instrumentAIProvider = (provider, providerName) => {
224
+ const resilient = withResilience(provider, providerName);
225
+ return {
226
+ stream: (params) => {
227
+ if (!params.onUsage && !params.onSpan) {
228
+ return resilient.stream(params);
229
+ }
230
+ return tapStream(resilient.stream(params), params, providerName);
231
+ }
232
+ };
233
+ };
13
234
  async function* tapStream(source, params, providerName) {
14
235
  const startedAt = Date.now();
15
236
  let lastUsage;
@@ -501,23 +722,27 @@ var fetchOpenAIStream = async function* (baseUrl, apiKey, body, signal) {
501
722
  });
502
723
  if (!response.ok) {
503
724
  const errorText = await response.text();
504
- throw new Error(`OpenAI API error ${response.status}: ${errorText}`);
725
+ throw ProviderError.fromResponse("openai", response.status, errorText);
505
726
  }
506
727
  if (!response.body) {
507
- throw new Error("OpenAI API returned no response body");
728
+ throw new ProviderError({
729
+ message: "OpenAI API returned no response body",
730
+ provider: "openai",
731
+ retryable: true
732
+ });
508
733
  }
509
734
  yield* parseSSEStream(response.body, signal);
510
735
  };
511
- var openai = (config) => {
512
- const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
513
- if (!config.apiKey && !config.tokenSource) {
736
+ var openai = (config2) => {
737
+ const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL;
738
+ if (!config2.apiKey && !config2.tokenSource) {
514
739
  throw new Error("openai() requires either apiKey or tokenSource");
515
740
  }
516
741
  const resolveKey = async () => {
517
- if (config.tokenSource) {
518
- return await Promise.resolve(config.tokenSource());
742
+ if (config2.tokenSource) {
743
+ return await Promise.resolve(config2.tokenSource());
519
744
  }
520
- return config.apiKey;
745
+ return config2.apiKey;
521
746
  };
522
747
  return instrumentAIProvider({
523
748
  stream: (params) => {
@@ -531,37 +756,37 @@ var openai = (config) => {
531
756
  };
532
757
 
533
758
  // src/ai/providers/openaiCompatible.ts
534
- var alibaba = (config) => openaiCompatible({
535
- apiKey: config.apiKey,
759
+ var alibaba = (config2) => openaiCompatible({
760
+ apiKey: config2.apiKey,
536
761
  baseUrl: "https://dashscope-intl.aliyuncs.com/compatible-mode"
537
762
  });
538
- var deepseek = (config) => openaiCompatible({
539
- apiKey: config.apiKey,
763
+ var deepseek = (config2) => openaiCompatible({
764
+ apiKey: config2.apiKey,
540
765
  baseUrl: "https://api.deepseek.com"
541
766
  });
542
- var google = (config) => openaiCompatible({
543
- apiKey: config.apiKey,
767
+ var google = (config2) => openaiCompatible({
768
+ apiKey: config2.apiKey,
544
769
  baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai"
545
770
  });
546
- var meta = (config) => openaiCompatible({
547
- apiKey: config.apiKey,
771
+ var meta = (config2) => openaiCompatible({
772
+ apiKey: config2.apiKey,
548
773
  baseUrl: "https://api.llama.com/compat/v1"
549
774
  });
550
- var mistralai = (config) => openaiCompatible({
551
- apiKey: config.apiKey,
775
+ var mistralai = (config2) => openaiCompatible({
776
+ apiKey: config2.apiKey,
552
777
  baseUrl: "https://api.mistral.ai"
553
778
  });
554
- var moonshot = (config) => openaiCompatible({
555
- apiKey: config.apiKey,
779
+ var moonshot = (config2) => openaiCompatible({
780
+ apiKey: config2.apiKey,
556
781
  baseUrl: "https://api.moonshot.ai"
557
782
  });
558
- var openaiCompatible = (config) => openai({
559
- apiKey: config.apiKey,
560
- baseUrl: config.baseUrl,
561
- tokenSource: config.tokenSource
783
+ var openaiCompatible = (config2) => openai({
784
+ apiKey: config2.apiKey,
785
+ baseUrl: config2.baseUrl,
786
+ tokenSource: config2.tokenSource
562
787
  });
563
- var xai = (config) => openaiCompatible({
564
- apiKey: config.apiKey,
788
+ var xai = (config2) => openaiCompatible({
789
+ apiKey: config2.apiKey,
565
790
  baseUrl: "https://api.x.ai"
566
791
  });
567
792
 
@@ -973,14 +1198,14 @@ var resolveImageModels = (imageModels) => {
973
1198
  }
974
1199
  return new Set(imageModels);
975
1200
  };
976
- var openaiResponses = (config) => {
977
- const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL2;
978
- const imageModels = resolveImageModels(config.imageModels);
1201
+ var openaiResponses = (config2) => {
1202
+ const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL2;
1203
+ const imageModels = resolveImageModels(config2.imageModels);
979
1204
  return instrumentAIProvider({
980
1205
  stream: (params) => {
981
1206
  const isImageModel = imageModels.has(params.model);
982
1207
  const body = buildRequestBody2(params, isImageModel);
983
- return fetchResponsesStream(baseUrl, config.apiKey, body, params.signal);
1208
+ return fetchResponsesStream(baseUrl, config2.apiKey, body, params.signal);
984
1209
  }
985
1210
  }, "openai-responses");
986
1211
  };
@@ -1265,14 +1490,14 @@ var resolveImageModels2 = (raw) => {
1265
1490
  }
1266
1491
  return new Set(raw);
1267
1492
  };
1268
- var gemini = (config) => {
1269
- const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL3;
1270
- const imageModels = resolveImageModels2(config.imageModels);
1493
+ var gemini = (config2) => {
1494
+ const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL3;
1495
+ const imageModels = resolveImageModels2(config2.imageModels);
1271
1496
  return instrumentAIProvider({
1272
1497
  stream: (params) => {
1273
1498
  const isImageModel = imageModels.has(params.model);
1274
1499
  const body = buildRequestBody3(params, isImageModel);
1275
- return fetchGeminiStream(baseUrl, config.apiKey, params.model, body, params.signal);
1500
+ return fetchGeminiStream(baseUrl, config2.apiKey, params.model, body, params.signal);
1276
1501
  }
1277
1502
  }, "gemini");
1278
1503
  };
@@ -1545,7 +1770,14 @@ var handleMessageStart = (parsed, state) => {
1545
1770
  var handleError = (parsed) => {
1546
1771
  const error = getRecord(parsed, "error");
1547
1772
  const errorMessage = error ? getString(error, "message") : "";
1548
- throw new Error(errorMessage || "Anthropic API error");
1773
+ const errorType = error ? getString(error, "type") : "";
1774
+ const retryable = errorType === "overloaded_error" || errorType === "rate_limit_error" || errorType === "api_error";
1775
+ throw new ProviderError({
1776
+ message: errorMessage || "Anthropic API error",
1777
+ provider: "anthropic",
1778
+ retryable,
1779
+ type: errorType || null
1780
+ });
1549
1781
  };
1550
1782
  var processEvent = (eventType, parsed, state) => {
1551
1783
  switch (eventType) {
@@ -1654,7 +1886,7 @@ async function* parseSSEStream4(body, signal) {
1654
1886
  reader.releaseLock();
1655
1887
  }
1656
1888
  }
1657
- var fetchAndStream = async function* (baseUrl, config, params) {
1889
+ var fetchAndStream = async function* (baseUrl, config2, params) {
1658
1890
  const body = buildRequestBody4(params);
1659
1891
  const target = `${baseUrl}/v1/messages`;
1660
1892
  const response = await fetch(target, {
@@ -1663,24 +1895,28 @@ var fetchAndStream = async function* (baseUrl, config, params) {
1663
1895
  headers: {
1664
1896
  "anthropic-version": API_VERSION,
1665
1897
  "Content-Type": "application/json",
1666
- "x-api-key": config.apiKey
1898
+ "x-api-key": config2.apiKey
1667
1899
  },
1668
1900
  method: "POST",
1669
1901
  signal: params.signal
1670
1902
  });
1671
1903
  if (!response.ok) {
1672
1904
  const errorText = await response.text();
1673
- throw new Error(`Anthropic API error ${response.status}: ${errorText}`);
1905
+ throw ProviderError.fromResponse("anthropic", response.status, errorText);
1674
1906
  }
1675
1907
  if (!response.body) {
1676
- throw new Error("Anthropic API returned no response body");
1908
+ throw new ProviderError({
1909
+ message: "Anthropic API returned no response body",
1910
+ provider: "anthropic",
1911
+ retryable: true
1912
+ });
1677
1913
  }
1678
1914
  yield* parseSSEStream4(response.body, params.signal);
1679
1915
  };
1680
- var anthropic = (config) => {
1681
- const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL4;
1916
+ var anthropic = (config2) => {
1917
+ const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL4;
1682
1918
  return instrumentAIProvider({
1683
- stream: (params) => fetchAndStream(baseUrl, config, params)
1919
+ stream: (params) => fetchAndStream(baseUrl, config2, params)
1684
1920
  }, "anthropic");
1685
1921
  };
1686
1922
 
@@ -1915,8 +2151,8 @@ var fetchAndStream2 = async function* (baseUrl, params) {
1915
2151
  }
1916
2152
  yield* parseNDJSONStream(response.body, params.signal);
1917
2153
  };
1918
- var ollama = (config = {}) => {
1919
- const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL5;
2154
+ var ollama = (config2 = {}) => {
2155
+ const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL5;
1920
2156
  return instrumentAIProvider({
1921
2157
  stream: (params) => fetchAndStream2(baseUrl, params)
1922
2158
  }, "ollama");
@@ -2747,24 +2983,24 @@ var buildUserMessage = (content, attachments) => {
2747
2983
  }
2748
2984
  return { content, role: "user" };
2749
2985
  };
2750
- var resolveModel = (config, parsed) => {
2986
+ var resolveModel = (config2, parsed) => {
2751
2987
  if (parsed.model) {
2752
2988
  return parsed.model;
2753
2989
  }
2754
- if (typeof config.model === "string") {
2755
- return config.model;
2990
+ if (typeof config2.model === "string") {
2991
+ return config2.model;
2756
2992
  }
2757
- if (typeof config.model === "function") {
2758
- return config.model(parsed.providerName);
2993
+ if (typeof config2.model === "function") {
2994
+ return config2.model(parsed.providerName);
2759
2995
  }
2760
2996
  return parsed.providerName;
2761
2997
  };
2762
- var resolveTools = (config, providerName, model) => typeof config.tools === "function" ? config.tools(providerName, model) : config.tools;
2763
- var resolveReasoning = (config, providerName, model) => typeof config.reasoning === "function" ? config.reasoning(providerName, model) : config.reasoning;
2764
- var aiChat = (config) => {
2765
- const path = config.path ?? DEFAULT_PATH;
2766
- const store = config.store ?? createMemoryStore();
2767
- const parseProvider = config.parseProvider ?? defaultParseProvider;
2998
+ var resolveTools = (config2, providerName, model) => typeof config2.tools === "function" ? config2.tools(providerName, model) : config2.tools;
2999
+ var resolveReasoning = (config2, providerName, model) => typeof config2.reasoning === "function" ? config2.reasoning(providerName, model) : config2.reasoning;
3000
+ var aiChat = (config2) => {
3001
+ const path = config2.path ?? DEFAULT_PATH;
3002
+ const store = config2.store ?? createMemoryStore();
3003
+ const parseProvider = config2.parseProvider ?? defaultParseProvider;
2768
3004
  const abortControllers = new Map;
2769
3005
  const handleCancel = (conversationId) => {
2770
3006
  const controller = abortControllers.get(conversationId);
@@ -2802,17 +3038,17 @@ var aiChat = (config) => {
2802
3038
  timestamp: Date.now()
2803
3039
  });
2804
3040
  await store.set(conversationId, conversation);
2805
- const model = resolveModel(config, parsed);
3041
+ const model = resolveModel(config2, parsed);
2806
3042
  const userMessage = buildUserMessage(content, attachments);
2807
3043
  await streamAI(ws, conversationId, messageId, {
2808
- maxTurns: config.maxTurns,
3044
+ maxTurns: config2.maxTurns,
2809
3045
  messages: [...history, userMessage],
2810
3046
  model,
2811
- provider: config.provider(providerName),
3047
+ provider: config2.provider(providerName),
2812
3048
  signal: controller.signal,
2813
- systemPrompt: config.systemPrompt,
2814
- reasoning: resolveReasoning(config, providerName, model),
2815
- tools: resolveTools(config, providerName, model),
3049
+ systemPrompt: config2.systemPrompt,
3050
+ reasoning: resolveReasoning(config2, providerName, model),
3051
+ tools: resolveTools(config2, providerName, model),
2816
3052
  onComplete: async (fullResponse, usage) => {
2817
3053
  const conv = await store.get(conversationId);
2818
3054
  if (conv) {
@@ -2826,15 +3062,15 @@ var aiChat = (config) => {
2826
3062
  await store.set(conversationId, conv);
2827
3063
  }
2828
3064
  abortControllers.delete(conversationId);
2829
- config.onComplete?.(conversationId, fullResponse, usage);
3065
+ config2.onComplete?.(conversationId, fullResponse, usage);
2830
3066
  }
2831
3067
  });
2832
3068
  };
2833
3069
  const htmxRoutes = () => {
2834
- if (!config.htmx) {
3070
+ if (!config2.htmx) {
2835
3071
  return new Elysia;
2836
3072
  }
2837
- const renderers = resolveRenderers(typeof config.htmx === "object" ? config.htmx.render : undefined);
3073
+ const renderers = resolveRenderers(typeof config2.htmx === "object" ? config2.htmx.render : undefined);
2838
3074
  return new Elysia().post(`${path}/message`, async ({ body }) => {
2839
3075
  const requestBody = body && typeof body === "object" ? body : {};
2840
3076
  const rawContent = "content" in requestBody ? String(requestBody.content) : undefined;
@@ -2872,21 +3108,21 @@ var aiChat = (config) => {
2872
3108
  }
2873
3109
  const parsed = parseProvider(conversation.messages.at(EXCLUDE_LAST_OFFSET)?.content ?? "");
2874
3110
  const { providerName } = parsed;
2875
- const model = resolveModel(config, parsed);
3111
+ const model = resolveModel(config2, parsed);
2876
3112
  const controller = new AbortController;
2877
3113
  abortControllers.set(conversationId, controller);
2878
3114
  const history = getHistory(conversation);
2879
3115
  const lastMsg = conversation.messages.at(EXCLUDE_LAST_OFFSET);
2880
3116
  const userMessage = buildUserMessage(lastMsg?.content ?? "", lastMsg?.attachments);
2881
3117
  const sseStream = streamAIToSSE(conversationId, messageId, {
2882
- maxTurns: config.maxTurns,
3118
+ maxTurns: config2.maxTurns,
2883
3119
  messages: [...history.slice(0, EXCLUDE_LAST_OFFSET), userMessage],
2884
3120
  model,
2885
- provider: config.provider(providerName),
3121
+ provider: config2.provider(providerName),
2886
3122
  signal: controller.signal,
2887
- systemPrompt: config.systemPrompt,
2888
- reasoning: resolveReasoning(config, providerName, model),
2889
- tools: resolveTools(config, providerName, model)
3123
+ systemPrompt: config2.systemPrompt,
3124
+ reasoning: resolveReasoning(config2, providerName, model),
3125
+ tools: resolveTools(config2, providerName, model)
2890
3126
  }, renderers);
2891
3127
  for await (const event of sseStream) {
2892
3128
  yield event;
@@ -3742,12 +3978,12 @@ var createAIStream = (path, conversationId) => {
3742
3978
  let currentMessages = [];
3743
3979
  let activeConversationId = conversationId ?? null;
3744
3980
  const syncState = () => {
3745
- const snapshot = store.getSnapshot();
3746
- const convId = activeConversationId ?? snapshot.activeConversationId;
3747
- const conversation = convId ? snapshot.conversations.get(convId) : undefined;
3748
- activeConversationId = convId ?? snapshot.activeConversationId;
3749
- currentError = snapshot.error;
3750
- currentIsStreaming = snapshot.isStreaming;
3981
+ const snapshot2 = store.getSnapshot();
3982
+ const convId = activeConversationId ?? snapshot2.activeConversationId;
3983
+ const conversation = convId ? snapshot2.conversations.get(convId) : undefined;
3984
+ activeConversationId = convId ?? snapshot2.activeConversationId;
3985
+ currentError = snapshot2.error;
3986
+ currentIsStreaming = snapshot2.isStreaming;
3751
3987
  currentMessages = conversation?.messages ?? [];
3752
3988
  listeners.forEach((listener) => listener());
3753
3989
  };
@@ -3828,35 +4064,35 @@ var readOAuth2ErrorDetail = async (response) => {
3828
4064
  const text = await response.clone().text().catch(() => "");
3829
4065
  return text.trim();
3830
4066
  };
3831
- var createOAuth2ClientCredentialsTokenSource = (config) => {
3832
- const fetchImpl = config.fetch ?? fetch;
3833
- const now = config.now ?? (() => Date.now());
3834
- const skewMs = config.expirySkewMs ?? 60000;
3835
- const fallbackTtl = config.fallbackTtlSeconds ?? 3600;
3836
- const scope = Array.isArray(config.scope) ? config.scope.join(" ") : config.scope;
4067
+ var createOAuth2ClientCredentialsTokenSource = (config2) => {
4068
+ const fetchImpl = config2.fetch ?? fetch;
4069
+ const now = config2.now ?? (() => Date.now());
4070
+ const skewMs = config2.expirySkewMs ?? 60000;
4071
+ const fallbackTtl = config2.fallbackTtlSeconds ?? 3600;
4072
+ const scope = Array.isArray(config2.scope) ? config2.scope.join(" ") : config2.scope;
3837
4073
  let cached = null;
3838
4074
  let inflight = null;
3839
4075
  const requestToken = async () => {
3840
4076
  const body = new URLSearchParams({ grant_type: "client_credentials" });
3841
4077
  if (scope)
3842
4078
  body.set("scope", scope);
3843
- if (config.audience)
3844
- body.set("audience", config.audience);
3845
- for (const [key, value] of Object.entries(config.extraParams ?? {})) {
4079
+ if (config2.audience)
4080
+ body.set("audience", config2.audience);
4081
+ for (const [key, value] of Object.entries(config2.extraParams ?? {})) {
3846
4082
  body.set(key, value);
3847
4083
  }
3848
4084
  const headers = {
3849
4085
  Accept: "application/json",
3850
4086
  "Content-Type": "application/x-www-form-urlencoded"
3851
4087
  };
3852
- if (config.authStyle === "basic") {
3853
- const encoded = btoa(`${config.clientId}:${config.clientSecret}`);
4088
+ if (config2.authStyle === "basic") {
4089
+ const encoded = btoa(`${config2.clientId}:${config2.clientSecret}`);
3854
4090
  headers.Authorization = `Basic ${encoded}`;
3855
4091
  } else {
3856
- body.set("client_id", config.clientId);
3857
- body.set("client_secret", config.clientSecret);
4092
+ body.set("client_id", config2.clientId);
4093
+ body.set("client_secret", config2.clientSecret);
3858
4094
  }
3859
- const response = await fetchImpl(config.tokenUrl, {
4095
+ const response = await fetchImpl(config2.tokenUrl, {
3860
4096
  body,
3861
4097
  headers,
3862
4098
  method: "POST"
@@ -3890,11 +4126,13 @@ var createOAuth2ClientCredentialsTokenSource = (config) => {
3890
4126
  };
3891
4127
  export {
3892
4128
  xai,
4129
+ withResilience,
3893
4130
  streamAIToSSE,
3894
4131
  streamAI,
3895
4132
  serverMessageToAction,
3896
4133
  serializeAIMessage,
3897
4134
  resolveRenderers,
4135
+ providerStatusPage,
3898
4136
  parseAIMessage,
3899
4137
  openaiResponses,
3900
4138
  openaiCompatible,
@@ -3904,6 +4142,7 @@ export {
3904
4142
  mistralai,
3905
4143
  meta,
3906
4144
  google,
4145
+ getProviderHealth,
3907
4146
  generateObjectAI,
3908
4147
  generateId,
3909
4148
  generateAIWithTools,
@@ -3916,10 +4155,13 @@ export {
3916
4155
  createConversationManager,
3917
4156
  createAIStream,
3918
4157
  createAIConnection,
4158
+ configureProviderResilience,
3919
4159
  anthropic,
3920
4160
  alibaba,
3921
- aiChat
4161
+ aiChat,
4162
+ ProviderError,
4163
+ PROVIDER_STATUS_PAGES
3922
4164
  };
3923
4165
 
3924
- //# debugId=8280CFC77A5D2DF464756E2164756E21
4166
+ //# debugId=4F9632D62D06633E64756E2164756E21
3925
4167
  //# sourceMappingURL=index.js.map