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