@absolutejs/ai 0.0.22 → 0.0.23

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
@@ -3,7 +3,7 @@ var __require = import.meta.require;
3
3
 
4
4
  // src/ai/errors/providerError.ts
5
5
  var PROVIDER_STATUS_PAGES = {
6
- anthropic: "https://status.anthropic.com",
6
+ anthropic: "https://status.claude.com",
7
7
  gemini: "https://status.cloud.google.com",
8
8
  google: "https://status.cloud.google.com",
9
9
  openai: "https://status.openai.com"
@@ -101,6 +101,7 @@ var recordFor = (provider) => {
101
101
  return existing;
102
102
  const fresh = {
103
103
  consecutiveFailures: 0,
104
+ external: null,
104
105
  lastError: null,
105
106
  lastFailureAt: null,
106
107
  lastSuccessAt: null,
@@ -110,6 +111,15 @@ var recordFor = (provider) => {
110
111
  health.set(provider, fresh);
111
112
  return fresh;
112
113
  };
114
+ var setProviderAvailability = (provider, status) => {
115
+ const record = recordFor(provider);
116
+ record.external = {
117
+ available: status.available,
118
+ checkedAt: Date.now(),
119
+ indicator: status.indicator ?? (status.available ? "operational" : "unknown"),
120
+ reason: status.reason ?? ""
121
+ };
122
+ };
113
123
  var noteSuccess = (provider) => {
114
124
  const record = recordFor(provider);
115
125
  record.state = "closed";
@@ -134,7 +144,8 @@ var noteFailure = (provider, error) => {
134
144
  };
135
145
  var snapshot = (provider, record) => ({
136
146
  consecutiveFailures: record.consecutiveFailures,
137
- healthy: record.state === "closed",
147
+ external: record.external,
148
+ healthy: record.state === "closed" && record.external?.available !== false,
138
149
  lastError: record.lastError,
139
150
  lastFailureAt: record.lastFailureAt,
140
151
  lastSuccessAt: record.lastSuccessAt,
@@ -170,6 +181,15 @@ var sleep = (ms, signal) => new Promise((resolve, reject) => {
170
181
  });
171
182
  var circuitOpen = (provider) => {
172
183
  const record = recordFor(provider);
184
+ if (record.external && !record.external.available) {
185
+ return new ProviderError({
186
+ message: `${provider} API is reported down${record.external.reason ? `: ${record.external.reason}` : ""}`,
187
+ provider,
188
+ retryable: true,
189
+ status: null,
190
+ type: record.external.indicator
191
+ });
192
+ }
173
193
  if (record.state !== "open")
174
194
  return null;
175
195
  if (record.nextProbeAt !== null && Date.now() >= record.nextProbeAt) {
@@ -4124,11 +4144,110 @@ var createOAuth2ClientCredentialsTokenSource = (config2) => {
4124
4144
  return inflight;
4125
4145
  };
4126
4146
  };
4147
+ // src/ai/providerStatusMonitor.ts
4148
+ var API_COMPONENT_BY_PROVIDER = {
4149
+ anthropic: "Claude API (api.anthropic.com)",
4150
+ openai: "Chat Completions"
4151
+ };
4152
+ var AVAILABLE_COMPONENT_STATUSES = new Set([
4153
+ "operational",
4154
+ "degraded_performance"
4155
+ ]);
4156
+ var AVAILABLE_PAGE_INDICATORS = new Set(["none", "minor"]);
4157
+ var isRecord6 = (value) => typeof value === "object" && value !== null;
4158
+ var readString = (record, key) => typeof record[key] === "string" ? record[key] : "";
4159
+ var findComponentStatus = (body, componentName) => {
4160
+ if (!isRecord6(body) || !Array.isArray(body.components))
4161
+ return null;
4162
+ const match = body.components.filter(isRecord6).find((component) => readString(component, "name") === componentName);
4163
+ return match ? readString(match, "status") : null;
4164
+ };
4165
+ var readPageIndicator = (body) => {
4166
+ if (!isRecord6(body) || !isRecord6(body.status))
4167
+ return null;
4168
+ const indicator = readString(body.status, "indicator");
4169
+ return indicator === "" ? null : indicator;
4170
+ };
4171
+ var fetchJson = async (url, signal) => {
4172
+ const response = await fetch(url, { signal });
4173
+ if (!response.ok)
4174
+ throw new Error(`status fetch ${response.status}`);
4175
+ return response.json();
4176
+ };
4177
+ var unknownStatus = (provider) => ({
4178
+ available: true,
4179
+ checkedAt: Date.now(),
4180
+ componentName: null,
4181
+ indicator: "unknown",
4182
+ provider,
4183
+ reason: "",
4184
+ statusPageUrl: providerStatusPage(provider)
4185
+ });
4186
+ var fetchProviderApiStatus = async (provider, signal) => {
4187
+ const base = PROVIDER_STATUS_PAGES[provider];
4188
+ if (base === undefined)
4189
+ return unknownStatus(provider);
4190
+ try {
4191
+ const componentName = API_COMPONENT_BY_PROVIDER[provider] ?? null;
4192
+ if (componentName !== null) {
4193
+ const components = await fetchJson(`${base}/api/v2/components.json`, signal);
4194
+ const status = findComponentStatus(components, componentName);
4195
+ if (status !== null) {
4196
+ const available2 = AVAILABLE_COMPONENT_STATUSES.has(status);
4197
+ return {
4198
+ available: available2,
4199
+ checkedAt: Date.now(),
4200
+ componentName,
4201
+ indicator: status,
4202
+ provider,
4203
+ reason: available2 ? "" : `${status} on ${componentName}`,
4204
+ statusPageUrl: base
4205
+ };
4206
+ }
4207
+ }
4208
+ const summary = await fetchJson(`${base}/api/v2/status.json`, signal);
4209
+ const indicator = readPageIndicator(summary);
4210
+ if (indicator === null)
4211
+ return unknownStatus(provider);
4212
+ const available = AVAILABLE_PAGE_INDICATORS.has(indicator);
4213
+ return {
4214
+ available,
4215
+ checkedAt: Date.now(),
4216
+ componentName: null,
4217
+ indicator,
4218
+ provider,
4219
+ reason: available ? "" : `page status: ${indicator}`,
4220
+ statusPageUrl: base
4221
+ };
4222
+ } catch {
4223
+ return unknownStatus(provider);
4224
+ }
4225
+ };
4226
+ var startProviderStatusMonitor = (options) => {
4227
+ const providers = options?.providers ?? ["anthropic", "openai"];
4228
+ const intervalMs = options?.intervalMs ?? 60000;
4229
+ const tick = async () => {
4230
+ const results = await Promise.all(providers.map((provider) => fetchProviderApiStatus(provider)));
4231
+ for (const status of results) {
4232
+ setProviderAvailability(status.provider, {
4233
+ available: status.available,
4234
+ indicator: status.indicator,
4235
+ reason: status.reason
4236
+ });
4237
+ options?.onUpdate?.(status);
4238
+ }
4239
+ };
4240
+ tick();
4241
+ const timer = setInterval(() => void tick(), intervalMs);
4242
+ return () => clearInterval(timer);
4243
+ };
4127
4244
  export {
4128
4245
  xai,
4129
4246
  withResilience,
4130
4247
  streamAIToSSE,
4131
4248
  streamAI,
4249
+ startProviderStatusMonitor,
4250
+ setProviderAvailability,
4132
4251
  serverMessageToAction,
4133
4252
  serializeAIMessage,
4134
4253
  resolveRenderers,
@@ -4148,6 +4267,7 @@ export {
4148
4267
  generateAIWithTools,
4149
4268
  generateAI,
4150
4269
  gemini,
4270
+ fetchProviderApiStatus,
4151
4271
  deepseek,
4152
4272
  createSyncConversationStore,
4153
4273
  createOAuth2ClientCredentialsTokenSource,
@@ -4163,5 +4283,5 @@ export {
4163
4283
  PROVIDER_STATUS_PAGES
4164
4284
  };
4165
4285
 
4166
- //# debugId=4F9632D62D06633E64756E2164756E21
4286
+ //# debugId=E077A15D83F1F94464756E2164756E21
4167
4287
  //# sourceMappingURL=index.js.map