@umituz/web-ai 1.0.0 → 1.0.2
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 +506 -193
- 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 +506 -193
- package/dist/content/index.js.map +1 -1
- package/dist/core/index.cjs +122 -15
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +13 -31
- package/dist/core/index.d.ts +13 -31
- package/dist/core/index.js +119 -16
- package/dist/core/index.js.map +1 -1
- package/dist/{create-ai-BhNaz86i.d.ts → create-ai-9PW752z8.d.ts} +14 -21
- package/dist/{create-ai-DGZFBOA1.d.cts → create-ai-CXYKPK6G.d.cts} +14 -21
- package/dist/hooks/index.cjs +631 -179
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +33 -7
- package/dist/hooks/index.d.ts +33 -7
- package/dist/hooks/index.js +631 -180
- 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 +666 -104
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -7
- package/dist/index.d.ts +8 -7
- package/dist/index.js +645 -105
- 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 +973 -130
- package/dist/providers/index.cjs.map +1 -1
- package/dist/providers/index.d.cts +84 -18
- package/dist/providers/index.d.ts +84 -18
- package/dist/providers/index.js +956 -131
- package/dist/providers/index.js.map +1 -1
- package/dist/text-generation.service-BQO3Tvz2.d.cts +66 -0
- package/dist/text-generation.service-CcYQM6Ch.d.ts +66 -0
- package/dist/wizard/index.d.cts +1 -1
- package/dist/wizard/index.d.ts +1 -1
- package/package.json +9 -1
- package/dist/index-DjX9ZKuM.d.cts +0 -14
- package/dist/index-DxLvE588.d.ts +0 -14
package/dist/index.js
CHANGED
|
@@ -41,17 +41,80 @@ var USER_FRIENDLY_ERROR_MESSAGES = {
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
// src/core/errors/ai-error.ts
|
|
44
|
-
var
|
|
44
|
+
var KNOWN_ERROR_TYPES = new Set(Object.values(AIErrorType));
|
|
45
|
+
function mapCodeToType(code) {
|
|
46
|
+
switch (code) {
|
|
47
|
+
case "VALIDATION_ERROR":
|
|
48
|
+
case "CLIENT_ERROR":
|
|
49
|
+
return "CLIENT_ERROR" /* CLIENT_ERROR */;
|
|
50
|
+
case "INVALID_API_KEY":
|
|
51
|
+
return "INVALID_API_KEY" /* INVALID_API_KEY */;
|
|
52
|
+
case "MISSING_CONFIG":
|
|
53
|
+
case "PROVIDER_UNAVAILABLE":
|
|
54
|
+
return "MISSING_CONFIG" /* MISSING_CONFIG */;
|
|
55
|
+
case "PROVIDER_QUOTA_EXHAUSTED":
|
|
56
|
+
case "RATE_LIMIT_ERROR":
|
|
57
|
+
return "RATE_LIMIT_ERROR" /* RATE_LIMIT_ERROR */;
|
|
58
|
+
case "NETWORK_ERROR":
|
|
59
|
+
case "TIMEOUT":
|
|
60
|
+
return "NETWORK_ERROR" /* NETWORK_ERROR */;
|
|
61
|
+
case "ABORT_ERROR":
|
|
62
|
+
case "ABORTED":
|
|
63
|
+
return "ABORT_ERROR" /* ABORT_ERROR */;
|
|
64
|
+
case "SERVER_ERROR":
|
|
65
|
+
case "PROVIDER_ERROR":
|
|
66
|
+
case "NO_RESULT":
|
|
67
|
+
return "SERVER_ERROR" /* SERVER_ERROR */;
|
|
68
|
+
default:
|
|
69
|
+
return "UNKNOWN_ERROR" /* UNKNOWN_ERROR */;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function mapMessageToCode(message, fallback = "UNKNOWN") {
|
|
73
|
+
const lower = message.toLowerCase();
|
|
74
|
+
if (lower.includes("validation")) return "VALIDATION_ERROR";
|
|
75
|
+
if (lower.includes("quota")) return "PROVIDER_QUOTA_EXHAUSTED";
|
|
76
|
+
if (lower.includes("unavailable")) return "PROVIDER_UNAVAILABLE";
|
|
77
|
+
if (lower.includes("timeout") || lower.includes("aborted")) {
|
|
78
|
+
return lower.includes("aborted") ? "ABORTED" : "TIMEOUT";
|
|
79
|
+
}
|
|
80
|
+
if (lower.includes("parse") || lower.includes("json")) return "PARSE_ERROR";
|
|
81
|
+
if (lower.includes("no result")) return "NO_RESULT";
|
|
82
|
+
if (lower.includes("network") || lower.includes("fetch")) return "NETWORK_ERROR";
|
|
83
|
+
return fallback;
|
|
84
|
+
}
|
|
85
|
+
var AIError = class _AIError extends Error {
|
|
45
86
|
type;
|
|
87
|
+
code;
|
|
46
88
|
cause;
|
|
47
89
|
metadata;
|
|
48
|
-
constructor(
|
|
49
|
-
|
|
90
|
+
constructor(typeOrMessage, messageOrCode, cause, metadata = {}) {
|
|
91
|
+
let effectiveType;
|
|
92
|
+
let effectiveMessage;
|
|
93
|
+
let effectiveCode;
|
|
94
|
+
if (KNOWN_ERROR_TYPES.has(typeOrMessage)) {
|
|
95
|
+
effectiveType = typeOrMessage;
|
|
96
|
+
effectiveMessage = messageOrCode ?? "";
|
|
97
|
+
effectiveCode = effectiveType;
|
|
98
|
+
} else {
|
|
99
|
+
effectiveMessage = typeOrMessage;
|
|
100
|
+
effectiveCode = messageOrCode ?? "UNKNOWN";
|
|
101
|
+
effectiveType = mapCodeToType(effectiveCode);
|
|
102
|
+
}
|
|
103
|
+
super(effectiveMessage);
|
|
50
104
|
this.name = "AIError";
|
|
51
|
-
this.type =
|
|
105
|
+
this.type = effectiveType;
|
|
106
|
+
this.code = effectiveCode;
|
|
52
107
|
this.cause = cause;
|
|
53
108
|
this.metadata = metadata;
|
|
54
109
|
}
|
|
110
|
+
static from(error, fallbackCode = "UNKNOWN") {
|
|
111
|
+
if (error instanceof _AIError) return error;
|
|
112
|
+
if (error instanceof Error) {
|
|
113
|
+
const code = mapMessageToCode(error.message, fallbackCode);
|
|
114
|
+
return new _AIError(error.message, code, error);
|
|
115
|
+
}
|
|
116
|
+
return new _AIError(String(error), fallbackCode, error);
|
|
117
|
+
}
|
|
55
118
|
toString() {
|
|
56
119
|
const statusPart = typeof this.metadata.status === "number" ? ` (HTTP ${this.metadata.status})` : "";
|
|
57
120
|
return `${this.name} [${this.type}]: ${this.message}${statusPart}`;
|
|
@@ -60,12 +123,21 @@ var AIError = class extends Error {
|
|
|
60
123
|
return {
|
|
61
124
|
name: this.name,
|
|
62
125
|
type: this.type,
|
|
126
|
+
code: this.code,
|
|
63
127
|
message: this.message,
|
|
64
128
|
metadata: this.metadata
|
|
65
129
|
};
|
|
66
130
|
}
|
|
67
131
|
};
|
|
68
132
|
|
|
133
|
+
// src/core/errors/groq-error.ts
|
|
134
|
+
var GroqError = class extends AIError {
|
|
135
|
+
constructor(type, message, cause, metadata = {}) {
|
|
136
|
+
super(type, message, cause, metadata);
|
|
137
|
+
this.name = "GroqError";
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
69
141
|
// src/core/errors/error-classifier.ts
|
|
70
142
|
var DEFAULT_RETRYABLE_TYPES = /* @__PURE__ */ new Set([
|
|
71
143
|
"NETWORK_ERROR" /* NETWORK_ERROR */,
|
|
@@ -344,6 +416,8 @@ function calculateExponentialBackoff(params) {
|
|
|
344
416
|
// src/core/constants/identifier.constants.ts
|
|
345
417
|
var MESSAGE_ID_PREFIX = "msg-";
|
|
346
418
|
var CHAT_MESSAGE_ID_SUFFIX_LENGTH = 9;
|
|
419
|
+
var CACHE_KEY_TYPE_COMPLETION = "completion";
|
|
420
|
+
var CACHE_KEY_TYPE_CHAT = "chat";
|
|
347
421
|
var USER_ROLE = "user";
|
|
348
422
|
var ASSISTANT_ROLE = "assistant";
|
|
349
423
|
var QUEUE_PRIORITY_USER_REQUEST = 10;
|
|
@@ -748,15 +822,22 @@ function oneOfCatalog(catalog, value) {
|
|
|
748
822
|
// src/core/constants/protocol.constants.ts
|
|
749
823
|
var SSE_PREFIX = "data: ";
|
|
750
824
|
var SSE_DONE_MARKER = "[DONE]";
|
|
751
|
-
var JSON_CODE_BLOCK_PATTERN = /```json
|
|
825
|
+
var JSON_CODE_BLOCK_PATTERN = /```(?:json)?\s*\n?([\s\S]*?)\n?```/;
|
|
752
826
|
var JSON_OBJECT_PATTERN = /\{[\s\S]*\}/;
|
|
827
|
+
var JSON_ARRAY_PATTERN = /\[[\s\S]*\]/;
|
|
753
828
|
|
|
754
829
|
// src/core/parsers/sse-lines.ts
|
|
755
830
|
function isSseDataLine(line) {
|
|
756
|
-
return line.startsWith(SSE_PREFIX);
|
|
831
|
+
return line.startsWith(SSE_PREFIX) || line.startsWith("data:");
|
|
757
832
|
}
|
|
758
833
|
function extractSseDataPayload(line) {
|
|
759
|
-
|
|
834
|
+
if (line.startsWith(SSE_PREFIX)) {
|
|
835
|
+
return line.slice(SSE_PREFIX.length);
|
|
836
|
+
}
|
|
837
|
+
if (line.startsWith("data:")) {
|
|
838
|
+
return line.slice(5);
|
|
839
|
+
}
|
|
840
|
+
return line;
|
|
760
841
|
}
|
|
761
842
|
function isSseDoneMarker(payload) {
|
|
762
843
|
return payload === SSE_DONE_MARKER;
|
|
@@ -828,7 +909,7 @@ var StreamingResponseParser = class {
|
|
|
828
909
|
// src/core/parsers/json-content-extractor.ts
|
|
829
910
|
function extractJsonFromCodeFence(content) {
|
|
830
911
|
const match = content.match(JSON_CODE_BLOCK_PATTERN);
|
|
831
|
-
if (match && match[1]) return match[1];
|
|
912
|
+
if (match && match[1]) return match[1].trim();
|
|
832
913
|
return null;
|
|
833
914
|
}
|
|
834
915
|
function extractJsonObject(content) {
|
|
@@ -836,8 +917,27 @@ function extractJsonObject(content) {
|
|
|
836
917
|
if (match && match[0]) return match[0];
|
|
837
918
|
return null;
|
|
838
919
|
}
|
|
920
|
+
function extractJsonArray(content) {
|
|
921
|
+
const match = content.match(JSON_ARRAY_PATTERN);
|
|
922
|
+
if (match && match[0]) return match[0];
|
|
923
|
+
return null;
|
|
924
|
+
}
|
|
925
|
+
function repairCommonJsonDefects(text) {
|
|
926
|
+
return text.replace(/(:\s*-?\d+(?:\.\d+)?)\s*"/g, "$1").replace(/(:\s*"[^"]*")"/g, "$1");
|
|
927
|
+
}
|
|
839
928
|
function extractJsonCandidate(content) {
|
|
840
|
-
|
|
929
|
+
const fromFence = extractJsonFromCodeFence(content);
|
|
930
|
+
if (fromFence) return fromFence;
|
|
931
|
+
const objectIndex = content.indexOf("{");
|
|
932
|
+
const arrayIndex = content.indexOf("[");
|
|
933
|
+
if (objectIndex !== -1 && (arrayIndex === -1 || objectIndex < arrayIndex)) {
|
|
934
|
+
const obj = extractJsonObject(content);
|
|
935
|
+
if (obj) return obj;
|
|
936
|
+
} else if (arrayIndex !== -1) {
|
|
937
|
+
const arr = extractJsonArray(content);
|
|
938
|
+
if (arr) return arr;
|
|
939
|
+
}
|
|
940
|
+
return content.trim();
|
|
841
941
|
}
|
|
842
942
|
|
|
843
943
|
// src/core/parsers/json-response.parser.ts
|
|
@@ -846,12 +946,17 @@ var JsonResponseParser = class {
|
|
|
846
946
|
const candidate = extractJsonCandidate(rawContent);
|
|
847
947
|
try {
|
|
848
948
|
return JSON.parse(candidate);
|
|
849
|
-
} catch
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
949
|
+
} catch {
|
|
950
|
+
try {
|
|
951
|
+
return JSON.parse(repairCommonJsonDefects(candidate));
|
|
952
|
+
} catch (error) {
|
|
953
|
+
throw new AIError(
|
|
954
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
955
|
+
"Failed to parse structured response as JSON",
|
|
956
|
+
error instanceof Error ? error : void 0,
|
|
957
|
+
{ rawContent }
|
|
958
|
+
);
|
|
959
|
+
}
|
|
855
960
|
}
|
|
856
961
|
}
|
|
857
962
|
};
|
|
@@ -977,38 +1082,6 @@ function isMediaProvider(provider) {
|
|
|
977
1082
|
return provider.capabilities.includes("image") || provider.capabilities.includes("video");
|
|
978
1083
|
}
|
|
979
1084
|
|
|
980
|
-
// src/content/domain/errors/AIErrors.ts
|
|
981
|
-
var AIError2 = class _AIError extends Error {
|
|
982
|
-
code;
|
|
983
|
-
cause;
|
|
984
|
-
constructor(message, code, cause) {
|
|
985
|
-
super(message);
|
|
986
|
-
this.name = "AIError";
|
|
987
|
-
this.code = code;
|
|
988
|
-
this.cause = cause;
|
|
989
|
-
}
|
|
990
|
-
static from(error, fallbackCode = "UNKNOWN") {
|
|
991
|
-
if (error instanceof _AIError) return error;
|
|
992
|
-
if (error instanceof Error) {
|
|
993
|
-
return new _AIError(error.message, mapMessageToCode(error.message, fallbackCode), error);
|
|
994
|
-
}
|
|
995
|
-
return new _AIError(String(error), fallbackCode, error);
|
|
996
|
-
}
|
|
997
|
-
};
|
|
998
|
-
function mapMessageToCode(message, fallback) {
|
|
999
|
-
const lower = message.toLowerCase();
|
|
1000
|
-
if (lower.includes("validation")) return "VALIDATION_ERROR";
|
|
1001
|
-
if (lower.includes("quota")) return "PROVIDER_QUOTA_EXHAUSTED";
|
|
1002
|
-
if (lower.includes("unavailable")) return "PROVIDER_UNAVAILABLE";
|
|
1003
|
-
if (lower.includes("timeout") || lower.includes("aborted")) {
|
|
1004
|
-
return lower.includes("aborted") ? "ABORTED" : "TIMEOUT";
|
|
1005
|
-
}
|
|
1006
|
-
if (lower.includes("parse") || lower.includes("json")) return "PARSE_ERROR";
|
|
1007
|
-
if (lower.includes("no result")) return "NO_RESULT";
|
|
1008
|
-
if (lower.includes("network") || lower.includes("fetch")) return "NETWORK_ERROR";
|
|
1009
|
-
return fallback;
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
1085
|
// src/content/domain/limits/ProviderTimingConfig.ts
|
|
1013
1086
|
var ProviderTimingConfig = {
|
|
1014
1087
|
DEFAULT_TIMEOUT_MS: 3e4,
|
|
@@ -1073,7 +1146,7 @@ var BaseProvider = class {
|
|
|
1073
1146
|
throw lastError || new Error("Retry attempts exhausted");
|
|
1074
1147
|
}
|
|
1075
1148
|
};
|
|
1076
|
-
var ProviderError = class extends
|
|
1149
|
+
var ProviderError = class extends AIError {
|
|
1077
1150
|
constructor(message, providerId, originalError) {
|
|
1078
1151
|
super(message, "PROVIDER_ERROR", originalError);
|
|
1079
1152
|
this.providerId = providerId;
|
|
@@ -1167,12 +1240,16 @@ var ProviderFactory = class {
|
|
|
1167
1240
|
let wake = null;
|
|
1168
1241
|
let finished = false;
|
|
1169
1242
|
let failure;
|
|
1243
|
+
const controller = new AbortController();
|
|
1244
|
+
const onAbort = () => controller.abort();
|
|
1245
|
+
request.signal?.addEventListener("abort", onAbort);
|
|
1246
|
+
const effectiveRequest = { ...request, signal: controller.signal };
|
|
1170
1247
|
const notify = () => {
|
|
1171
1248
|
const resolve = wake;
|
|
1172
1249
|
wake = null;
|
|
1173
1250
|
resolve?.();
|
|
1174
1251
|
};
|
|
1175
|
-
const completion = this.chatStream(
|
|
1252
|
+
const completion = this.chatStream(effectiveRequest, {
|
|
1176
1253
|
onChunk: (chunk) => {
|
|
1177
1254
|
queue.push(chunk);
|
|
1178
1255
|
notify();
|
|
@@ -1188,18 +1265,23 @@ var ProviderFactory = class {
|
|
|
1188
1265
|
notify();
|
|
1189
1266
|
}
|
|
1190
1267
|
);
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1268
|
+
try {
|
|
1269
|
+
while (!finished || queue.length > 0) {
|
|
1270
|
+
if (queue.length === 0 && !finished) {
|
|
1271
|
+
await new Promise((resolve) => {
|
|
1272
|
+
wake = resolve;
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
while (queue.length > 0) {
|
|
1276
|
+
yield queue.shift();
|
|
1277
|
+
}
|
|
1278
|
+
if (failure) throw failure;
|
|
1199
1279
|
}
|
|
1200
|
-
|
|
1280
|
+
await completion;
|
|
1281
|
+
} finally {
|
|
1282
|
+
controller.abort();
|
|
1283
|
+
request.signal?.removeEventListener("abort", onAbort);
|
|
1201
1284
|
}
|
|
1202
|
-
await completion;
|
|
1203
1285
|
}
|
|
1204
1286
|
async generateJson(request) {
|
|
1205
1287
|
const effective = request.model || request.tier ? request : { ...request, tier: this.defaultTier };
|
|
@@ -1608,11 +1690,14 @@ async function consumeAnthropicStream(stream, callbacks) {
|
|
|
1608
1690
|
break;
|
|
1609
1691
|
case "message_stop":
|
|
1610
1692
|
break;
|
|
1611
|
-
case "error":
|
|
1693
|
+
case "error": {
|
|
1694
|
+
const errType = event.error.type;
|
|
1695
|
+
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 */;
|
|
1612
1696
|
throw new AIError(
|
|
1613
|
-
|
|
1697
|
+
mappedType,
|
|
1614
1698
|
event.error.message || "Anthropic stream failed mid-flight"
|
|
1615
1699
|
);
|
|
1700
|
+
}
|
|
1616
1701
|
}
|
|
1617
1702
|
};
|
|
1618
1703
|
try {
|
|
@@ -1804,12 +1889,22 @@ var DEFAULT_GENERATION_CONFIG = {
|
|
|
1804
1889
|
maxTokens: 1024,
|
|
1805
1890
|
topP: 1
|
|
1806
1891
|
};
|
|
1892
|
+
var DEFAULT_MODELS = {
|
|
1893
|
+
TEXT: GROQ_MODELS.LLAMA_3_1_8B_INSTANT,
|
|
1894
|
+
FAST: GROQ_MODELS.LLAMA_3_1_8B_INSTANT,
|
|
1895
|
+
EXPERIMENTAL: GROQ_MODELS.GPT_OSS_20B
|
|
1896
|
+
};
|
|
1807
1897
|
var GROQ_BASE_URL = "https://api.groq.com/openai/v1";
|
|
1898
|
+
var DEFAULT_BASE_URL = GROQ_BASE_URL;
|
|
1808
1899
|
var CHAT_COMPLETIONS_PATH = "/chat/completions";
|
|
1900
|
+
var API_ENDPOINTS = {
|
|
1901
|
+
CHAT: CHAT_COMPLETIONS_PATH
|
|
1902
|
+
};
|
|
1809
1903
|
var GROQ_TIMEOUTS = {
|
|
1810
1904
|
DEFAULT: 3e4,
|
|
1811
1905
|
STREAMING: 6e4
|
|
1812
1906
|
};
|
|
1907
|
+
var TIMEOUTS = GROQ_TIMEOUTS;
|
|
1813
1908
|
var HTTP_HEADERS = {
|
|
1814
1909
|
CONTENT_TYPE: "Content-Type",
|
|
1815
1910
|
APPLICATION_JSON: "application/json",
|
|
@@ -1868,13 +1963,65 @@ var GroqChatRequestBuilder = class _GroqChatRequestBuilder {
|
|
|
1868
1963
|
}
|
|
1869
1964
|
};
|
|
1870
1965
|
|
|
1966
|
+
// src/providers/groq/groq-config-store.ts
|
|
1967
|
+
var GroqConfigStore = class {
|
|
1968
|
+
config = null;
|
|
1969
|
+
initialize(config) {
|
|
1970
|
+
const validation = validateApiKey(config.apiKey, { minLength: 1 });
|
|
1971
|
+
if (!validation.valid) {
|
|
1972
|
+
throw new GroqError("INVALID_API_KEY" /* INVALID_API_KEY */, validation.reason ?? "Invalid API key");
|
|
1973
|
+
}
|
|
1974
|
+
const normalized = {
|
|
1975
|
+
apiKey: config.apiKey.trim(),
|
|
1976
|
+
baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
|
|
1977
|
+
timeoutMs: config.timeoutMs ?? TIMEOUTS.DEFAULT,
|
|
1978
|
+
...config.models !== void 0 ? { models: config.models } : {},
|
|
1979
|
+
...config.textModel !== void 0 ? { textModel: config.textModel } : {}
|
|
1980
|
+
};
|
|
1981
|
+
this.config = normalized;
|
|
1982
|
+
return normalized;
|
|
1983
|
+
}
|
|
1984
|
+
get() {
|
|
1985
|
+
if (!this.config) {
|
|
1986
|
+
throw new GroqError(
|
|
1987
|
+
"MISSING_CONFIG" /* MISSING_CONFIG */,
|
|
1988
|
+
"Client not initialized. Call configureProvider first."
|
|
1989
|
+
);
|
|
1990
|
+
}
|
|
1991
|
+
return this.config;
|
|
1992
|
+
}
|
|
1993
|
+
getOrNull() {
|
|
1994
|
+
return this.config;
|
|
1995
|
+
}
|
|
1996
|
+
isInitialized() {
|
|
1997
|
+
return this.config !== null;
|
|
1998
|
+
}
|
|
1999
|
+
setApiKey(apiKey) {
|
|
2000
|
+
const current = this.get();
|
|
2001
|
+
const validation = validateApiKey(apiKey, { minLength: 1 });
|
|
2002
|
+
if (!validation.valid) {
|
|
2003
|
+
throw new GroqError("INVALID_API_KEY" /* INVALID_API_KEY */, validation.reason ?? "Invalid API key");
|
|
2004
|
+
}
|
|
2005
|
+
this.config = { ...current, apiKey: apiKey.trim() };
|
|
2006
|
+
}
|
|
2007
|
+
reset() {
|
|
2008
|
+
this.config = null;
|
|
2009
|
+
}
|
|
2010
|
+
};
|
|
2011
|
+
|
|
1871
2012
|
// src/providers/groq/groq-http-transport.ts
|
|
1872
2013
|
var GroqHttpTransport = class {
|
|
1873
|
-
constructor(
|
|
1874
|
-
this.
|
|
2014
|
+
constructor(configSource) {
|
|
2015
|
+
this.configSource = configSource;
|
|
1875
2016
|
}
|
|
1876
|
-
|
|
2017
|
+
configSource;
|
|
1877
2018
|
pendingAbortControllers = /* @__PURE__ */ new Set();
|
|
2019
|
+
getConfig() {
|
|
2020
|
+
if ("get" in this.configSource && typeof this.configSource.get === "function") {
|
|
2021
|
+
return this.configSource.get();
|
|
2022
|
+
}
|
|
2023
|
+
return this.configSource;
|
|
2024
|
+
}
|
|
1878
2025
|
cancelPendingRequests() {
|
|
1879
2026
|
for (const controller of this.pendingAbortControllers) {
|
|
1880
2027
|
controller.abort();
|
|
@@ -1889,7 +2036,7 @@ var GroqHttpTransport = class {
|
|
|
1889
2036
|
}
|
|
1890
2037
|
async streamChatCompletion(request, options = {}) {
|
|
1891
2038
|
const url = `${this.baseUrl()}${CHAT_COMPLETIONS_PATH}`;
|
|
1892
|
-
const timeout = this.
|
|
2039
|
+
const timeout = this.getConfig().timeoutMs ?? GROQ_TIMEOUTS.STREAMING;
|
|
1893
2040
|
const controller = new AbortController();
|
|
1894
2041
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1895
2042
|
const onExternalAbort = () => controller.abort();
|
|
@@ -1916,11 +2063,11 @@ var GroqHttpTransport = class {
|
|
|
1916
2063
|
}
|
|
1917
2064
|
}
|
|
1918
2065
|
baseUrl() {
|
|
1919
|
-
return this.
|
|
2066
|
+
return this.getConfig().baseUrl ?? GROQ_BASE_URL;
|
|
1920
2067
|
}
|
|
1921
2068
|
async request(endpoint, body) {
|
|
1922
2069
|
const url = `${this.baseUrl()}${endpoint}`;
|
|
1923
|
-
const timeout = this.
|
|
2070
|
+
const timeout = this.getConfig().timeoutMs ?? GROQ_TIMEOUTS.DEFAULT;
|
|
1924
2071
|
const controller = new AbortController();
|
|
1925
2072
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1926
2073
|
this.pendingAbortControllers.add(controller);
|
|
@@ -1943,7 +2090,7 @@ var GroqHttpTransport = class {
|
|
|
1943
2090
|
buildHeaders() {
|
|
1944
2091
|
return {
|
|
1945
2092
|
[HTTP_HEADERS.CONTENT_TYPE]: HTTP_HEADERS.APPLICATION_JSON,
|
|
1946
|
-
[HTTP_HEADERS.AUTHORIZATION]: `${HTTP_HEADERS.BEARER_PREFIX}${this.
|
|
2093
|
+
[HTTP_HEADERS.AUTHORIZATION]: `${HTTP_HEADERS.BEARER_PREFIX}${this.getConfig().apiKey}`
|
|
1947
2094
|
};
|
|
1948
2095
|
}
|
|
1949
2096
|
async throwFromErrorResponse(response) {
|
|
@@ -1987,21 +2134,40 @@ var GroqHttpTransport = class {
|
|
|
1987
2134
|
|
|
1988
2135
|
// src/providers/groq/groq-http-client.ts
|
|
1989
2136
|
var GroqHttpClient = class {
|
|
2137
|
+
configStore;
|
|
1990
2138
|
transport;
|
|
1991
2139
|
executor;
|
|
1992
|
-
constructor(
|
|
1993
|
-
|
|
2140
|
+
constructor(configOrDeps, maybeDeps = {}) {
|
|
2141
|
+
const isConfig = typeof configOrDeps === "object" && configOrDeps !== null && "apiKey" in configOrDeps && typeof configOrDeps.apiKey === "string";
|
|
2142
|
+
const deps = isConfig ? maybeDeps : configOrDeps ?? {};
|
|
2143
|
+
this.configStore = deps.configStore ?? new GroqConfigStore();
|
|
2144
|
+
if (isConfig) {
|
|
2145
|
+
this.configStore.initialize(configOrDeps);
|
|
2146
|
+
}
|
|
2147
|
+
this.transport = deps.transport ?? new GroqHttpTransport(this.configStore);
|
|
1994
2148
|
const retryManager2 = deps.retryManager ?? new RetryManager();
|
|
1995
2149
|
const queue = deps.queue ?? new RequestQueue();
|
|
1996
2150
|
const deduplicator = deps.deduplicator ?? new RequestDeduplicator();
|
|
1997
2151
|
this.executor = new CompositeExecutor([
|
|
1998
2152
|
new DedupeExecutor(deduplicator, {
|
|
1999
|
-
generateKey: (request) => deduplicatorKey(request,
|
|
2153
|
+
generateKey: (request) => deduplicatorKey(request, this.configStore.isInitialized() ? this.configStore.get().apiKey : "")
|
|
2000
2154
|
}),
|
|
2001
2155
|
new RetryExecutor(retryManager2),
|
|
2002
2156
|
new QueueExecutor(queue, QUEUE_PRIORITY_USER_REQUEST)
|
|
2003
2157
|
]);
|
|
2004
2158
|
}
|
|
2159
|
+
initialize(config) {
|
|
2160
|
+
this.configStore.initialize(config);
|
|
2161
|
+
}
|
|
2162
|
+
isInitialized() {
|
|
2163
|
+
return this.configStore.isInitialized();
|
|
2164
|
+
}
|
|
2165
|
+
getApiKey() {
|
|
2166
|
+
return this.configStore.get().apiKey;
|
|
2167
|
+
}
|
|
2168
|
+
setApiKey(apiKey) {
|
|
2169
|
+
this.configStore.setApiKey(apiKey);
|
|
2170
|
+
}
|
|
2005
2171
|
cancelPendingRequests() {
|
|
2006
2172
|
this.transport.cancelPendingRequests();
|
|
2007
2173
|
}
|
|
@@ -2014,6 +2180,10 @@ var GroqHttpClient = class {
|
|
|
2014
2180
|
streamChatCompletion(request, options) {
|
|
2015
2181
|
return this.transport.streamChatCompletion(request, options);
|
|
2016
2182
|
}
|
|
2183
|
+
reset() {
|
|
2184
|
+
this.transport.cancelPendingRequests();
|
|
2185
|
+
this.configStore.reset();
|
|
2186
|
+
}
|
|
2017
2187
|
};
|
|
2018
2188
|
function deduplicatorKey(request, apiKey) {
|
|
2019
2189
|
const { model, messages, stream: _stream, ...rest } = request;
|
|
@@ -2070,6 +2240,13 @@ async function consumeGroqStream(stream, callbacks) {
|
|
|
2070
2240
|
} catch {
|
|
2071
2241
|
return;
|
|
2072
2242
|
}
|
|
2243
|
+
const errorBody = chunk.error;
|
|
2244
|
+
if (errorBody) {
|
|
2245
|
+
throw new AIError(
|
|
2246
|
+
errorBody.message?.toLowerCase().includes("rate limit") ? "RATE_LIMIT_ERROR" /* RATE_LIMIT_ERROR */ : "SERVER_ERROR" /* SERVER_ERROR */,
|
|
2247
|
+
errorBody.message || "Groq stream failed mid-flight"
|
|
2248
|
+
);
|
|
2249
|
+
}
|
|
2073
2250
|
if (chunk.model) model = chunk.model;
|
|
2074
2251
|
const choice = chunk.choices?.[0];
|
|
2075
2252
|
const delta = choice?.delta?.content;
|
|
@@ -2084,13 +2261,6 @@ async function consumeGroqStream(stream, callbacks) {
|
|
|
2084
2261
|
if (tailUsage) {
|
|
2085
2262
|
usage = mapGroqUsage(tailUsage);
|
|
2086
2263
|
}
|
|
2087
|
-
const errorBody = chunk.error;
|
|
2088
|
-
if (errorBody) {
|
|
2089
|
-
throw new AIError(
|
|
2090
|
-
"SERVER_ERROR" /* SERVER_ERROR */,
|
|
2091
|
-
errorBody.message || "Groq stream failed mid-flight"
|
|
2092
|
-
);
|
|
2093
|
-
}
|
|
2094
2264
|
};
|
|
2095
2265
|
try {
|
|
2096
2266
|
while (true) {
|
|
@@ -2357,7 +2527,9 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2357
2527
|
headers: this.authHeaders()
|
|
2358
2528
|
}
|
|
2359
2529
|
);
|
|
2360
|
-
|
|
2530
|
+
if (response.ok) return "healthy";
|
|
2531
|
+
if (response.status === 401 || response.status === 403) return "unavailable";
|
|
2532
|
+
return "degraded";
|
|
2361
2533
|
} catch {
|
|
2362
2534
|
return "unavailable";
|
|
2363
2535
|
}
|
|
@@ -2368,6 +2540,8 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2368
2540
|
async generate(request) {
|
|
2369
2541
|
try {
|
|
2370
2542
|
const model = request.model ?? this.resolveModel(request.tier ?? "balanced");
|
|
2543
|
+
const systemMessages = request.messages.filter((m) => m.role === "system");
|
|
2544
|
+
const systemPrompt = request.systemPrompt && request.systemPrompt.length > 0 ? request.systemPrompt : systemMessages.length > 0 ? systemMessages.map((m) => m.content).join("\n") : void 0;
|
|
2371
2545
|
const response = await this.withRetry(async () => {
|
|
2372
2546
|
return await this.fetchWithTimeout(
|
|
2373
2547
|
`${this.config.baseUrl}/models/${model}:generateContent`,
|
|
@@ -2375,22 +2549,28 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2375
2549
|
method: "POST",
|
|
2376
2550
|
headers: this.authHeaders(),
|
|
2377
2551
|
body: JSON.stringify({
|
|
2378
|
-
systemInstruction:
|
|
2552
|
+
systemInstruction: systemPrompt && systemPrompt.length > 0 ? { parts: [{ text: systemPrompt }] } : void 0,
|
|
2379
2553
|
contents: toGeminiContents(request.messages),
|
|
2380
2554
|
generationConfig: {
|
|
2381
|
-
temperature: request.temperature
|
|
2382
|
-
maxOutputTokens: request.maxTokens
|
|
2383
|
-
topP: request.topP
|
|
2555
|
+
temperature: request.temperature ?? 0.7,
|
|
2556
|
+
maxOutputTokens: request.maxTokens ?? 2048,
|
|
2557
|
+
topP: request.topP ?? 0.9
|
|
2384
2558
|
}
|
|
2385
2559
|
})
|
|
2386
2560
|
}
|
|
2387
2561
|
);
|
|
2388
2562
|
});
|
|
2389
2563
|
if (!response.ok) {
|
|
2390
|
-
|
|
2564
|
+
const message = await extractErrorMessageFromResponse(response);
|
|
2565
|
+
throw new AIError(
|
|
2566
|
+
classifyHttpStatus(response.status),
|
|
2567
|
+
`Gemini API error (${response.status}): ${message}`,
|
|
2568
|
+
void 0,
|
|
2569
|
+
{ status: response.status, model }
|
|
2570
|
+
);
|
|
2391
2571
|
}
|
|
2392
2572
|
const data = await response.json();
|
|
2393
|
-
const text = data.candidates[0]?.content?.parts?.map((part) => part.text ?? "").join("") ?? "";
|
|
2573
|
+
const text = data.candidates?.[0]?.content?.parts?.map((part) => part.text ?? "").join("") ?? "";
|
|
2394
2574
|
if (text.length === 0) {
|
|
2395
2575
|
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No content generated from Gemini API", void 0, { model });
|
|
2396
2576
|
}
|
|
@@ -2403,7 +2583,7 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2403
2583
|
} : void 0,
|
|
2404
2584
|
model,
|
|
2405
2585
|
providerId: this.id,
|
|
2406
|
-
finishReason: mapGeminiFinishReason(data.candidates[0]?.finishReason)
|
|
2586
|
+
finishReason: mapGeminiFinishReason(data.candidates?.[0]?.finishReason)
|
|
2407
2587
|
};
|
|
2408
2588
|
} catch (error) {
|
|
2409
2589
|
if (error instanceof AIError) throw error;
|
|
@@ -2455,12 +2635,18 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2455
2635
|
);
|
|
2456
2636
|
});
|
|
2457
2637
|
if (!response.ok) {
|
|
2458
|
-
|
|
2638
|
+
const message = await extractErrorMessageFromResponse(response);
|
|
2639
|
+
throw new AIError(
|
|
2640
|
+
classifyHttpStatus(response.status),
|
|
2641
|
+
`Gemini image generation error (${response.status}): ${message}`,
|
|
2642
|
+
void 0,
|
|
2643
|
+
{ status: response.status }
|
|
2644
|
+
);
|
|
2459
2645
|
}
|
|
2460
2646
|
const data = await response.json();
|
|
2461
|
-
const imageData = data.candidates[0]?.content?.parts[0]?.inlineData;
|
|
2647
|
+
const imageData = data.candidates?.[0]?.content?.parts?.[0]?.inlineData;
|
|
2462
2648
|
if (!imageData) {
|
|
2463
|
-
throw new
|
|
2649
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No image data in Gemini response");
|
|
2464
2650
|
}
|
|
2465
2651
|
const url = `data:${imageData.mimeType};base64,${imageData.data}`;
|
|
2466
2652
|
return {
|
|
@@ -2779,17 +2965,70 @@ var PrunaProvider = class {
|
|
|
2779
2965
|
async estimateCost(_request) {
|
|
2780
2966
|
return 1;
|
|
2781
2967
|
}
|
|
2782
|
-
async generateImage(
|
|
2783
|
-
|
|
2968
|
+
async generateImage(request) {
|
|
2969
|
+
let finalUrl;
|
|
2970
|
+
const model = this.config.models?.textToImage;
|
|
2971
|
+
for await (const stage of generateWithPruna(
|
|
2972
|
+
{ prompt: request.prompt, model, quality: request.quality },
|
|
2973
|
+
this.config.apiKey
|
|
2974
|
+
)) {
|
|
2975
|
+
if (stage.error) throw stage.error;
|
|
2976
|
+
if (stage.result?.url) finalUrl = stage.result.url;
|
|
2977
|
+
}
|
|
2978
|
+
if (!finalUrl) {
|
|
2979
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No image generated by Pruna AI");
|
|
2980
|
+
}
|
|
2981
|
+
return {
|
|
2982
|
+
id: Date.now().toString(),
|
|
2983
|
+
type: "image",
|
|
2984
|
+
url: finalUrl,
|
|
2985
|
+
metadata: { provider: this.id, model: model ?? "p-image" },
|
|
2986
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2987
|
+
};
|
|
2784
2988
|
}
|
|
2785
|
-
async generateVideo(
|
|
2786
|
-
|
|
2989
|
+
async generateVideo(request) {
|
|
2990
|
+
let finalUrl;
|
|
2991
|
+
const model = this.config.models?.textToVideo;
|
|
2992
|
+
for await (const stage of generateWithPruna(
|
|
2993
|
+
{ prompt: request.prompt, model, duration: request.duration, aspectRatio: request.aspectRatio },
|
|
2994
|
+
this.config.apiKey
|
|
2995
|
+
)) {
|
|
2996
|
+
if (stage.error) throw stage.error;
|
|
2997
|
+
if (stage.result?.url) finalUrl = stage.result.url;
|
|
2998
|
+
}
|
|
2999
|
+
if (!finalUrl) {
|
|
3000
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No video generated by Pruna AI");
|
|
3001
|
+
}
|
|
3002
|
+
return {
|
|
3003
|
+
id: Date.now().toString(),
|
|
3004
|
+
type: "video",
|
|
3005
|
+
url: finalUrl,
|
|
3006
|
+
metadata: { provider: this.id, model: model ?? "p-video" },
|
|
3007
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3008
|
+
};
|
|
2787
3009
|
}
|
|
2788
|
-
async imageToVideo(
|
|
2789
|
-
|
|
3010
|
+
async imageToVideo(request) {
|
|
3011
|
+
let finalUrl;
|
|
3012
|
+
for await (const stage of generateWithPruna(
|
|
3013
|
+
{ image: request.imageUrl, prompt: request.prompt, duration: request.duration, motion: request.motion },
|
|
3014
|
+
this.config.apiKey
|
|
3015
|
+
)) {
|
|
3016
|
+
if (stage.error) throw stage.error;
|
|
3017
|
+
if (stage.result?.url) finalUrl = stage.result.url;
|
|
3018
|
+
}
|
|
3019
|
+
if (!finalUrl) {
|
|
3020
|
+
throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No video generated from image by Pruna AI");
|
|
3021
|
+
}
|
|
3022
|
+
return {
|
|
3023
|
+
id: Date.now().toString(),
|
|
3024
|
+
type: "video",
|
|
3025
|
+
url: finalUrl,
|
|
3026
|
+
metadata: { provider: this.id, model: "p-image-to-video" },
|
|
3027
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3028
|
+
};
|
|
2790
3029
|
}
|
|
2791
3030
|
async videoToVideo(_request) {
|
|
2792
|
-
throw new AIError("
|
|
3031
|
+
throw new AIError("CLIENT_ERROR" /* CLIENT_ERROR */, "Pruna AI provider does not support video-to-video conversion");
|
|
2793
3032
|
}
|
|
2794
3033
|
};
|
|
2795
3034
|
function createPrunaProvider(config) {
|
|
@@ -2821,6 +3060,278 @@ function createAI(config = {}) {
|
|
|
2821
3060
|
return factory;
|
|
2822
3061
|
}
|
|
2823
3062
|
|
|
3063
|
+
// src/providers/groq/groq-messages.ts
|
|
3064
|
+
var createUserMessage = (content) => ({
|
|
3065
|
+
role: "user",
|
|
3066
|
+
content
|
|
3067
|
+
});
|
|
3068
|
+
var createAssistantMessage = (content) => ({
|
|
3069
|
+
role: "assistant",
|
|
3070
|
+
content
|
|
3071
|
+
});
|
|
3072
|
+
var createSystemMessage = (content) => ({
|
|
3073
|
+
role: "system",
|
|
3074
|
+
content
|
|
3075
|
+
});
|
|
3076
|
+
var createMessage = (role, content) => ({
|
|
3077
|
+
role,
|
|
3078
|
+
content
|
|
3079
|
+
});
|
|
3080
|
+
var promptToMessages = (prompt) => [
|
|
3081
|
+
createUserMessage(prompt)
|
|
3082
|
+
];
|
|
3083
|
+
var extractTextFromMessages = (messages) => messages.map((m) => m.content).join("\n\n");
|
|
3084
|
+
var formatMessagesForDisplay = (messages) => messages.map((m) => `[${m.role.toUpperCase()}]: ${m.content}`).join("\n\n---\n\n");
|
|
3085
|
+
|
|
3086
|
+
// src/providers/groq/groq-structured-json.ts
|
|
3087
|
+
async function requestStructuredJson(client, request) {
|
|
3088
|
+
const chatRequest = {
|
|
3089
|
+
model: request.model,
|
|
3090
|
+
messages: [createUserMessage(request.instructions)],
|
|
3091
|
+
temperature: request.temperature,
|
|
3092
|
+
max_tokens: request.maxTokens,
|
|
3093
|
+
response_format: { type: "json_object" },
|
|
3094
|
+
...request.reasoningEffort !== void 0 ? { reasoning_effort: request.reasoningEffort } : {}
|
|
3095
|
+
};
|
|
3096
|
+
const response = await client.postChatCompletion(chatRequest);
|
|
3097
|
+
const content = response.choices[0]?.message?.content ?? "";
|
|
3098
|
+
const candidate = extractJsonCandidate(content);
|
|
3099
|
+
try {
|
|
3100
|
+
return JSON.parse(candidate);
|
|
3101
|
+
} catch (err) {
|
|
3102
|
+
throw new GroqError(
|
|
3103
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
3104
|
+
"model response contained no parsable json object",
|
|
3105
|
+
err instanceof Error ? err : void 0
|
|
3106
|
+
);
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3110
|
+
// src/providers/groq/text-generation.service.ts
|
|
3111
|
+
var STRUCTURED_OUTPUT_TEMPERATURE = 0.1;
|
|
3112
|
+
var TextGenerationService = class {
|
|
3113
|
+
constructor(httpClient, cache = new CacheManager(), defaultModel = DEFAULT_MODELS.TEXT) {
|
|
3114
|
+
this.httpClient = httpClient;
|
|
3115
|
+
this.cache = cache;
|
|
3116
|
+
this.defaultModel = defaultModel;
|
|
3117
|
+
}
|
|
3118
|
+
httpClient;
|
|
3119
|
+
cache;
|
|
3120
|
+
defaultModel;
|
|
3121
|
+
id = "groq-text-generation";
|
|
3122
|
+
name = "Groq Text Generation";
|
|
3123
|
+
capabilities = ["text"];
|
|
3124
|
+
jsonParser = new JsonResponseParser();
|
|
3125
|
+
generateCompletion(prompt, options = {}) {
|
|
3126
|
+
const model = options.model ?? this.defaultModel;
|
|
3127
|
+
return this.executeWithCache(
|
|
3128
|
+
{
|
|
3129
|
+
type: CACHE_KEY_TYPE_COMPLETION,
|
|
3130
|
+
model,
|
|
3131
|
+
prompt,
|
|
3132
|
+
config: options.generationConfig
|
|
3133
|
+
},
|
|
3134
|
+
async () => {
|
|
3135
|
+
const request = GroqChatRequestBuilder.for(model).withMessages([createUserMessage(prompt)]).withConfig(options.generationConfig).build();
|
|
3136
|
+
const response = await this.httpClient.postChatCompletion(request);
|
|
3137
|
+
return this.extractContent(response.choices[0]?.message?.content);
|
|
3138
|
+
}
|
|
3139
|
+
);
|
|
3140
|
+
}
|
|
3141
|
+
generateChatCompletion(messages, options = {}) {
|
|
3142
|
+
const model = options.model ?? this.defaultModel;
|
|
3143
|
+
return this.executeWithCache(
|
|
3144
|
+
{
|
|
3145
|
+
type: CACHE_KEY_TYPE_CHAT,
|
|
3146
|
+
model,
|
|
3147
|
+
messages: [...messages],
|
|
3148
|
+
config: options.generationConfig
|
|
3149
|
+
},
|
|
3150
|
+
async () => {
|
|
3151
|
+
const request = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(options.generationConfig).build();
|
|
3152
|
+
const response = await this.httpClient.postChatCompletion(request);
|
|
3153
|
+
return this.extractContent(response.choices[0]?.message?.content);
|
|
3154
|
+
}
|
|
3155
|
+
);
|
|
3156
|
+
}
|
|
3157
|
+
generateStructured(promptOrRequest, options) {
|
|
3158
|
+
if (typeof promptOrRequest === "string") {
|
|
3159
|
+
const model2 = options?.model ?? this.defaultModel;
|
|
3160
|
+
const jsonPrompt = StructuredPromptBuilder.for(promptOrRequest).withSchema(options?.schema).build();
|
|
3161
|
+
const request = GroqChatRequestBuilder.for(model2).withMessages([createUserMessage(jsonPrompt)]).withConfig({
|
|
3162
|
+
...options?.generationConfig,
|
|
3163
|
+
temperature: STRUCTURED_OUTPUT_TEMPERATURE
|
|
3164
|
+
}).build();
|
|
3165
|
+
return this.httpClient.postChatCompletion(request).then((response) => {
|
|
3166
|
+
const content = this.extractContent(response.choices[0]?.message?.content);
|
|
3167
|
+
return this.jsonParser.parse(content);
|
|
3168
|
+
});
|
|
3169
|
+
}
|
|
3170
|
+
const req = promptOrRequest;
|
|
3171
|
+
const model = req.model ?? (req.tier ? this.resolveModel(req.tier) : this.defaultModel);
|
|
3172
|
+
const schemaObj = req.schema;
|
|
3173
|
+
const messages = [];
|
|
3174
|
+
if (req.systemPrompt) {
|
|
3175
|
+
messages.push({ role: "system", content: req.systemPrompt });
|
|
3176
|
+
}
|
|
3177
|
+
for (const m of req.messages) {
|
|
3178
|
+
messages.push({ role: m.role, content: m.content });
|
|
3179
|
+
}
|
|
3180
|
+
const lastMsg = messages[messages.length - 1];
|
|
3181
|
+
if (lastMsg) {
|
|
3182
|
+
const structuredPrompt = StructuredPromptBuilder.for(lastMsg.content).withSchema(schemaObj).build();
|
|
3183
|
+
messages[messages.length - 1] = { ...lastMsg, content: structuredPrompt };
|
|
3184
|
+
}
|
|
3185
|
+
const groqReq = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig({
|
|
3186
|
+
temperature: req.temperature ?? STRUCTURED_OUTPUT_TEMPERATURE,
|
|
3187
|
+
maxTokens: req.maxTokens
|
|
3188
|
+
}).build();
|
|
3189
|
+
return this.httpClient.postChatCompletion(groqReq).then((response) => {
|
|
3190
|
+
const content = this.extractContent(response.choices[0]?.message?.content);
|
|
3191
|
+
const parsed = this.jsonParser.parse(content);
|
|
3192
|
+
const genResult = {
|
|
3193
|
+
text: content,
|
|
3194
|
+
model: response.model,
|
|
3195
|
+
providerId: this.id,
|
|
3196
|
+
finishReason: response.choices[0]?.finish_reason ?? "stop",
|
|
3197
|
+
usage: response.usage ? {
|
|
3198
|
+
inputTokens: response.usage.prompt_tokens,
|
|
3199
|
+
outputTokens: response.usage.completion_tokens,
|
|
3200
|
+
totalTokens: response.usage.total_tokens
|
|
3201
|
+
} : void 0
|
|
3202
|
+
};
|
|
3203
|
+
return { value: parsed, result: genResult };
|
|
3204
|
+
});
|
|
3205
|
+
}
|
|
3206
|
+
streamCompletion(prompt, callbacks, options = {}) {
|
|
3207
|
+
return this.streamChatCompletion([createUserMessage(prompt)], callbacks, options);
|
|
3208
|
+
}
|
|
3209
|
+
async streamChatCompletion(messages, callbacks, options = {}) {
|
|
3210
|
+
const model = options.model ?? this.defaultModel;
|
|
3211
|
+
const request = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(options.generationConfig).withStream(true).build();
|
|
3212
|
+
const parser = new StreamingResponseParser(
|
|
3213
|
+
{
|
|
3214
|
+
onChunk: (chunk) => callbacks.onChunk?.(chunk)
|
|
3215
|
+
},
|
|
3216
|
+
extractContentFromSsePayload
|
|
3217
|
+
);
|
|
3218
|
+
try {
|
|
3219
|
+
const stream = await this.httpClient.streamChatCompletion(request, {
|
|
3220
|
+
signal: options.signal
|
|
3221
|
+
});
|
|
3222
|
+
const fullText = await parser.parse(stream);
|
|
3223
|
+
callbacks.onComplete?.(fullText);
|
|
3224
|
+
return fullText;
|
|
3225
|
+
} catch (error) {
|
|
3226
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
3227
|
+
callbacks.onError?.(err);
|
|
3228
|
+
throw err;
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
clearCache() {
|
|
3232
|
+
this.cache.clear();
|
|
3233
|
+
}
|
|
3234
|
+
// --- ITextProvider implementation ---
|
|
3235
|
+
resolveModel(tier) {
|
|
3236
|
+
return GROQ_TIERS[tier] ?? this.defaultModel;
|
|
3237
|
+
}
|
|
3238
|
+
async generate(request) {
|
|
3239
|
+
const messages = [];
|
|
3240
|
+
if (request.systemPrompt) {
|
|
3241
|
+
messages.push({ role: "system", content: request.systemPrompt });
|
|
3242
|
+
}
|
|
3243
|
+
for (const m of request.messages) {
|
|
3244
|
+
messages.push({ role: m.role, content: m.content });
|
|
3245
|
+
}
|
|
3246
|
+
const model = request.model ?? (request.tier ? this.resolveModel(request.tier) : this.defaultModel);
|
|
3247
|
+
const groqReq = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig({
|
|
3248
|
+
temperature: request.temperature,
|
|
3249
|
+
maxTokens: request.maxTokens
|
|
3250
|
+
}).build();
|
|
3251
|
+
const resp = await this.httpClient.postChatCompletion(groqReq);
|
|
3252
|
+
const content = resp.choices[0]?.message?.content ?? "";
|
|
3253
|
+
return {
|
|
3254
|
+
text: content,
|
|
3255
|
+
finishReason: resp.choices[0]?.finish_reason ?? "stop",
|
|
3256
|
+
model: resp.model,
|
|
3257
|
+
providerId: this.id,
|
|
3258
|
+
usage: resp.usage ? {
|
|
3259
|
+
inputTokens: resp.usage.prompt_tokens,
|
|
3260
|
+
outputTokens: resp.usage.completion_tokens,
|
|
3261
|
+
totalTokens: resp.usage.total_tokens
|
|
3262
|
+
} : void 0
|
|
3263
|
+
};
|
|
3264
|
+
}
|
|
3265
|
+
async stream(request, callbacks) {
|
|
3266
|
+
const messages = [];
|
|
3267
|
+
if (request.systemPrompt) {
|
|
3268
|
+
messages.push({ role: "system", content: request.systemPrompt });
|
|
3269
|
+
}
|
|
3270
|
+
for (const m of request.messages) {
|
|
3271
|
+
messages.push({ role: m.role, content: m.content });
|
|
3272
|
+
}
|
|
3273
|
+
const model = request.model ?? (request.tier ? this.resolveModel(request.tier) : this.defaultModel);
|
|
3274
|
+
const text = await this.streamChatCompletion(
|
|
3275
|
+
messages,
|
|
3276
|
+
{
|
|
3277
|
+
onChunk: callbacks.onChunk,
|
|
3278
|
+
onError: callbacks.onError
|
|
3279
|
+
},
|
|
3280
|
+
{
|
|
3281
|
+
model,
|
|
3282
|
+
signal: request.signal,
|
|
3283
|
+
generationConfig: {
|
|
3284
|
+
temperature: request.temperature,
|
|
3285
|
+
maxTokens: request.maxTokens
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
);
|
|
3289
|
+
const result = {
|
|
3290
|
+
text,
|
|
3291
|
+
finishReason: "stop",
|
|
3292
|
+
model,
|
|
3293
|
+
providerId: this.id
|
|
3294
|
+
};
|
|
3295
|
+
callbacks.onComplete?.(result);
|
|
3296
|
+
return result;
|
|
3297
|
+
}
|
|
3298
|
+
async countTokens(text) {
|
|
3299
|
+
return Math.max(1, Math.ceil(text.length / 4));
|
|
3300
|
+
}
|
|
3301
|
+
async estimateCost(_request) {
|
|
3302
|
+
return 0;
|
|
3303
|
+
}
|
|
3304
|
+
async healthCheck() {
|
|
3305
|
+
try {
|
|
3306
|
+
await this.generateCompletion("ping", {
|
|
3307
|
+
generationConfig: { maxTokens: 1 }
|
|
3308
|
+
});
|
|
3309
|
+
return "healthy";
|
|
3310
|
+
} catch {
|
|
3311
|
+
return "unavailable";
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
async executeWithCache(params, factory) {
|
|
3315
|
+
const key = this.cache.generateKey(params);
|
|
3316
|
+
const cached = this.cache.get(key);
|
|
3317
|
+
if (cached !== null) {
|
|
3318
|
+
return cached;
|
|
3319
|
+
}
|
|
3320
|
+
const result = await factory();
|
|
3321
|
+
this.cache.set(key, result);
|
|
3322
|
+
return result;
|
|
3323
|
+
}
|
|
3324
|
+
extractContent(content) {
|
|
3325
|
+
if (!content) {
|
|
3326
|
+
throw new GroqError(
|
|
3327
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
3328
|
+
"No content generated from Groq API"
|
|
3329
|
+
);
|
|
3330
|
+
}
|
|
3331
|
+
return content;
|
|
3332
|
+
}
|
|
3333
|
+
};
|
|
3334
|
+
|
|
2824
3335
|
// src/core/calculations/random-base36-suffix.ts
|
|
2825
3336
|
var BASE_36_RADIX = 36;
|
|
2826
3337
|
var DECIMAL_OFFSET = 2;
|
|
@@ -2941,9 +3452,12 @@ var ChatService = class {
|
|
|
2941
3452
|
};
|
|
2942
3453
|
}
|
|
2943
3454
|
async getConversations() {
|
|
3455
|
+
if (this.storage && "getConversations" in this.storage && typeof this.storage.getConversations === "function") {
|
|
3456
|
+
return this.storage.getConversations();
|
|
3457
|
+
}
|
|
2944
3458
|
return [];
|
|
2945
3459
|
}
|
|
2946
|
-
async sendMessage(input) {
|
|
3460
|
+
async sendMessage(input, signal) {
|
|
2947
3461
|
const userMessage = {
|
|
2948
3462
|
...messageFormatter.toChatMessage(input.text, "user"),
|
|
2949
3463
|
type: input.type ?? "text",
|
|
@@ -2952,13 +3466,14 @@ var ChatService = class {
|
|
|
2952
3466
|
const aiResponse = await this.generateAIResponse(
|
|
2953
3467
|
input.companionId,
|
|
2954
3468
|
input.text,
|
|
2955
|
-
[]
|
|
3469
|
+
[],
|
|
3470
|
+
signal
|
|
2956
3471
|
);
|
|
2957
3472
|
return { userMessage, aiResponse };
|
|
2958
3473
|
}
|
|
2959
|
-
async generateAIResponse(companionId, userMessage, context = []) {
|
|
3474
|
+
async generateAIResponse(companionId, userMessage, context = [], signal) {
|
|
2960
3475
|
const result = await this.run({
|
|
2961
|
-
...this.buildRequest(userMessage, context)
|
|
3476
|
+
...this.buildRequest(userMessage, context, signal)
|
|
2962
3477
|
});
|
|
2963
3478
|
return {
|
|
2964
3479
|
...messageFormatter.toChatMessage(result.text, "assistant"),
|
|
@@ -2974,12 +3489,12 @@ var ChatService = class {
|
|
|
2974
3489
|
}
|
|
2975
3490
|
};
|
|
2976
3491
|
}
|
|
2977
|
-
async generateStreamingResponse(userMessage, context, onChunk) {
|
|
2978
|
-
const request = this.buildRequest(userMessage, context);
|
|
3492
|
+
async generateStreamingResponse(userMessage, context, onChunk, signal) {
|
|
3493
|
+
const request = this.buildRequest(userMessage, context, signal);
|
|
2979
3494
|
const result = await this.runStream(request, { onChunk });
|
|
2980
3495
|
return result.text;
|
|
2981
3496
|
}
|
|
2982
|
-
buildRequest(userMessage, context) {
|
|
3497
|
+
buildRequest(userMessage, context, signal) {
|
|
2983
3498
|
const messages = messageFormatter.toCoreMessages(context);
|
|
2984
3499
|
messages.push({ role: "user", content: userMessage });
|
|
2985
3500
|
return {
|
|
@@ -2988,7 +3503,8 @@ var ChatService = class {
|
|
|
2988
3503
|
model: this.config.model,
|
|
2989
3504
|
tier: this.config.tier,
|
|
2990
3505
|
temperature: this.config.temperature,
|
|
2991
|
-
maxTokens: this.config.maxTokens
|
|
3506
|
+
maxTokens: this.config.maxTokens,
|
|
3507
|
+
...signal !== void 0 ? { signal } : {}
|
|
2992
3508
|
};
|
|
2993
3509
|
}
|
|
2994
3510
|
resolveSystemPrompt() {
|
|
@@ -3043,6 +3559,30 @@ function readNumber(source, keys) {
|
|
|
3043
3559
|
return null;
|
|
3044
3560
|
}
|
|
3045
3561
|
|
|
3046
|
-
|
|
3562
|
+
// src/providers/groq/groq-container.ts
|
|
3563
|
+
var container = null;
|
|
3564
|
+
function configureProvider(config) {
|
|
3565
|
+
const configStore = new GroqConfigStore();
|
|
3566
|
+
const transport = new GroqHttpTransport(configStore);
|
|
3567
|
+
const httpClient = new GroqHttpClient({ configStore, transport });
|
|
3568
|
+
httpClient.initialize(config);
|
|
3569
|
+
const textGeneration = new TextGenerationService(
|
|
3570
|
+
httpClient,
|
|
3571
|
+
new CacheManager(),
|
|
3572
|
+
config.textModel
|
|
3573
|
+
);
|
|
3574
|
+
const chat = new ChatService(textGeneration);
|
|
3575
|
+
container = { groqHttpClient: httpClient, textGeneration, chat };
|
|
3576
|
+
return container;
|
|
3577
|
+
}
|
|
3578
|
+
function getProvider() {
|
|
3579
|
+
return container;
|
|
3580
|
+
}
|
|
3581
|
+
function resetProvider() {
|
|
3582
|
+
container?.groqHttpClient.reset();
|
|
3583
|
+
container = null;
|
|
3584
|
+
}
|
|
3585
|
+
|
|
3586
|
+
export { AIError, AIErrorType, ANTHROPIC_API_VERSION, ANTHROPIC_DEFAULT_MAX_TOKENS, ANTHROPIC_MODELS, ANTHROPIC_TIERS, API_ENDPOINTS, AnthropicHttpTransport, AnthropicProvider, AnthropicRequestBuilder, BaseProvider, CacheManager, ChatIdGenerator, ChatService, CompositeExecutor, DEFAULT_API_KEY_RULE, DEFAULT_BASE_URL, DEFAULT_ERROR_CLASSIFICATION_RULE, DEFAULT_GENERATION_CONFIG, DEFAULT_HTTP_STATUS_RULE, DEFAULT_MODELS, DEFAULT_PROMPT_STRATEGY, DEFAULT_RETRY_BACKOFF_MULTIPLIER, DEFAULT_RETRY_INITIAL_DELAY_MS, DEFAULT_RETRY_JITTER_FACTOR, DEFAULT_RETRY_MAX_ATTEMPTS, DEFAULT_RETRY_MAX_DELAY_MS, DebounceManager, DedupeExecutor, FalProvider, GEMINI_TIERS, GROQ_MODELS, GROQ_TIERS, GeminiProvider, GroqChatRequestBuilder, GroqConfigStore, GroqError, AIErrorType as GroqErrorType, GroqHttpClient, GroqHttpTransport, GroqProvider, JSON_CODE_BLOCK_PATTERN, JSON_OBJECT_PATTERN, JsonResponseParser, ProviderError, ProviderFactory, PrunaProvider, QueueExecutor, RequestDeduplicator, RequestQueue, RetryExecutor, RetryManager, SSE_BRIDGE_EVENTS, SSE_DONE_MARKER, SSE_PREFIX, StreamingResponseParser, StructuredPromptBuilder, TEXT_TIERS, TIMEOUTS, TextGenerationService, ThrottleManager, USER_FRIENDLY_ERROR_MESSAGES, asObjectArray, asRecord, asStringArray, asTrimmedOptionalString, buildCacheKey, buildHttpStatusFallback, cacheManager, chatIdGenerator, clampScore, classifyHttpStatus, configureProvider, consumeAnthropicStream, consumeGroqStream, createAI, createAssistantMessage, createFalProvider, createGeminiProvider, createMessage, createPrunaProvider, createSseResponse, createSystemMessage, createUserMessage, debounce, debounceManager, defaultEffortForModel, describeAIErrorType, extractContentFromSsePayload, extractErrorMessageFromJsonBody, extractErrorMessageFromResponse, extractJsonArray, extractJsonCandidate, extractJsonFromCodeFence, extractJsonObject, extractSseDataPayload, extractTextFromMessages, extractTokenUsage, formatErrorForLogging, formatMessagesForDisplay, generateWithPruna, getProvider, isAuthErrorType, isMediaProvider, isRetryableErrorType, isSseDataLine, isSseDoneMarker, isTextProvider, isTextTier, isValidApiKey, mapAnthropicStopReason, mergeTierOverrides, messageFormatter, normalizeSseChunk, oneOfCatalog, promptToMessages, repairCommonJsonDefects, requestDeduplicator, requestQueue, requestStructuredJson, resetProvider, resolveModel, resolveUserFriendlyErrorMessage, resolveUserFriendlyMessage, retryManager, splitSseLines, throttle, throttleManager, toGroqMessages, validateApiKey, withRetry };
|
|
3047
3587
|
//# sourceMappingURL=index.js.map
|
|
3048
3588
|
//# sourceMappingURL=index.js.map
|