@umituz/web-ai 1.0.0 → 1.0.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/{ABTesting-DDqNhHtP.d.ts → AIErrors-B2ogd1PB.d.ts} +14 -1
- package/dist/{ABTesting-DWBtKTMQ.d.cts → AIErrors-C5EasV_c.d.cts} +14 -1
- package/dist/{ProviderConfig-a55tLhWT.d.cts → ProviderConfig-DIFa9nmG.d.cts} +10 -1
- package/dist/{ProviderConfig-a55tLhWT.d.ts → ProviderConfig-DIFa9nmG.d.ts} +10 -1
- package/dist/chat/index.cjs +114 -23
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +4 -4
- package/dist/chat/index.d.ts +4 -4
- package/dist/chat/index.js +114 -23
- package/dist/chat/index.js.map +1 -1
- package/dist/{chat.service-DBKq9I2c.d.cts → chat.service-CL1qtYxe.d.cts} +7 -7
- package/dist/{chat.service-RQn8UTXD.d.ts → chat.service-q05GnhEm.d.ts} +7 -7
- package/dist/content/index.cjs +393 -186
- package/dist/content/index.cjs.map +1 -1
- package/dist/content/index.d.cts +7 -8
- package/dist/content/index.d.ts +7 -8
- package/dist/content/index.js +393 -186
- package/dist/content/index.js.map +1 -1
- package/dist/core/index.cjs +112 -15
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +5 -33
- package/dist/core/index.d.ts +5 -33
- package/dist/core/index.js +111 -16
- package/dist/core/index.js.map +1 -1
- package/dist/{create-ai-DGZFBOA1.d.cts → create-ai-DOI9jD3v.d.cts} +4 -21
- package/dist/{create-ai-BhNaz86i.d.ts → create-ai-DXEoke8-.d.ts} +4 -21
- package/dist/hooks/index.cjs +359 -169
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +6 -6
- package/dist/hooks/index.d.ts +6 -6
- package/dist/hooks/index.js +359 -169
- package/dist/hooks/index.js.map +1 -1
- package/dist/index-DIHz8_OJ.d.ts +48 -0
- package/dist/index-DKHNcMbl.d.cts +48 -0
- package/dist/index.cjs +245 -94
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +244 -95
- package/dist/index.js.map +1 -1
- package/dist/{provider.factory-COsnprLH.d.cts → provider.factory-BxsfK4WW.d.cts} +1 -1
- package/dist/{provider.factory-CpWFyjbw.d.ts → provider.factory-DfDfk0dK.d.ts} +1 -1
- package/dist/providers/index.cjs +281 -124
- package/dist/providers/index.cjs.map +1 -1
- package/dist/providers/index.d.cts +11 -12
- package/dist/providers/index.d.ts +11 -12
- package/dist/providers/index.js +281 -124
- package/dist/providers/index.js.map +1 -1
- package/dist/wizard/index.d.cts +1 -1
- package/dist/wizard/index.d.ts +1 -1
- package/package.json +4 -1
- package/dist/index-DjX9ZKuM.d.cts +0 -14
- package/dist/index-DxLvE588.d.ts +0 -14
package/dist/providers/index.js
CHANGED
|
@@ -6,25 +6,49 @@ function isMediaProvider(provider) {
|
|
|
6
6
|
return provider.capabilities.includes("image") || provider.capabilities.includes("video");
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
// src/
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
9
|
+
// src/core/errors/ai-error-types.ts
|
|
10
|
+
var AIErrorType = /* @__PURE__ */ ((AIErrorType2) => {
|
|
11
|
+
AIErrorType2["INVALID_API_KEY"] = "INVALID_API_KEY";
|
|
12
|
+
AIErrorType2["MISSING_CONFIG"] = "MISSING_CONFIG";
|
|
13
|
+
AIErrorType2["NETWORK_ERROR"] = "NETWORK_ERROR";
|
|
14
|
+
AIErrorType2["ABORT_ERROR"] = "ABORT_ERROR";
|
|
15
|
+
AIErrorType2["RATE_LIMIT_ERROR"] = "RATE_LIMIT_ERROR";
|
|
16
|
+
AIErrorType2["SERVER_ERROR"] = "SERVER_ERROR";
|
|
17
|
+
AIErrorType2["CLIENT_ERROR"] = "CLIENT_ERROR";
|
|
18
|
+
AIErrorType2["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
|
|
19
|
+
return AIErrorType2;
|
|
20
|
+
})(AIErrorType || {});
|
|
21
|
+
|
|
22
|
+
// src/core/errors/ai-error.ts
|
|
23
|
+
var KNOWN_ERROR_TYPES = new Set(Object.values(AIErrorType));
|
|
24
|
+
function mapCodeToType(code) {
|
|
25
|
+
switch (code) {
|
|
26
|
+
case "VALIDATION_ERROR":
|
|
27
|
+
case "CLIENT_ERROR":
|
|
28
|
+
return "CLIENT_ERROR" /* CLIENT_ERROR */;
|
|
29
|
+
case "INVALID_API_KEY":
|
|
30
|
+
return "INVALID_API_KEY" /* INVALID_API_KEY */;
|
|
31
|
+
case "MISSING_CONFIG":
|
|
32
|
+
case "PROVIDER_UNAVAILABLE":
|
|
33
|
+
return "MISSING_CONFIG" /* MISSING_CONFIG */;
|
|
34
|
+
case "PROVIDER_QUOTA_EXHAUSTED":
|
|
35
|
+
case "RATE_LIMIT_ERROR":
|
|
36
|
+
return "RATE_LIMIT_ERROR" /* RATE_LIMIT_ERROR */;
|
|
37
|
+
case "NETWORK_ERROR":
|
|
38
|
+
case "TIMEOUT":
|
|
39
|
+
return "NETWORK_ERROR" /* NETWORK_ERROR */;
|
|
40
|
+
case "ABORT_ERROR":
|
|
41
|
+
case "ABORTED":
|
|
42
|
+
return "ABORT_ERROR" /* ABORT_ERROR */;
|
|
43
|
+
case "SERVER_ERROR":
|
|
44
|
+
case "PROVIDER_ERROR":
|
|
45
|
+
case "NO_RESULT":
|
|
46
|
+
return "SERVER_ERROR" /* SERVER_ERROR */;
|
|
47
|
+
default:
|
|
48
|
+
return "UNKNOWN_ERROR" /* UNKNOWN_ERROR */;
|
|
25
49
|
}
|
|
26
|
-
}
|
|
27
|
-
function mapMessageToCode(message, fallback) {
|
|
50
|
+
}
|
|
51
|
+
function mapMessageToCode(message, fallback = "UNKNOWN") {
|
|
28
52
|
const lower = message.toLowerCase();
|
|
29
53
|
if (lower.includes("validation")) return "VALIDATION_ERROR";
|
|
30
54
|
if (lower.includes("quota")) return "PROVIDER_QUOTA_EXHAUSTED";
|
|
@@ -37,6 +61,53 @@ function mapMessageToCode(message, fallback) {
|
|
|
37
61
|
if (lower.includes("network") || lower.includes("fetch")) return "NETWORK_ERROR";
|
|
38
62
|
return fallback;
|
|
39
63
|
}
|
|
64
|
+
var AIError = class _AIError extends Error {
|
|
65
|
+
type;
|
|
66
|
+
code;
|
|
67
|
+
cause;
|
|
68
|
+
metadata;
|
|
69
|
+
constructor(typeOrMessage, messageOrCode, cause, metadata = {}) {
|
|
70
|
+
let effectiveType;
|
|
71
|
+
let effectiveMessage;
|
|
72
|
+
let effectiveCode;
|
|
73
|
+
if (KNOWN_ERROR_TYPES.has(typeOrMessage)) {
|
|
74
|
+
effectiveType = typeOrMessage;
|
|
75
|
+
effectiveMessage = messageOrCode ?? "";
|
|
76
|
+
effectiveCode = effectiveType;
|
|
77
|
+
} else {
|
|
78
|
+
effectiveMessage = typeOrMessage;
|
|
79
|
+
effectiveCode = messageOrCode ?? "UNKNOWN";
|
|
80
|
+
effectiveType = mapCodeToType(effectiveCode);
|
|
81
|
+
}
|
|
82
|
+
super(effectiveMessage);
|
|
83
|
+
this.name = "AIError";
|
|
84
|
+
this.type = effectiveType;
|
|
85
|
+
this.code = effectiveCode;
|
|
86
|
+
this.cause = cause;
|
|
87
|
+
this.metadata = metadata;
|
|
88
|
+
}
|
|
89
|
+
static from(error, fallbackCode = "UNKNOWN") {
|
|
90
|
+
if (error instanceof _AIError) return error;
|
|
91
|
+
if (error instanceof Error) {
|
|
92
|
+
const code = mapMessageToCode(error.message, fallbackCode);
|
|
93
|
+
return new _AIError(error.message, code, error);
|
|
94
|
+
}
|
|
95
|
+
return new _AIError(String(error), fallbackCode, error);
|
|
96
|
+
}
|
|
97
|
+
toString() {
|
|
98
|
+
const statusPart = typeof this.metadata.status === "number" ? ` (HTTP ${this.metadata.status})` : "";
|
|
99
|
+
return `${this.name} [${this.type}]: ${this.message}${statusPart}`;
|
|
100
|
+
}
|
|
101
|
+
toJSON() {
|
|
102
|
+
return {
|
|
103
|
+
name: this.name,
|
|
104
|
+
type: this.type,
|
|
105
|
+
code: this.code,
|
|
106
|
+
message: this.message,
|
|
107
|
+
metadata: this.metadata
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
};
|
|
40
111
|
|
|
41
112
|
// src/content/domain/limits/ProviderTimingConfig.ts
|
|
42
113
|
var ProviderTimingConfig = {
|
|
@@ -111,32 +182,6 @@ var ProviderError = class extends AIError {
|
|
|
111
182
|
providerId;
|
|
112
183
|
};
|
|
113
184
|
|
|
114
|
-
// src/core/errors/ai-error.ts
|
|
115
|
-
var AIError2 = class extends Error {
|
|
116
|
-
type;
|
|
117
|
-
cause;
|
|
118
|
-
metadata;
|
|
119
|
-
constructor(type, message, cause, metadata = {}) {
|
|
120
|
-
super(message);
|
|
121
|
-
this.name = "AIError";
|
|
122
|
-
this.type = type;
|
|
123
|
-
this.cause = cause;
|
|
124
|
-
this.metadata = metadata;
|
|
125
|
-
}
|
|
126
|
-
toString() {
|
|
127
|
-
const statusPart = typeof this.metadata.status === "number" ? ` (HTTP ${this.metadata.status})` : "";
|
|
128
|
-
return `${this.name} [${this.type}]: ${this.message}${statusPart}`;
|
|
129
|
-
}
|
|
130
|
-
toJSON() {
|
|
131
|
-
return {
|
|
132
|
-
name: this.name,
|
|
133
|
-
type: this.type,
|
|
134
|
-
message: this.message,
|
|
135
|
-
metadata: this.metadata
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
185
|
// src/core/errors/error-classifier.ts
|
|
141
186
|
var DEFAULT_RETRYABLE_TYPES = /* @__PURE__ */ new Set([
|
|
142
187
|
"NETWORK_ERROR" /* NETWORK_ERROR */,
|
|
@@ -262,7 +307,7 @@ var ProviderFactory = class {
|
|
|
262
307
|
}
|
|
263
308
|
}
|
|
264
309
|
}
|
|
265
|
-
const failure = new
|
|
310
|
+
const failure = new AIError(
|
|
266
311
|
"SERVER_ERROR" /* SERVER_ERROR */,
|
|
267
312
|
`All providers failed for capability 'text'`,
|
|
268
313
|
lastError instanceof Error ? lastError : void 0
|
|
@@ -276,12 +321,16 @@ var ProviderFactory = class {
|
|
|
276
321
|
let wake = null;
|
|
277
322
|
let finished = false;
|
|
278
323
|
let failure;
|
|
324
|
+
const controller = new AbortController();
|
|
325
|
+
const onAbort = () => controller.abort();
|
|
326
|
+
request.signal?.addEventListener("abort", onAbort);
|
|
327
|
+
const effectiveRequest = { ...request, signal: controller.signal };
|
|
279
328
|
const notify = () => {
|
|
280
329
|
const resolve = wake;
|
|
281
330
|
wake = null;
|
|
282
331
|
resolve?.();
|
|
283
332
|
};
|
|
284
|
-
const completion = this.chatStream(
|
|
333
|
+
const completion = this.chatStream(effectiveRequest, {
|
|
285
334
|
onChunk: (chunk) => {
|
|
286
335
|
queue.push(chunk);
|
|
287
336
|
notify();
|
|
@@ -297,18 +346,23 @@ var ProviderFactory = class {
|
|
|
297
346
|
notify();
|
|
298
347
|
}
|
|
299
348
|
);
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
349
|
+
try {
|
|
350
|
+
while (!finished || queue.length > 0) {
|
|
351
|
+
if (queue.length === 0 && !finished) {
|
|
352
|
+
await new Promise((resolve) => {
|
|
353
|
+
wake = resolve;
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
while (queue.length > 0) {
|
|
357
|
+
yield queue.shift();
|
|
358
|
+
}
|
|
359
|
+
if (failure) throw failure;
|
|
308
360
|
}
|
|
309
|
-
|
|
361
|
+
await completion;
|
|
362
|
+
} finally {
|
|
363
|
+
controller.abort();
|
|
364
|
+
request.signal?.removeEventListener("abort", onAbort);
|
|
310
365
|
}
|
|
311
|
-
await completion;
|
|
312
366
|
}
|
|
313
367
|
async generateJson(request) {
|
|
314
368
|
const effective = request.model || request.tier ? request : { ...request, tier: this.defaultTier };
|
|
@@ -416,7 +470,7 @@ var ProviderFactory = class {
|
|
|
416
470
|
}
|
|
417
471
|
}
|
|
418
472
|
}
|
|
419
|
-
throw new
|
|
473
|
+
throw new AIError(
|
|
420
474
|
"SERVER_ERROR" /* SERVER_ERROR */,
|
|
421
475
|
`All providers failed for capability '${capability}'`,
|
|
422
476
|
lastError instanceof Error ? lastError : void 0
|
|
@@ -445,7 +499,7 @@ var ProviderFactory = class {
|
|
|
445
499
|
}
|
|
446
500
|
}
|
|
447
501
|
noProviderError(capability) {
|
|
448
|
-
return new
|
|
502
|
+
return new AIError(
|
|
449
503
|
"MISSING_CONFIG" /* MISSING_CONFIG */,
|
|
450
504
|
`No provider registered for capability '${capability}' \u2014 create one with createAI() and include its config block`
|
|
451
505
|
);
|
|
@@ -455,15 +509,22 @@ var ProviderFactory = class {
|
|
|
455
509
|
// src/core/constants/protocol.constants.ts
|
|
456
510
|
var SSE_PREFIX = "data: ";
|
|
457
511
|
var SSE_DONE_MARKER = "[DONE]";
|
|
458
|
-
var JSON_CODE_BLOCK_PATTERN = /```json
|
|
512
|
+
var JSON_CODE_BLOCK_PATTERN = /```(?:json)?\s*\n?([\s\S]*?)\n?```/;
|
|
459
513
|
var JSON_OBJECT_PATTERN = /\{[\s\S]*\}/;
|
|
514
|
+
var JSON_ARRAY_PATTERN = /\[[\s\S]*\]/;
|
|
460
515
|
|
|
461
516
|
// src/core/parsers/sse-lines.ts
|
|
462
517
|
function isSseDataLine(line) {
|
|
463
|
-
return line.startsWith(SSE_PREFIX);
|
|
518
|
+
return line.startsWith(SSE_PREFIX) || line.startsWith("data:");
|
|
464
519
|
}
|
|
465
520
|
function extractSseDataPayload(line) {
|
|
466
|
-
|
|
521
|
+
if (line.startsWith(SSE_PREFIX)) {
|
|
522
|
+
return line.slice(SSE_PREFIX.length);
|
|
523
|
+
}
|
|
524
|
+
if (line.startsWith("data:")) {
|
|
525
|
+
return line.slice(5);
|
|
526
|
+
}
|
|
527
|
+
return line;
|
|
467
528
|
}
|
|
468
529
|
function isSseDoneMarker(payload) {
|
|
469
530
|
return payload === SSE_DONE_MARKER;
|
|
@@ -472,7 +533,7 @@ function isSseDoneMarker(payload) {
|
|
|
472
533
|
// src/core/parsers/json-content-extractor.ts
|
|
473
534
|
function extractJsonFromCodeFence(content) {
|
|
474
535
|
const match = content.match(JSON_CODE_BLOCK_PATTERN);
|
|
475
|
-
if (match && match[1]) return match[1];
|
|
536
|
+
if (match && match[1]) return match[1].trim();
|
|
476
537
|
return null;
|
|
477
538
|
}
|
|
478
539
|
function extractJsonObject(content) {
|
|
@@ -480,8 +541,27 @@ function extractJsonObject(content) {
|
|
|
480
541
|
if (match && match[0]) return match[0];
|
|
481
542
|
return null;
|
|
482
543
|
}
|
|
544
|
+
function extractJsonArray(content) {
|
|
545
|
+
const match = content.match(JSON_ARRAY_PATTERN);
|
|
546
|
+
if (match && match[0]) return match[0];
|
|
547
|
+
return null;
|
|
548
|
+
}
|
|
549
|
+
function repairCommonJsonDefects(text) {
|
|
550
|
+
return text.replace(/(:\s*-?\d+(?:\.\d+)?)\s*"/g, "$1").replace(/(:\s*"[^"]*")"/g, "$1");
|
|
551
|
+
}
|
|
483
552
|
function extractJsonCandidate(content) {
|
|
484
|
-
|
|
553
|
+
const fromFence = extractJsonFromCodeFence(content);
|
|
554
|
+
if (fromFence) return fromFence;
|
|
555
|
+
const objectIndex = content.indexOf("{");
|
|
556
|
+
const arrayIndex = content.indexOf("[");
|
|
557
|
+
if (objectIndex !== -1 && (arrayIndex === -1 || objectIndex < arrayIndex)) {
|
|
558
|
+
const obj = extractJsonObject(content);
|
|
559
|
+
if (obj) return obj;
|
|
560
|
+
} else if (arrayIndex !== -1) {
|
|
561
|
+
const arr = extractJsonArray(content);
|
|
562
|
+
if (arr) return arr;
|
|
563
|
+
}
|
|
564
|
+
return content.trim();
|
|
485
565
|
}
|
|
486
566
|
|
|
487
567
|
// src/core/parsers/json-response.parser.ts
|
|
@@ -490,12 +570,17 @@ var JsonResponseParser = class {
|
|
|
490
570
|
const candidate = extractJsonCandidate(rawContent);
|
|
491
571
|
try {
|
|
492
572
|
return JSON.parse(candidate);
|
|
493
|
-
} catch
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
573
|
+
} catch {
|
|
574
|
+
try {
|
|
575
|
+
return JSON.parse(repairCommonJsonDefects(candidate));
|
|
576
|
+
} catch (error) {
|
|
577
|
+
throw new AIError(
|
|
578
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
579
|
+
"Failed to parse structured response as JSON",
|
|
580
|
+
error instanceof Error ? error : void 0,
|
|
581
|
+
{ rawContent }
|
|
582
|
+
);
|
|
583
|
+
}
|
|
499
584
|
}
|
|
500
585
|
}
|
|
501
586
|
};
|
|
@@ -621,7 +706,7 @@ var AnthropicHttpTransport = class {
|
|
|
621
706
|
});
|
|
622
707
|
if (!response.ok) await this.throwFromErrorResponse(response);
|
|
623
708
|
if (!response.body) {
|
|
624
|
-
throw new
|
|
709
|
+
throw new AIError("NETWORK_ERROR" /* NETWORK_ERROR */, "Response body is null");
|
|
625
710
|
}
|
|
626
711
|
return response.body;
|
|
627
712
|
} catch (error) {
|
|
@@ -654,7 +739,7 @@ var AnthropicHttpTransport = class {
|
|
|
654
739
|
status: response.status,
|
|
655
740
|
url: response.url
|
|
656
741
|
};
|
|
657
|
-
throw new
|
|
742
|
+
throw new AIError(
|
|
658
743
|
classifyHttpStatus(response.status),
|
|
659
744
|
errorMessage,
|
|
660
745
|
void 0,
|
|
@@ -662,24 +747,24 @@ var AnthropicHttpTransport = class {
|
|
|
662
747
|
);
|
|
663
748
|
}
|
|
664
749
|
normalizeError(error) {
|
|
665
|
-
if (error instanceof
|
|
750
|
+
if (error instanceof AIError) return error;
|
|
666
751
|
if (error instanceof Error) {
|
|
667
752
|
if (error.name === "AbortError") {
|
|
668
|
-
return new
|
|
753
|
+
return new AIError(
|
|
669
754
|
"ABORT_ERROR" /* ABORT_ERROR */,
|
|
670
755
|
"Request was aborted by the client",
|
|
671
756
|
error
|
|
672
757
|
);
|
|
673
758
|
}
|
|
674
759
|
if (error.name === "TypeError" && error.message.toLowerCase().includes("network")) {
|
|
675
|
-
return new
|
|
760
|
+
return new AIError(
|
|
676
761
|
"NETWORK_ERROR" /* NETWORK_ERROR */,
|
|
677
762
|
"Network error: Unable to connect to the AI service",
|
|
678
763
|
error
|
|
679
764
|
);
|
|
680
765
|
}
|
|
681
766
|
}
|
|
682
|
-
return new
|
|
767
|
+
return new AIError(
|
|
683
768
|
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
684
769
|
error instanceof Error ? error.message : "Unknown error occurred",
|
|
685
770
|
error instanceof Error ? error : void 0
|
|
@@ -809,11 +894,14 @@ async function consumeAnthropicStream(stream, callbacks) {
|
|
|
809
894
|
break;
|
|
810
895
|
case "message_stop":
|
|
811
896
|
break;
|
|
812
|
-
case "error":
|
|
813
|
-
|
|
814
|
-
|
|
897
|
+
case "error": {
|
|
898
|
+
const errType = event.error.type;
|
|
899
|
+
const mappedType = errType === "rate_limit_error" ? "RATE_LIMIT_ERROR" /* RATE_LIMIT_ERROR */ : errType === "authentication_error" ? "INVALID_API_KEY" /* INVALID_API_KEY */ : errType === "invalid_request_error" ? "CLIENT_ERROR" /* CLIENT_ERROR */ : "SERVER_ERROR" /* SERVER_ERROR */;
|
|
900
|
+
throw new AIError(
|
|
901
|
+
mappedType,
|
|
815
902
|
event.error.message || "Anthropic stream failed mid-flight"
|
|
816
903
|
);
|
|
904
|
+
}
|
|
817
905
|
}
|
|
818
906
|
};
|
|
819
907
|
try {
|
|
@@ -828,8 +916,8 @@ async function consumeAnthropicStream(stream, callbacks) {
|
|
|
828
916
|
buffer += decoder.decode();
|
|
829
917
|
if (buffer.length > 0) consumeLine(buffer);
|
|
830
918
|
} catch (error) {
|
|
831
|
-
if (error instanceof
|
|
832
|
-
throw new
|
|
919
|
+
if (error instanceof AIError) throw error;
|
|
920
|
+
throw new AIError(
|
|
833
921
|
"NETWORK_ERROR" /* NETWORK_ERROR */,
|
|
834
922
|
"Stream was interrupted",
|
|
835
923
|
error instanceof Error ? error : void 0
|
|
@@ -891,7 +979,7 @@ var AnthropicProvider = class {
|
|
|
891
979
|
const messages = [...request.messages];
|
|
892
980
|
const lastUserIndex = findLastIndex(messages, (m) => m.role === "user");
|
|
893
981
|
if (lastUserIndex === -1) {
|
|
894
|
-
throw new
|
|
982
|
+
throw new AIError(
|
|
895
983
|
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
896
984
|
"generateStructured requires at least one user message"
|
|
897
985
|
);
|
|
@@ -946,7 +1034,7 @@ var AnthropicProvider = class {
|
|
|
946
1034
|
finishReason
|
|
947
1035
|
};
|
|
948
1036
|
}
|
|
949
|
-
throw new
|
|
1037
|
+
throw new AIError(
|
|
950
1038
|
"SERVER_ERROR" /* SERVER_ERROR */,
|
|
951
1039
|
"No content generated from Anthropic API",
|
|
952
1040
|
void 0,
|
|
@@ -1151,7 +1239,7 @@ var RetryManager = class {
|
|
|
1151
1239
|
}
|
|
1152
1240
|
shouldRetry(error, options) {
|
|
1153
1241
|
if (options.shouldRetry) return options.shouldRetry(error);
|
|
1154
|
-
if (error instanceof
|
|
1242
|
+
if (error instanceof AIError) {
|
|
1155
1243
|
return isRetryableErrorType(error.type, DEFAULT_ERROR_CLASSIFICATION_RULE);
|
|
1156
1244
|
}
|
|
1157
1245
|
const lower = error.message.toLowerCase();
|
|
@@ -1396,7 +1484,7 @@ var GroqHttpTransport = class {
|
|
|
1396
1484
|
});
|
|
1397
1485
|
if (!response.ok) await this.throwFromErrorResponse(response);
|
|
1398
1486
|
if (!response.body) {
|
|
1399
|
-
throw new
|
|
1487
|
+
throw new AIError("NETWORK_ERROR" /* NETWORK_ERROR */, "Response body is null");
|
|
1400
1488
|
}
|
|
1401
1489
|
return response.body;
|
|
1402
1490
|
} catch (error) {
|
|
@@ -1444,7 +1532,7 @@ var GroqHttpTransport = class {
|
|
|
1444
1532
|
status: response.status,
|
|
1445
1533
|
url: response.url
|
|
1446
1534
|
};
|
|
1447
|
-
throw new
|
|
1535
|
+
throw new AIError(
|
|
1448
1536
|
classifyHttpStatus(response.status),
|
|
1449
1537
|
errorMessage,
|
|
1450
1538
|
void 0,
|
|
@@ -1452,24 +1540,24 @@ var GroqHttpTransport = class {
|
|
|
1452
1540
|
);
|
|
1453
1541
|
}
|
|
1454
1542
|
normalizeError(error) {
|
|
1455
|
-
if (error instanceof
|
|
1543
|
+
if (error instanceof AIError) return error;
|
|
1456
1544
|
if (error instanceof Error) {
|
|
1457
1545
|
if (error.name === "AbortError") {
|
|
1458
|
-
return new
|
|
1546
|
+
return new AIError(
|
|
1459
1547
|
"ABORT_ERROR" /* ABORT_ERROR */,
|
|
1460
1548
|
"Request was aborted by the client",
|
|
1461
1549
|
error
|
|
1462
1550
|
);
|
|
1463
1551
|
}
|
|
1464
1552
|
if (error.name === "TypeError" && error.message.toLowerCase().includes("network")) {
|
|
1465
|
-
return new
|
|
1553
|
+
return new AIError(
|
|
1466
1554
|
"NETWORK_ERROR" /* NETWORK_ERROR */,
|
|
1467
1555
|
"Network error: Unable to connect to the AI service",
|
|
1468
1556
|
error
|
|
1469
1557
|
);
|
|
1470
1558
|
}
|
|
1471
1559
|
}
|
|
1472
|
-
return new
|
|
1560
|
+
return new AIError(
|
|
1473
1561
|
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
1474
1562
|
error instanceof Error ? error.message : "Unknown error occurred",
|
|
1475
1563
|
error instanceof Error ? error : void 0
|
|
@@ -1620,6 +1708,13 @@ async function consumeGroqStream(stream, callbacks) {
|
|
|
1620
1708
|
} catch {
|
|
1621
1709
|
return;
|
|
1622
1710
|
}
|
|
1711
|
+
const errorBody = chunk.error;
|
|
1712
|
+
if (errorBody) {
|
|
1713
|
+
throw new AIError(
|
|
1714
|
+
errorBody.message?.toLowerCase().includes("rate limit") ? "RATE_LIMIT_ERROR" /* RATE_LIMIT_ERROR */ : "SERVER_ERROR" /* SERVER_ERROR */,
|
|
1715
|
+
errorBody.message || "Groq stream failed mid-flight"
|
|
1716
|
+
);
|
|
1717
|
+
}
|
|
1623
1718
|
if (chunk.model) model = chunk.model;
|
|
1624
1719
|
const choice = chunk.choices?.[0];
|
|
1625
1720
|
const delta = choice?.delta?.content;
|
|
@@ -1634,13 +1729,6 @@ async function consumeGroqStream(stream, callbacks) {
|
|
|
1634
1729
|
if (tailUsage) {
|
|
1635
1730
|
usage = mapGroqUsage(tailUsage);
|
|
1636
1731
|
}
|
|
1637
|
-
const errorBody = chunk.error;
|
|
1638
|
-
if (errorBody) {
|
|
1639
|
-
throw new AIError2(
|
|
1640
|
-
"SERVER_ERROR" /* SERVER_ERROR */,
|
|
1641
|
-
errorBody.message || "Groq stream failed mid-flight"
|
|
1642
|
-
);
|
|
1643
|
-
}
|
|
1644
1732
|
};
|
|
1645
1733
|
try {
|
|
1646
1734
|
while (true) {
|
|
@@ -1654,8 +1742,8 @@ async function consumeGroqStream(stream, callbacks) {
|
|
|
1654
1742
|
buffer += decoder.decode();
|
|
1655
1743
|
if (buffer.length > 0) consumeLine(buffer);
|
|
1656
1744
|
} catch (error) {
|
|
1657
|
-
if (error instanceof
|
|
1658
|
-
throw new
|
|
1745
|
+
if (error instanceof AIError) throw error;
|
|
1746
|
+
throw new AIError(
|
|
1659
1747
|
"NETWORK_ERROR" /* NETWORK_ERROR */,
|
|
1660
1748
|
"Stream was interrupted",
|
|
1661
1749
|
error instanceof Error ? error : void 0
|
|
@@ -1713,7 +1801,7 @@ var GroqProvider = class {
|
|
|
1713
1801
|
const choice = response.choices?.[0];
|
|
1714
1802
|
const text = choice?.message?.content ?? "";
|
|
1715
1803
|
if (text.length === 0) {
|
|
1716
|
-
throw new
|
|
1804
|
+
throw new AIError(
|
|
1717
1805
|
"SERVER_ERROR" /* SERVER_ERROR */,
|
|
1718
1806
|
"No content generated from Groq API",
|
|
1719
1807
|
void 0,
|
|
@@ -1735,7 +1823,7 @@ var GroqProvider = class {
|
|
|
1735
1823
|
const messages = toGroqMessages(request.messages, request.systemPrompt);
|
|
1736
1824
|
const lastUserIndex = findLastIndex2(messages, (m) => m.role === "user");
|
|
1737
1825
|
if (lastUserIndex === -1) {
|
|
1738
|
-
throw new
|
|
1826
|
+
throw new AIError(
|
|
1739
1827
|
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
1740
1828
|
"generateStructured requires at least one user message"
|
|
1741
1829
|
);
|
|
@@ -1749,7 +1837,7 @@ var GroqProvider = class {
|
|
|
1749
1837
|
const choice = response.choices?.[0];
|
|
1750
1838
|
const text = choice?.message?.content ?? "";
|
|
1751
1839
|
if (text.length === 0) {
|
|
1752
|
-
throw new
|
|
1840
|
+
throw new AIError(
|
|
1753
1841
|
"SERVER_ERROR" /* SERVER_ERROR */,
|
|
1754
1842
|
"No content generated from Groq API",
|
|
1755
1843
|
void 0,
|
|
@@ -1776,7 +1864,7 @@ var GroqProvider = class {
|
|
|
1776
1864
|
try {
|
|
1777
1865
|
const outcome = await consumeGroqStream(streamBody, callbacks);
|
|
1778
1866
|
if (outcome.text.length === 0) {
|
|
1779
|
-
throw new
|
|
1867
|
+
throw new AIError(
|
|
1780
1868
|
"SERVER_ERROR" /* SERVER_ERROR */,
|
|
1781
1869
|
"No content generated from Groq API",
|
|
1782
1870
|
void 0,
|
|
@@ -1907,7 +1995,9 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
1907
1995
|
headers: this.authHeaders()
|
|
1908
1996
|
}
|
|
1909
1997
|
);
|
|
1910
|
-
|
|
1998
|
+
if (response.ok) return "healthy";
|
|
1999
|
+
if (response.status === 401 || response.status === 403) return "unavailable";
|
|
2000
|
+
return "degraded";
|
|
1911
2001
|
} catch {
|
|
1912
2002
|
return "unavailable";
|
|
1913
2003
|
}
|
|
@@ -1918,6 +2008,8 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
1918
2008
|
async generate(request) {
|
|
1919
2009
|
try {
|
|
1920
2010
|
const model = request.model ?? this.resolveModel(request.tier ?? "balanced");
|
|
2011
|
+
const systemMessages = request.messages.filter((m) => m.role === "system");
|
|
2012
|
+
const systemPrompt = request.systemPrompt && request.systemPrompt.length > 0 ? request.systemPrompt : systemMessages.length > 0 ? systemMessages.map((m) => m.content).join("\n") : void 0;
|
|
1921
2013
|
const response = await this.withRetry(async () => {
|
|
1922
2014
|
return await this.fetchWithTimeout(
|
|
1923
2015
|
`${this.config.baseUrl}/models/${model}:generateContent`,
|
|
@@ -1925,24 +2017,30 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
1925
2017
|
method: "POST",
|
|
1926
2018
|
headers: this.authHeaders(),
|
|
1927
2019
|
body: JSON.stringify({
|
|
1928
|
-
systemInstruction:
|
|
2020
|
+
systemInstruction: systemPrompt && systemPrompt.length > 0 ? { parts: [{ text: systemPrompt }] } : void 0,
|
|
1929
2021
|
contents: toGeminiContents(request.messages),
|
|
1930
2022
|
generationConfig: {
|
|
1931
|
-
temperature: request.temperature
|
|
1932
|
-
maxOutputTokens: request.maxTokens
|
|
1933
|
-
topP: request.topP
|
|
2023
|
+
temperature: request.temperature ?? 0.7,
|
|
2024
|
+
maxOutputTokens: request.maxTokens ?? 2048,
|
|
2025
|
+
topP: request.topP ?? 0.9
|
|
1934
2026
|
}
|
|
1935
2027
|
})
|
|
1936
2028
|
}
|
|
1937
2029
|
);
|
|
1938
2030
|
});
|
|
1939
2031
|
if (!response.ok) {
|
|
1940
|
-
|
|
2032
|
+
const message = await extractErrorMessageFromResponse(response);
|
|
2033
|
+
throw new AIError(
|
|
2034
|
+
classifyHttpStatus(response.status),
|
|
2035
|
+
`Gemini API error (${response.status}): ${message}`,
|
|
2036
|
+
void 0,
|
|
2037
|
+
{ status: response.status, model }
|
|
2038
|
+
);
|
|
1941
2039
|
}
|
|
1942
2040
|
const data = await response.json();
|
|
1943
|
-
const text = data.candidates[0]?.content?.parts?.map((part) => part.text ?? "").join("") ?? "";
|
|
2041
|
+
const text = data.candidates?.[0]?.content?.parts?.map((part) => part.text ?? "").join("") ?? "";
|
|
1944
2042
|
if (text.length === 0) {
|
|
1945
|
-
throw new
|
|
2043
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No content generated from Gemini API", void 0, { model });
|
|
1946
2044
|
}
|
|
1947
2045
|
return {
|
|
1948
2046
|
text,
|
|
@@ -1953,11 +2051,11 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
1953
2051
|
} : void 0,
|
|
1954
2052
|
model,
|
|
1955
2053
|
providerId: this.id,
|
|
1956
|
-
finishReason: mapGeminiFinishReason(data.candidates[0]?.finishReason)
|
|
2054
|
+
finishReason: mapGeminiFinishReason(data.candidates?.[0]?.finishReason)
|
|
1957
2055
|
};
|
|
1958
2056
|
} catch (error) {
|
|
1959
|
-
if (error instanceof
|
|
1960
|
-
throw new
|
|
2057
|
+
if (error instanceof AIError) throw error;
|
|
2058
|
+
throw new AIError(
|
|
1961
2059
|
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
1962
2060
|
`Gemini text generation failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1963
2061
|
error instanceof Error ? error : void 0
|
|
@@ -1968,7 +2066,7 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
1968
2066
|
const messages = [...request.messages];
|
|
1969
2067
|
const lastUserIndex = findLastIndex3(messages, (m) => m.role === "user");
|
|
1970
2068
|
if (lastUserIndex === -1) {
|
|
1971
|
-
throw new
|
|
2069
|
+
throw new AIError(
|
|
1972
2070
|
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
1973
2071
|
"generateStructured requires at least one user message"
|
|
1974
2072
|
);
|
|
@@ -2005,12 +2103,18 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2005
2103
|
);
|
|
2006
2104
|
});
|
|
2007
2105
|
if (!response.ok) {
|
|
2008
|
-
|
|
2106
|
+
const message = await extractErrorMessageFromResponse(response);
|
|
2107
|
+
throw new AIError(
|
|
2108
|
+
classifyHttpStatus(response.status),
|
|
2109
|
+
`Gemini image generation error (${response.status}): ${message}`,
|
|
2110
|
+
void 0,
|
|
2111
|
+
{ status: response.status }
|
|
2112
|
+
);
|
|
2009
2113
|
}
|
|
2010
2114
|
const data = await response.json();
|
|
2011
|
-
const imageData = data.candidates[0]?.content?.parts[0]?.inlineData;
|
|
2115
|
+
const imageData = data.candidates?.[0]?.content?.parts?.[0]?.inlineData;
|
|
2012
2116
|
if (!imageData) {
|
|
2013
|
-
throw new
|
|
2117
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No image data in Gemini response");
|
|
2014
2118
|
}
|
|
2015
2119
|
const url = `data:${imageData.mimeType};base64,${imageData.data}`;
|
|
2016
2120
|
return {
|
|
@@ -2329,17 +2433,70 @@ var PrunaProvider = class {
|
|
|
2329
2433
|
async estimateCost(_request) {
|
|
2330
2434
|
return 1;
|
|
2331
2435
|
}
|
|
2332
|
-
async generateImage(
|
|
2333
|
-
|
|
2436
|
+
async generateImage(request) {
|
|
2437
|
+
let finalUrl;
|
|
2438
|
+
const model = this.config.models?.textToImage;
|
|
2439
|
+
for await (const stage of generateWithPruna(
|
|
2440
|
+
{ prompt: request.prompt, model, quality: request.quality },
|
|
2441
|
+
this.config.apiKey
|
|
2442
|
+
)) {
|
|
2443
|
+
if (stage.error) throw stage.error;
|
|
2444
|
+
if (stage.result?.url) finalUrl = stage.result.url;
|
|
2445
|
+
}
|
|
2446
|
+
if (!finalUrl) {
|
|
2447
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No image generated by Pruna AI");
|
|
2448
|
+
}
|
|
2449
|
+
return {
|
|
2450
|
+
id: Date.now().toString(),
|
|
2451
|
+
type: "image",
|
|
2452
|
+
url: finalUrl,
|
|
2453
|
+
metadata: { provider: this.id, model: model ?? "p-image" },
|
|
2454
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2455
|
+
};
|
|
2334
2456
|
}
|
|
2335
|
-
async generateVideo(
|
|
2336
|
-
|
|
2457
|
+
async generateVideo(request) {
|
|
2458
|
+
let finalUrl;
|
|
2459
|
+
const model = this.config.models?.textToVideo;
|
|
2460
|
+
for await (const stage of generateWithPruna(
|
|
2461
|
+
{ prompt: request.prompt, model, duration: request.duration, aspectRatio: request.aspectRatio },
|
|
2462
|
+
this.config.apiKey
|
|
2463
|
+
)) {
|
|
2464
|
+
if (stage.error) throw stage.error;
|
|
2465
|
+
if (stage.result?.url) finalUrl = stage.result.url;
|
|
2466
|
+
}
|
|
2467
|
+
if (!finalUrl) {
|
|
2468
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No video generated by Pruna AI");
|
|
2469
|
+
}
|
|
2470
|
+
return {
|
|
2471
|
+
id: Date.now().toString(),
|
|
2472
|
+
type: "video",
|
|
2473
|
+
url: finalUrl,
|
|
2474
|
+
metadata: { provider: this.id, model: model ?? "p-video" },
|
|
2475
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2476
|
+
};
|
|
2337
2477
|
}
|
|
2338
|
-
async imageToVideo(
|
|
2339
|
-
|
|
2478
|
+
async imageToVideo(request) {
|
|
2479
|
+
let finalUrl;
|
|
2480
|
+
for await (const stage of generateWithPruna(
|
|
2481
|
+
{ image: request.imageUrl, prompt: request.prompt, duration: request.duration, motion: request.motion },
|
|
2482
|
+
this.config.apiKey
|
|
2483
|
+
)) {
|
|
2484
|
+
if (stage.error) throw stage.error;
|
|
2485
|
+
if (stage.result?.url) finalUrl = stage.result.url;
|
|
2486
|
+
}
|
|
2487
|
+
if (!finalUrl) {
|
|
2488
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No video generated from image by Pruna AI");
|
|
2489
|
+
}
|
|
2490
|
+
return {
|
|
2491
|
+
id: Date.now().toString(),
|
|
2492
|
+
type: "video",
|
|
2493
|
+
url: finalUrl,
|
|
2494
|
+
metadata: { provider: this.id, model: "p-image-to-video" },
|
|
2495
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2496
|
+
};
|
|
2340
2497
|
}
|
|
2341
2498
|
async videoToVideo(_request) {
|
|
2342
|
-
throw new
|
|
2499
|
+
throw new AIError("CLIENT_ERROR" /* CLIENT_ERROR */, "Pruna AI provider does not support video-to-video conversion");
|
|
2343
2500
|
}
|
|
2344
2501
|
};
|
|
2345
2502
|
function createPrunaProvider(config) {
|