@umituz/web-ai 1.0.1 → 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/content/index.cjs +116 -10
- package/dist/content/index.cjs.map +1 -1
- package/dist/content/index.d.cts +1 -1
- package/dist/content/index.d.ts +1 -1
- package/dist/content/index.js +116 -10
- package/dist/content/index.js.map +1 -1
- package/dist/core/index.cjs +10 -0
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +13 -3
- package/dist/core/index.d.ts +13 -3
- package/dist/core/index.js +9 -1
- package/dist/core/index.js.map +1 -1
- package/dist/{create-ai-DXEoke8-.d.ts → create-ai-9PW752z8.d.ts} +11 -1
- package/dist/{create-ai-DOI9jD3v.d.cts → create-ai-CXYKPK6G.d.cts} +11 -1
- package/dist/hooks/index.cjs +272 -10
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +28 -2
- package/dist/hooks/index.d.ts +28 -2
- package/dist/hooks/index.js +272 -11
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +421 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +402 -11
- package/dist/index.js.map +1 -1
- package/dist/providers/index.cjs +696 -10
- package/dist/providers/index.cjs.map +1 -1
- package/dist/providers/index.d.cts +75 -8
- package/dist/providers/index.d.ts +75 -8
- package/dist/providers/index.js +679 -11
- 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/package.json +6 -1
package/dist/providers/index.js
CHANGED
|
@@ -182,6 +182,14 @@ var ProviderError = class extends AIError {
|
|
|
182
182
|
providerId;
|
|
183
183
|
};
|
|
184
184
|
|
|
185
|
+
// src/core/errors/groq-error.ts
|
|
186
|
+
var GroqError = class extends AIError {
|
|
187
|
+
constructor(type, message, cause, metadata = {}) {
|
|
188
|
+
super(type, message, cause, metadata);
|
|
189
|
+
this.name = "GroqError";
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
185
193
|
// src/core/errors/error-classifier.ts
|
|
186
194
|
var DEFAULT_RETRYABLE_TYPES = /* @__PURE__ */ new Set([
|
|
187
195
|
"NETWORK_ERROR" /* NETWORK_ERROR */,
|
|
@@ -530,6 +538,56 @@ function isSseDoneMarker(payload) {
|
|
|
530
538
|
return payload === SSE_DONE_MARKER;
|
|
531
539
|
}
|
|
532
540
|
|
|
541
|
+
// src/core/parsers/streaming-response.parser.ts
|
|
542
|
+
var StreamingResponseParser = class {
|
|
543
|
+
constructor(callbacks, extractDelta) {
|
|
544
|
+
this.callbacks = callbacks;
|
|
545
|
+
this.extractDelta = extractDelta;
|
|
546
|
+
}
|
|
547
|
+
callbacks;
|
|
548
|
+
extractDelta;
|
|
549
|
+
decoder = new TextDecoder();
|
|
550
|
+
async parse(stream) {
|
|
551
|
+
const reader = stream.getReader();
|
|
552
|
+
const contentChunks = [];
|
|
553
|
+
let buffer = "";
|
|
554
|
+
const consumeLine = (rawLine) => {
|
|
555
|
+
const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
|
|
556
|
+
const trimmed = line.trim();
|
|
557
|
+
if (trimmed.length === 0 || !isSseDataLine(trimmed)) return;
|
|
558
|
+
const payload = extractSseDataPayload(trimmed);
|
|
559
|
+
if (isSseDoneMarker(payload)) return;
|
|
560
|
+
const content = this.extractDelta(payload);
|
|
561
|
+
if (content !== null) {
|
|
562
|
+
contentChunks.push(content);
|
|
563
|
+
this.callbacks.onChunk(content);
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
try {
|
|
567
|
+
while (true) {
|
|
568
|
+
const { done, value } = await reader.read();
|
|
569
|
+
if (done) break;
|
|
570
|
+
buffer += this.decoder.decode(value, { stream: true });
|
|
571
|
+
const lines = buffer.split("\n");
|
|
572
|
+
buffer = lines.pop() ?? "";
|
|
573
|
+
for (const line of lines) consumeLine(line);
|
|
574
|
+
}
|
|
575
|
+
buffer += this.decoder.decode();
|
|
576
|
+
if (buffer.length > 0) consumeLine(buffer);
|
|
577
|
+
} catch (error) {
|
|
578
|
+
if (error instanceof AIError) throw error;
|
|
579
|
+
throw new AIError(
|
|
580
|
+
"NETWORK_ERROR" /* NETWORK_ERROR */,
|
|
581
|
+
"Stream was interrupted",
|
|
582
|
+
error instanceof Error ? error : void 0
|
|
583
|
+
);
|
|
584
|
+
} finally {
|
|
585
|
+
reader.releaseLock();
|
|
586
|
+
}
|
|
587
|
+
return contentChunks.join("");
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
|
|
533
591
|
// src/core/parsers/json-content-extractor.ts
|
|
534
592
|
function extractJsonFromCodeFence(content) {
|
|
535
593
|
const match = content.match(JSON_CODE_BLOCK_PATTERN);
|
|
@@ -1188,6 +1246,12 @@ function calculateExponentialBackoff(params) {
|
|
|
1188
1246
|
}
|
|
1189
1247
|
|
|
1190
1248
|
// src/core/constants/identifier.constants.ts
|
|
1249
|
+
var MESSAGE_ID_PREFIX = "msg-";
|
|
1250
|
+
var CHAT_MESSAGE_ID_SUFFIX_LENGTH = 9;
|
|
1251
|
+
var CACHE_KEY_TYPE_COMPLETION = "completion";
|
|
1252
|
+
var CACHE_KEY_TYPE_CHAT = "chat";
|
|
1253
|
+
var USER_ROLE = "user";
|
|
1254
|
+
var ASSISTANT_ROLE = "assistant";
|
|
1191
1255
|
var QUEUE_PRIORITY_USER_REQUEST = 10;
|
|
1192
1256
|
var DEFAULT_RETRY_MAX_ATTEMPTS = 3;
|
|
1193
1257
|
var DEFAULT_RETRY_INITIAL_DELAY_MS = 1e3;
|
|
@@ -1361,6 +1425,27 @@ var RequestDeduplicator = class {
|
|
|
1361
1425
|
}
|
|
1362
1426
|
};
|
|
1363
1427
|
|
|
1428
|
+
// src/core/utils/api-key-validator.ts
|
|
1429
|
+
var DEFAULT_API_KEY_RULE = {
|
|
1430
|
+
minLength: 10
|
|
1431
|
+
};
|
|
1432
|
+
function validateApiKey(apiKey, rule = DEFAULT_API_KEY_RULE) {
|
|
1433
|
+
if (!apiKey) {
|
|
1434
|
+
return { valid: false, reason: "API key is required" };
|
|
1435
|
+
}
|
|
1436
|
+
const trimmed = apiKey.trim();
|
|
1437
|
+
if (trimmed.length === 0) {
|
|
1438
|
+
return { valid: false, reason: "API key cannot be empty" };
|
|
1439
|
+
}
|
|
1440
|
+
if (trimmed.length < rule.minLength) {
|
|
1441
|
+
return {
|
|
1442
|
+
valid: false,
|
|
1443
|
+
reason: `API key must be at least ${rule.minLength} characters`
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
return { valid: true };
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1364
1449
|
// src/providers/groq/groq.constants.ts
|
|
1365
1450
|
var GROQ_MODELS = {
|
|
1366
1451
|
LLAMA_3_1_8B_INSTANT: "llama-3.1-8b-instant",
|
|
@@ -1384,12 +1469,22 @@ var DEFAULT_GENERATION_CONFIG = {
|
|
|
1384
1469
|
maxTokens: 1024,
|
|
1385
1470
|
topP: 1
|
|
1386
1471
|
};
|
|
1472
|
+
var DEFAULT_MODELS = {
|
|
1473
|
+
TEXT: GROQ_MODELS.LLAMA_3_1_8B_INSTANT,
|
|
1474
|
+
FAST: GROQ_MODELS.LLAMA_3_1_8B_INSTANT,
|
|
1475
|
+
EXPERIMENTAL: GROQ_MODELS.GPT_OSS_20B
|
|
1476
|
+
};
|
|
1387
1477
|
var GROQ_BASE_URL = "https://api.groq.com/openai/v1";
|
|
1478
|
+
var DEFAULT_BASE_URL = GROQ_BASE_URL;
|
|
1388
1479
|
var CHAT_COMPLETIONS_PATH = "/chat/completions";
|
|
1480
|
+
var API_ENDPOINTS = {
|
|
1481
|
+
CHAT: CHAT_COMPLETIONS_PATH
|
|
1482
|
+
};
|
|
1389
1483
|
var GROQ_TIMEOUTS = {
|
|
1390
1484
|
DEFAULT: 3e4,
|
|
1391
1485
|
STREAMING: 6e4
|
|
1392
1486
|
};
|
|
1487
|
+
var TIMEOUTS = GROQ_TIMEOUTS;
|
|
1393
1488
|
var HTTP_HEADERS = {
|
|
1394
1489
|
CONTENT_TYPE: "Content-Type",
|
|
1395
1490
|
APPLICATION_JSON: "application/json",
|
|
@@ -1448,13 +1543,65 @@ var GroqChatRequestBuilder = class _GroqChatRequestBuilder {
|
|
|
1448
1543
|
}
|
|
1449
1544
|
};
|
|
1450
1545
|
|
|
1546
|
+
// src/providers/groq/groq-config-store.ts
|
|
1547
|
+
var GroqConfigStore = class {
|
|
1548
|
+
config = null;
|
|
1549
|
+
initialize(config) {
|
|
1550
|
+
const validation = validateApiKey(config.apiKey, { minLength: 1 });
|
|
1551
|
+
if (!validation.valid) {
|
|
1552
|
+
throw new GroqError("INVALID_API_KEY" /* INVALID_API_KEY */, validation.reason ?? "Invalid API key");
|
|
1553
|
+
}
|
|
1554
|
+
const normalized = {
|
|
1555
|
+
apiKey: config.apiKey.trim(),
|
|
1556
|
+
baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
|
|
1557
|
+
timeoutMs: config.timeoutMs ?? TIMEOUTS.DEFAULT,
|
|
1558
|
+
...config.models !== void 0 ? { models: config.models } : {},
|
|
1559
|
+
...config.textModel !== void 0 ? { textModel: config.textModel } : {}
|
|
1560
|
+
};
|
|
1561
|
+
this.config = normalized;
|
|
1562
|
+
return normalized;
|
|
1563
|
+
}
|
|
1564
|
+
get() {
|
|
1565
|
+
if (!this.config) {
|
|
1566
|
+
throw new GroqError(
|
|
1567
|
+
"MISSING_CONFIG" /* MISSING_CONFIG */,
|
|
1568
|
+
"Client not initialized. Call configureProvider first."
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
return this.config;
|
|
1572
|
+
}
|
|
1573
|
+
getOrNull() {
|
|
1574
|
+
return this.config;
|
|
1575
|
+
}
|
|
1576
|
+
isInitialized() {
|
|
1577
|
+
return this.config !== null;
|
|
1578
|
+
}
|
|
1579
|
+
setApiKey(apiKey) {
|
|
1580
|
+
const current = this.get();
|
|
1581
|
+
const validation = validateApiKey(apiKey, { minLength: 1 });
|
|
1582
|
+
if (!validation.valid) {
|
|
1583
|
+
throw new GroqError("INVALID_API_KEY" /* INVALID_API_KEY */, validation.reason ?? "Invalid API key");
|
|
1584
|
+
}
|
|
1585
|
+
this.config = { ...current, apiKey: apiKey.trim() };
|
|
1586
|
+
}
|
|
1587
|
+
reset() {
|
|
1588
|
+
this.config = null;
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
|
|
1451
1592
|
// src/providers/groq/groq-http-transport.ts
|
|
1452
1593
|
var GroqHttpTransport = class {
|
|
1453
|
-
constructor(
|
|
1454
|
-
this.
|
|
1594
|
+
constructor(configSource) {
|
|
1595
|
+
this.configSource = configSource;
|
|
1455
1596
|
}
|
|
1456
|
-
|
|
1597
|
+
configSource;
|
|
1457
1598
|
pendingAbortControllers = /* @__PURE__ */ new Set();
|
|
1599
|
+
getConfig() {
|
|
1600
|
+
if ("get" in this.configSource && typeof this.configSource.get === "function") {
|
|
1601
|
+
return this.configSource.get();
|
|
1602
|
+
}
|
|
1603
|
+
return this.configSource;
|
|
1604
|
+
}
|
|
1458
1605
|
cancelPendingRequests() {
|
|
1459
1606
|
for (const controller of this.pendingAbortControllers) {
|
|
1460
1607
|
controller.abort();
|
|
@@ -1469,7 +1616,7 @@ var GroqHttpTransport = class {
|
|
|
1469
1616
|
}
|
|
1470
1617
|
async streamChatCompletion(request, options = {}) {
|
|
1471
1618
|
const url = `${this.baseUrl()}${CHAT_COMPLETIONS_PATH}`;
|
|
1472
|
-
const timeout = this.
|
|
1619
|
+
const timeout = this.getConfig().timeoutMs ?? GROQ_TIMEOUTS.STREAMING;
|
|
1473
1620
|
const controller = new AbortController();
|
|
1474
1621
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1475
1622
|
const onExternalAbort = () => controller.abort();
|
|
@@ -1496,11 +1643,11 @@ var GroqHttpTransport = class {
|
|
|
1496
1643
|
}
|
|
1497
1644
|
}
|
|
1498
1645
|
baseUrl() {
|
|
1499
|
-
return this.
|
|
1646
|
+
return this.getConfig().baseUrl ?? GROQ_BASE_URL;
|
|
1500
1647
|
}
|
|
1501
1648
|
async request(endpoint, body) {
|
|
1502
1649
|
const url = `${this.baseUrl()}${endpoint}`;
|
|
1503
|
-
const timeout = this.
|
|
1650
|
+
const timeout = this.getConfig().timeoutMs ?? GROQ_TIMEOUTS.DEFAULT;
|
|
1504
1651
|
const controller = new AbortController();
|
|
1505
1652
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1506
1653
|
this.pendingAbortControllers.add(controller);
|
|
@@ -1523,7 +1670,7 @@ var GroqHttpTransport = class {
|
|
|
1523
1670
|
buildHeaders() {
|
|
1524
1671
|
return {
|
|
1525
1672
|
[HTTP_HEADERS.CONTENT_TYPE]: HTTP_HEADERS.APPLICATION_JSON,
|
|
1526
|
-
[HTTP_HEADERS.AUTHORIZATION]: `${HTTP_HEADERS.BEARER_PREFIX}${this.
|
|
1673
|
+
[HTTP_HEADERS.AUTHORIZATION]: `${HTTP_HEADERS.BEARER_PREFIX}${this.getConfig().apiKey}`
|
|
1527
1674
|
};
|
|
1528
1675
|
}
|
|
1529
1676
|
async throwFromErrorResponse(response) {
|
|
@@ -1625,21 +1772,40 @@ var CompositeExecutor = class {
|
|
|
1625
1772
|
|
|
1626
1773
|
// src/providers/groq/groq-http-client.ts
|
|
1627
1774
|
var GroqHttpClient = class {
|
|
1775
|
+
configStore;
|
|
1628
1776
|
transport;
|
|
1629
1777
|
executor;
|
|
1630
|
-
constructor(
|
|
1631
|
-
|
|
1778
|
+
constructor(configOrDeps, maybeDeps = {}) {
|
|
1779
|
+
const isConfig = typeof configOrDeps === "object" && configOrDeps !== null && "apiKey" in configOrDeps && typeof configOrDeps.apiKey === "string";
|
|
1780
|
+
const deps = isConfig ? maybeDeps : configOrDeps ?? {};
|
|
1781
|
+
this.configStore = deps.configStore ?? new GroqConfigStore();
|
|
1782
|
+
if (isConfig) {
|
|
1783
|
+
this.configStore.initialize(configOrDeps);
|
|
1784
|
+
}
|
|
1785
|
+
this.transport = deps.transport ?? new GroqHttpTransport(this.configStore);
|
|
1632
1786
|
const retryManager2 = deps.retryManager ?? new RetryManager();
|
|
1633
1787
|
const queue = deps.queue ?? new RequestQueue();
|
|
1634
1788
|
const deduplicator = deps.deduplicator ?? new RequestDeduplicator();
|
|
1635
1789
|
this.executor = new CompositeExecutor([
|
|
1636
1790
|
new DedupeExecutor(deduplicator, {
|
|
1637
|
-
generateKey: (request) => deduplicatorKey(request,
|
|
1791
|
+
generateKey: (request) => deduplicatorKey(request, this.configStore.isInitialized() ? this.configStore.get().apiKey : "")
|
|
1638
1792
|
}),
|
|
1639
1793
|
new RetryExecutor(retryManager2),
|
|
1640
1794
|
new QueueExecutor(queue, QUEUE_PRIORITY_USER_REQUEST)
|
|
1641
1795
|
]);
|
|
1642
1796
|
}
|
|
1797
|
+
initialize(config) {
|
|
1798
|
+
this.configStore.initialize(config);
|
|
1799
|
+
}
|
|
1800
|
+
isInitialized() {
|
|
1801
|
+
return this.configStore.isInitialized();
|
|
1802
|
+
}
|
|
1803
|
+
getApiKey() {
|
|
1804
|
+
return this.configStore.get().apiKey;
|
|
1805
|
+
}
|
|
1806
|
+
setApiKey(apiKey) {
|
|
1807
|
+
this.configStore.setApiKey(apiKey);
|
|
1808
|
+
}
|
|
1643
1809
|
cancelPendingRequests() {
|
|
1644
1810
|
this.transport.cancelPendingRequests();
|
|
1645
1811
|
}
|
|
@@ -1652,6 +1818,10 @@ var GroqHttpClient = class {
|
|
|
1652
1818
|
streamChatCompletion(request, options) {
|
|
1653
1819
|
return this.transport.streamChatCompletion(request, options);
|
|
1654
1820
|
}
|
|
1821
|
+
reset() {
|
|
1822
|
+
this.transport.cancelPendingRequests();
|
|
1823
|
+
this.configStore.reset();
|
|
1824
|
+
}
|
|
1655
1825
|
};
|
|
1656
1826
|
function deduplicatorKey(request, apiKey) {
|
|
1657
1827
|
const { model, messages, stream: _stream, ...rest } = request;
|
|
@@ -2528,6 +2698,504 @@ function createAI(config = {}) {
|
|
|
2528
2698
|
return factory;
|
|
2529
2699
|
}
|
|
2530
2700
|
|
|
2531
|
-
|
|
2701
|
+
// src/providers/groq/groq-messages.ts
|
|
2702
|
+
var createUserMessage = (content) => ({
|
|
2703
|
+
role: "user",
|
|
2704
|
+
content
|
|
2705
|
+
});
|
|
2706
|
+
var createAssistantMessage = (content) => ({
|
|
2707
|
+
role: "assistant",
|
|
2708
|
+
content
|
|
2709
|
+
});
|
|
2710
|
+
var createSystemMessage = (content) => ({
|
|
2711
|
+
role: "system",
|
|
2712
|
+
content
|
|
2713
|
+
});
|
|
2714
|
+
var createMessage = (role, content) => ({
|
|
2715
|
+
role,
|
|
2716
|
+
content
|
|
2717
|
+
});
|
|
2718
|
+
var promptToMessages = (prompt) => [
|
|
2719
|
+
createUserMessage(prompt)
|
|
2720
|
+
];
|
|
2721
|
+
var extractTextFromMessages = (messages) => messages.map((m) => m.content).join("\n\n");
|
|
2722
|
+
var formatMessagesForDisplay = (messages) => messages.map((m) => `[${m.role.toUpperCase()}]: ${m.content}`).join("\n\n---\n\n");
|
|
2723
|
+
|
|
2724
|
+
// src/providers/groq/groq-structured-json.ts
|
|
2725
|
+
async function requestStructuredJson(client, request) {
|
|
2726
|
+
const chatRequest = {
|
|
2727
|
+
model: request.model,
|
|
2728
|
+
messages: [createUserMessage(request.instructions)],
|
|
2729
|
+
temperature: request.temperature,
|
|
2730
|
+
max_tokens: request.maxTokens,
|
|
2731
|
+
response_format: { type: "json_object" },
|
|
2732
|
+
...request.reasoningEffort !== void 0 ? { reasoning_effort: request.reasoningEffort } : {}
|
|
2733
|
+
};
|
|
2734
|
+
const response = await client.postChatCompletion(chatRequest);
|
|
2735
|
+
const content = response.choices[0]?.message?.content ?? "";
|
|
2736
|
+
const candidate = extractJsonCandidate(content);
|
|
2737
|
+
try {
|
|
2738
|
+
return JSON.parse(candidate);
|
|
2739
|
+
} catch (err) {
|
|
2740
|
+
throw new GroqError(
|
|
2741
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
2742
|
+
"model response contained no parsable json object",
|
|
2743
|
+
err instanceof Error ? err : void 0
|
|
2744
|
+
);
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
// src/providers/groq/text-generation.service.ts
|
|
2749
|
+
var STRUCTURED_OUTPUT_TEMPERATURE = 0.1;
|
|
2750
|
+
var TextGenerationService = class {
|
|
2751
|
+
constructor(httpClient, cache = new CacheManager(), defaultModel = DEFAULT_MODELS.TEXT) {
|
|
2752
|
+
this.httpClient = httpClient;
|
|
2753
|
+
this.cache = cache;
|
|
2754
|
+
this.defaultModel = defaultModel;
|
|
2755
|
+
}
|
|
2756
|
+
httpClient;
|
|
2757
|
+
cache;
|
|
2758
|
+
defaultModel;
|
|
2759
|
+
id = "groq-text-generation";
|
|
2760
|
+
name = "Groq Text Generation";
|
|
2761
|
+
capabilities = ["text"];
|
|
2762
|
+
jsonParser = new JsonResponseParser();
|
|
2763
|
+
generateCompletion(prompt, options = {}) {
|
|
2764
|
+
const model = options.model ?? this.defaultModel;
|
|
2765
|
+
return this.executeWithCache(
|
|
2766
|
+
{
|
|
2767
|
+
type: CACHE_KEY_TYPE_COMPLETION,
|
|
2768
|
+
model,
|
|
2769
|
+
prompt,
|
|
2770
|
+
config: options.generationConfig
|
|
2771
|
+
},
|
|
2772
|
+
async () => {
|
|
2773
|
+
const request = GroqChatRequestBuilder.for(model).withMessages([createUserMessage(prompt)]).withConfig(options.generationConfig).build();
|
|
2774
|
+
const response = await this.httpClient.postChatCompletion(request);
|
|
2775
|
+
return this.extractContent(response.choices[0]?.message?.content);
|
|
2776
|
+
}
|
|
2777
|
+
);
|
|
2778
|
+
}
|
|
2779
|
+
generateChatCompletion(messages, options = {}) {
|
|
2780
|
+
const model = options.model ?? this.defaultModel;
|
|
2781
|
+
return this.executeWithCache(
|
|
2782
|
+
{
|
|
2783
|
+
type: CACHE_KEY_TYPE_CHAT,
|
|
2784
|
+
model,
|
|
2785
|
+
messages: [...messages],
|
|
2786
|
+
config: options.generationConfig
|
|
2787
|
+
},
|
|
2788
|
+
async () => {
|
|
2789
|
+
const request = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(options.generationConfig).build();
|
|
2790
|
+
const response = await this.httpClient.postChatCompletion(request);
|
|
2791
|
+
return this.extractContent(response.choices[0]?.message?.content);
|
|
2792
|
+
}
|
|
2793
|
+
);
|
|
2794
|
+
}
|
|
2795
|
+
generateStructured(promptOrRequest, options) {
|
|
2796
|
+
if (typeof promptOrRequest === "string") {
|
|
2797
|
+
const model2 = options?.model ?? this.defaultModel;
|
|
2798
|
+
const jsonPrompt = StructuredPromptBuilder.for(promptOrRequest).withSchema(options?.schema).build();
|
|
2799
|
+
const request = GroqChatRequestBuilder.for(model2).withMessages([createUserMessage(jsonPrompt)]).withConfig({
|
|
2800
|
+
...options?.generationConfig,
|
|
2801
|
+
temperature: STRUCTURED_OUTPUT_TEMPERATURE
|
|
2802
|
+
}).build();
|
|
2803
|
+
return this.httpClient.postChatCompletion(request).then((response) => {
|
|
2804
|
+
const content = this.extractContent(response.choices[0]?.message?.content);
|
|
2805
|
+
return this.jsonParser.parse(content);
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
const req = promptOrRequest;
|
|
2809
|
+
const model = req.model ?? (req.tier ? this.resolveModel(req.tier) : this.defaultModel);
|
|
2810
|
+
const schemaObj = req.schema;
|
|
2811
|
+
const messages = [];
|
|
2812
|
+
if (req.systemPrompt) {
|
|
2813
|
+
messages.push({ role: "system", content: req.systemPrompt });
|
|
2814
|
+
}
|
|
2815
|
+
for (const m of req.messages) {
|
|
2816
|
+
messages.push({ role: m.role, content: m.content });
|
|
2817
|
+
}
|
|
2818
|
+
const lastMsg = messages[messages.length - 1];
|
|
2819
|
+
if (lastMsg) {
|
|
2820
|
+
const structuredPrompt = StructuredPromptBuilder.for(lastMsg.content).withSchema(schemaObj).build();
|
|
2821
|
+
messages[messages.length - 1] = { ...lastMsg, content: structuredPrompt };
|
|
2822
|
+
}
|
|
2823
|
+
const groqReq = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig({
|
|
2824
|
+
temperature: req.temperature ?? STRUCTURED_OUTPUT_TEMPERATURE,
|
|
2825
|
+
maxTokens: req.maxTokens
|
|
2826
|
+
}).build();
|
|
2827
|
+
return this.httpClient.postChatCompletion(groqReq).then((response) => {
|
|
2828
|
+
const content = this.extractContent(response.choices[0]?.message?.content);
|
|
2829
|
+
const parsed = this.jsonParser.parse(content);
|
|
2830
|
+
const genResult = {
|
|
2831
|
+
text: content,
|
|
2832
|
+
model: response.model,
|
|
2833
|
+
providerId: this.id,
|
|
2834
|
+
finishReason: response.choices[0]?.finish_reason ?? "stop",
|
|
2835
|
+
usage: response.usage ? {
|
|
2836
|
+
inputTokens: response.usage.prompt_tokens,
|
|
2837
|
+
outputTokens: response.usage.completion_tokens,
|
|
2838
|
+
totalTokens: response.usage.total_tokens
|
|
2839
|
+
} : void 0
|
|
2840
|
+
};
|
|
2841
|
+
return { value: parsed, result: genResult };
|
|
2842
|
+
});
|
|
2843
|
+
}
|
|
2844
|
+
streamCompletion(prompt, callbacks, options = {}) {
|
|
2845
|
+
return this.streamChatCompletion([createUserMessage(prompt)], callbacks, options);
|
|
2846
|
+
}
|
|
2847
|
+
async streamChatCompletion(messages, callbacks, options = {}) {
|
|
2848
|
+
const model = options.model ?? this.defaultModel;
|
|
2849
|
+
const request = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(options.generationConfig).withStream(true).build();
|
|
2850
|
+
const parser = new StreamingResponseParser(
|
|
2851
|
+
{
|
|
2852
|
+
onChunk: (chunk) => callbacks.onChunk?.(chunk)
|
|
2853
|
+
},
|
|
2854
|
+
extractContentFromSsePayload
|
|
2855
|
+
);
|
|
2856
|
+
try {
|
|
2857
|
+
const stream = await this.httpClient.streamChatCompletion(request, {
|
|
2858
|
+
signal: options.signal
|
|
2859
|
+
});
|
|
2860
|
+
const fullText = await parser.parse(stream);
|
|
2861
|
+
callbacks.onComplete?.(fullText);
|
|
2862
|
+
return fullText;
|
|
2863
|
+
} catch (error) {
|
|
2864
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
2865
|
+
callbacks.onError?.(err);
|
|
2866
|
+
throw err;
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
clearCache() {
|
|
2870
|
+
this.cache.clear();
|
|
2871
|
+
}
|
|
2872
|
+
// --- ITextProvider implementation ---
|
|
2873
|
+
resolveModel(tier) {
|
|
2874
|
+
return GROQ_TIERS[tier] ?? this.defaultModel;
|
|
2875
|
+
}
|
|
2876
|
+
async generate(request) {
|
|
2877
|
+
const messages = [];
|
|
2878
|
+
if (request.systemPrompt) {
|
|
2879
|
+
messages.push({ role: "system", content: request.systemPrompt });
|
|
2880
|
+
}
|
|
2881
|
+
for (const m of request.messages) {
|
|
2882
|
+
messages.push({ role: m.role, content: m.content });
|
|
2883
|
+
}
|
|
2884
|
+
const model = request.model ?? (request.tier ? this.resolveModel(request.tier) : this.defaultModel);
|
|
2885
|
+
const groqReq = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig({
|
|
2886
|
+
temperature: request.temperature,
|
|
2887
|
+
maxTokens: request.maxTokens
|
|
2888
|
+
}).build();
|
|
2889
|
+
const resp = await this.httpClient.postChatCompletion(groqReq);
|
|
2890
|
+
const content = resp.choices[0]?.message?.content ?? "";
|
|
2891
|
+
return {
|
|
2892
|
+
text: content,
|
|
2893
|
+
finishReason: resp.choices[0]?.finish_reason ?? "stop",
|
|
2894
|
+
model: resp.model,
|
|
2895
|
+
providerId: this.id,
|
|
2896
|
+
usage: resp.usage ? {
|
|
2897
|
+
inputTokens: resp.usage.prompt_tokens,
|
|
2898
|
+
outputTokens: resp.usage.completion_tokens,
|
|
2899
|
+
totalTokens: resp.usage.total_tokens
|
|
2900
|
+
} : void 0
|
|
2901
|
+
};
|
|
2902
|
+
}
|
|
2903
|
+
async stream(request, callbacks) {
|
|
2904
|
+
const messages = [];
|
|
2905
|
+
if (request.systemPrompt) {
|
|
2906
|
+
messages.push({ role: "system", content: request.systemPrompt });
|
|
2907
|
+
}
|
|
2908
|
+
for (const m of request.messages) {
|
|
2909
|
+
messages.push({ role: m.role, content: m.content });
|
|
2910
|
+
}
|
|
2911
|
+
const model = request.model ?? (request.tier ? this.resolveModel(request.tier) : this.defaultModel);
|
|
2912
|
+
const text = await this.streamChatCompletion(
|
|
2913
|
+
messages,
|
|
2914
|
+
{
|
|
2915
|
+
onChunk: callbacks.onChunk,
|
|
2916
|
+
onError: callbacks.onError
|
|
2917
|
+
},
|
|
2918
|
+
{
|
|
2919
|
+
model,
|
|
2920
|
+
signal: request.signal,
|
|
2921
|
+
generationConfig: {
|
|
2922
|
+
temperature: request.temperature,
|
|
2923
|
+
maxTokens: request.maxTokens
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
);
|
|
2927
|
+
const result = {
|
|
2928
|
+
text,
|
|
2929
|
+
finishReason: "stop",
|
|
2930
|
+
model,
|
|
2931
|
+
providerId: this.id
|
|
2932
|
+
};
|
|
2933
|
+
callbacks.onComplete?.(result);
|
|
2934
|
+
return result;
|
|
2935
|
+
}
|
|
2936
|
+
async countTokens(text) {
|
|
2937
|
+
return Math.max(1, Math.ceil(text.length / 4));
|
|
2938
|
+
}
|
|
2939
|
+
async estimateCost(_request) {
|
|
2940
|
+
return 0;
|
|
2941
|
+
}
|
|
2942
|
+
async healthCheck() {
|
|
2943
|
+
try {
|
|
2944
|
+
await this.generateCompletion("ping", {
|
|
2945
|
+
generationConfig: { maxTokens: 1 }
|
|
2946
|
+
});
|
|
2947
|
+
return "healthy";
|
|
2948
|
+
} catch {
|
|
2949
|
+
return "unavailable";
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
async executeWithCache(params, factory) {
|
|
2953
|
+
const key = this.cache.generateKey(params);
|
|
2954
|
+
const cached = this.cache.get(key);
|
|
2955
|
+
if (cached !== null) {
|
|
2956
|
+
return cached;
|
|
2957
|
+
}
|
|
2958
|
+
const result = await factory();
|
|
2959
|
+
this.cache.set(key, result);
|
|
2960
|
+
return result;
|
|
2961
|
+
}
|
|
2962
|
+
extractContent(content) {
|
|
2963
|
+
if (!content) {
|
|
2964
|
+
throw new GroqError(
|
|
2965
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
2966
|
+
"No content generated from Groq API"
|
|
2967
|
+
);
|
|
2968
|
+
}
|
|
2969
|
+
return content;
|
|
2970
|
+
}
|
|
2971
|
+
};
|
|
2972
|
+
|
|
2973
|
+
// src/core/calculations/random-base36-suffix.ts
|
|
2974
|
+
var BASE_36_RADIX = 36;
|
|
2975
|
+
var DECIMAL_OFFSET = 2;
|
|
2976
|
+
function generateRandomBase36Suffix(length, random = Math.random) {
|
|
2977
|
+
if (length <= 0) return "";
|
|
2978
|
+
const raw = random().toString(BASE_36_RADIX).slice(DECIMAL_OFFSET);
|
|
2979
|
+
if (raw.length >= length) return raw.slice(0, length);
|
|
2980
|
+
let result = raw;
|
|
2981
|
+
while (result.length < length) {
|
|
2982
|
+
result += random().toString(BASE_36_RADIX).slice(DECIMAL_OFFSET);
|
|
2983
|
+
}
|
|
2984
|
+
return result.slice(0, length);
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
// src/chat/utils/chat-id-generator.ts
|
|
2988
|
+
var ID_PART_DELIMITER = "-";
|
|
2989
|
+
var ChatIdGenerator = class {
|
|
2990
|
+
counter = 0;
|
|
2991
|
+
randomLength;
|
|
2992
|
+
constructor(randomLength = CHAT_MESSAGE_ID_SUFFIX_LENGTH) {
|
|
2993
|
+
this.randomLength = randomLength;
|
|
2994
|
+
}
|
|
2995
|
+
next(sender) {
|
|
2996
|
+
this.counter += 1;
|
|
2997
|
+
const random = generateRandomBase36Suffix(this.randomLength);
|
|
2998
|
+
return [
|
|
2999
|
+
MESSAGE_ID_PREFIX,
|
|
3000
|
+
Date.now(),
|
|
3001
|
+
sender,
|
|
3002
|
+
this.counter,
|
|
3003
|
+
random
|
|
3004
|
+
].join(ID_PART_DELIMITER);
|
|
3005
|
+
}
|
|
3006
|
+
};
|
|
3007
|
+
var chatIdGenerator = new ChatIdGenerator();
|
|
3008
|
+
|
|
3009
|
+
// src/chat/utils/message-formatter.ts
|
|
3010
|
+
var MessageFormatter = class {
|
|
3011
|
+
constructor(idGenerator = chatIdGenerator) {
|
|
3012
|
+
this.idGenerator = idGenerator;
|
|
3013
|
+
}
|
|
3014
|
+
idGenerator;
|
|
3015
|
+
/** Maps chat-domain history to neutral core messages; system senders are
|
|
3016
|
+
* dropped — the system prompt travels on the request's own slot. */
|
|
3017
|
+
toCoreMessages(messages) {
|
|
3018
|
+
const coreMessages = [];
|
|
3019
|
+
for (const message of messages) {
|
|
3020
|
+
if (message.sender === "system") continue;
|
|
3021
|
+
coreMessages.push({
|
|
3022
|
+
role: message.sender === "user" ? USER_ROLE : ASSISTANT_ROLE,
|
|
3023
|
+
content: message.content
|
|
3024
|
+
});
|
|
3025
|
+
}
|
|
3026
|
+
return coreMessages;
|
|
3027
|
+
}
|
|
3028
|
+
toChatMessage(content, sender) {
|
|
3029
|
+
return {
|
|
3030
|
+
id: this.idGenerator.next(sender),
|
|
3031
|
+
sender,
|
|
3032
|
+
content: content.trim(),
|
|
3033
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3034
|
+
type: "text"
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
3037
|
+
};
|
|
3038
|
+
var messageFormatter = new MessageFormatter();
|
|
3039
|
+
|
|
3040
|
+
// src/chat/utils/prompt-strategy.ts
|
|
3041
|
+
var DEFAULT_PROMPT_STRATEGY = {
|
|
3042
|
+
resolve: (config) => {
|
|
3043
|
+
if (config.systemPrompt && config.systemPrompt.length > 0) {
|
|
3044
|
+
return config.systemPrompt;
|
|
3045
|
+
}
|
|
3046
|
+
return void 0;
|
|
3047
|
+
}
|
|
3048
|
+
};
|
|
3049
|
+
|
|
3050
|
+
// src/chat/services/chat.service.ts
|
|
3051
|
+
var DEFAULT_CONFIG = {
|
|
3052
|
+
temperature: 0.8,
|
|
3053
|
+
maxTokens: 500
|
|
3054
|
+
};
|
|
3055
|
+
var ChatService = class {
|
|
3056
|
+
constructor(engine) {
|
|
3057
|
+
this.engine = engine;
|
|
3058
|
+
}
|
|
3059
|
+
engine;
|
|
3060
|
+
config = DEFAULT_CONFIG;
|
|
3061
|
+
promptStrategy = DEFAULT_PROMPT_STRATEGY;
|
|
3062
|
+
storage = null;
|
|
3063
|
+
initialize(config) {
|
|
3064
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
3065
|
+
}
|
|
3066
|
+
updateConfig(config) {
|
|
3067
|
+
this.config = { ...this.config, ...config };
|
|
3068
|
+
}
|
|
3069
|
+
setPromptStrategy(strategy) {
|
|
3070
|
+
this.promptStrategy = strategy;
|
|
3071
|
+
}
|
|
3072
|
+
setStorage(storage) {
|
|
3073
|
+
this.storage = storage;
|
|
3074
|
+
}
|
|
3075
|
+
async getConversation(conversationId) {
|
|
3076
|
+
const storage = this.requireStorage();
|
|
3077
|
+
const messages = await storage.getMessages(conversationId);
|
|
3078
|
+
if (messages.length === 0) return null;
|
|
3079
|
+
const last = messages[messages.length - 1];
|
|
3080
|
+
const first = messages[0];
|
|
3081
|
+
const companionId = String(first.metadata?.["companionId"] ?? "unknown");
|
|
3082
|
+
const companionName = String(first.metadata?.["companionName"] ?? "Unknown");
|
|
3083
|
+
return {
|
|
3084
|
+
id: conversationId,
|
|
3085
|
+
companionId,
|
|
3086
|
+
companionName,
|
|
3087
|
+
lastMessage: last,
|
|
3088
|
+
messageCount: messages.length,
|
|
3089
|
+
updatedAt: last.timestamp
|
|
3090
|
+
};
|
|
3091
|
+
}
|
|
3092
|
+
async getConversations() {
|
|
3093
|
+
if (this.storage && "getConversations" in this.storage && typeof this.storage.getConversations === "function") {
|
|
3094
|
+
return this.storage.getConversations();
|
|
3095
|
+
}
|
|
3096
|
+
return [];
|
|
3097
|
+
}
|
|
3098
|
+
async sendMessage(input, signal) {
|
|
3099
|
+
const userMessage = {
|
|
3100
|
+
...messageFormatter.toChatMessage(input.text, "user"),
|
|
3101
|
+
type: input.type ?? "text",
|
|
3102
|
+
...input.imageUrl !== void 0 ? { imageUrl: input.imageUrl } : {}
|
|
3103
|
+
};
|
|
3104
|
+
const aiResponse = await this.generateAIResponse(
|
|
3105
|
+
input.companionId,
|
|
3106
|
+
input.text,
|
|
3107
|
+
[],
|
|
3108
|
+
signal
|
|
3109
|
+
);
|
|
3110
|
+
return { userMessage, aiResponse };
|
|
3111
|
+
}
|
|
3112
|
+
async generateAIResponse(companionId, userMessage, context = [], signal) {
|
|
3113
|
+
const result = await this.run({
|
|
3114
|
+
...this.buildRequest(userMessage, context, signal)
|
|
3115
|
+
});
|
|
3116
|
+
return {
|
|
3117
|
+
...messageFormatter.toChatMessage(result.text, "assistant"),
|
|
3118
|
+
metadata: {
|
|
3119
|
+
companionId,
|
|
3120
|
+
model: result.model,
|
|
3121
|
+
usage: {
|
|
3122
|
+
input_tokens: result.usage?.inputTokens,
|
|
3123
|
+
output_tokens: result.usage?.outputTokens,
|
|
3124
|
+
total_tokens: result.usage?.totalTokens
|
|
3125
|
+
},
|
|
3126
|
+
finishReason: result.finishReason
|
|
3127
|
+
}
|
|
3128
|
+
};
|
|
3129
|
+
}
|
|
3130
|
+
async generateStreamingResponse(userMessage, context, onChunk, signal) {
|
|
3131
|
+
const request = this.buildRequest(userMessage, context, signal);
|
|
3132
|
+
const result = await this.runStream(request, { onChunk });
|
|
3133
|
+
return result.text;
|
|
3134
|
+
}
|
|
3135
|
+
buildRequest(userMessage, context, signal) {
|
|
3136
|
+
const messages = messageFormatter.toCoreMessages(context);
|
|
3137
|
+
messages.push({ role: "user", content: userMessage });
|
|
3138
|
+
return {
|
|
3139
|
+
messages,
|
|
3140
|
+
systemPrompt: this.resolveSystemPrompt(),
|
|
3141
|
+
model: this.config.model,
|
|
3142
|
+
tier: this.config.tier,
|
|
3143
|
+
temperature: this.config.temperature,
|
|
3144
|
+
maxTokens: this.config.maxTokens,
|
|
3145
|
+
...signal !== void 0 ? { signal } : {}
|
|
3146
|
+
};
|
|
3147
|
+
}
|
|
3148
|
+
resolveSystemPrompt() {
|
|
3149
|
+
const prompt = this.promptStrategy.resolve(this.config);
|
|
3150
|
+
return prompt && prompt.length > 0 ? prompt : void 0;
|
|
3151
|
+
}
|
|
3152
|
+
async run(request) {
|
|
3153
|
+
if (this.engine instanceof ProviderFactory) {
|
|
3154
|
+
return this.engine.chat(request);
|
|
3155
|
+
}
|
|
3156
|
+
return this.engine.generate(request);
|
|
3157
|
+
}
|
|
3158
|
+
async runStream(request, callbacks) {
|
|
3159
|
+
if (this.engine instanceof ProviderFactory) {
|
|
3160
|
+
return this.engine.chatStream(request, callbacks);
|
|
3161
|
+
}
|
|
3162
|
+
return this.engine.stream(request, callbacks);
|
|
3163
|
+
}
|
|
3164
|
+
requireStorage() {
|
|
3165
|
+
if (!this.storage) {
|
|
3166
|
+
throw new AIError(
|
|
3167
|
+
"MISSING_CONFIG" /* MISSING_CONFIG */,
|
|
3168
|
+
"ChatService.getConversation requires setStorage() to be called first."
|
|
3169
|
+
);
|
|
3170
|
+
}
|
|
3171
|
+
return this.storage;
|
|
3172
|
+
}
|
|
3173
|
+
};
|
|
3174
|
+
|
|
3175
|
+
// src/providers/groq/groq-container.ts
|
|
3176
|
+
var container = null;
|
|
3177
|
+
function configureProvider(config) {
|
|
3178
|
+
const configStore = new GroqConfigStore();
|
|
3179
|
+
const transport = new GroqHttpTransport(configStore);
|
|
3180
|
+
const httpClient = new GroqHttpClient({ configStore, transport });
|
|
3181
|
+
httpClient.initialize(config);
|
|
3182
|
+
const textGeneration = new TextGenerationService(
|
|
3183
|
+
httpClient,
|
|
3184
|
+
new CacheManager(),
|
|
3185
|
+
config.textModel
|
|
3186
|
+
);
|
|
3187
|
+
const chat = new ChatService(textGeneration);
|
|
3188
|
+
container = { groqHttpClient: httpClient, textGeneration, chat };
|
|
3189
|
+
return container;
|
|
3190
|
+
}
|
|
3191
|
+
function getProvider() {
|
|
3192
|
+
return container;
|
|
3193
|
+
}
|
|
3194
|
+
function resetProvider() {
|
|
3195
|
+
container?.groqHttpClient.reset();
|
|
3196
|
+
container = null;
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3199
|
+
export { ANTHROPIC_API_VERSION, ANTHROPIC_DEFAULT_MAX_TOKENS, ANTHROPIC_MODELS, ANTHROPIC_TIERS, API_ENDPOINTS, AnthropicHttpTransport, AnthropicProvider, AnthropicRequestBuilder, BaseProvider, DEFAULT_BASE_URL, DEFAULT_GENERATION_CONFIG, DEFAULT_MODELS, FalProvider, GEMINI_TIERS, GROQ_MODELS, GROQ_TIERS, GeminiProvider, GroqChatRequestBuilder, GroqConfigStore, GroqHttpClient, GroqHttpTransport, GroqProvider, ProviderError, ProviderFactory, PrunaProvider, TIMEOUTS, TextGenerationService, configureProvider, consumeAnthropicStream, consumeGroqStream, createAI, createAssistantMessage, createFalProvider, createGeminiProvider, createMessage, createPrunaProvider, createSystemMessage, createUserMessage, defaultEffortForModel, extractContentFromSsePayload, extractTextFromMessages, formatMessagesForDisplay, generateWithPruna, getProvider, isMediaProvider, isTextProvider, mapAnthropicStopReason, promptToMessages, requestStructuredJson, resetProvider, toGroqMessages };
|
|
2532
3200
|
//# sourceMappingURL=index.js.map
|
|
2533
3201
|
//# sourceMappingURL=index.js.map
|