@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
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { c as TextTier } from './index-fXjxTR5W.js';
|
|
2
|
+
|
|
3
|
+
declare enum AIErrorType {
|
|
4
|
+
INVALID_API_KEY = "INVALID_API_KEY",
|
|
5
|
+
MISSING_CONFIG = "MISSING_CONFIG",
|
|
6
|
+
NETWORK_ERROR = "NETWORK_ERROR",
|
|
7
|
+
ABORT_ERROR = "ABORT_ERROR",
|
|
8
|
+
RATE_LIMIT_ERROR = "RATE_LIMIT_ERROR",
|
|
9
|
+
SERVER_ERROR = "SERVER_ERROR",
|
|
10
|
+
CLIENT_ERROR = "CLIENT_ERROR",
|
|
11
|
+
UNKNOWN_ERROR = "UNKNOWN_ERROR"
|
|
12
|
+
}
|
|
13
|
+
declare const USER_FRIENDLY_ERROR_MESSAGES: Readonly<Record<AIErrorType, string>>;
|
|
14
|
+
|
|
15
|
+
interface AIErrorMetadata {
|
|
16
|
+
readonly status?: number;
|
|
17
|
+
readonly url?: string;
|
|
18
|
+
readonly [key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
declare class AIError extends Error {
|
|
21
|
+
readonly type: AIErrorType;
|
|
22
|
+
readonly code: string;
|
|
23
|
+
readonly cause?: unknown;
|
|
24
|
+
readonly metadata: AIErrorMetadata;
|
|
25
|
+
constructor(typeOrMessage: AIErrorType | string, messageOrCode?: string, cause?: unknown, metadata?: AIErrorMetadata);
|
|
26
|
+
static from(error: unknown, fallbackCode?: string): AIError;
|
|
27
|
+
toString(): string;
|
|
28
|
+
toJSON(): {
|
|
29
|
+
name: string;
|
|
30
|
+
type: AIErrorType;
|
|
31
|
+
code: string;
|
|
32
|
+
message: string;
|
|
33
|
+
metadata: AIErrorMetadata;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Per-provider default model per tier. Config can override any slot; an
|
|
39
|
+
* explicit `model` on a request overrides everything. This table is the knob
|
|
40
|
+
* that turns "switch from Claude to Groq" into a config edit.
|
|
41
|
+
*/
|
|
42
|
+
type TierModelMap = Readonly<Partial<Record<TextTier, string>>>;
|
|
43
|
+
declare const TEXT_TIERS: ReadonlyArray<TextTier>;
|
|
44
|
+
declare function isTextTier(value: unknown): value is TextTier;
|
|
45
|
+
declare function resolveModel(tiers: TierModelMap, tier: TextTier, providerId: string): string;
|
|
46
|
+
declare function mergeTierOverrides(defaults: TierModelMap, overrides?: TierModelMap): TierModelMap;
|
|
47
|
+
|
|
48
|
+
export { AIError as A, TEXT_TIERS as T, USER_FRIENDLY_ERROR_MESSAGES as U, type AIErrorMetadata as a, AIErrorType as b, type TierModelMap as c, isTextTier as i, mergeTierOverrides as m, resolveModel as r };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { c as TextTier } from './index-fXjxTR5W.cjs';
|
|
2
|
+
|
|
3
|
+
declare enum AIErrorType {
|
|
4
|
+
INVALID_API_KEY = "INVALID_API_KEY",
|
|
5
|
+
MISSING_CONFIG = "MISSING_CONFIG",
|
|
6
|
+
NETWORK_ERROR = "NETWORK_ERROR",
|
|
7
|
+
ABORT_ERROR = "ABORT_ERROR",
|
|
8
|
+
RATE_LIMIT_ERROR = "RATE_LIMIT_ERROR",
|
|
9
|
+
SERVER_ERROR = "SERVER_ERROR",
|
|
10
|
+
CLIENT_ERROR = "CLIENT_ERROR",
|
|
11
|
+
UNKNOWN_ERROR = "UNKNOWN_ERROR"
|
|
12
|
+
}
|
|
13
|
+
declare const USER_FRIENDLY_ERROR_MESSAGES: Readonly<Record<AIErrorType, string>>;
|
|
14
|
+
|
|
15
|
+
interface AIErrorMetadata {
|
|
16
|
+
readonly status?: number;
|
|
17
|
+
readonly url?: string;
|
|
18
|
+
readonly [key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
declare class AIError extends Error {
|
|
21
|
+
readonly type: AIErrorType;
|
|
22
|
+
readonly code: string;
|
|
23
|
+
readonly cause?: unknown;
|
|
24
|
+
readonly metadata: AIErrorMetadata;
|
|
25
|
+
constructor(typeOrMessage: AIErrorType | string, messageOrCode?: string, cause?: unknown, metadata?: AIErrorMetadata);
|
|
26
|
+
static from(error: unknown, fallbackCode?: string): AIError;
|
|
27
|
+
toString(): string;
|
|
28
|
+
toJSON(): {
|
|
29
|
+
name: string;
|
|
30
|
+
type: AIErrorType;
|
|
31
|
+
code: string;
|
|
32
|
+
message: string;
|
|
33
|
+
metadata: AIErrorMetadata;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Per-provider default model per tier. Config can override any slot; an
|
|
39
|
+
* explicit `model` on a request overrides everything. This table is the knob
|
|
40
|
+
* that turns "switch from Claude to Groq" into a config edit.
|
|
41
|
+
*/
|
|
42
|
+
type TierModelMap = Readonly<Partial<Record<TextTier, string>>>;
|
|
43
|
+
declare const TEXT_TIERS: ReadonlyArray<TextTier>;
|
|
44
|
+
declare function isTextTier(value: unknown): value is TextTier;
|
|
45
|
+
declare function resolveModel(tiers: TierModelMap, tier: TextTier, providerId: string): string;
|
|
46
|
+
declare function mergeTierOverrides(defaults: TierModelMap, overrides?: TierModelMap): TierModelMap;
|
|
47
|
+
|
|
48
|
+
export { AIError as A, TEXT_TIERS as T, USER_FRIENDLY_ERROR_MESSAGES as U, type AIErrorMetadata as a, AIErrorType as b, type TierModelMap as c, isTextTier as i, mergeTierOverrides as m, resolveModel as r };
|
package/dist/index.cjs
CHANGED
|
@@ -43,17 +43,80 @@ var USER_FRIENDLY_ERROR_MESSAGES = {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
// src/core/errors/ai-error.ts
|
|
46
|
-
var
|
|
46
|
+
var KNOWN_ERROR_TYPES = new Set(Object.values(AIErrorType));
|
|
47
|
+
function mapCodeToType(code) {
|
|
48
|
+
switch (code) {
|
|
49
|
+
case "VALIDATION_ERROR":
|
|
50
|
+
case "CLIENT_ERROR":
|
|
51
|
+
return "CLIENT_ERROR" /* CLIENT_ERROR */;
|
|
52
|
+
case "INVALID_API_KEY":
|
|
53
|
+
return "INVALID_API_KEY" /* INVALID_API_KEY */;
|
|
54
|
+
case "MISSING_CONFIG":
|
|
55
|
+
case "PROVIDER_UNAVAILABLE":
|
|
56
|
+
return "MISSING_CONFIG" /* MISSING_CONFIG */;
|
|
57
|
+
case "PROVIDER_QUOTA_EXHAUSTED":
|
|
58
|
+
case "RATE_LIMIT_ERROR":
|
|
59
|
+
return "RATE_LIMIT_ERROR" /* RATE_LIMIT_ERROR */;
|
|
60
|
+
case "NETWORK_ERROR":
|
|
61
|
+
case "TIMEOUT":
|
|
62
|
+
return "NETWORK_ERROR" /* NETWORK_ERROR */;
|
|
63
|
+
case "ABORT_ERROR":
|
|
64
|
+
case "ABORTED":
|
|
65
|
+
return "ABORT_ERROR" /* ABORT_ERROR */;
|
|
66
|
+
case "SERVER_ERROR":
|
|
67
|
+
case "PROVIDER_ERROR":
|
|
68
|
+
case "NO_RESULT":
|
|
69
|
+
return "SERVER_ERROR" /* SERVER_ERROR */;
|
|
70
|
+
default:
|
|
71
|
+
return "UNKNOWN_ERROR" /* UNKNOWN_ERROR */;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function mapMessageToCode(message, fallback = "UNKNOWN") {
|
|
75
|
+
const lower = message.toLowerCase();
|
|
76
|
+
if (lower.includes("validation")) return "VALIDATION_ERROR";
|
|
77
|
+
if (lower.includes("quota")) return "PROVIDER_QUOTA_EXHAUSTED";
|
|
78
|
+
if (lower.includes("unavailable")) return "PROVIDER_UNAVAILABLE";
|
|
79
|
+
if (lower.includes("timeout") || lower.includes("aborted")) {
|
|
80
|
+
return lower.includes("aborted") ? "ABORTED" : "TIMEOUT";
|
|
81
|
+
}
|
|
82
|
+
if (lower.includes("parse") || lower.includes("json")) return "PARSE_ERROR";
|
|
83
|
+
if (lower.includes("no result")) return "NO_RESULT";
|
|
84
|
+
if (lower.includes("network") || lower.includes("fetch")) return "NETWORK_ERROR";
|
|
85
|
+
return fallback;
|
|
86
|
+
}
|
|
87
|
+
var AIError = class _AIError extends Error {
|
|
47
88
|
type;
|
|
89
|
+
code;
|
|
48
90
|
cause;
|
|
49
91
|
metadata;
|
|
50
|
-
constructor(
|
|
51
|
-
|
|
92
|
+
constructor(typeOrMessage, messageOrCode, cause, metadata = {}) {
|
|
93
|
+
let effectiveType;
|
|
94
|
+
let effectiveMessage;
|
|
95
|
+
let effectiveCode;
|
|
96
|
+
if (KNOWN_ERROR_TYPES.has(typeOrMessage)) {
|
|
97
|
+
effectiveType = typeOrMessage;
|
|
98
|
+
effectiveMessage = messageOrCode ?? "";
|
|
99
|
+
effectiveCode = effectiveType;
|
|
100
|
+
} else {
|
|
101
|
+
effectiveMessage = typeOrMessage;
|
|
102
|
+
effectiveCode = messageOrCode ?? "UNKNOWN";
|
|
103
|
+
effectiveType = mapCodeToType(effectiveCode);
|
|
104
|
+
}
|
|
105
|
+
super(effectiveMessage);
|
|
52
106
|
this.name = "AIError";
|
|
53
|
-
this.type =
|
|
107
|
+
this.type = effectiveType;
|
|
108
|
+
this.code = effectiveCode;
|
|
54
109
|
this.cause = cause;
|
|
55
110
|
this.metadata = metadata;
|
|
56
111
|
}
|
|
112
|
+
static from(error, fallbackCode = "UNKNOWN") {
|
|
113
|
+
if (error instanceof _AIError) return error;
|
|
114
|
+
if (error instanceof Error) {
|
|
115
|
+
const code = mapMessageToCode(error.message, fallbackCode);
|
|
116
|
+
return new _AIError(error.message, code, error);
|
|
117
|
+
}
|
|
118
|
+
return new _AIError(String(error), fallbackCode, error);
|
|
119
|
+
}
|
|
57
120
|
toString() {
|
|
58
121
|
const statusPart = typeof this.metadata.status === "number" ? ` (HTTP ${this.metadata.status})` : "";
|
|
59
122
|
return `${this.name} [${this.type}]: ${this.message}${statusPart}`;
|
|
@@ -62,6 +125,7 @@ var AIError = class extends Error {
|
|
|
62
125
|
return {
|
|
63
126
|
name: this.name,
|
|
64
127
|
type: this.type,
|
|
128
|
+
code: this.code,
|
|
65
129
|
message: this.message,
|
|
66
130
|
metadata: this.metadata
|
|
67
131
|
};
|
|
@@ -750,15 +814,22 @@ function oneOfCatalog(catalog, value) {
|
|
|
750
814
|
// src/core/constants/protocol.constants.ts
|
|
751
815
|
var SSE_PREFIX = "data: ";
|
|
752
816
|
var SSE_DONE_MARKER = "[DONE]";
|
|
753
|
-
var JSON_CODE_BLOCK_PATTERN = /```json
|
|
817
|
+
var JSON_CODE_BLOCK_PATTERN = /```(?:json)?\s*\n?([\s\S]*?)\n?```/;
|
|
754
818
|
var JSON_OBJECT_PATTERN = /\{[\s\S]*\}/;
|
|
819
|
+
var JSON_ARRAY_PATTERN = /\[[\s\S]*\]/;
|
|
755
820
|
|
|
756
821
|
// src/core/parsers/sse-lines.ts
|
|
757
822
|
function isSseDataLine(line) {
|
|
758
|
-
return line.startsWith(SSE_PREFIX);
|
|
823
|
+
return line.startsWith(SSE_PREFIX) || line.startsWith("data:");
|
|
759
824
|
}
|
|
760
825
|
function extractSseDataPayload(line) {
|
|
761
|
-
|
|
826
|
+
if (line.startsWith(SSE_PREFIX)) {
|
|
827
|
+
return line.slice(SSE_PREFIX.length);
|
|
828
|
+
}
|
|
829
|
+
if (line.startsWith("data:")) {
|
|
830
|
+
return line.slice(5);
|
|
831
|
+
}
|
|
832
|
+
return line;
|
|
762
833
|
}
|
|
763
834
|
function isSseDoneMarker(payload) {
|
|
764
835
|
return payload === SSE_DONE_MARKER;
|
|
@@ -830,7 +901,7 @@ var StreamingResponseParser = class {
|
|
|
830
901
|
// src/core/parsers/json-content-extractor.ts
|
|
831
902
|
function extractJsonFromCodeFence(content) {
|
|
832
903
|
const match = content.match(JSON_CODE_BLOCK_PATTERN);
|
|
833
|
-
if (match && match[1]) return match[1];
|
|
904
|
+
if (match && match[1]) return match[1].trim();
|
|
834
905
|
return null;
|
|
835
906
|
}
|
|
836
907
|
function extractJsonObject(content) {
|
|
@@ -838,8 +909,27 @@ function extractJsonObject(content) {
|
|
|
838
909
|
if (match && match[0]) return match[0];
|
|
839
910
|
return null;
|
|
840
911
|
}
|
|
912
|
+
function extractJsonArray(content) {
|
|
913
|
+
const match = content.match(JSON_ARRAY_PATTERN);
|
|
914
|
+
if (match && match[0]) return match[0];
|
|
915
|
+
return null;
|
|
916
|
+
}
|
|
917
|
+
function repairCommonJsonDefects(text) {
|
|
918
|
+
return text.replace(/(:\s*-?\d+(?:\.\d+)?)\s*"/g, "$1").replace(/(:\s*"[^"]*")"/g, "$1");
|
|
919
|
+
}
|
|
841
920
|
function extractJsonCandidate(content) {
|
|
842
|
-
|
|
921
|
+
const fromFence = extractJsonFromCodeFence(content);
|
|
922
|
+
if (fromFence) return fromFence;
|
|
923
|
+
const objectIndex = content.indexOf("{");
|
|
924
|
+
const arrayIndex = content.indexOf("[");
|
|
925
|
+
if (objectIndex !== -1 && (arrayIndex === -1 || objectIndex < arrayIndex)) {
|
|
926
|
+
const obj = extractJsonObject(content);
|
|
927
|
+
if (obj) return obj;
|
|
928
|
+
} else if (arrayIndex !== -1) {
|
|
929
|
+
const arr = extractJsonArray(content);
|
|
930
|
+
if (arr) return arr;
|
|
931
|
+
}
|
|
932
|
+
return content.trim();
|
|
843
933
|
}
|
|
844
934
|
|
|
845
935
|
// src/core/parsers/json-response.parser.ts
|
|
@@ -848,12 +938,17 @@ var JsonResponseParser = class {
|
|
|
848
938
|
const candidate = extractJsonCandidate(rawContent);
|
|
849
939
|
try {
|
|
850
940
|
return JSON.parse(candidate);
|
|
851
|
-
} catch
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
941
|
+
} catch {
|
|
942
|
+
try {
|
|
943
|
+
return JSON.parse(repairCommonJsonDefects(candidate));
|
|
944
|
+
} catch (error) {
|
|
945
|
+
throw new AIError(
|
|
946
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
947
|
+
"Failed to parse structured response as JSON",
|
|
948
|
+
error instanceof Error ? error : void 0,
|
|
949
|
+
{ rawContent }
|
|
950
|
+
);
|
|
951
|
+
}
|
|
857
952
|
}
|
|
858
953
|
}
|
|
859
954
|
};
|
|
@@ -979,38 +1074,6 @@ function isMediaProvider(provider) {
|
|
|
979
1074
|
return provider.capabilities.includes("image") || provider.capabilities.includes("video");
|
|
980
1075
|
}
|
|
981
1076
|
|
|
982
|
-
// src/content/domain/errors/AIErrors.ts
|
|
983
|
-
var AIError2 = class _AIError extends Error {
|
|
984
|
-
code;
|
|
985
|
-
cause;
|
|
986
|
-
constructor(message, code, cause) {
|
|
987
|
-
super(message);
|
|
988
|
-
this.name = "AIError";
|
|
989
|
-
this.code = code;
|
|
990
|
-
this.cause = cause;
|
|
991
|
-
}
|
|
992
|
-
static from(error, fallbackCode = "UNKNOWN") {
|
|
993
|
-
if (error instanceof _AIError) return error;
|
|
994
|
-
if (error instanceof Error) {
|
|
995
|
-
return new _AIError(error.message, mapMessageToCode(error.message, fallbackCode), error);
|
|
996
|
-
}
|
|
997
|
-
return new _AIError(String(error), fallbackCode, error);
|
|
998
|
-
}
|
|
999
|
-
};
|
|
1000
|
-
function mapMessageToCode(message, fallback) {
|
|
1001
|
-
const lower = message.toLowerCase();
|
|
1002
|
-
if (lower.includes("validation")) return "VALIDATION_ERROR";
|
|
1003
|
-
if (lower.includes("quota")) return "PROVIDER_QUOTA_EXHAUSTED";
|
|
1004
|
-
if (lower.includes("unavailable")) return "PROVIDER_UNAVAILABLE";
|
|
1005
|
-
if (lower.includes("timeout") || lower.includes("aborted")) {
|
|
1006
|
-
return lower.includes("aborted") ? "ABORTED" : "TIMEOUT";
|
|
1007
|
-
}
|
|
1008
|
-
if (lower.includes("parse") || lower.includes("json")) return "PARSE_ERROR";
|
|
1009
|
-
if (lower.includes("no result")) return "NO_RESULT";
|
|
1010
|
-
if (lower.includes("network") || lower.includes("fetch")) return "NETWORK_ERROR";
|
|
1011
|
-
return fallback;
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
1077
|
// src/content/domain/limits/ProviderTimingConfig.ts
|
|
1015
1078
|
var ProviderTimingConfig = {
|
|
1016
1079
|
DEFAULT_TIMEOUT_MS: 3e4,
|
|
@@ -1075,7 +1138,7 @@ var BaseProvider = class {
|
|
|
1075
1138
|
throw lastError || new Error("Retry attempts exhausted");
|
|
1076
1139
|
}
|
|
1077
1140
|
};
|
|
1078
|
-
var ProviderError = class extends
|
|
1141
|
+
var ProviderError = class extends AIError {
|
|
1079
1142
|
constructor(message, providerId, originalError) {
|
|
1080
1143
|
super(message, "PROVIDER_ERROR", originalError);
|
|
1081
1144
|
this.providerId = providerId;
|
|
@@ -1169,12 +1232,16 @@ var ProviderFactory = class {
|
|
|
1169
1232
|
let wake = null;
|
|
1170
1233
|
let finished = false;
|
|
1171
1234
|
let failure;
|
|
1235
|
+
const controller = new AbortController();
|
|
1236
|
+
const onAbort = () => controller.abort();
|
|
1237
|
+
request.signal?.addEventListener("abort", onAbort);
|
|
1238
|
+
const effectiveRequest = { ...request, signal: controller.signal };
|
|
1172
1239
|
const notify = () => {
|
|
1173
1240
|
const resolve = wake;
|
|
1174
1241
|
wake = null;
|
|
1175
1242
|
resolve?.();
|
|
1176
1243
|
};
|
|
1177
|
-
const completion = this.chatStream(
|
|
1244
|
+
const completion = this.chatStream(effectiveRequest, {
|
|
1178
1245
|
onChunk: (chunk) => {
|
|
1179
1246
|
queue.push(chunk);
|
|
1180
1247
|
notify();
|
|
@@ -1190,18 +1257,23 @@ var ProviderFactory = class {
|
|
|
1190
1257
|
notify();
|
|
1191
1258
|
}
|
|
1192
1259
|
);
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1260
|
+
try {
|
|
1261
|
+
while (!finished || queue.length > 0) {
|
|
1262
|
+
if (queue.length === 0 && !finished) {
|
|
1263
|
+
await new Promise((resolve) => {
|
|
1264
|
+
wake = resolve;
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
while (queue.length > 0) {
|
|
1268
|
+
yield queue.shift();
|
|
1269
|
+
}
|
|
1270
|
+
if (failure) throw failure;
|
|
1201
1271
|
}
|
|
1202
|
-
|
|
1272
|
+
await completion;
|
|
1273
|
+
} finally {
|
|
1274
|
+
controller.abort();
|
|
1275
|
+
request.signal?.removeEventListener("abort", onAbort);
|
|
1203
1276
|
}
|
|
1204
|
-
await completion;
|
|
1205
1277
|
}
|
|
1206
1278
|
async generateJson(request) {
|
|
1207
1279
|
const effective = request.model || request.tier ? request : { ...request, tier: this.defaultTier };
|
|
@@ -1610,11 +1682,14 @@ async function consumeAnthropicStream(stream, callbacks) {
|
|
|
1610
1682
|
break;
|
|
1611
1683
|
case "message_stop":
|
|
1612
1684
|
break;
|
|
1613
|
-
case "error":
|
|
1685
|
+
case "error": {
|
|
1686
|
+
const errType = event.error.type;
|
|
1687
|
+
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 */;
|
|
1614
1688
|
throw new AIError(
|
|
1615
|
-
|
|
1689
|
+
mappedType,
|
|
1616
1690
|
event.error.message || "Anthropic stream failed mid-flight"
|
|
1617
1691
|
);
|
|
1692
|
+
}
|
|
1618
1693
|
}
|
|
1619
1694
|
};
|
|
1620
1695
|
try {
|
|
@@ -2072,6 +2147,13 @@ async function consumeGroqStream(stream, callbacks) {
|
|
|
2072
2147
|
} catch {
|
|
2073
2148
|
return;
|
|
2074
2149
|
}
|
|
2150
|
+
const errorBody = chunk.error;
|
|
2151
|
+
if (errorBody) {
|
|
2152
|
+
throw new AIError(
|
|
2153
|
+
errorBody.message?.toLowerCase().includes("rate limit") ? "RATE_LIMIT_ERROR" /* RATE_LIMIT_ERROR */ : "SERVER_ERROR" /* SERVER_ERROR */,
|
|
2154
|
+
errorBody.message || "Groq stream failed mid-flight"
|
|
2155
|
+
);
|
|
2156
|
+
}
|
|
2075
2157
|
if (chunk.model) model = chunk.model;
|
|
2076
2158
|
const choice = chunk.choices?.[0];
|
|
2077
2159
|
const delta = choice?.delta?.content;
|
|
@@ -2086,13 +2168,6 @@ async function consumeGroqStream(stream, callbacks) {
|
|
|
2086
2168
|
if (tailUsage) {
|
|
2087
2169
|
usage = mapGroqUsage(tailUsage);
|
|
2088
2170
|
}
|
|
2089
|
-
const errorBody = chunk.error;
|
|
2090
|
-
if (errorBody) {
|
|
2091
|
-
throw new AIError(
|
|
2092
|
-
"SERVER_ERROR" /* SERVER_ERROR */,
|
|
2093
|
-
errorBody.message || "Groq stream failed mid-flight"
|
|
2094
|
-
);
|
|
2095
|
-
}
|
|
2096
2171
|
};
|
|
2097
2172
|
try {
|
|
2098
2173
|
while (true) {
|
|
@@ -2359,7 +2434,9 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2359
2434
|
headers: this.authHeaders()
|
|
2360
2435
|
}
|
|
2361
2436
|
);
|
|
2362
|
-
|
|
2437
|
+
if (response.ok) return "healthy";
|
|
2438
|
+
if (response.status === 401 || response.status === 403) return "unavailable";
|
|
2439
|
+
return "degraded";
|
|
2363
2440
|
} catch {
|
|
2364
2441
|
return "unavailable";
|
|
2365
2442
|
}
|
|
@@ -2370,6 +2447,8 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2370
2447
|
async generate(request) {
|
|
2371
2448
|
try {
|
|
2372
2449
|
const model = request.model ?? this.resolveModel(request.tier ?? "balanced");
|
|
2450
|
+
const systemMessages = request.messages.filter((m) => m.role === "system");
|
|
2451
|
+
const systemPrompt = request.systemPrompt && request.systemPrompt.length > 0 ? request.systemPrompt : systemMessages.length > 0 ? systemMessages.map((m) => m.content).join("\n") : void 0;
|
|
2373
2452
|
const response = await this.withRetry(async () => {
|
|
2374
2453
|
return await this.fetchWithTimeout(
|
|
2375
2454
|
`${this.config.baseUrl}/models/${model}:generateContent`,
|
|
@@ -2377,22 +2456,28 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2377
2456
|
method: "POST",
|
|
2378
2457
|
headers: this.authHeaders(),
|
|
2379
2458
|
body: JSON.stringify({
|
|
2380
|
-
systemInstruction:
|
|
2459
|
+
systemInstruction: systemPrompt && systemPrompt.length > 0 ? { parts: [{ text: systemPrompt }] } : void 0,
|
|
2381
2460
|
contents: toGeminiContents(request.messages),
|
|
2382
2461
|
generationConfig: {
|
|
2383
|
-
temperature: request.temperature
|
|
2384
|
-
maxOutputTokens: request.maxTokens
|
|
2385
|
-
topP: request.topP
|
|
2462
|
+
temperature: request.temperature ?? 0.7,
|
|
2463
|
+
maxOutputTokens: request.maxTokens ?? 2048,
|
|
2464
|
+
topP: request.topP ?? 0.9
|
|
2386
2465
|
}
|
|
2387
2466
|
})
|
|
2388
2467
|
}
|
|
2389
2468
|
);
|
|
2390
2469
|
});
|
|
2391
2470
|
if (!response.ok) {
|
|
2392
|
-
|
|
2471
|
+
const message = await extractErrorMessageFromResponse(response);
|
|
2472
|
+
throw new AIError(
|
|
2473
|
+
classifyHttpStatus(response.status),
|
|
2474
|
+
`Gemini API error (${response.status}): ${message}`,
|
|
2475
|
+
void 0,
|
|
2476
|
+
{ status: response.status, model }
|
|
2477
|
+
);
|
|
2393
2478
|
}
|
|
2394
2479
|
const data = await response.json();
|
|
2395
|
-
const text = data.candidates[0]?.content?.parts?.map((part) => part.text ?? "").join("") ?? "";
|
|
2480
|
+
const text = data.candidates?.[0]?.content?.parts?.map((part) => part.text ?? "").join("") ?? "";
|
|
2396
2481
|
if (text.length === 0) {
|
|
2397
2482
|
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No content generated from Gemini API", void 0, { model });
|
|
2398
2483
|
}
|
|
@@ -2405,7 +2490,7 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2405
2490
|
} : void 0,
|
|
2406
2491
|
model,
|
|
2407
2492
|
providerId: this.id,
|
|
2408
|
-
finishReason: mapGeminiFinishReason(data.candidates[0]?.finishReason)
|
|
2493
|
+
finishReason: mapGeminiFinishReason(data.candidates?.[0]?.finishReason)
|
|
2409
2494
|
};
|
|
2410
2495
|
} catch (error) {
|
|
2411
2496
|
if (error instanceof AIError) throw error;
|
|
@@ -2457,12 +2542,18 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2457
2542
|
);
|
|
2458
2543
|
});
|
|
2459
2544
|
if (!response.ok) {
|
|
2460
|
-
|
|
2545
|
+
const message = await extractErrorMessageFromResponse(response);
|
|
2546
|
+
throw new AIError(
|
|
2547
|
+
classifyHttpStatus(response.status),
|
|
2548
|
+
`Gemini image generation error (${response.status}): ${message}`,
|
|
2549
|
+
void 0,
|
|
2550
|
+
{ status: response.status }
|
|
2551
|
+
);
|
|
2461
2552
|
}
|
|
2462
2553
|
const data = await response.json();
|
|
2463
|
-
const imageData = data.candidates[0]?.content?.parts[0]?.inlineData;
|
|
2554
|
+
const imageData = data.candidates?.[0]?.content?.parts?.[0]?.inlineData;
|
|
2464
2555
|
if (!imageData) {
|
|
2465
|
-
throw new
|
|
2556
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No image data in Gemini response");
|
|
2466
2557
|
}
|
|
2467
2558
|
const url = `data:${imageData.mimeType};base64,${imageData.data}`;
|
|
2468
2559
|
return {
|
|
@@ -2781,17 +2872,70 @@ var PrunaProvider = class {
|
|
|
2781
2872
|
async estimateCost(_request) {
|
|
2782
2873
|
return 1;
|
|
2783
2874
|
}
|
|
2784
|
-
async generateImage(
|
|
2785
|
-
|
|
2875
|
+
async generateImage(request) {
|
|
2876
|
+
let finalUrl;
|
|
2877
|
+
const model = this.config.models?.textToImage;
|
|
2878
|
+
for await (const stage of generateWithPruna(
|
|
2879
|
+
{ prompt: request.prompt, model, quality: request.quality },
|
|
2880
|
+
this.config.apiKey
|
|
2881
|
+
)) {
|
|
2882
|
+
if (stage.error) throw stage.error;
|
|
2883
|
+
if (stage.result?.url) finalUrl = stage.result.url;
|
|
2884
|
+
}
|
|
2885
|
+
if (!finalUrl) {
|
|
2886
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No image generated by Pruna AI");
|
|
2887
|
+
}
|
|
2888
|
+
return {
|
|
2889
|
+
id: Date.now().toString(),
|
|
2890
|
+
type: "image",
|
|
2891
|
+
url: finalUrl,
|
|
2892
|
+
metadata: { provider: this.id, model: model ?? "p-image" },
|
|
2893
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2894
|
+
};
|
|
2786
2895
|
}
|
|
2787
|
-
async generateVideo(
|
|
2788
|
-
|
|
2896
|
+
async generateVideo(request) {
|
|
2897
|
+
let finalUrl;
|
|
2898
|
+
const model = this.config.models?.textToVideo;
|
|
2899
|
+
for await (const stage of generateWithPruna(
|
|
2900
|
+
{ prompt: request.prompt, model, duration: request.duration, aspectRatio: request.aspectRatio },
|
|
2901
|
+
this.config.apiKey
|
|
2902
|
+
)) {
|
|
2903
|
+
if (stage.error) throw stage.error;
|
|
2904
|
+
if (stage.result?.url) finalUrl = stage.result.url;
|
|
2905
|
+
}
|
|
2906
|
+
if (!finalUrl) {
|
|
2907
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No video generated by Pruna AI");
|
|
2908
|
+
}
|
|
2909
|
+
return {
|
|
2910
|
+
id: Date.now().toString(),
|
|
2911
|
+
type: "video",
|
|
2912
|
+
url: finalUrl,
|
|
2913
|
+
metadata: { provider: this.id, model: model ?? "p-video" },
|
|
2914
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2915
|
+
};
|
|
2789
2916
|
}
|
|
2790
|
-
async imageToVideo(
|
|
2791
|
-
|
|
2917
|
+
async imageToVideo(request) {
|
|
2918
|
+
let finalUrl;
|
|
2919
|
+
for await (const stage of generateWithPruna(
|
|
2920
|
+
{ image: request.imageUrl, prompt: request.prompt, duration: request.duration, motion: request.motion },
|
|
2921
|
+
this.config.apiKey
|
|
2922
|
+
)) {
|
|
2923
|
+
if (stage.error) throw stage.error;
|
|
2924
|
+
if (stage.result?.url) finalUrl = stage.result.url;
|
|
2925
|
+
}
|
|
2926
|
+
if (!finalUrl) {
|
|
2927
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No video generated from image by Pruna AI");
|
|
2928
|
+
}
|
|
2929
|
+
return {
|
|
2930
|
+
id: Date.now().toString(),
|
|
2931
|
+
type: "video",
|
|
2932
|
+
url: finalUrl,
|
|
2933
|
+
metadata: { provider: this.id, model: "p-image-to-video" },
|
|
2934
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2935
|
+
};
|
|
2792
2936
|
}
|
|
2793
2937
|
async videoToVideo(_request) {
|
|
2794
|
-
throw new AIError("
|
|
2938
|
+
throw new AIError("CLIENT_ERROR" /* CLIENT_ERROR */, "Pruna AI provider does not support video-to-video conversion");
|
|
2795
2939
|
}
|
|
2796
2940
|
};
|
|
2797
2941
|
function createPrunaProvider(config) {
|
|
@@ -2943,9 +3087,12 @@ var ChatService = class {
|
|
|
2943
3087
|
};
|
|
2944
3088
|
}
|
|
2945
3089
|
async getConversations() {
|
|
3090
|
+
if (this.storage && "getConversations" in this.storage && typeof this.storage.getConversations === "function") {
|
|
3091
|
+
return this.storage.getConversations();
|
|
3092
|
+
}
|
|
2946
3093
|
return [];
|
|
2947
3094
|
}
|
|
2948
|
-
async sendMessage(input) {
|
|
3095
|
+
async sendMessage(input, signal) {
|
|
2949
3096
|
const userMessage = {
|
|
2950
3097
|
...messageFormatter.toChatMessage(input.text, "user"),
|
|
2951
3098
|
type: input.type ?? "text",
|
|
@@ -2954,13 +3101,14 @@ var ChatService = class {
|
|
|
2954
3101
|
const aiResponse = await this.generateAIResponse(
|
|
2955
3102
|
input.companionId,
|
|
2956
3103
|
input.text,
|
|
2957
|
-
[]
|
|
3104
|
+
[],
|
|
3105
|
+
signal
|
|
2958
3106
|
);
|
|
2959
3107
|
return { userMessage, aiResponse };
|
|
2960
3108
|
}
|
|
2961
|
-
async generateAIResponse(companionId, userMessage, context = []) {
|
|
3109
|
+
async generateAIResponse(companionId, userMessage, context = [], signal) {
|
|
2962
3110
|
const result = await this.run({
|
|
2963
|
-
...this.buildRequest(userMessage, context)
|
|
3111
|
+
...this.buildRequest(userMessage, context, signal)
|
|
2964
3112
|
});
|
|
2965
3113
|
return {
|
|
2966
3114
|
...messageFormatter.toChatMessage(result.text, "assistant"),
|
|
@@ -2976,12 +3124,12 @@ var ChatService = class {
|
|
|
2976
3124
|
}
|
|
2977
3125
|
};
|
|
2978
3126
|
}
|
|
2979
|
-
async generateStreamingResponse(userMessage, context, onChunk) {
|
|
2980
|
-
const request = this.buildRequest(userMessage, context);
|
|
3127
|
+
async generateStreamingResponse(userMessage, context, onChunk, signal) {
|
|
3128
|
+
const request = this.buildRequest(userMessage, context, signal);
|
|
2981
3129
|
const result = await this.runStream(request, { onChunk });
|
|
2982
3130
|
return result.text;
|
|
2983
3131
|
}
|
|
2984
|
-
buildRequest(userMessage, context) {
|
|
3132
|
+
buildRequest(userMessage, context, signal) {
|
|
2985
3133
|
const messages = messageFormatter.toCoreMessages(context);
|
|
2986
3134
|
messages.push({ role: "user", content: userMessage });
|
|
2987
3135
|
return {
|
|
@@ -2990,7 +3138,8 @@ var ChatService = class {
|
|
|
2990
3138
|
model: this.config.model,
|
|
2991
3139
|
tier: this.config.tier,
|
|
2992
3140
|
temperature: this.config.temperature,
|
|
2993
|
-
maxTokens: this.config.maxTokens
|
|
3141
|
+
maxTokens: this.config.maxTokens,
|
|
3142
|
+
...signal !== void 0 ? { signal } : {}
|
|
2994
3143
|
};
|
|
2995
3144
|
}
|
|
2996
3145
|
resolveSystemPrompt() {
|
|
@@ -3122,6 +3271,7 @@ exports.describeAIErrorType = describeAIErrorType;
|
|
|
3122
3271
|
exports.extractContentFromSsePayload = extractContentFromSsePayload;
|
|
3123
3272
|
exports.extractErrorMessageFromJsonBody = extractErrorMessageFromJsonBody;
|
|
3124
3273
|
exports.extractErrorMessageFromResponse = extractErrorMessageFromResponse;
|
|
3274
|
+
exports.extractJsonArray = extractJsonArray;
|
|
3125
3275
|
exports.extractJsonCandidate = extractJsonCandidate;
|
|
3126
3276
|
exports.extractJsonFromCodeFence = extractJsonFromCodeFence;
|
|
3127
3277
|
exports.extractJsonObject = extractJsonObject;
|
|
@@ -3142,6 +3292,7 @@ exports.mergeTierOverrides = mergeTierOverrides;
|
|
|
3142
3292
|
exports.messageFormatter = messageFormatter;
|
|
3143
3293
|
exports.normalizeSseChunk = normalizeSseChunk;
|
|
3144
3294
|
exports.oneOfCatalog = oneOfCatalog;
|
|
3295
|
+
exports.repairCommonJsonDefects = repairCommonJsonDefects;
|
|
3145
3296
|
exports.requestDeduplicator = requestDeduplicator;
|
|
3146
3297
|
exports.requestQueue = requestQueue;
|
|
3147
3298
|
exports.resolveModel = resolveModel;
|