@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.
Files changed (55) hide show
  1. package/dist/{ABTesting-DDqNhHtP.d.ts → AIErrors-B2ogd1PB.d.ts} +14 -1
  2. package/dist/{ABTesting-DWBtKTMQ.d.cts → AIErrors-C5EasV_c.d.cts} +14 -1
  3. package/dist/{ProviderConfig-a55tLhWT.d.cts → ProviderConfig-DIFa9nmG.d.cts} +10 -1
  4. package/dist/{ProviderConfig-a55tLhWT.d.ts → ProviderConfig-DIFa9nmG.d.ts} +10 -1
  5. package/dist/chat/index.cjs +114 -23
  6. package/dist/chat/index.cjs.map +1 -1
  7. package/dist/chat/index.d.cts +4 -4
  8. package/dist/chat/index.d.ts +4 -4
  9. package/dist/chat/index.js +114 -23
  10. package/dist/chat/index.js.map +1 -1
  11. package/dist/{chat.service-DBKq9I2c.d.cts → chat.service-CL1qtYxe.d.cts} +7 -7
  12. package/dist/{chat.service-RQn8UTXD.d.ts → chat.service-q05GnhEm.d.ts} +7 -7
  13. package/dist/content/index.cjs +506 -193
  14. package/dist/content/index.cjs.map +1 -1
  15. package/dist/content/index.d.cts +7 -8
  16. package/dist/content/index.d.ts +7 -8
  17. package/dist/content/index.js +506 -193
  18. package/dist/content/index.js.map +1 -1
  19. package/dist/core/index.cjs +122 -15
  20. package/dist/core/index.cjs.map +1 -1
  21. package/dist/core/index.d.cts +13 -31
  22. package/dist/core/index.d.ts +13 -31
  23. package/dist/core/index.js +119 -16
  24. package/dist/core/index.js.map +1 -1
  25. package/dist/{create-ai-BhNaz86i.d.ts → create-ai-9PW752z8.d.ts} +14 -21
  26. package/dist/{create-ai-DGZFBOA1.d.cts → create-ai-CXYKPK6G.d.cts} +14 -21
  27. package/dist/hooks/index.cjs +631 -179
  28. package/dist/hooks/index.cjs.map +1 -1
  29. package/dist/hooks/index.d.cts +33 -7
  30. package/dist/hooks/index.d.ts +33 -7
  31. package/dist/hooks/index.js +631 -180
  32. package/dist/hooks/index.js.map +1 -1
  33. package/dist/index-DIHz8_OJ.d.ts +48 -0
  34. package/dist/index-DKHNcMbl.d.cts +48 -0
  35. package/dist/index.cjs +666 -104
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +8 -7
  38. package/dist/index.d.ts +8 -7
  39. package/dist/index.js +645 -105
  40. package/dist/index.js.map +1 -1
  41. package/dist/{provider.factory-COsnprLH.d.cts → provider.factory-BxsfK4WW.d.cts} +1 -1
  42. package/dist/{provider.factory-CpWFyjbw.d.ts → provider.factory-DfDfk0dK.d.ts} +1 -1
  43. package/dist/providers/index.cjs +973 -130
  44. package/dist/providers/index.cjs.map +1 -1
  45. package/dist/providers/index.d.cts +84 -18
  46. package/dist/providers/index.d.ts +84 -18
  47. package/dist/providers/index.js +956 -131
  48. package/dist/providers/index.js.map +1 -1
  49. package/dist/text-generation.service-BQO3Tvz2.d.cts +66 -0
  50. package/dist/text-generation.service-CcYQM6Ch.d.ts +66 -0
  51. package/dist/wizard/index.d.cts +1 -1
  52. package/dist/wizard/index.d.ts +1 -1
  53. package/package.json +9 -1
  54. package/dist/index-DjX9ZKuM.d.cts +0 -14
  55. package/dist/index-DxLvE588.d.ts +0 -14
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 AIError = class extends Error {
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(type, message, cause, metadata = {}) {
51
- super(message);
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 = 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,12 +125,21 @@ 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
  };
68
132
  }
69
133
  };
70
134
 
135
+ // src/core/errors/groq-error.ts
136
+ var GroqError = class extends AIError {
137
+ constructor(type, message, cause, metadata = {}) {
138
+ super(type, message, cause, metadata);
139
+ this.name = "GroqError";
140
+ }
141
+ };
142
+
71
143
  // src/core/errors/error-classifier.ts
72
144
  var DEFAULT_RETRYABLE_TYPES = /* @__PURE__ */ new Set([
73
145
  "NETWORK_ERROR" /* NETWORK_ERROR */,
@@ -346,6 +418,8 @@ function calculateExponentialBackoff(params) {
346
418
  // src/core/constants/identifier.constants.ts
347
419
  var MESSAGE_ID_PREFIX = "msg-";
348
420
  var CHAT_MESSAGE_ID_SUFFIX_LENGTH = 9;
421
+ var CACHE_KEY_TYPE_COMPLETION = "completion";
422
+ var CACHE_KEY_TYPE_CHAT = "chat";
349
423
  var USER_ROLE = "user";
350
424
  var ASSISTANT_ROLE = "assistant";
351
425
  var QUEUE_PRIORITY_USER_REQUEST = 10;
@@ -750,15 +824,22 @@ function oneOfCatalog(catalog, value) {
750
824
  // src/core/constants/protocol.constants.ts
751
825
  var SSE_PREFIX = "data: ";
752
826
  var SSE_DONE_MARKER = "[DONE]";
753
- var JSON_CODE_BLOCK_PATTERN = /```json\n([\s\S]*?)\n```/;
827
+ var JSON_CODE_BLOCK_PATTERN = /```(?:json)?\s*\n?([\s\S]*?)\n?```/;
754
828
  var JSON_OBJECT_PATTERN = /\{[\s\S]*\}/;
829
+ var JSON_ARRAY_PATTERN = /\[[\s\S]*\]/;
755
830
 
756
831
  // src/core/parsers/sse-lines.ts
757
832
  function isSseDataLine(line) {
758
- return line.startsWith(SSE_PREFIX);
833
+ return line.startsWith(SSE_PREFIX) || line.startsWith("data:");
759
834
  }
760
835
  function extractSseDataPayload(line) {
761
- return line.slice(SSE_PREFIX.length);
836
+ if (line.startsWith(SSE_PREFIX)) {
837
+ return line.slice(SSE_PREFIX.length);
838
+ }
839
+ if (line.startsWith("data:")) {
840
+ return line.slice(5);
841
+ }
842
+ return line;
762
843
  }
763
844
  function isSseDoneMarker(payload) {
764
845
  return payload === SSE_DONE_MARKER;
@@ -830,7 +911,7 @@ var StreamingResponseParser = class {
830
911
  // src/core/parsers/json-content-extractor.ts
831
912
  function extractJsonFromCodeFence(content) {
832
913
  const match = content.match(JSON_CODE_BLOCK_PATTERN);
833
- if (match && match[1]) return match[1];
914
+ if (match && match[1]) return match[1].trim();
834
915
  return null;
835
916
  }
836
917
  function extractJsonObject(content) {
@@ -838,8 +919,27 @@ function extractJsonObject(content) {
838
919
  if (match && match[0]) return match[0];
839
920
  return null;
840
921
  }
922
+ function extractJsonArray(content) {
923
+ const match = content.match(JSON_ARRAY_PATTERN);
924
+ if (match && match[0]) return match[0];
925
+ return null;
926
+ }
927
+ function repairCommonJsonDefects(text) {
928
+ return text.replace(/(:\s*-?\d+(?:\.\d+)?)\s*"/g, "$1").replace(/(:\s*"[^"]*")"/g, "$1");
929
+ }
841
930
  function extractJsonCandidate(content) {
842
- return extractJsonFromCodeFence(content) ?? extractJsonObject(content) ?? content;
931
+ const fromFence = extractJsonFromCodeFence(content);
932
+ if (fromFence) return fromFence;
933
+ const objectIndex = content.indexOf("{");
934
+ const arrayIndex = content.indexOf("[");
935
+ if (objectIndex !== -1 && (arrayIndex === -1 || objectIndex < arrayIndex)) {
936
+ const obj = extractJsonObject(content);
937
+ if (obj) return obj;
938
+ } else if (arrayIndex !== -1) {
939
+ const arr = extractJsonArray(content);
940
+ if (arr) return arr;
941
+ }
942
+ return content.trim();
843
943
  }
844
944
 
845
945
  // src/core/parsers/json-response.parser.ts
@@ -848,12 +948,17 @@ var JsonResponseParser = class {
848
948
  const candidate = extractJsonCandidate(rawContent);
849
949
  try {
850
950
  return JSON.parse(candidate);
851
- } catch (error) {
852
- throw new AIError(
853
- "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
854
- "Failed to parse structured response as JSON",
855
- error instanceof Error ? error : void 0
856
- );
951
+ } catch {
952
+ try {
953
+ return JSON.parse(repairCommonJsonDefects(candidate));
954
+ } catch (error) {
955
+ throw new AIError(
956
+ "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
957
+ "Failed to parse structured response as JSON",
958
+ error instanceof Error ? error : void 0,
959
+ { rawContent }
960
+ );
961
+ }
857
962
  }
858
963
  }
859
964
  };
@@ -979,38 +1084,6 @@ function isMediaProvider(provider) {
979
1084
  return provider.capabilities.includes("image") || provider.capabilities.includes("video");
980
1085
  }
981
1086
 
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
1087
  // src/content/domain/limits/ProviderTimingConfig.ts
1015
1088
  var ProviderTimingConfig = {
1016
1089
  DEFAULT_TIMEOUT_MS: 3e4,
@@ -1075,7 +1148,7 @@ var BaseProvider = class {
1075
1148
  throw lastError || new Error("Retry attempts exhausted");
1076
1149
  }
1077
1150
  };
1078
- var ProviderError = class extends AIError2 {
1151
+ var ProviderError = class extends AIError {
1079
1152
  constructor(message, providerId, originalError) {
1080
1153
  super(message, "PROVIDER_ERROR", originalError);
1081
1154
  this.providerId = providerId;
@@ -1169,12 +1242,16 @@ var ProviderFactory = class {
1169
1242
  let wake = null;
1170
1243
  let finished = false;
1171
1244
  let failure;
1245
+ const controller = new AbortController();
1246
+ const onAbort = () => controller.abort();
1247
+ request.signal?.addEventListener("abort", onAbort);
1248
+ const effectiveRequest = { ...request, signal: controller.signal };
1172
1249
  const notify = () => {
1173
1250
  const resolve = wake;
1174
1251
  wake = null;
1175
1252
  resolve?.();
1176
1253
  };
1177
- const completion = this.chatStream(request, {
1254
+ const completion = this.chatStream(effectiveRequest, {
1178
1255
  onChunk: (chunk) => {
1179
1256
  queue.push(chunk);
1180
1257
  notify();
@@ -1190,18 +1267,23 @@ var ProviderFactory = class {
1190
1267
  notify();
1191
1268
  }
1192
1269
  );
1193
- while (!finished || queue.length > 0) {
1194
- if (queue.length === 0 && !finished) {
1195
- await new Promise((resolve) => {
1196
- wake = resolve;
1197
- });
1198
- }
1199
- while (queue.length > 0) {
1200
- yield queue.shift();
1270
+ try {
1271
+ while (!finished || queue.length > 0) {
1272
+ if (queue.length === 0 && !finished) {
1273
+ await new Promise((resolve) => {
1274
+ wake = resolve;
1275
+ });
1276
+ }
1277
+ while (queue.length > 0) {
1278
+ yield queue.shift();
1279
+ }
1280
+ if (failure) throw failure;
1201
1281
  }
1202
- if (failure) throw failure;
1282
+ await completion;
1283
+ } finally {
1284
+ controller.abort();
1285
+ request.signal?.removeEventListener("abort", onAbort);
1203
1286
  }
1204
- await completion;
1205
1287
  }
1206
1288
  async generateJson(request) {
1207
1289
  const effective = request.model || request.tier ? request : { ...request, tier: this.defaultTier };
@@ -1610,11 +1692,14 @@ async function consumeAnthropicStream(stream, callbacks) {
1610
1692
  break;
1611
1693
  case "message_stop":
1612
1694
  break;
1613
- case "error":
1695
+ case "error": {
1696
+ const errType = event.error.type;
1697
+ 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
1698
  throw new AIError(
1615
- event.error.type === "rate_limit_error" ? "RATE_LIMIT_ERROR" /* RATE_LIMIT_ERROR */ : "SERVER_ERROR" /* SERVER_ERROR */,
1699
+ mappedType,
1616
1700
  event.error.message || "Anthropic stream failed mid-flight"
1617
1701
  );
1702
+ }
1618
1703
  }
1619
1704
  };
1620
1705
  try {
@@ -1806,12 +1891,22 @@ var DEFAULT_GENERATION_CONFIG = {
1806
1891
  maxTokens: 1024,
1807
1892
  topP: 1
1808
1893
  };
1894
+ var DEFAULT_MODELS = {
1895
+ TEXT: GROQ_MODELS.LLAMA_3_1_8B_INSTANT,
1896
+ FAST: GROQ_MODELS.LLAMA_3_1_8B_INSTANT,
1897
+ EXPERIMENTAL: GROQ_MODELS.GPT_OSS_20B
1898
+ };
1809
1899
  var GROQ_BASE_URL = "https://api.groq.com/openai/v1";
1900
+ var DEFAULT_BASE_URL = GROQ_BASE_URL;
1810
1901
  var CHAT_COMPLETIONS_PATH = "/chat/completions";
1902
+ var API_ENDPOINTS = {
1903
+ CHAT: CHAT_COMPLETIONS_PATH
1904
+ };
1811
1905
  var GROQ_TIMEOUTS = {
1812
1906
  DEFAULT: 3e4,
1813
1907
  STREAMING: 6e4
1814
1908
  };
1909
+ var TIMEOUTS = GROQ_TIMEOUTS;
1815
1910
  var HTTP_HEADERS = {
1816
1911
  CONTENT_TYPE: "Content-Type",
1817
1912
  APPLICATION_JSON: "application/json",
@@ -1870,13 +1965,65 @@ var GroqChatRequestBuilder = class _GroqChatRequestBuilder {
1870
1965
  }
1871
1966
  };
1872
1967
 
1968
+ // src/providers/groq/groq-config-store.ts
1969
+ var GroqConfigStore = class {
1970
+ config = null;
1971
+ initialize(config) {
1972
+ const validation = validateApiKey(config.apiKey, { minLength: 1 });
1973
+ if (!validation.valid) {
1974
+ throw new GroqError("INVALID_API_KEY" /* INVALID_API_KEY */, validation.reason ?? "Invalid API key");
1975
+ }
1976
+ const normalized = {
1977
+ apiKey: config.apiKey.trim(),
1978
+ baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
1979
+ timeoutMs: config.timeoutMs ?? TIMEOUTS.DEFAULT,
1980
+ ...config.models !== void 0 ? { models: config.models } : {},
1981
+ ...config.textModel !== void 0 ? { textModel: config.textModel } : {}
1982
+ };
1983
+ this.config = normalized;
1984
+ return normalized;
1985
+ }
1986
+ get() {
1987
+ if (!this.config) {
1988
+ throw new GroqError(
1989
+ "MISSING_CONFIG" /* MISSING_CONFIG */,
1990
+ "Client not initialized. Call configureProvider first."
1991
+ );
1992
+ }
1993
+ return this.config;
1994
+ }
1995
+ getOrNull() {
1996
+ return this.config;
1997
+ }
1998
+ isInitialized() {
1999
+ return this.config !== null;
2000
+ }
2001
+ setApiKey(apiKey) {
2002
+ const current = this.get();
2003
+ const validation = validateApiKey(apiKey, { minLength: 1 });
2004
+ if (!validation.valid) {
2005
+ throw new GroqError("INVALID_API_KEY" /* INVALID_API_KEY */, validation.reason ?? "Invalid API key");
2006
+ }
2007
+ this.config = { ...current, apiKey: apiKey.trim() };
2008
+ }
2009
+ reset() {
2010
+ this.config = null;
2011
+ }
2012
+ };
2013
+
1873
2014
  // src/providers/groq/groq-http-transport.ts
1874
2015
  var GroqHttpTransport = class {
1875
- constructor(config) {
1876
- this.config = config;
2016
+ constructor(configSource) {
2017
+ this.configSource = configSource;
1877
2018
  }
1878
- config;
2019
+ configSource;
1879
2020
  pendingAbortControllers = /* @__PURE__ */ new Set();
2021
+ getConfig() {
2022
+ if ("get" in this.configSource && typeof this.configSource.get === "function") {
2023
+ return this.configSource.get();
2024
+ }
2025
+ return this.configSource;
2026
+ }
1880
2027
  cancelPendingRequests() {
1881
2028
  for (const controller of this.pendingAbortControllers) {
1882
2029
  controller.abort();
@@ -1891,7 +2038,7 @@ var GroqHttpTransport = class {
1891
2038
  }
1892
2039
  async streamChatCompletion(request, options = {}) {
1893
2040
  const url = `${this.baseUrl()}${CHAT_COMPLETIONS_PATH}`;
1894
- const timeout = this.config.timeoutMs ?? GROQ_TIMEOUTS.STREAMING;
2041
+ const timeout = this.getConfig().timeoutMs ?? GROQ_TIMEOUTS.STREAMING;
1895
2042
  const controller = new AbortController();
1896
2043
  const timeoutId = setTimeout(() => controller.abort(), timeout);
1897
2044
  const onExternalAbort = () => controller.abort();
@@ -1918,11 +2065,11 @@ var GroqHttpTransport = class {
1918
2065
  }
1919
2066
  }
1920
2067
  baseUrl() {
1921
- return this.config.baseUrl ?? GROQ_BASE_URL;
2068
+ return this.getConfig().baseUrl ?? GROQ_BASE_URL;
1922
2069
  }
1923
2070
  async request(endpoint, body) {
1924
2071
  const url = `${this.baseUrl()}${endpoint}`;
1925
- const timeout = this.config.timeoutMs ?? GROQ_TIMEOUTS.DEFAULT;
2072
+ const timeout = this.getConfig().timeoutMs ?? GROQ_TIMEOUTS.DEFAULT;
1926
2073
  const controller = new AbortController();
1927
2074
  const timeoutId = setTimeout(() => controller.abort(), timeout);
1928
2075
  this.pendingAbortControllers.add(controller);
@@ -1945,7 +2092,7 @@ var GroqHttpTransport = class {
1945
2092
  buildHeaders() {
1946
2093
  return {
1947
2094
  [HTTP_HEADERS.CONTENT_TYPE]: HTTP_HEADERS.APPLICATION_JSON,
1948
- [HTTP_HEADERS.AUTHORIZATION]: `${HTTP_HEADERS.BEARER_PREFIX}${this.config.apiKey}`
2095
+ [HTTP_HEADERS.AUTHORIZATION]: `${HTTP_HEADERS.BEARER_PREFIX}${this.getConfig().apiKey}`
1949
2096
  };
1950
2097
  }
1951
2098
  async throwFromErrorResponse(response) {
@@ -1989,21 +2136,40 @@ var GroqHttpTransport = class {
1989
2136
 
1990
2137
  // src/providers/groq/groq-http-client.ts
1991
2138
  var GroqHttpClient = class {
2139
+ configStore;
1992
2140
  transport;
1993
2141
  executor;
1994
- constructor(config, deps = {}) {
1995
- this.transport = deps.transport ?? new GroqHttpTransport(config);
2142
+ constructor(configOrDeps, maybeDeps = {}) {
2143
+ const isConfig = typeof configOrDeps === "object" && configOrDeps !== null && "apiKey" in configOrDeps && typeof configOrDeps.apiKey === "string";
2144
+ const deps = isConfig ? maybeDeps : configOrDeps ?? {};
2145
+ this.configStore = deps.configStore ?? new GroqConfigStore();
2146
+ if (isConfig) {
2147
+ this.configStore.initialize(configOrDeps);
2148
+ }
2149
+ this.transport = deps.transport ?? new GroqHttpTransport(this.configStore);
1996
2150
  const retryManager2 = deps.retryManager ?? new RetryManager();
1997
2151
  const queue = deps.queue ?? new RequestQueue();
1998
2152
  const deduplicator = deps.deduplicator ?? new RequestDeduplicator();
1999
2153
  this.executor = new CompositeExecutor([
2000
2154
  new DedupeExecutor(deduplicator, {
2001
- generateKey: (request) => deduplicatorKey(request, config.apiKey)
2155
+ generateKey: (request) => deduplicatorKey(request, this.configStore.isInitialized() ? this.configStore.get().apiKey : "")
2002
2156
  }),
2003
2157
  new RetryExecutor(retryManager2),
2004
2158
  new QueueExecutor(queue, QUEUE_PRIORITY_USER_REQUEST)
2005
2159
  ]);
2006
2160
  }
2161
+ initialize(config) {
2162
+ this.configStore.initialize(config);
2163
+ }
2164
+ isInitialized() {
2165
+ return this.configStore.isInitialized();
2166
+ }
2167
+ getApiKey() {
2168
+ return this.configStore.get().apiKey;
2169
+ }
2170
+ setApiKey(apiKey) {
2171
+ this.configStore.setApiKey(apiKey);
2172
+ }
2007
2173
  cancelPendingRequests() {
2008
2174
  this.transport.cancelPendingRequests();
2009
2175
  }
@@ -2016,6 +2182,10 @@ var GroqHttpClient = class {
2016
2182
  streamChatCompletion(request, options) {
2017
2183
  return this.transport.streamChatCompletion(request, options);
2018
2184
  }
2185
+ reset() {
2186
+ this.transport.cancelPendingRequests();
2187
+ this.configStore.reset();
2188
+ }
2019
2189
  };
2020
2190
  function deduplicatorKey(request, apiKey) {
2021
2191
  const { model, messages, stream: _stream, ...rest } = request;
@@ -2072,6 +2242,13 @@ async function consumeGroqStream(stream, callbacks) {
2072
2242
  } catch {
2073
2243
  return;
2074
2244
  }
2245
+ const errorBody = chunk.error;
2246
+ if (errorBody) {
2247
+ throw new AIError(
2248
+ errorBody.message?.toLowerCase().includes("rate limit") ? "RATE_LIMIT_ERROR" /* RATE_LIMIT_ERROR */ : "SERVER_ERROR" /* SERVER_ERROR */,
2249
+ errorBody.message || "Groq stream failed mid-flight"
2250
+ );
2251
+ }
2075
2252
  if (chunk.model) model = chunk.model;
2076
2253
  const choice = chunk.choices?.[0];
2077
2254
  const delta = choice?.delta?.content;
@@ -2086,13 +2263,6 @@ async function consumeGroqStream(stream, callbacks) {
2086
2263
  if (tailUsage) {
2087
2264
  usage = mapGroqUsage(tailUsage);
2088
2265
  }
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
2266
  };
2097
2267
  try {
2098
2268
  while (true) {
@@ -2359,7 +2529,9 @@ var GeminiProvider = class extends BaseProvider {
2359
2529
  headers: this.authHeaders()
2360
2530
  }
2361
2531
  );
2362
- return response.ok ? "healthy" : "unavailable";
2532
+ if (response.ok) return "healthy";
2533
+ if (response.status === 401 || response.status === 403) return "unavailable";
2534
+ return "degraded";
2363
2535
  } catch {
2364
2536
  return "unavailable";
2365
2537
  }
@@ -2370,6 +2542,8 @@ var GeminiProvider = class extends BaseProvider {
2370
2542
  async generate(request) {
2371
2543
  try {
2372
2544
  const model = request.model ?? this.resolveModel(request.tier ?? "balanced");
2545
+ const systemMessages = request.messages.filter((m) => m.role === "system");
2546
+ const systemPrompt = request.systemPrompt && request.systemPrompt.length > 0 ? request.systemPrompt : systemMessages.length > 0 ? systemMessages.map((m) => m.content).join("\n") : void 0;
2373
2547
  const response = await this.withRetry(async () => {
2374
2548
  return await this.fetchWithTimeout(
2375
2549
  `${this.config.baseUrl}/models/${model}:generateContent`,
@@ -2377,22 +2551,28 @@ var GeminiProvider = class extends BaseProvider {
2377
2551
  method: "POST",
2378
2552
  headers: this.authHeaders(),
2379
2553
  body: JSON.stringify({
2380
- systemInstruction: request.systemPrompt && request.systemPrompt.length > 0 ? { parts: [{ text: request.systemPrompt }] } : void 0,
2554
+ systemInstruction: systemPrompt && systemPrompt.length > 0 ? { parts: [{ text: systemPrompt }] } : void 0,
2381
2555
  contents: toGeminiContents(request.messages),
2382
2556
  generationConfig: {
2383
- temperature: request.temperature || 0.7,
2384
- maxOutputTokens: request.maxTokens || 2048,
2385
- topP: request.topP || 0.9
2557
+ temperature: request.temperature ?? 0.7,
2558
+ maxOutputTokens: request.maxTokens ?? 2048,
2559
+ topP: request.topP ?? 0.9
2386
2560
  }
2387
2561
  })
2388
2562
  }
2389
2563
  );
2390
2564
  });
2391
2565
  if (!response.ok) {
2392
- throw new Error(`Gemini API error: ${response.statusText}`);
2566
+ const message = await extractErrorMessageFromResponse(response);
2567
+ throw new AIError(
2568
+ classifyHttpStatus(response.status),
2569
+ `Gemini API error (${response.status}): ${message}`,
2570
+ void 0,
2571
+ { status: response.status, model }
2572
+ );
2393
2573
  }
2394
2574
  const data = await response.json();
2395
- const text = data.candidates[0]?.content?.parts?.map((part) => part.text ?? "").join("") ?? "";
2575
+ const text = data.candidates?.[0]?.content?.parts?.map((part) => part.text ?? "").join("") ?? "";
2396
2576
  if (text.length === 0) {
2397
2577
  throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No content generated from Gemini API", void 0, { model });
2398
2578
  }
@@ -2405,7 +2585,7 @@ var GeminiProvider = class extends BaseProvider {
2405
2585
  } : void 0,
2406
2586
  model,
2407
2587
  providerId: this.id,
2408
- finishReason: mapGeminiFinishReason(data.candidates[0]?.finishReason)
2588
+ finishReason: mapGeminiFinishReason(data.candidates?.[0]?.finishReason)
2409
2589
  };
2410
2590
  } catch (error) {
2411
2591
  if (error instanceof AIError) throw error;
@@ -2457,12 +2637,18 @@ var GeminiProvider = class extends BaseProvider {
2457
2637
  );
2458
2638
  });
2459
2639
  if (!response.ok) {
2460
- throw new Error(`Gemini API error: ${response.statusText}`);
2640
+ const message = await extractErrorMessageFromResponse(response);
2641
+ throw new AIError(
2642
+ classifyHttpStatus(response.status),
2643
+ `Gemini image generation error (${response.status}): ${message}`,
2644
+ void 0,
2645
+ { status: response.status }
2646
+ );
2461
2647
  }
2462
2648
  const data = await response.json();
2463
- const imageData = data.candidates[0]?.content?.parts[0]?.inlineData;
2649
+ const imageData = data.candidates?.[0]?.content?.parts?.[0]?.inlineData;
2464
2650
  if (!imageData) {
2465
- throw new Error("No image data in response");
2651
+ throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No image data in Gemini response");
2466
2652
  }
2467
2653
  const url = `data:${imageData.mimeType};base64,${imageData.data}`;
2468
2654
  return {
@@ -2781,17 +2967,70 @@ var PrunaProvider = class {
2781
2967
  async estimateCost(_request) {
2782
2968
  return 1;
2783
2969
  }
2784
- async generateImage(_request) {
2785
- throw new AIError("UNKNOWN_ERROR" /* UNKNOWN_ERROR */, "Use generateWithPruna instead");
2970
+ async generateImage(request) {
2971
+ let finalUrl;
2972
+ const model = this.config.models?.textToImage;
2973
+ for await (const stage of generateWithPruna(
2974
+ { prompt: request.prompt, model, quality: request.quality },
2975
+ this.config.apiKey
2976
+ )) {
2977
+ if (stage.error) throw stage.error;
2978
+ if (stage.result?.url) finalUrl = stage.result.url;
2979
+ }
2980
+ if (!finalUrl) {
2981
+ throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No image generated by Pruna AI");
2982
+ }
2983
+ return {
2984
+ id: Date.now().toString(),
2985
+ type: "image",
2986
+ url: finalUrl,
2987
+ metadata: { provider: this.id, model: model ?? "p-image" },
2988
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
2989
+ };
2786
2990
  }
2787
- async generateVideo(_request) {
2788
- throw new AIError("UNKNOWN_ERROR" /* UNKNOWN_ERROR */, "Use generateWithPruna instead");
2991
+ async generateVideo(request) {
2992
+ let finalUrl;
2993
+ const model = this.config.models?.textToVideo;
2994
+ for await (const stage of generateWithPruna(
2995
+ { prompt: request.prompt, model, duration: request.duration, aspectRatio: request.aspectRatio },
2996
+ this.config.apiKey
2997
+ )) {
2998
+ if (stage.error) throw stage.error;
2999
+ if (stage.result?.url) finalUrl = stage.result.url;
3000
+ }
3001
+ if (!finalUrl) {
3002
+ throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No video generated by Pruna AI");
3003
+ }
3004
+ return {
3005
+ id: Date.now().toString(),
3006
+ type: "video",
3007
+ url: finalUrl,
3008
+ metadata: { provider: this.id, model: model ?? "p-video" },
3009
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
3010
+ };
2789
3011
  }
2790
- async imageToVideo(_request) {
2791
- throw new AIError("UNKNOWN_ERROR" /* UNKNOWN_ERROR */, "Use generateWithPruna instead");
3012
+ async imageToVideo(request) {
3013
+ let finalUrl;
3014
+ for await (const stage of generateWithPruna(
3015
+ { image: request.imageUrl, prompt: request.prompt, duration: request.duration, motion: request.motion },
3016
+ this.config.apiKey
3017
+ )) {
3018
+ if (stage.error) throw stage.error;
3019
+ if (stage.result?.url) finalUrl = stage.result.url;
3020
+ }
3021
+ if (!finalUrl) {
3022
+ throw new AIError("SERVER_ERROR" /* SERVER_ERROR */, "No video generated from image by Pruna AI");
3023
+ }
3024
+ return {
3025
+ id: Date.now().toString(),
3026
+ type: "video",
3027
+ url: finalUrl,
3028
+ metadata: { provider: this.id, model: "p-image-to-video" },
3029
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
3030
+ };
2792
3031
  }
2793
3032
  async videoToVideo(_request) {
2794
- throw new AIError("UNKNOWN_ERROR" /* UNKNOWN_ERROR */, "Use generateWithPruna instead");
3033
+ throw new AIError("CLIENT_ERROR" /* CLIENT_ERROR */, "Pruna AI provider does not support video-to-video conversion");
2795
3034
  }
2796
3035
  };
2797
3036
  function createPrunaProvider(config) {
@@ -2823,6 +3062,278 @@ function createAI(config = {}) {
2823
3062
  return factory;
2824
3063
  }
2825
3064
 
3065
+ // src/providers/groq/groq-messages.ts
3066
+ var createUserMessage = (content) => ({
3067
+ role: "user",
3068
+ content
3069
+ });
3070
+ var createAssistantMessage = (content) => ({
3071
+ role: "assistant",
3072
+ content
3073
+ });
3074
+ var createSystemMessage = (content) => ({
3075
+ role: "system",
3076
+ content
3077
+ });
3078
+ var createMessage = (role, content) => ({
3079
+ role,
3080
+ content
3081
+ });
3082
+ var promptToMessages = (prompt) => [
3083
+ createUserMessage(prompt)
3084
+ ];
3085
+ var extractTextFromMessages = (messages) => messages.map((m) => m.content).join("\n\n");
3086
+ var formatMessagesForDisplay = (messages) => messages.map((m) => `[${m.role.toUpperCase()}]: ${m.content}`).join("\n\n---\n\n");
3087
+
3088
+ // src/providers/groq/groq-structured-json.ts
3089
+ async function requestStructuredJson(client, request) {
3090
+ const chatRequest = {
3091
+ model: request.model,
3092
+ messages: [createUserMessage(request.instructions)],
3093
+ temperature: request.temperature,
3094
+ max_tokens: request.maxTokens,
3095
+ response_format: { type: "json_object" },
3096
+ ...request.reasoningEffort !== void 0 ? { reasoning_effort: request.reasoningEffort } : {}
3097
+ };
3098
+ const response = await client.postChatCompletion(chatRequest);
3099
+ const content = response.choices[0]?.message?.content ?? "";
3100
+ const candidate = extractJsonCandidate(content);
3101
+ try {
3102
+ return JSON.parse(candidate);
3103
+ } catch (err) {
3104
+ throw new GroqError(
3105
+ "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
3106
+ "model response contained no parsable json object",
3107
+ err instanceof Error ? err : void 0
3108
+ );
3109
+ }
3110
+ }
3111
+
3112
+ // src/providers/groq/text-generation.service.ts
3113
+ var STRUCTURED_OUTPUT_TEMPERATURE = 0.1;
3114
+ var TextGenerationService = class {
3115
+ constructor(httpClient, cache = new CacheManager(), defaultModel = DEFAULT_MODELS.TEXT) {
3116
+ this.httpClient = httpClient;
3117
+ this.cache = cache;
3118
+ this.defaultModel = defaultModel;
3119
+ }
3120
+ httpClient;
3121
+ cache;
3122
+ defaultModel;
3123
+ id = "groq-text-generation";
3124
+ name = "Groq Text Generation";
3125
+ capabilities = ["text"];
3126
+ jsonParser = new JsonResponseParser();
3127
+ generateCompletion(prompt, options = {}) {
3128
+ const model = options.model ?? this.defaultModel;
3129
+ return this.executeWithCache(
3130
+ {
3131
+ type: CACHE_KEY_TYPE_COMPLETION,
3132
+ model,
3133
+ prompt,
3134
+ config: options.generationConfig
3135
+ },
3136
+ async () => {
3137
+ const request = GroqChatRequestBuilder.for(model).withMessages([createUserMessage(prompt)]).withConfig(options.generationConfig).build();
3138
+ const response = await this.httpClient.postChatCompletion(request);
3139
+ return this.extractContent(response.choices[0]?.message?.content);
3140
+ }
3141
+ );
3142
+ }
3143
+ generateChatCompletion(messages, options = {}) {
3144
+ const model = options.model ?? this.defaultModel;
3145
+ return this.executeWithCache(
3146
+ {
3147
+ type: CACHE_KEY_TYPE_CHAT,
3148
+ model,
3149
+ messages: [...messages],
3150
+ config: options.generationConfig
3151
+ },
3152
+ async () => {
3153
+ const request = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(options.generationConfig).build();
3154
+ const response = await this.httpClient.postChatCompletion(request);
3155
+ return this.extractContent(response.choices[0]?.message?.content);
3156
+ }
3157
+ );
3158
+ }
3159
+ generateStructured(promptOrRequest, options) {
3160
+ if (typeof promptOrRequest === "string") {
3161
+ const model2 = options?.model ?? this.defaultModel;
3162
+ const jsonPrompt = StructuredPromptBuilder.for(promptOrRequest).withSchema(options?.schema).build();
3163
+ const request = GroqChatRequestBuilder.for(model2).withMessages([createUserMessage(jsonPrompt)]).withConfig({
3164
+ ...options?.generationConfig,
3165
+ temperature: STRUCTURED_OUTPUT_TEMPERATURE
3166
+ }).build();
3167
+ return this.httpClient.postChatCompletion(request).then((response) => {
3168
+ const content = this.extractContent(response.choices[0]?.message?.content);
3169
+ return this.jsonParser.parse(content);
3170
+ });
3171
+ }
3172
+ const req = promptOrRequest;
3173
+ const model = req.model ?? (req.tier ? this.resolveModel(req.tier) : this.defaultModel);
3174
+ const schemaObj = req.schema;
3175
+ const messages = [];
3176
+ if (req.systemPrompt) {
3177
+ messages.push({ role: "system", content: req.systemPrompt });
3178
+ }
3179
+ for (const m of req.messages) {
3180
+ messages.push({ role: m.role, content: m.content });
3181
+ }
3182
+ const lastMsg = messages[messages.length - 1];
3183
+ if (lastMsg) {
3184
+ const structuredPrompt = StructuredPromptBuilder.for(lastMsg.content).withSchema(schemaObj).build();
3185
+ messages[messages.length - 1] = { ...lastMsg, content: structuredPrompt };
3186
+ }
3187
+ const groqReq = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig({
3188
+ temperature: req.temperature ?? STRUCTURED_OUTPUT_TEMPERATURE,
3189
+ maxTokens: req.maxTokens
3190
+ }).build();
3191
+ return this.httpClient.postChatCompletion(groqReq).then((response) => {
3192
+ const content = this.extractContent(response.choices[0]?.message?.content);
3193
+ const parsed = this.jsonParser.parse(content);
3194
+ const genResult = {
3195
+ text: content,
3196
+ model: response.model,
3197
+ providerId: this.id,
3198
+ finishReason: response.choices[0]?.finish_reason ?? "stop",
3199
+ usage: response.usage ? {
3200
+ inputTokens: response.usage.prompt_tokens,
3201
+ outputTokens: response.usage.completion_tokens,
3202
+ totalTokens: response.usage.total_tokens
3203
+ } : void 0
3204
+ };
3205
+ return { value: parsed, result: genResult };
3206
+ });
3207
+ }
3208
+ streamCompletion(prompt, callbacks, options = {}) {
3209
+ return this.streamChatCompletion([createUserMessage(prompt)], callbacks, options);
3210
+ }
3211
+ async streamChatCompletion(messages, callbacks, options = {}) {
3212
+ const model = options.model ?? this.defaultModel;
3213
+ const request = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(options.generationConfig).withStream(true).build();
3214
+ const parser = new StreamingResponseParser(
3215
+ {
3216
+ onChunk: (chunk) => callbacks.onChunk?.(chunk)
3217
+ },
3218
+ extractContentFromSsePayload
3219
+ );
3220
+ try {
3221
+ const stream = await this.httpClient.streamChatCompletion(request, {
3222
+ signal: options.signal
3223
+ });
3224
+ const fullText = await parser.parse(stream);
3225
+ callbacks.onComplete?.(fullText);
3226
+ return fullText;
3227
+ } catch (error) {
3228
+ const err = error instanceof Error ? error : new Error(String(error));
3229
+ callbacks.onError?.(err);
3230
+ throw err;
3231
+ }
3232
+ }
3233
+ clearCache() {
3234
+ this.cache.clear();
3235
+ }
3236
+ // --- ITextProvider implementation ---
3237
+ resolveModel(tier) {
3238
+ return GROQ_TIERS[tier] ?? this.defaultModel;
3239
+ }
3240
+ async generate(request) {
3241
+ const messages = [];
3242
+ if (request.systemPrompt) {
3243
+ messages.push({ role: "system", content: request.systemPrompt });
3244
+ }
3245
+ for (const m of request.messages) {
3246
+ messages.push({ role: m.role, content: m.content });
3247
+ }
3248
+ const model = request.model ?? (request.tier ? this.resolveModel(request.tier) : this.defaultModel);
3249
+ const groqReq = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig({
3250
+ temperature: request.temperature,
3251
+ maxTokens: request.maxTokens
3252
+ }).build();
3253
+ const resp = await this.httpClient.postChatCompletion(groqReq);
3254
+ const content = resp.choices[0]?.message?.content ?? "";
3255
+ return {
3256
+ text: content,
3257
+ finishReason: resp.choices[0]?.finish_reason ?? "stop",
3258
+ model: resp.model,
3259
+ providerId: this.id,
3260
+ usage: resp.usage ? {
3261
+ inputTokens: resp.usage.prompt_tokens,
3262
+ outputTokens: resp.usage.completion_tokens,
3263
+ totalTokens: resp.usage.total_tokens
3264
+ } : void 0
3265
+ };
3266
+ }
3267
+ async stream(request, callbacks) {
3268
+ const messages = [];
3269
+ if (request.systemPrompt) {
3270
+ messages.push({ role: "system", content: request.systemPrompt });
3271
+ }
3272
+ for (const m of request.messages) {
3273
+ messages.push({ role: m.role, content: m.content });
3274
+ }
3275
+ const model = request.model ?? (request.tier ? this.resolveModel(request.tier) : this.defaultModel);
3276
+ const text = await this.streamChatCompletion(
3277
+ messages,
3278
+ {
3279
+ onChunk: callbacks.onChunk,
3280
+ onError: callbacks.onError
3281
+ },
3282
+ {
3283
+ model,
3284
+ signal: request.signal,
3285
+ generationConfig: {
3286
+ temperature: request.temperature,
3287
+ maxTokens: request.maxTokens
3288
+ }
3289
+ }
3290
+ );
3291
+ const result = {
3292
+ text,
3293
+ finishReason: "stop",
3294
+ model,
3295
+ providerId: this.id
3296
+ };
3297
+ callbacks.onComplete?.(result);
3298
+ return result;
3299
+ }
3300
+ async countTokens(text) {
3301
+ return Math.max(1, Math.ceil(text.length / 4));
3302
+ }
3303
+ async estimateCost(_request) {
3304
+ return 0;
3305
+ }
3306
+ async healthCheck() {
3307
+ try {
3308
+ await this.generateCompletion("ping", {
3309
+ generationConfig: { maxTokens: 1 }
3310
+ });
3311
+ return "healthy";
3312
+ } catch {
3313
+ return "unavailable";
3314
+ }
3315
+ }
3316
+ async executeWithCache(params, factory) {
3317
+ const key = this.cache.generateKey(params);
3318
+ const cached = this.cache.get(key);
3319
+ if (cached !== null) {
3320
+ return cached;
3321
+ }
3322
+ const result = await factory();
3323
+ this.cache.set(key, result);
3324
+ return result;
3325
+ }
3326
+ extractContent(content) {
3327
+ if (!content) {
3328
+ throw new GroqError(
3329
+ "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
3330
+ "No content generated from Groq API"
3331
+ );
3332
+ }
3333
+ return content;
3334
+ }
3335
+ };
3336
+
2826
3337
  // src/core/calculations/random-base36-suffix.ts
2827
3338
  var BASE_36_RADIX = 36;
2828
3339
  var DECIMAL_OFFSET = 2;
@@ -2943,9 +3454,12 @@ var ChatService = class {
2943
3454
  };
2944
3455
  }
2945
3456
  async getConversations() {
3457
+ if (this.storage && "getConversations" in this.storage && typeof this.storage.getConversations === "function") {
3458
+ return this.storage.getConversations();
3459
+ }
2946
3460
  return [];
2947
3461
  }
2948
- async sendMessage(input) {
3462
+ async sendMessage(input, signal) {
2949
3463
  const userMessage = {
2950
3464
  ...messageFormatter.toChatMessage(input.text, "user"),
2951
3465
  type: input.type ?? "text",
@@ -2954,13 +3468,14 @@ var ChatService = class {
2954
3468
  const aiResponse = await this.generateAIResponse(
2955
3469
  input.companionId,
2956
3470
  input.text,
2957
- []
3471
+ [],
3472
+ signal
2958
3473
  );
2959
3474
  return { userMessage, aiResponse };
2960
3475
  }
2961
- async generateAIResponse(companionId, userMessage, context = []) {
3476
+ async generateAIResponse(companionId, userMessage, context = [], signal) {
2962
3477
  const result = await this.run({
2963
- ...this.buildRequest(userMessage, context)
3478
+ ...this.buildRequest(userMessage, context, signal)
2964
3479
  });
2965
3480
  return {
2966
3481
  ...messageFormatter.toChatMessage(result.text, "assistant"),
@@ -2976,12 +3491,12 @@ var ChatService = class {
2976
3491
  }
2977
3492
  };
2978
3493
  }
2979
- async generateStreamingResponse(userMessage, context, onChunk) {
2980
- const request = this.buildRequest(userMessage, context);
3494
+ async generateStreamingResponse(userMessage, context, onChunk, signal) {
3495
+ const request = this.buildRequest(userMessage, context, signal);
2981
3496
  const result = await this.runStream(request, { onChunk });
2982
3497
  return result.text;
2983
3498
  }
2984
- buildRequest(userMessage, context) {
3499
+ buildRequest(userMessage, context, signal) {
2985
3500
  const messages = messageFormatter.toCoreMessages(context);
2986
3501
  messages.push({ role: "user", content: userMessage });
2987
3502
  return {
@@ -2990,7 +3505,8 @@ var ChatService = class {
2990
3505
  model: this.config.model,
2991
3506
  tier: this.config.tier,
2992
3507
  temperature: this.config.temperature,
2993
- maxTokens: this.config.maxTokens
3508
+ maxTokens: this.config.maxTokens,
3509
+ ...signal !== void 0 ? { signal } : {}
2994
3510
  };
2995
3511
  }
2996
3512
  resolveSystemPrompt() {
@@ -3045,12 +3561,37 @@ function readNumber(source, keys) {
3045
3561
  return null;
3046
3562
  }
3047
3563
 
3564
+ // src/providers/groq/groq-container.ts
3565
+ var container = null;
3566
+ function configureProvider(config) {
3567
+ const configStore = new GroqConfigStore();
3568
+ const transport = new GroqHttpTransport(configStore);
3569
+ const httpClient = new GroqHttpClient({ configStore, transport });
3570
+ httpClient.initialize(config);
3571
+ const textGeneration = new TextGenerationService(
3572
+ httpClient,
3573
+ new CacheManager(),
3574
+ config.textModel
3575
+ );
3576
+ const chat = new ChatService(textGeneration);
3577
+ container = { groqHttpClient: httpClient, textGeneration, chat };
3578
+ return container;
3579
+ }
3580
+ function getProvider() {
3581
+ return container;
3582
+ }
3583
+ function resetProvider() {
3584
+ container?.groqHttpClient.reset();
3585
+ container = null;
3586
+ }
3587
+
3048
3588
  exports.AIError = AIError;
3049
3589
  exports.AIErrorType = AIErrorType;
3050
3590
  exports.ANTHROPIC_API_VERSION = ANTHROPIC_API_VERSION;
3051
3591
  exports.ANTHROPIC_DEFAULT_MAX_TOKENS = ANTHROPIC_DEFAULT_MAX_TOKENS;
3052
3592
  exports.ANTHROPIC_MODELS = ANTHROPIC_MODELS;
3053
3593
  exports.ANTHROPIC_TIERS = ANTHROPIC_TIERS;
3594
+ exports.API_ENDPOINTS = API_ENDPOINTS;
3054
3595
  exports.AnthropicHttpTransport = AnthropicHttpTransport;
3055
3596
  exports.AnthropicProvider = AnthropicProvider;
3056
3597
  exports.AnthropicRequestBuilder = AnthropicRequestBuilder;
@@ -3060,8 +3601,11 @@ exports.ChatIdGenerator = ChatIdGenerator;
3060
3601
  exports.ChatService = ChatService;
3061
3602
  exports.CompositeExecutor = CompositeExecutor;
3062
3603
  exports.DEFAULT_API_KEY_RULE = DEFAULT_API_KEY_RULE;
3604
+ exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
3063
3605
  exports.DEFAULT_ERROR_CLASSIFICATION_RULE = DEFAULT_ERROR_CLASSIFICATION_RULE;
3606
+ exports.DEFAULT_GENERATION_CONFIG = DEFAULT_GENERATION_CONFIG;
3064
3607
  exports.DEFAULT_HTTP_STATUS_RULE = DEFAULT_HTTP_STATUS_RULE;
3608
+ exports.DEFAULT_MODELS = DEFAULT_MODELS;
3065
3609
  exports.DEFAULT_PROMPT_STRATEGY = DEFAULT_PROMPT_STRATEGY;
3066
3610
  exports.DEFAULT_RETRY_BACKOFF_MULTIPLIER = DEFAULT_RETRY_BACKOFF_MULTIPLIER;
3067
3611
  exports.DEFAULT_RETRY_INITIAL_DELAY_MS = DEFAULT_RETRY_INITIAL_DELAY_MS;
@@ -3076,6 +3620,9 @@ exports.GROQ_MODELS = GROQ_MODELS;
3076
3620
  exports.GROQ_TIERS = GROQ_TIERS;
3077
3621
  exports.GeminiProvider = GeminiProvider;
3078
3622
  exports.GroqChatRequestBuilder = GroqChatRequestBuilder;
3623
+ exports.GroqConfigStore = GroqConfigStore;
3624
+ exports.GroqError = GroqError;
3625
+ exports.GroqErrorType = AIErrorType;
3079
3626
  exports.GroqHttpClient = GroqHttpClient;
3080
3627
  exports.GroqHttpTransport = GroqHttpTransport;
3081
3628
  exports.GroqProvider = GroqProvider;
@@ -3096,6 +3643,8 @@ exports.SSE_PREFIX = SSE_PREFIX;
3096
3643
  exports.StreamingResponseParser = StreamingResponseParser;
3097
3644
  exports.StructuredPromptBuilder = StructuredPromptBuilder;
3098
3645
  exports.TEXT_TIERS = TEXT_TIERS;
3646
+ exports.TIMEOUTS = TIMEOUTS;
3647
+ exports.TextGenerationService = TextGenerationService;
3099
3648
  exports.ThrottleManager = ThrottleManager;
3100
3649
  exports.USER_FRIENDLY_ERROR_MESSAGES = USER_FRIENDLY_ERROR_MESSAGES;
3101
3650
  exports.asObjectArray = asObjectArray;
@@ -3108,13 +3657,18 @@ exports.cacheManager = cacheManager;
3108
3657
  exports.chatIdGenerator = chatIdGenerator;
3109
3658
  exports.clampScore = clampScore;
3110
3659
  exports.classifyHttpStatus = classifyHttpStatus;
3660
+ exports.configureProvider = configureProvider;
3111
3661
  exports.consumeAnthropicStream = consumeAnthropicStream;
3112
3662
  exports.consumeGroqStream = consumeGroqStream;
3113
3663
  exports.createAI = createAI;
3664
+ exports.createAssistantMessage = createAssistantMessage;
3114
3665
  exports.createFalProvider = createFalProvider;
3115
3666
  exports.createGeminiProvider = createGeminiProvider;
3667
+ exports.createMessage = createMessage;
3116
3668
  exports.createPrunaProvider = createPrunaProvider;
3117
3669
  exports.createSseResponse = createSseResponse;
3670
+ exports.createSystemMessage = createSystemMessage;
3671
+ exports.createUserMessage = createUserMessage;
3118
3672
  exports.debounce = debounce;
3119
3673
  exports.debounceManager = debounceManager;
3120
3674
  exports.defaultEffortForModel = defaultEffortForModel;
@@ -3122,13 +3676,17 @@ exports.describeAIErrorType = describeAIErrorType;
3122
3676
  exports.extractContentFromSsePayload = extractContentFromSsePayload;
3123
3677
  exports.extractErrorMessageFromJsonBody = extractErrorMessageFromJsonBody;
3124
3678
  exports.extractErrorMessageFromResponse = extractErrorMessageFromResponse;
3679
+ exports.extractJsonArray = extractJsonArray;
3125
3680
  exports.extractJsonCandidate = extractJsonCandidate;
3126
3681
  exports.extractJsonFromCodeFence = extractJsonFromCodeFence;
3127
3682
  exports.extractJsonObject = extractJsonObject;
3128
3683
  exports.extractSseDataPayload = extractSseDataPayload;
3684
+ exports.extractTextFromMessages = extractTextFromMessages;
3129
3685
  exports.extractTokenUsage = extractTokenUsage;
3130
3686
  exports.formatErrorForLogging = formatErrorForLogging;
3687
+ exports.formatMessagesForDisplay = formatMessagesForDisplay;
3131
3688
  exports.generateWithPruna = generateWithPruna;
3689
+ exports.getProvider = getProvider;
3132
3690
  exports.isAuthErrorType = isAuthErrorType;
3133
3691
  exports.isMediaProvider = isMediaProvider;
3134
3692
  exports.isRetryableErrorType = isRetryableErrorType;
@@ -3142,8 +3700,12 @@ exports.mergeTierOverrides = mergeTierOverrides;
3142
3700
  exports.messageFormatter = messageFormatter;
3143
3701
  exports.normalizeSseChunk = normalizeSseChunk;
3144
3702
  exports.oneOfCatalog = oneOfCatalog;
3703
+ exports.promptToMessages = promptToMessages;
3704
+ exports.repairCommonJsonDefects = repairCommonJsonDefects;
3145
3705
  exports.requestDeduplicator = requestDeduplicator;
3146
3706
  exports.requestQueue = requestQueue;
3707
+ exports.requestStructuredJson = requestStructuredJson;
3708
+ exports.resetProvider = resetProvider;
3147
3709
  exports.resolveModel = resolveModel;
3148
3710
  exports.resolveUserFriendlyErrorMessage = resolveUserFriendlyErrorMessage;
3149
3711
  exports.resolveUserFriendlyMessage = resolveUserFriendlyMessage;