@umituz/web-ai 1.0.1 → 1.0.3
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/cancellation-error-CKcZRhFg.d.ts +129 -0
- package/dist/cancellation-error-DwHrDKBz.d.cts +129 -0
- package/dist/content/index.cjs +914 -37
- 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 +914 -37
- 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 +1192 -39
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +64 -2
- package/dist/hooks/index.d.ts +64 -2
- package/dist/hooks/index.js +1188 -40
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +1230 -37
- 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 +1201 -38
- package/dist/index.js.map +1 -1
- package/dist/providers/index.cjs +1505 -37
- package/dist/providers/index.cjs.map +1 -1
- package/dist/providers/index.d.cts +115 -8
- package/dist/providers/index.d.ts +115 -8
- package/dist/providers/index.js +1478 -38
- package/dist/providers/index.js.map +1 -1
- package/package.json +11 -1
package/dist/providers/index.cjs
CHANGED
|
@@ -184,6 +184,14 @@ var ProviderError = class extends AIError {
|
|
|
184
184
|
providerId;
|
|
185
185
|
};
|
|
186
186
|
|
|
187
|
+
// src/core/errors/groq-error.ts
|
|
188
|
+
var GroqError = class extends AIError {
|
|
189
|
+
constructor(type, message, cause, metadata = {}) {
|
|
190
|
+
super(type, message, cause, metadata);
|
|
191
|
+
this.name = "GroqError";
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
187
195
|
// src/core/errors/error-classifier.ts
|
|
188
196
|
var DEFAULT_RETRYABLE_TYPES = /* @__PURE__ */ new Set([
|
|
189
197
|
"NETWORK_ERROR" /* NETWORK_ERROR */,
|
|
@@ -532,6 +540,56 @@ function isSseDoneMarker(payload) {
|
|
|
532
540
|
return payload === SSE_DONE_MARKER;
|
|
533
541
|
}
|
|
534
542
|
|
|
543
|
+
// src/core/parsers/streaming-response.parser.ts
|
|
544
|
+
var StreamingResponseParser = class {
|
|
545
|
+
constructor(callbacks, extractDelta) {
|
|
546
|
+
this.callbacks = callbacks;
|
|
547
|
+
this.extractDelta = extractDelta;
|
|
548
|
+
}
|
|
549
|
+
callbacks;
|
|
550
|
+
extractDelta;
|
|
551
|
+
decoder = new TextDecoder();
|
|
552
|
+
async parse(stream) {
|
|
553
|
+
const reader = stream.getReader();
|
|
554
|
+
const contentChunks = [];
|
|
555
|
+
let buffer = "";
|
|
556
|
+
const consumeLine = (rawLine) => {
|
|
557
|
+
const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
|
|
558
|
+
const trimmed = line.trim();
|
|
559
|
+
if (trimmed.length === 0 || !isSseDataLine(trimmed)) return;
|
|
560
|
+
const payload = extractSseDataPayload(trimmed);
|
|
561
|
+
if (isSseDoneMarker(payload)) return;
|
|
562
|
+
const content = this.extractDelta(payload);
|
|
563
|
+
if (content !== null) {
|
|
564
|
+
contentChunks.push(content);
|
|
565
|
+
this.callbacks.onChunk(content);
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
try {
|
|
569
|
+
while (true) {
|
|
570
|
+
const { done, value } = await reader.read();
|
|
571
|
+
if (done) break;
|
|
572
|
+
buffer += this.decoder.decode(value, { stream: true });
|
|
573
|
+
const lines = buffer.split("\n");
|
|
574
|
+
buffer = lines.pop() ?? "";
|
|
575
|
+
for (const line of lines) consumeLine(line);
|
|
576
|
+
}
|
|
577
|
+
buffer += this.decoder.decode();
|
|
578
|
+
if (buffer.length > 0) consumeLine(buffer);
|
|
579
|
+
} catch (error) {
|
|
580
|
+
if (error instanceof AIError) throw error;
|
|
581
|
+
throw new AIError(
|
|
582
|
+
"NETWORK_ERROR" /* NETWORK_ERROR */,
|
|
583
|
+
"Stream was interrupted",
|
|
584
|
+
error instanceof Error ? error : void 0
|
|
585
|
+
);
|
|
586
|
+
} finally {
|
|
587
|
+
reader.releaseLock();
|
|
588
|
+
}
|
|
589
|
+
return contentChunks.join("");
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
|
|
535
593
|
// src/core/parsers/json-content-extractor.ts
|
|
536
594
|
function extractJsonFromCodeFence(content) {
|
|
537
595
|
const match = content.match(JSON_CODE_BLOCK_PATTERN);
|
|
@@ -1190,6 +1248,12 @@ function calculateExponentialBackoff(params) {
|
|
|
1190
1248
|
}
|
|
1191
1249
|
|
|
1192
1250
|
// src/core/constants/identifier.constants.ts
|
|
1251
|
+
var MESSAGE_ID_PREFIX = "msg-";
|
|
1252
|
+
var CHAT_MESSAGE_ID_SUFFIX_LENGTH = 9;
|
|
1253
|
+
var CACHE_KEY_TYPE_COMPLETION = "completion";
|
|
1254
|
+
var CACHE_KEY_TYPE_CHAT = "chat";
|
|
1255
|
+
var USER_ROLE = "user";
|
|
1256
|
+
var ASSISTANT_ROLE = "assistant";
|
|
1193
1257
|
var QUEUE_PRIORITY_USER_REQUEST = 10;
|
|
1194
1258
|
var DEFAULT_RETRY_MAX_ATTEMPTS = 3;
|
|
1195
1259
|
var DEFAULT_RETRY_INITIAL_DELAY_MS = 1e3;
|
|
@@ -1363,6 +1427,27 @@ var RequestDeduplicator = class {
|
|
|
1363
1427
|
}
|
|
1364
1428
|
};
|
|
1365
1429
|
|
|
1430
|
+
// src/core/utils/api-key-validator.ts
|
|
1431
|
+
var DEFAULT_API_KEY_RULE = {
|
|
1432
|
+
minLength: 10
|
|
1433
|
+
};
|
|
1434
|
+
function validateApiKey(apiKey, rule = DEFAULT_API_KEY_RULE) {
|
|
1435
|
+
if (!apiKey) {
|
|
1436
|
+
return { valid: false, reason: "API key is required" };
|
|
1437
|
+
}
|
|
1438
|
+
const trimmed = apiKey.trim();
|
|
1439
|
+
if (trimmed.length === 0) {
|
|
1440
|
+
return { valid: false, reason: "API key cannot be empty" };
|
|
1441
|
+
}
|
|
1442
|
+
if (trimmed.length < rule.minLength) {
|
|
1443
|
+
return {
|
|
1444
|
+
valid: false,
|
|
1445
|
+
reason: `API key must be at least ${rule.minLength} characters`
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
return { valid: true };
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1366
1451
|
// src/providers/groq/groq.constants.ts
|
|
1367
1452
|
var GROQ_MODELS = {
|
|
1368
1453
|
LLAMA_3_1_8B_INSTANT: "llama-3.1-8b-instant",
|
|
@@ -1386,12 +1471,22 @@ var DEFAULT_GENERATION_CONFIG = {
|
|
|
1386
1471
|
maxTokens: 1024,
|
|
1387
1472
|
topP: 1
|
|
1388
1473
|
};
|
|
1474
|
+
var DEFAULT_MODELS = {
|
|
1475
|
+
TEXT: GROQ_MODELS.LLAMA_3_1_8B_INSTANT,
|
|
1476
|
+
FAST: GROQ_MODELS.LLAMA_3_1_8B_INSTANT,
|
|
1477
|
+
EXPERIMENTAL: GROQ_MODELS.GPT_OSS_20B
|
|
1478
|
+
};
|
|
1389
1479
|
var GROQ_BASE_URL = "https://api.groq.com/openai/v1";
|
|
1480
|
+
var DEFAULT_BASE_URL = GROQ_BASE_URL;
|
|
1390
1481
|
var CHAT_COMPLETIONS_PATH = "/chat/completions";
|
|
1482
|
+
var API_ENDPOINTS = {
|
|
1483
|
+
CHAT: CHAT_COMPLETIONS_PATH
|
|
1484
|
+
};
|
|
1391
1485
|
var GROQ_TIMEOUTS = {
|
|
1392
1486
|
DEFAULT: 3e4,
|
|
1393
1487
|
STREAMING: 6e4
|
|
1394
1488
|
};
|
|
1489
|
+
var TIMEOUTS = GROQ_TIMEOUTS;
|
|
1395
1490
|
var HTTP_HEADERS = {
|
|
1396
1491
|
CONTENT_TYPE: "Content-Type",
|
|
1397
1492
|
APPLICATION_JSON: "application/json",
|
|
@@ -1450,13 +1545,65 @@ var GroqChatRequestBuilder = class _GroqChatRequestBuilder {
|
|
|
1450
1545
|
}
|
|
1451
1546
|
};
|
|
1452
1547
|
|
|
1548
|
+
// src/providers/groq/groq-config-store.ts
|
|
1549
|
+
var GroqConfigStore = class {
|
|
1550
|
+
config = null;
|
|
1551
|
+
initialize(config) {
|
|
1552
|
+
const validation = validateApiKey(config.apiKey, { minLength: 1 });
|
|
1553
|
+
if (!validation.valid) {
|
|
1554
|
+
throw new GroqError("INVALID_API_KEY" /* INVALID_API_KEY */, validation.reason ?? "Invalid API key");
|
|
1555
|
+
}
|
|
1556
|
+
const normalized = {
|
|
1557
|
+
apiKey: config.apiKey.trim(),
|
|
1558
|
+
baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
|
|
1559
|
+
timeoutMs: config.timeoutMs ?? TIMEOUTS.DEFAULT,
|
|
1560
|
+
...config.models !== void 0 ? { models: config.models } : {},
|
|
1561
|
+
...config.textModel !== void 0 ? { textModel: config.textModel } : {}
|
|
1562
|
+
};
|
|
1563
|
+
this.config = normalized;
|
|
1564
|
+
return normalized;
|
|
1565
|
+
}
|
|
1566
|
+
get() {
|
|
1567
|
+
if (!this.config) {
|
|
1568
|
+
throw new GroqError(
|
|
1569
|
+
"MISSING_CONFIG" /* MISSING_CONFIG */,
|
|
1570
|
+
"Client not initialized. Call configureProvider first."
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1573
|
+
return this.config;
|
|
1574
|
+
}
|
|
1575
|
+
getOrNull() {
|
|
1576
|
+
return this.config;
|
|
1577
|
+
}
|
|
1578
|
+
isInitialized() {
|
|
1579
|
+
return this.config !== null;
|
|
1580
|
+
}
|
|
1581
|
+
setApiKey(apiKey) {
|
|
1582
|
+
const current = this.get();
|
|
1583
|
+
const validation = validateApiKey(apiKey, { minLength: 1 });
|
|
1584
|
+
if (!validation.valid) {
|
|
1585
|
+
throw new GroqError("INVALID_API_KEY" /* INVALID_API_KEY */, validation.reason ?? "Invalid API key");
|
|
1586
|
+
}
|
|
1587
|
+
this.config = { ...current, apiKey: apiKey.trim() };
|
|
1588
|
+
}
|
|
1589
|
+
reset() {
|
|
1590
|
+
this.config = null;
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
|
|
1453
1594
|
// src/providers/groq/groq-http-transport.ts
|
|
1454
1595
|
var GroqHttpTransport = class {
|
|
1455
|
-
constructor(
|
|
1456
|
-
this.
|
|
1596
|
+
constructor(configSource) {
|
|
1597
|
+
this.configSource = configSource;
|
|
1457
1598
|
}
|
|
1458
|
-
|
|
1599
|
+
configSource;
|
|
1459
1600
|
pendingAbortControllers = /* @__PURE__ */ new Set();
|
|
1601
|
+
getConfig() {
|
|
1602
|
+
if ("get" in this.configSource && typeof this.configSource.get === "function") {
|
|
1603
|
+
return this.configSource.get();
|
|
1604
|
+
}
|
|
1605
|
+
return this.configSource;
|
|
1606
|
+
}
|
|
1460
1607
|
cancelPendingRequests() {
|
|
1461
1608
|
for (const controller of this.pendingAbortControllers) {
|
|
1462
1609
|
controller.abort();
|
|
@@ -1471,7 +1618,7 @@ var GroqHttpTransport = class {
|
|
|
1471
1618
|
}
|
|
1472
1619
|
async streamChatCompletion(request, options = {}) {
|
|
1473
1620
|
const url = `${this.baseUrl()}${CHAT_COMPLETIONS_PATH}`;
|
|
1474
|
-
const timeout = this.
|
|
1621
|
+
const timeout = this.getConfig().timeoutMs ?? GROQ_TIMEOUTS.STREAMING;
|
|
1475
1622
|
const controller = new AbortController();
|
|
1476
1623
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1477
1624
|
const onExternalAbort = () => controller.abort();
|
|
@@ -1498,11 +1645,11 @@ var GroqHttpTransport = class {
|
|
|
1498
1645
|
}
|
|
1499
1646
|
}
|
|
1500
1647
|
baseUrl() {
|
|
1501
|
-
return this.
|
|
1648
|
+
return this.getConfig().baseUrl ?? GROQ_BASE_URL;
|
|
1502
1649
|
}
|
|
1503
1650
|
async request(endpoint, body) {
|
|
1504
1651
|
const url = `${this.baseUrl()}${endpoint}`;
|
|
1505
|
-
const timeout = this.
|
|
1652
|
+
const timeout = this.getConfig().timeoutMs ?? GROQ_TIMEOUTS.DEFAULT;
|
|
1506
1653
|
const controller = new AbortController();
|
|
1507
1654
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1508
1655
|
this.pendingAbortControllers.add(controller);
|
|
@@ -1525,7 +1672,7 @@ var GroqHttpTransport = class {
|
|
|
1525
1672
|
buildHeaders() {
|
|
1526
1673
|
return {
|
|
1527
1674
|
[HTTP_HEADERS.CONTENT_TYPE]: HTTP_HEADERS.APPLICATION_JSON,
|
|
1528
|
-
[HTTP_HEADERS.AUTHORIZATION]: `${HTTP_HEADERS.BEARER_PREFIX}${this.
|
|
1675
|
+
[HTTP_HEADERS.AUTHORIZATION]: `${HTTP_HEADERS.BEARER_PREFIX}${this.getConfig().apiKey}`
|
|
1529
1676
|
};
|
|
1530
1677
|
}
|
|
1531
1678
|
async throwFromErrorResponse(response) {
|
|
@@ -1627,21 +1774,40 @@ var CompositeExecutor = class {
|
|
|
1627
1774
|
|
|
1628
1775
|
// src/providers/groq/groq-http-client.ts
|
|
1629
1776
|
var GroqHttpClient = class {
|
|
1777
|
+
configStore;
|
|
1630
1778
|
transport;
|
|
1631
1779
|
executor;
|
|
1632
|
-
constructor(
|
|
1633
|
-
|
|
1780
|
+
constructor(configOrDeps, maybeDeps = {}) {
|
|
1781
|
+
const isConfig = typeof configOrDeps === "object" && configOrDeps !== null && "apiKey" in configOrDeps && typeof configOrDeps.apiKey === "string";
|
|
1782
|
+
const deps = isConfig ? maybeDeps : configOrDeps ?? {};
|
|
1783
|
+
this.configStore = deps.configStore ?? new GroqConfigStore();
|
|
1784
|
+
if (isConfig) {
|
|
1785
|
+
this.configStore.initialize(configOrDeps);
|
|
1786
|
+
}
|
|
1787
|
+
this.transport = deps.transport ?? new GroqHttpTransport(this.configStore);
|
|
1634
1788
|
const retryManager2 = deps.retryManager ?? new RetryManager();
|
|
1635
1789
|
const queue = deps.queue ?? new RequestQueue();
|
|
1636
1790
|
const deduplicator = deps.deduplicator ?? new RequestDeduplicator();
|
|
1637
1791
|
this.executor = new CompositeExecutor([
|
|
1638
1792
|
new DedupeExecutor(deduplicator, {
|
|
1639
|
-
generateKey: (request) => deduplicatorKey(request,
|
|
1793
|
+
generateKey: (request) => deduplicatorKey(request, this.configStore.isInitialized() ? this.configStore.get().apiKey : "")
|
|
1640
1794
|
}),
|
|
1641
1795
|
new RetryExecutor(retryManager2),
|
|
1642
1796
|
new QueueExecutor(queue, QUEUE_PRIORITY_USER_REQUEST)
|
|
1643
1797
|
]);
|
|
1644
1798
|
}
|
|
1799
|
+
initialize(config) {
|
|
1800
|
+
this.configStore.initialize(config);
|
|
1801
|
+
}
|
|
1802
|
+
isInitialized() {
|
|
1803
|
+
return this.configStore.isInitialized();
|
|
1804
|
+
}
|
|
1805
|
+
getApiKey() {
|
|
1806
|
+
return this.configStore.get().apiKey;
|
|
1807
|
+
}
|
|
1808
|
+
setApiKey(apiKey) {
|
|
1809
|
+
this.configStore.setApiKey(apiKey);
|
|
1810
|
+
}
|
|
1645
1811
|
cancelPendingRequests() {
|
|
1646
1812
|
this.transport.cancelPendingRequests();
|
|
1647
1813
|
}
|
|
@@ -1654,6 +1820,10 @@ var GroqHttpClient = class {
|
|
|
1654
1820
|
streamChatCompletion(request, options) {
|
|
1655
1821
|
return this.transport.streamChatCompletion(request, options);
|
|
1656
1822
|
}
|
|
1823
|
+
reset() {
|
|
1824
|
+
this.transport.cancelPendingRequests();
|
|
1825
|
+
this.configStore.reset();
|
|
1826
|
+
}
|
|
1657
1827
|
};
|
|
1658
1828
|
function deduplicatorKey(request, apiKey) {
|
|
1659
1829
|
const { model, messages, stream: _stream, ...rest } = request;
|
|
@@ -2385,39 +2555,811 @@ function createFalProvider(config) {
|
|
|
2385
2555
|
return new FalProvider(config);
|
|
2386
2556
|
}
|
|
2387
2557
|
|
|
2388
|
-
// src/providers/pruna/
|
|
2389
|
-
var
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2558
|
+
// src/providers/pruna/client/core/constants/limits.ts
|
|
2559
|
+
var DEFAULT_ASPECT_RATIO = "16:9";
|
|
2560
|
+
var P_VIDEO_DEFAULTS = {
|
|
2561
|
+
duration: 5,
|
|
2562
|
+
resolution: "720p",
|
|
2563
|
+
fps: 24,
|
|
2564
|
+
draft: false,
|
|
2565
|
+
promptUpsampling: true
|
|
2566
|
+
};
|
|
2567
|
+
var POLL_DEFAULTS = {
|
|
2568
|
+
intervalMs: 3e3,
|
|
2569
|
+
maxAttempts: 120,
|
|
2570
|
+
maxIntervalMs: 1e4,
|
|
2571
|
+
backoffBase: 1.5,
|
|
2572
|
+
jitterPercent: 0.1
|
|
2573
|
+
};
|
|
2574
|
+
var DEFAULT_DEDUPLICATOR_TTL_MS = 3e4;
|
|
2575
|
+
var DEDUPLICATOR_CLEANUP_GRACE_MS = 100;
|
|
2576
|
+
|
|
2577
|
+
// src/providers/pruna/client/core/constants/network.ts
|
|
2578
|
+
var HTTPS_PREFIX = "https://";
|
|
2579
|
+
var HTTP_PREFIX = "http://";
|
|
2580
|
+
var BASE64_MARKER = "base64,";
|
|
2581
|
+
var PRUNA_BASE_URL = "https://api.pruna.ai";
|
|
2582
|
+
var PRUNA_PREDICTIONS_URL = `${PRUNA_BASE_URL}/v1/predictions`;
|
|
2583
|
+
var PRUNA_FILES_URL = `${PRUNA_BASE_URL}/v1/files`;
|
|
2584
|
+
var AUTH_FAILURE_STATUSES = [401, 403];
|
|
2585
|
+
var MIN_API_KEY_LENGTH = 1;
|
|
2586
|
+
var MAX_API_KEY_LENGTH = 256;
|
|
2587
|
+
|
|
2588
|
+
// src/providers/pruna/client/core/constants/mime-types.ts
|
|
2589
|
+
var MIME_PNG = "image/png";
|
|
2590
|
+
var MIME_JPEG = "image/jpeg";
|
|
2591
|
+
var MIME_WEBP = "image/webp";
|
|
2592
|
+
var DEFAULT_IMAGE_MIME = MIME_PNG;
|
|
2593
|
+
var MIME_FILE_EXTENSION = {
|
|
2594
|
+
[MIME_PNG]: "png",
|
|
2595
|
+
[MIME_JPEG]: "jpg",
|
|
2596
|
+
[MIME_WEBP]: "webp"
|
|
2597
|
+
};
|
|
2598
|
+
var IMAGE_SIGNATURES = {
|
|
2599
|
+
PNG: [137, 80],
|
|
2600
|
+
JPEG: [255, 216],
|
|
2601
|
+
WEBP_RIFF: [82, 73]
|
|
2602
|
+
};
|
|
2603
|
+
|
|
2604
|
+
// src/providers/pruna/client/core/errors/cancellation-error.ts
|
|
2605
|
+
var CANCELLATION_MESSAGE = "Request cancelled by user";
|
|
2606
|
+
var CancellationError = class extends Error {
|
|
2607
|
+
constructor(message = CANCELLATION_MESSAGE) {
|
|
2608
|
+
super(message);
|
|
2609
|
+
this.name = "CancellationError";
|
|
2610
|
+
}
|
|
2611
|
+
};
|
|
2612
|
+
|
|
2613
|
+
// src/providers/pruna/client/core/errors/authentication-error.ts
|
|
2614
|
+
var AUTHENTICATION_MESSAGE = "Authentication failed. Please check your API key.";
|
|
2615
|
+
var AuthenticationError = class extends Error {
|
|
2616
|
+
constructor(message = AUTHENTICATION_MESSAGE) {
|
|
2617
|
+
super(message);
|
|
2618
|
+
this.name = "AuthenticationError";
|
|
2619
|
+
}
|
|
2620
|
+
};
|
|
2621
|
+
|
|
2622
|
+
// src/providers/pruna/client/core/errors/timeout-error.ts
|
|
2623
|
+
var TIMEOUT_MESSAGE = "Generation timed out. Maximum polling attempts reached.";
|
|
2624
|
+
var TimeoutError = class extends Error {
|
|
2625
|
+
constructor(message = TIMEOUT_MESSAGE) {
|
|
2626
|
+
super(message);
|
|
2627
|
+
this.name = "TimeoutError";
|
|
2394
2628
|
}
|
|
2395
|
-
|
|
2629
|
+
};
|
|
2630
|
+
|
|
2631
|
+
// src/providers/pruna/client/core/errors/validation-error.ts
|
|
2632
|
+
var ValidationError = class extends Error {
|
|
2633
|
+
field;
|
|
2634
|
+
reason;
|
|
2635
|
+
receivedValue;
|
|
2636
|
+
constructor(context) {
|
|
2637
|
+
super(`Invalid ${context.field}: ${context.reason}`);
|
|
2638
|
+
this.name = "ValidationError";
|
|
2639
|
+
this.field = context.field;
|
|
2640
|
+
this.reason = context.reason;
|
|
2641
|
+
this.receivedValue = context.receivedValue;
|
|
2642
|
+
}
|
|
2643
|
+
};
|
|
2644
|
+
|
|
2645
|
+
// src/providers/pruna/client/core/utils/base64.ts
|
|
2646
|
+
var globalScope = globalThis;
|
|
2647
|
+
var hasBuffer = typeof globalScope.Buffer?.from === "function";
|
|
2648
|
+
function base64ToBytes(raw) {
|
|
2649
|
+
if (hasBuffer) {
|
|
2650
|
+
const bufferFactory = globalScope.Buffer;
|
|
2651
|
+
if (!bufferFactory) {
|
|
2652
|
+
throw new Error("Buffer unavailable despite detection flag");
|
|
2653
|
+
}
|
|
2654
|
+
const buf = bufferFactory.from(raw, "base64");
|
|
2655
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
2656
|
+
}
|
|
2657
|
+
const decoded = atob(raw);
|
|
2658
|
+
return Uint8Array.from(decoded, (char) => char.charCodeAt(0));
|
|
2396
2659
|
}
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
if (
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2660
|
+
|
|
2661
|
+
// src/providers/pruna/client/core/utils/mime-detector.ts
|
|
2662
|
+
var MIN_SIGNATURE_BYTES = 2;
|
|
2663
|
+
function matchesSignature(bytes, signature) {
|
|
2664
|
+
if (bytes.length < signature.length) return false;
|
|
2665
|
+
return signature.every((value, index) => bytes[index] === value);
|
|
2666
|
+
}
|
|
2667
|
+
function detectImageMime(bytes) {
|
|
2668
|
+
if (bytes.length < MIN_SIGNATURE_BYTES) return DEFAULT_IMAGE_MIME;
|
|
2669
|
+
if (matchesSignature(bytes, IMAGE_SIGNATURES.PNG)) return MIME_PNG;
|
|
2670
|
+
if (matchesSignature(bytes, IMAGE_SIGNATURES.JPEG)) return MIME_JPEG;
|
|
2671
|
+
if (matchesSignature(bytes, IMAGE_SIGNATURES.WEBP_RIFF)) return MIME_WEBP;
|
|
2672
|
+
return DEFAULT_IMAGE_MIME;
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
// src/providers/pruna/client/core/utils/api-error-parser.ts
|
|
2676
|
+
async function parseApiError(response, fallback) {
|
|
2677
|
+
const payload = await response.json().catch(() => ({ message: response.statusText }));
|
|
2678
|
+
const message = payload.message ?? `${fallback}: ${response.status}`;
|
|
2679
|
+
const error = new Error(message);
|
|
2680
|
+
error.statusCode = response.status;
|
|
2681
|
+
return error;
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
// src/providers/pruna/client/core/protocol/http-status.ts
|
|
2685
|
+
function isAuthFailureStatus(status) {
|
|
2686
|
+
return AUTH_FAILURE_STATUSES.includes(status);
|
|
2687
|
+
}
|
|
2688
|
+
|
|
2689
|
+
// src/providers/pruna/client/core/protocol/job-status.ts
|
|
2690
|
+
var TERMINAL_SUCCESS_STATUSES = ["succeeded", "completed"];
|
|
2691
|
+
var TERMINAL_FAILURE_STATUSES = ["failed"];
|
|
2692
|
+
function isTerminalSuccessStatus(status) {
|
|
2693
|
+
if (!status) return false;
|
|
2694
|
+
return TERMINAL_SUCCESS_STATUSES.includes(status);
|
|
2695
|
+
}
|
|
2696
|
+
function isTerminalFailureStatus(status) {
|
|
2697
|
+
if (!status) return false;
|
|
2698
|
+
return TERMINAL_FAILURE_STATUSES.includes(status);
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2701
|
+
// src/providers/pruna/client/core/protocol/abort-signal-classifier.ts
|
|
2702
|
+
function isAbortError(err) {
|
|
2703
|
+
if (err instanceof DOMException && err.code === DOMException.ABORT_ERR) return true;
|
|
2704
|
+
if (err instanceof Error && err.name === "AbortError") return true;
|
|
2705
|
+
return false;
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
// src/providers/pruna/client/core/protocol/pruna-url-builder.ts
|
|
2709
|
+
function isAbsoluteHttpUrl(value) {
|
|
2710
|
+
return value.startsWith(HTTPS_PREFIX) || value.startsWith(HTTP_PREFIX);
|
|
2711
|
+
}
|
|
2712
|
+
function isHttpsUrl(value) {
|
|
2713
|
+
return value.startsWith(HTTPS_PREFIX);
|
|
2714
|
+
}
|
|
2715
|
+
function buildPrunaApiUrl(pathOrUrl) {
|
|
2716
|
+
if (isAbsoluteHttpUrl(pathOrUrl)) return pathOrUrl;
|
|
2717
|
+
return `${PRUNA_BASE_URL}${pathOrUrl}`;
|
|
2718
|
+
}
|
|
2719
|
+
function buildFileUrlById(fileId) {
|
|
2720
|
+
return `${PRUNA_FILES_URL}/${fileId}`;
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
// src/providers/pruna/client/core/math/exponential-backoff.ts
|
|
2724
|
+
function calculateExponentialBackoff2(inputs) {
|
|
2725
|
+
const {
|
|
2726
|
+
attempt,
|
|
2727
|
+
baseIntervalMs,
|
|
2728
|
+
maxIntervalMs = POLL_DEFAULTS.maxIntervalMs,
|
|
2729
|
+
jitterPercent = POLL_DEFAULTS.jitterPercent,
|
|
2730
|
+
growthBase = POLL_DEFAULTS.backoffBase
|
|
2731
|
+
} = inputs;
|
|
2732
|
+
const safeAttempt = Math.max(0, attempt);
|
|
2733
|
+
const safeBase = Math.max(0, baseIntervalMs);
|
|
2734
|
+
const exponentialDelay = Math.min(safeBase * Math.pow(growthBase, safeAttempt), maxIntervalMs);
|
|
2735
|
+
const jitter = exponentialDelay * jitterPercent * Math.random();
|
|
2736
|
+
return exponentialDelay + jitter;
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2739
|
+
// src/providers/pruna/client/core/utils/uri-resolver.ts
|
|
2740
|
+
var uriCache = /* @__PURE__ */ new WeakMap();
|
|
2741
|
+
function stripBase64Prefix(image) {
|
|
2742
|
+
if (isHttpsUrl(image)) return image;
|
|
2743
|
+
const base64Index = image.indexOf(BASE64_MARKER);
|
|
2744
|
+
return base64Index !== -1 ? image.slice(base64Index + BASE64_MARKER.length) : image;
|
|
2745
|
+
}
|
|
2746
|
+
function readOutput(output) {
|
|
2747
|
+
if (typeof output === "string") return output;
|
|
2748
|
+
if (Array.isArray(output) && output.length > 0) return output[0] ?? null;
|
|
2749
|
+
if (output !== null && typeof output === "object" && "url" in output) {
|
|
2750
|
+
return output.url;
|
|
2751
|
+
}
|
|
2752
|
+
return null;
|
|
2753
|
+
}
|
|
2754
|
+
function extractUri(data) {
|
|
2755
|
+
const cached = uriCache.get(data);
|
|
2756
|
+
if (cached !== void 0) return cached;
|
|
2757
|
+
if (!isTerminalSuccessStatus(data.status)) {
|
|
2758
|
+
uriCache.set(data, null);
|
|
2759
|
+
return null;
|
|
2760
|
+
}
|
|
2761
|
+
const result = data.generation_url ?? readOutput(data.output) ?? data.video_url ?? data.data ?? null;
|
|
2762
|
+
uriCache.set(data, result);
|
|
2763
|
+
return result;
|
|
2764
|
+
}
|
|
2765
|
+
function resolveUri(uri) {
|
|
2766
|
+
return uri.startsWith("/") ? `${PRUNA_BASE_URL}${uri}` : uri;
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
// src/providers/pruna/client/core/services/pruna-client.service.ts
|
|
2770
|
+
function buildFileExtension(mime) {
|
|
2771
|
+
return MIME_FILE_EXTENSION[mime] ?? "bin";
|
|
2772
|
+
}
|
|
2773
|
+
async function uploadImage(base64OrUrl, apiKey, onProgress) {
|
|
2774
|
+
if (isHttpsUrl(base64OrUrl)) return base64OrUrl;
|
|
2775
|
+
if (base64OrUrl.startsWith(HTTP_PREFIX)) {
|
|
2776
|
+
throw new Error("Only HTTPS URLs are supported for security.");
|
|
2777
|
+
}
|
|
2778
|
+
onProgress?.("uploading");
|
|
2779
|
+
const raw = stripBase64Prefix(base64OrUrl);
|
|
2780
|
+
let bytes;
|
|
2781
|
+
try {
|
|
2782
|
+
bytes = base64ToBytes(raw);
|
|
2783
|
+
} catch {
|
|
2784
|
+
throw new Error("Invalid image format. Provide base64 or a valid HTTPS URL.");
|
|
2785
|
+
}
|
|
2786
|
+
const mime = detectImageMime(bytes);
|
|
2787
|
+
const buffer = bytes.buffer.slice(
|
|
2788
|
+
bytes.byteOffset,
|
|
2789
|
+
bytes.byteOffset + bytes.byteLength
|
|
2790
|
+
);
|
|
2791
|
+
const blob = new Blob([buffer], { type: mime });
|
|
2792
|
+
const formData = new FormData();
|
|
2793
|
+
formData.append("content", blob, `upload.${buildFileExtension(mime)}`);
|
|
2794
|
+
const res = await fetch(PRUNA_FILES_URL, {
|
|
2795
|
+
method: "POST",
|
|
2796
|
+
headers: { apikey: apiKey },
|
|
2797
|
+
body: formData
|
|
2798
|
+
});
|
|
2799
|
+
if (!res.ok) {
|
|
2800
|
+
throw await parseApiError(res, "File upload error");
|
|
2801
|
+
}
|
|
2802
|
+
const data = await res.json();
|
|
2803
|
+
return data.urls?.get ?? buildFileUrlById(data.id ?? "");
|
|
2804
|
+
}
|
|
2805
|
+
async function submitPrediction(model, input, apiKey, signal, onProgress) {
|
|
2806
|
+
onProgress?.("predicting");
|
|
2807
|
+
const res = await fetch(PRUNA_PREDICTIONS_URL, {
|
|
2808
|
+
method: "POST",
|
|
2809
|
+
headers: {
|
|
2810
|
+
apikey: apiKey,
|
|
2811
|
+
Model: model,
|
|
2812
|
+
"Try-Sync": "true",
|
|
2813
|
+
"Content-Type": "application/json"
|
|
2814
|
+
},
|
|
2815
|
+
body: JSON.stringify({ input }),
|
|
2816
|
+
signal
|
|
2817
|
+
});
|
|
2818
|
+
if (!res.ok) {
|
|
2819
|
+
throw await parseApiError(res, "API error");
|
|
2820
|
+
}
|
|
2821
|
+
return res.json();
|
|
2822
|
+
}
|
|
2823
|
+
var GenerationFailedError = class extends Error {
|
|
2824
|
+
constructor(message) {
|
|
2825
|
+
super(message);
|
|
2826
|
+
this.name = "GenerationFailedError";
|
|
2827
|
+
}
|
|
2828
|
+
};
|
|
2829
|
+
async function attemptPoll(fullUrl, apiKey, signal) {
|
|
2830
|
+
let res;
|
|
2831
|
+
try {
|
|
2832
|
+
res = await fetch(fullUrl, { headers: { apikey: apiKey }, signal });
|
|
2833
|
+
} catch (err) {
|
|
2834
|
+
if (isAbortError(err)) throw new CancellationError();
|
|
2835
|
+
return { outcome: "transient-failure" };
|
|
2836
|
+
}
|
|
2837
|
+
if (!res.ok) {
|
|
2838
|
+
if (isAuthFailureStatus(res.status)) throw new AuthenticationError();
|
|
2839
|
+
return { outcome: "transient-failure" };
|
|
2840
|
+
}
|
|
2841
|
+
let data;
|
|
2842
|
+
try {
|
|
2843
|
+
data = await res.json();
|
|
2844
|
+
} catch {
|
|
2845
|
+
return { outcome: "transient-failure" };
|
|
2846
|
+
}
|
|
2847
|
+
if (isTerminalSuccessStatus(data.status)) {
|
|
2848
|
+
const uri = extractUri(data);
|
|
2849
|
+
if (uri) return { outcome: "succeeded", uri: resolveUri(uri) };
|
|
2850
|
+
return { outcome: "transient-failure" };
|
|
2851
|
+
}
|
|
2852
|
+
if (isTerminalFailureStatus(data.status)) {
|
|
2853
|
+
throw new GenerationFailedError(data.error ?? "Generation failed during processing.");
|
|
2854
|
+
}
|
|
2855
|
+
return { outcome: "continue" };
|
|
2856
|
+
}
|
|
2857
|
+
async function pollForResult(pollUrl, apiKey, maxAttempts = POLL_DEFAULTS.maxAttempts, intervalMs = POLL_DEFAULTS.intervalMs, signal, onProgress) {
|
|
2858
|
+
const fullUrl = isAbsoluteHttpUrl(pollUrl) ? pollUrl : buildPrunaApiUrl(pollUrl);
|
|
2859
|
+
const controller = new AbortController();
|
|
2860
|
+
const onExternalAbort = () => controller.abort();
|
|
2861
|
+
signal?.addEventListener("abort", onExternalAbort);
|
|
2862
|
+
try {
|
|
2863
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
2864
|
+
if (signal?.aborted) throw new CancellationError();
|
|
2865
|
+
const delay = calculateExponentialBackoff2({ attempt: i, baseIntervalMs: intervalMs });
|
|
2866
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2867
|
+
if (signal?.aborted) throw new CancellationError();
|
|
2868
|
+
onProgress?.("polling", i + 1);
|
|
2869
|
+
const result = await attemptPoll(fullUrl, apiKey, controller.signal);
|
|
2870
|
+
if (result.outcome === "succeeded" && result.uri) {
|
|
2871
|
+
return result.uri;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
throw new TimeoutError();
|
|
2875
|
+
} finally {
|
|
2876
|
+
signal?.removeEventListener("abort", onExternalAbort);
|
|
2877
|
+
controller.abort();
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2881
|
+
// src/providers/pruna/client/core/math/comparison-hash.ts
|
|
2882
|
+
function sortKeysDeep(value) {
|
|
2883
|
+
if (Array.isArray(value)) {
|
|
2884
|
+
return value.map(sortKeysDeep);
|
|
2885
|
+
}
|
|
2886
|
+
if (value !== null && typeof value === "object") {
|
|
2887
|
+
const record = value;
|
|
2888
|
+
return Object.keys(record).sort().reduce((acc, key) => {
|
|
2889
|
+
acc[key] = sortKeysDeep(record[key]);
|
|
2890
|
+
return acc;
|
|
2891
|
+
}, {});
|
|
2892
|
+
}
|
|
2893
|
+
return value;
|
|
2894
|
+
}
|
|
2895
|
+
function hashValue(value) {
|
|
2896
|
+
if (value === null || typeof value !== "object") {
|
|
2897
|
+
return String(value);
|
|
2898
|
+
}
|
|
2899
|
+
try {
|
|
2900
|
+
return JSON.stringify(sortKeysDeep(value));
|
|
2901
|
+
} catch {
|
|
2902
|
+
return String(value);
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
function compositeHash(...values) {
|
|
2906
|
+
return values.map(hashValue).join("|");
|
|
2907
|
+
}
|
|
2908
|
+
|
|
2909
|
+
// src/providers/pruna/client/core/math/cache-key-derivation.ts
|
|
2910
|
+
function deriveGenerationCacheKey(apiKey, input) {
|
|
2911
|
+
return `${apiKey}:${compositeHash(input)}`;
|
|
2912
|
+
}
|
|
2913
|
+
|
|
2914
|
+
// src/providers/pruna/client/core/validation/api-key-validator.ts
|
|
2915
|
+
function assertValidApiKey(apiKey) {
|
|
2916
|
+
if (typeof apiKey !== "string") {
|
|
2917
|
+
throw new ValidationError({
|
|
2918
|
+
field: "apiKey",
|
|
2919
|
+
reason: "must be a string",
|
|
2920
|
+
receivedValue: typeof apiKey
|
|
2921
|
+
});
|
|
2922
|
+
}
|
|
2923
|
+
if (apiKey.length < MIN_API_KEY_LENGTH) {
|
|
2924
|
+
throw new ValidationError({
|
|
2925
|
+
field: "apiKey",
|
|
2926
|
+
reason: "must not be empty",
|
|
2927
|
+
receivedValue: apiKey
|
|
2928
|
+
});
|
|
2929
|
+
}
|
|
2930
|
+
if (apiKey.length > MAX_API_KEY_LENGTH) {
|
|
2931
|
+
throw new ValidationError({
|
|
2932
|
+
field: "apiKey",
|
|
2933
|
+
reason: `exceeds maximum length of ${MAX_API_KEY_LENGTH}`,
|
|
2934
|
+
receivedValue: apiKey.length
|
|
2935
|
+
});
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
|
|
2939
|
+
// src/providers/pruna/client/core/validation/image-source-validator.ts
|
|
2940
|
+
function classifyImageSource(source) {
|
|
2941
|
+
if (source.startsWith(HTTPS_PREFIX)) return "https-url";
|
|
2942
|
+
if (source.startsWith(HTTP_PREFIX)) return "http-url";
|
|
2943
|
+
if (source.includes(BASE64_MARKER) || /^[A-Za-z0-9+/=]+$/.test(source)) return "base64";
|
|
2944
|
+
return "unknown";
|
|
2945
|
+
}
|
|
2946
|
+
function assertSecureImageSource(image, fieldName = "image") {
|
|
2947
|
+
if (typeof image !== "string") {
|
|
2948
|
+
throw new ValidationError({
|
|
2949
|
+
field: fieldName,
|
|
2950
|
+
reason: "must be a string",
|
|
2951
|
+
receivedValue: typeof image
|
|
2952
|
+
});
|
|
2953
|
+
}
|
|
2954
|
+
const kind = classifyImageSource(image);
|
|
2955
|
+
if (kind === "http-url") {
|
|
2956
|
+
throw new ValidationError({
|
|
2957
|
+
field: fieldName,
|
|
2958
|
+
reason: "HTTP URLs are not supported; use HTTPS or a base64 data URI",
|
|
2959
|
+
receivedValue: image
|
|
2960
|
+
});
|
|
2961
|
+
}
|
|
2962
|
+
if (kind === "unknown") {
|
|
2963
|
+
throw new ValidationError({
|
|
2964
|
+
field: fieldName,
|
|
2965
|
+
reason: "must be an HTTPS URL or a base64 data URI",
|
|
2966
|
+
receivedValue: typeof image
|
|
2967
|
+
});
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
|
|
2971
|
+
// src/providers/pruna/client/core/validation/aspect-ratio-validator.ts
|
|
2972
|
+
var SUPPORTED_ASPECT_RATIOS = [
|
|
2973
|
+
"16:9",
|
|
2974
|
+
"9:16",
|
|
2975
|
+
"1:1",
|
|
2976
|
+
"4:3",
|
|
2977
|
+
"3:4",
|
|
2978
|
+
"3:2",
|
|
2979
|
+
"2:3"
|
|
2980
|
+
];
|
|
2981
|
+
function isSupportedAspectRatio(value) {
|
|
2982
|
+
return typeof value === "string" && SUPPORTED_ASPECT_RATIOS.includes(value);
|
|
2983
|
+
}
|
|
2984
|
+
function assertValidAspectRatio(value, fieldName = "aspect_ratio") {
|
|
2985
|
+
if (value === void 0 || value === null) return;
|
|
2986
|
+
if (!isSupportedAspectRatio(value)) {
|
|
2987
|
+
throw new ValidationError({
|
|
2988
|
+
field: fieldName,
|
|
2989
|
+
reason: `must be one of ${SUPPORTED_ASPECT_RATIOS.join(", ")}`,
|
|
2990
|
+
receivedValue: value
|
|
2991
|
+
});
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
// src/providers/pruna/client/core/validation/resolution-validator.ts
|
|
2996
|
+
var SUPPORTED_RESOLUTIONS = ["720p", "1080p"];
|
|
2997
|
+
function isSupportedResolution(value) {
|
|
2998
|
+
return typeof value === "string" && SUPPORTED_RESOLUTIONS.includes(value);
|
|
2999
|
+
}
|
|
3000
|
+
function assertValidResolution(value, fieldName = "resolution") {
|
|
3001
|
+
if (value === void 0 || value === null) return;
|
|
3002
|
+
if (!isSupportedResolution(value)) {
|
|
3003
|
+
throw new ValidationError({
|
|
3004
|
+
field: fieldName,
|
|
3005
|
+
reason: `must be one of ${SUPPORTED_RESOLUTIONS.join(", ")}`,
|
|
3006
|
+
receivedValue: value
|
|
3007
|
+
});
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
|
|
3011
|
+
// src/providers/pruna/client/core/validation/duration-validator.ts
|
|
3012
|
+
var MIN_VIDEO_DURATION_SECONDS = 1;
|
|
3013
|
+
var MAX_VIDEO_DURATION_SECONDS = 30;
|
|
3014
|
+
function isValidDuration(value) {
|
|
3015
|
+
return typeof value === "number" && Number.isFinite(value) && value >= MIN_VIDEO_DURATION_SECONDS && value <= MAX_VIDEO_DURATION_SECONDS && Number.isInteger(value);
|
|
3016
|
+
}
|
|
3017
|
+
function assertValidDuration(value, fieldName = "duration") {
|
|
3018
|
+
if (value === void 0 || value === null) return;
|
|
3019
|
+
if (!isValidDuration(value)) {
|
|
3020
|
+
throw new ValidationError({
|
|
3021
|
+
field: fieldName,
|
|
3022
|
+
reason: `must be an integer between ${MIN_VIDEO_DURATION_SECONDS} and ${MAX_VIDEO_DURATION_SECONDS} seconds`,
|
|
3023
|
+
receivedValue: value
|
|
3024
|
+
});
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
|
|
3028
|
+
// src/providers/pruna/client/core/validation/prompt-validator.ts
|
|
3029
|
+
var MIN_PROMPT_LENGTH = 1;
|
|
3030
|
+
var MAX_PROMPT_LENGTH = 4e3;
|
|
3031
|
+
function assertValidPrompt(value, fieldName = "prompt") {
|
|
3032
|
+
if (typeof value !== "string") {
|
|
3033
|
+
throw new ValidationError({
|
|
3034
|
+
field: fieldName,
|
|
3035
|
+
reason: "must be a string",
|
|
3036
|
+
receivedValue: typeof value
|
|
3037
|
+
});
|
|
3038
|
+
}
|
|
3039
|
+
if (value.trim().length < MIN_PROMPT_LENGTH) {
|
|
3040
|
+
throw new ValidationError({
|
|
3041
|
+
field: fieldName,
|
|
3042
|
+
reason: "must not be empty or whitespace-only",
|
|
3043
|
+
receivedValue: value
|
|
3044
|
+
});
|
|
3045
|
+
}
|
|
3046
|
+
if (value.length > MAX_PROMPT_LENGTH) {
|
|
3047
|
+
throw new ValidationError({
|
|
3048
|
+
field: fieldName,
|
|
3049
|
+
reason: `exceeds maximum length of ${MAX_PROMPT_LENGTH} characters`,
|
|
3050
|
+
receivedValue: value.length
|
|
3051
|
+
});
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
// src/providers/pruna/client/core/validation/seed-validator.ts
|
|
3056
|
+
var MIN_SEED = -2147483648;
|
|
3057
|
+
var MAX_SEED = 2147483647;
|
|
3058
|
+
function isValidSeed(value) {
|
|
3059
|
+
return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value >= MIN_SEED && value <= MAX_SEED;
|
|
3060
|
+
}
|
|
3061
|
+
function assertValidSeed(value, fieldName = "seed") {
|
|
3062
|
+
if (value === void 0 || value === null) return;
|
|
3063
|
+
if (!isValidSeed(value)) {
|
|
3064
|
+
throw new ValidationError({
|
|
3065
|
+
field: fieldName,
|
|
3066
|
+
reason: `must be an integer in [${MIN_SEED}, ${MAX_SEED}]`,
|
|
3067
|
+
receivedValue: value
|
|
3068
|
+
});
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
|
|
3072
|
+
// src/providers/pruna/client/core/protocol/input-type-guard.ts
|
|
3073
|
+
function isTextToImageInput(input) {
|
|
3074
|
+
return input.model === "p-image";
|
|
3075
|
+
}
|
|
3076
|
+
function isImageToImageInput(input) {
|
|
3077
|
+
return input.model === "p-image-edit";
|
|
3078
|
+
}
|
|
3079
|
+
function isImageToVideoInput(input) {
|
|
3080
|
+
return input.model === "p-video";
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
// src/providers/pruna/client/core/utils/request-deduplicator.ts
|
|
3084
|
+
var RequestDeduplicator2 = class {
|
|
3085
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
3086
|
+
ttl;
|
|
3087
|
+
constructor(ttl = DEFAULT_DEDUPLICATOR_TTL_MS) {
|
|
3088
|
+
this.ttl = ttl;
|
|
3089
|
+
}
|
|
3090
|
+
execute(key, fn) {
|
|
3091
|
+
const existing = this.pendingRequests.get(key);
|
|
3092
|
+
if (existing) {
|
|
3093
|
+
if (Date.now() - existing.timestamp < this.ttl) {
|
|
3094
|
+
return existing.promise;
|
|
3095
|
+
}
|
|
3096
|
+
this.pendingRequests.delete(key);
|
|
3097
|
+
}
|
|
3098
|
+
const promise = fn().finally(() => {
|
|
3099
|
+
setTimeout(() => {
|
|
3100
|
+
this.pendingRequests.delete(key);
|
|
3101
|
+
}, DEDUPLICATOR_CLEANUP_GRACE_MS);
|
|
3102
|
+
});
|
|
3103
|
+
this.pendingRequests.set(key, { promise, timestamp: Date.now() });
|
|
3104
|
+
return promise;
|
|
3105
|
+
}
|
|
3106
|
+
clear() {
|
|
3107
|
+
this.pendingRequests.clear();
|
|
3108
|
+
}
|
|
3109
|
+
size() {
|
|
3110
|
+
this.purgeExpired();
|
|
3111
|
+
return this.pendingRequests.size;
|
|
3112
|
+
}
|
|
3113
|
+
purgeExpired() {
|
|
3114
|
+
const now = Date.now();
|
|
3115
|
+
for (const [key, value] of this.pendingRequests) {
|
|
3116
|
+
if (now - value.timestamp >= this.ttl) {
|
|
3117
|
+
this.pendingRequests.delete(key);
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
};
|
|
3122
|
+
var globalDeduplicator = new RequestDeduplicator2();
|
|
3123
|
+
|
|
3124
|
+
// src/providers/pruna/client/generation/builders/text-to-image.builder.ts
|
|
3125
|
+
var TextToImageInputBuilder = class {
|
|
3126
|
+
model = "p-image";
|
|
3127
|
+
build(input, _context) {
|
|
3128
|
+
const payload = {
|
|
3129
|
+
prompt: input.prompt,
|
|
3130
|
+
aspect_ratio: input.aspect_ratio ?? DEFAULT_ASPECT_RATIO
|
|
3131
|
+
};
|
|
3132
|
+
if (input.seed !== void 0) {
|
|
3133
|
+
payload.seed = input.seed;
|
|
3134
|
+
}
|
|
3135
|
+
return Promise.resolve(payload);
|
|
3136
|
+
}
|
|
3137
|
+
};
|
|
3138
|
+
|
|
3139
|
+
// src/providers/pruna/client/generation/builders/image-to-image.builder.ts
|
|
3140
|
+
var ImageToImageInputBuilder = class {
|
|
3141
|
+
model = "p-image-edit";
|
|
3142
|
+
build(input, _context) {
|
|
3143
|
+
const payload = {
|
|
3144
|
+
images: [stripBase64Prefix(input.image)],
|
|
3145
|
+
prompt: input.prompt,
|
|
3146
|
+
aspect_ratio: input.aspect_ratio ?? DEFAULT_ASPECT_RATIO
|
|
3147
|
+
};
|
|
3148
|
+
if (input.seed !== void 0) {
|
|
3149
|
+
payload.seed = input.seed;
|
|
3150
|
+
}
|
|
3151
|
+
return Promise.resolve(payload);
|
|
3152
|
+
}
|
|
3153
|
+
};
|
|
3154
|
+
|
|
3155
|
+
// src/providers/pruna/client/generation/builders/image-to-video.builder.ts
|
|
3156
|
+
var ImageToVideoInputBuilder = class {
|
|
3157
|
+
model = "p-video";
|
|
3158
|
+
async build(input, context) {
|
|
3159
|
+
if (context.signal?.aborted) {
|
|
3160
|
+
throw new CancellationError();
|
|
3161
|
+
}
|
|
3162
|
+
const fileUrl = await uploadImage(
|
|
3163
|
+
input.image,
|
|
3164
|
+
context.apiKey,
|
|
3165
|
+
context.onProgress
|
|
3166
|
+
);
|
|
3167
|
+
return {
|
|
3168
|
+
image: fileUrl,
|
|
3169
|
+
prompt: input.prompt,
|
|
3170
|
+
duration: input.duration ?? P_VIDEO_DEFAULTS.duration,
|
|
3171
|
+
resolution: input.resolution ?? P_VIDEO_DEFAULTS.resolution,
|
|
3172
|
+
fps: P_VIDEO_DEFAULTS.fps,
|
|
3173
|
+
draft: input.draft ?? P_VIDEO_DEFAULTS.draft,
|
|
3174
|
+
aspect_ratio: input.aspect_ratio ?? DEFAULT_ASPECT_RATIO,
|
|
3175
|
+
prompt_upsampling: P_VIDEO_DEFAULTS.promptUpsampling
|
|
2412
3176
|
};
|
|
2413
|
-
return;
|
|
2414
3177
|
}
|
|
2415
|
-
|
|
3178
|
+
};
|
|
3179
|
+
|
|
3180
|
+
// src/providers/pruna/client/generation/builders/model-input-builder.ts
|
|
3181
|
+
var ModelInputBuilderRegistry = class {
|
|
3182
|
+
builders = /* @__PURE__ */ new Map();
|
|
3183
|
+
register(builder) {
|
|
3184
|
+
this.builders.set(builder.model, builder);
|
|
3185
|
+
return this;
|
|
3186
|
+
}
|
|
3187
|
+
resolve(model) {
|
|
3188
|
+
const builder = this.builders.get(model);
|
|
3189
|
+
if (!builder) {
|
|
3190
|
+
throw new Error(`No input builder registered for model: ${model}`);
|
|
3191
|
+
}
|
|
3192
|
+
return builder;
|
|
3193
|
+
}
|
|
3194
|
+
};
|
|
3195
|
+
|
|
3196
|
+
// src/providers/pruna/client/generation/builders/builder-factory.ts
|
|
3197
|
+
function createDefaultBuilderRegistry() {
|
|
3198
|
+
return new ModelInputBuilderRegistry().register(new TextToImageInputBuilder()).register(new ImageToImageInputBuilder()).register(new ImageToVideoInputBuilder());
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3201
|
+
// src/providers/pruna/client/generation/services/generation.service.ts
|
|
3202
|
+
var builderRegistry = createDefaultBuilderRegistry();
|
|
3203
|
+
function validateGenerateInput(input) {
|
|
3204
|
+
assertValidPrompt(input.prompt, `${input.model}.prompt`);
|
|
3205
|
+
assertValidAspectRatio(input.aspect_ratio, `${input.model}.aspect_ratio`);
|
|
3206
|
+
if (isTextToImageInput(input)) {
|
|
3207
|
+
assertValidSeed(input.seed, `${input.model}.seed`);
|
|
3208
|
+
} else if (isImageToImageInput(input)) {
|
|
3209
|
+
assertSecureImageSource(input.image, `${input.model}.image`);
|
|
3210
|
+
assertValidSeed(input.seed, `${input.model}.seed`);
|
|
3211
|
+
} else if (isImageToVideoInput(input)) {
|
|
3212
|
+
assertSecureImageSource(input.image, `${input.model}.image`);
|
|
3213
|
+
assertValidDuration(input.duration, `${input.model}.duration`);
|
|
3214
|
+
assertValidResolution(input.resolution, `${input.model}.resolution`);
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
async function generate(apiKey, input, options = {}) {
|
|
3218
|
+
assertValidApiKey(apiKey);
|
|
3219
|
+
validateGenerateInput(input);
|
|
3220
|
+
const { signal, onProgress, useCache = true } = options;
|
|
3221
|
+
if (useCache) {
|
|
3222
|
+
const cacheKey = deriveGenerationCacheKey(apiKey, input);
|
|
3223
|
+
return globalDeduplicator.execute(
|
|
3224
|
+
cacheKey,
|
|
3225
|
+
() => generateInternal(apiKey, input, { signal, onProgress })
|
|
3226
|
+
);
|
|
3227
|
+
}
|
|
3228
|
+
return generateInternal(apiKey, input, { signal, onProgress });
|
|
3229
|
+
}
|
|
3230
|
+
async function generateInternal(apiKey, input, options) {
|
|
3231
|
+
const { signal, onProgress } = options;
|
|
3232
|
+
const builder = builderRegistry.resolve(input.model);
|
|
3233
|
+
const modelInput = await builder.build(input, { apiKey, signal, onProgress });
|
|
3234
|
+
const response = await submitPrediction(input.model, modelInput, apiKey, signal, onProgress);
|
|
3235
|
+
const syncUri = extractUri(response);
|
|
3236
|
+
if (syncUri) {
|
|
3237
|
+
return { url: resolveUri(syncUri), model: input.model };
|
|
3238
|
+
}
|
|
3239
|
+
const pollUrl = response.get_url ?? response.status_url;
|
|
2416
3240
|
if (!pollUrl) {
|
|
2417
|
-
throw new Error("Pruna
|
|
3241
|
+
throw new Error("Pruna API returned no result and no polling URL.");
|
|
2418
3242
|
}
|
|
2419
|
-
const
|
|
2420
|
-
|
|
3243
|
+
const url = await pollForResult(
|
|
3244
|
+
pollUrl,
|
|
3245
|
+
apiKey,
|
|
3246
|
+
POLL_DEFAULTS.maxAttempts,
|
|
3247
|
+
POLL_DEFAULTS.intervalMs,
|
|
3248
|
+
signal,
|
|
3249
|
+
onProgress
|
|
3250
|
+
);
|
|
3251
|
+
return { url, model: input.model };
|
|
3252
|
+
}
|
|
3253
|
+
async function generateImageThenVideo(apiKey, input, options = {}) {
|
|
3254
|
+
assertValidApiKey(apiKey);
|
|
3255
|
+
assertValidPrompt(input.prompt, "text-to-video.prompt");
|
|
3256
|
+
assertValidAspectRatio(input.aspect_ratio, "text-to-video.aspect_ratio");
|
|
3257
|
+
assertValidDuration(input.duration, "text-to-video.duration");
|
|
3258
|
+
assertValidResolution(input.resolution, "text-to-video.resolution");
|
|
3259
|
+
const { signal, onProgress } = options;
|
|
3260
|
+
const aspectRatio = input.aspect_ratio ?? DEFAULT_ASPECT_RATIO;
|
|
3261
|
+
onProgress?.("predicting", 1);
|
|
3262
|
+
const imageResult = await generate(
|
|
3263
|
+
apiKey,
|
|
3264
|
+
{ model: "p-image", prompt: input.prompt, aspect_ratio: aspectRatio },
|
|
3265
|
+
{ signal }
|
|
3266
|
+
);
|
|
3267
|
+
onProgress?.("predicting", 2);
|
|
3268
|
+
return generate(
|
|
3269
|
+
apiKey,
|
|
3270
|
+
{
|
|
3271
|
+
model: "p-video",
|
|
3272
|
+
prompt: input.prompt,
|
|
3273
|
+
image: imageResult.url,
|
|
3274
|
+
duration: input.duration ?? P_VIDEO_DEFAULTS.duration,
|
|
3275
|
+
resolution: input.resolution ?? P_VIDEO_DEFAULTS.resolution,
|
|
3276
|
+
aspect_ratio: aspectRatio,
|
|
3277
|
+
draft: input.draft ?? P_VIDEO_DEFAULTS.draft
|
|
3278
|
+
},
|
|
3279
|
+
{ signal, onProgress }
|
|
3280
|
+
);
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
// src/providers/pruna/pruna-generate.ts
|
|
3284
|
+
async function* generateWithPruna(request, apiKey, signal, onProgress) {
|
|
3285
|
+
const stages = [];
|
|
3286
|
+
let notify = null;
|
|
3287
|
+
let done = false;
|
|
3288
|
+
const wake = () => {
|
|
3289
|
+
const fn = notify;
|
|
3290
|
+
if (fn) {
|
|
3291
|
+
notify = null;
|
|
3292
|
+
fn();
|
|
3293
|
+
}
|
|
3294
|
+
};
|
|
3295
|
+
const handleProgress = (stage) => {
|
|
3296
|
+
stages.push({ stage });
|
|
3297
|
+
onProgress?.(stage);
|
|
3298
|
+
wake();
|
|
3299
|
+
};
|
|
3300
|
+
const promise = (async () => {
|
|
3301
|
+
try {
|
|
3302
|
+
const model = request.model ?? (request.image ? "p-image-edit" : "p-image");
|
|
3303
|
+
if (model === "p-video" && !request.image && request.prompt) {
|
|
3304
|
+
const videoRes = await generateImageThenVideo(
|
|
3305
|
+
apiKey,
|
|
3306
|
+
{
|
|
3307
|
+
prompt: request.prompt,
|
|
3308
|
+
duration: request.duration ?? 5,
|
|
3309
|
+
aspect_ratio: request.aspectRatio ?? request.aspect_ratio ?? "16:9"
|
|
3310
|
+
},
|
|
3311
|
+
{ signal, onProgress: handleProgress }
|
|
3312
|
+
);
|
|
3313
|
+
stages.push({
|
|
3314
|
+
stage: "polling",
|
|
3315
|
+
result: { url: videoRes.url, model: "p-video" }
|
|
3316
|
+
});
|
|
3317
|
+
return;
|
|
3318
|
+
}
|
|
3319
|
+
const input = {
|
|
3320
|
+
model,
|
|
3321
|
+
prompt: request.prompt ?? "",
|
|
3322
|
+
aspect_ratio: request.aspectRatio ?? request.aspect_ratio ?? "1:1",
|
|
3323
|
+
...request.image ? { image: request.image } : {},
|
|
3324
|
+
...request.duration ? { duration: request.duration } : {},
|
|
3325
|
+
...request.resolution ? { resolution: request.resolution } : {},
|
|
3326
|
+
...request.seed !== void 0 ? { seed: request.seed } : {}
|
|
3327
|
+
};
|
|
3328
|
+
const res = await generate(apiKey, input, {
|
|
3329
|
+
signal,
|
|
3330
|
+
onProgress: handleProgress
|
|
3331
|
+
});
|
|
3332
|
+
stages.push({
|
|
3333
|
+
stage: "polling",
|
|
3334
|
+
result: { url: res.url, model: res.model }
|
|
3335
|
+
});
|
|
3336
|
+
} catch (err) {
|
|
3337
|
+
stages.push({
|
|
3338
|
+
stage: "processing",
|
|
3339
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
3340
|
+
});
|
|
3341
|
+
} finally {
|
|
3342
|
+
done = true;
|
|
3343
|
+
wake();
|
|
3344
|
+
}
|
|
3345
|
+
})();
|
|
3346
|
+
while (!done || stages.length > 0) {
|
|
3347
|
+
if (stages.length === 0 && !done) {
|
|
3348
|
+
await new Promise((resolve) => {
|
|
3349
|
+
notify = resolve;
|
|
3350
|
+
});
|
|
3351
|
+
notify = null;
|
|
3352
|
+
}
|
|
3353
|
+
while (stages.length > 0) {
|
|
3354
|
+
const nextStage = stages.shift();
|
|
3355
|
+
if (!nextStage) continue;
|
|
3356
|
+
yield nextStage;
|
|
3357
|
+
if (nextStage.error) {
|
|
3358
|
+
throw nextStage.error;
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
await promise;
|
|
2421
3363
|
}
|
|
2422
3364
|
|
|
2423
3365
|
// src/providers/pruna/pruna.provider.ts
|
|
@@ -2530,38 +3472,564 @@ function createAI(config = {}) {
|
|
|
2530
3472
|
return factory;
|
|
2531
3473
|
}
|
|
2532
3474
|
|
|
3475
|
+
// src/providers/groq/groq-messages.ts
|
|
3476
|
+
var createUserMessage = (content) => ({
|
|
3477
|
+
role: "user",
|
|
3478
|
+
content
|
|
3479
|
+
});
|
|
3480
|
+
var createAssistantMessage = (content) => ({
|
|
3481
|
+
role: "assistant",
|
|
3482
|
+
content
|
|
3483
|
+
});
|
|
3484
|
+
var createSystemMessage = (content) => ({
|
|
3485
|
+
role: "system",
|
|
3486
|
+
content
|
|
3487
|
+
});
|
|
3488
|
+
var createMessage = (role, content) => ({
|
|
3489
|
+
role,
|
|
3490
|
+
content
|
|
3491
|
+
});
|
|
3492
|
+
var promptToMessages = (prompt) => [
|
|
3493
|
+
createUserMessage(prompt)
|
|
3494
|
+
];
|
|
3495
|
+
var extractTextFromMessages = (messages) => messages.map((m) => m.content).join("\n\n");
|
|
3496
|
+
var formatMessagesForDisplay = (messages) => messages.map((m) => `[${m.role.toUpperCase()}]: ${m.content}`).join("\n\n---\n\n");
|
|
3497
|
+
|
|
3498
|
+
// src/providers/groq/groq-structured-json.ts
|
|
3499
|
+
async function requestStructuredJson(client, request) {
|
|
3500
|
+
const chatRequest = {
|
|
3501
|
+
model: request.model,
|
|
3502
|
+
messages: [createUserMessage(request.instructions)],
|
|
3503
|
+
temperature: request.temperature,
|
|
3504
|
+
max_tokens: request.maxTokens,
|
|
3505
|
+
response_format: { type: "json_object" },
|
|
3506
|
+
...request.reasoningEffort !== void 0 ? { reasoning_effort: request.reasoningEffort } : {}
|
|
3507
|
+
};
|
|
3508
|
+
const response = await client.postChatCompletion(chatRequest);
|
|
3509
|
+
const content = response.choices[0]?.message?.content ?? "";
|
|
3510
|
+
const candidate = extractJsonCandidate(content);
|
|
3511
|
+
try {
|
|
3512
|
+
return JSON.parse(candidate);
|
|
3513
|
+
} catch (err) {
|
|
3514
|
+
throw new GroqError(
|
|
3515
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
3516
|
+
"model response contained no parsable json object",
|
|
3517
|
+
err instanceof Error ? err : void 0
|
|
3518
|
+
);
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
|
|
3522
|
+
// src/providers/groq/text-generation.service.ts
|
|
3523
|
+
var STRUCTURED_OUTPUT_TEMPERATURE = 0.1;
|
|
3524
|
+
var TextGenerationService = class {
|
|
3525
|
+
constructor(httpClient, cache = new CacheManager(), defaultModel = DEFAULT_MODELS.TEXT) {
|
|
3526
|
+
this.httpClient = httpClient;
|
|
3527
|
+
this.cache = cache;
|
|
3528
|
+
this.defaultModel = defaultModel;
|
|
3529
|
+
}
|
|
3530
|
+
httpClient;
|
|
3531
|
+
cache;
|
|
3532
|
+
defaultModel;
|
|
3533
|
+
id = "groq-text-generation";
|
|
3534
|
+
name = "Groq Text Generation";
|
|
3535
|
+
capabilities = ["text"];
|
|
3536
|
+
jsonParser = new JsonResponseParser();
|
|
3537
|
+
generateCompletion(prompt, options = {}) {
|
|
3538
|
+
const model = options.model ?? this.defaultModel;
|
|
3539
|
+
return this.executeWithCache(
|
|
3540
|
+
{
|
|
3541
|
+
type: CACHE_KEY_TYPE_COMPLETION,
|
|
3542
|
+
model,
|
|
3543
|
+
prompt,
|
|
3544
|
+
config: options.generationConfig
|
|
3545
|
+
},
|
|
3546
|
+
async () => {
|
|
3547
|
+
const request = GroqChatRequestBuilder.for(model).withMessages([createUserMessage(prompt)]).withConfig(options.generationConfig).build();
|
|
3548
|
+
const response = await this.httpClient.postChatCompletion(request);
|
|
3549
|
+
return this.extractContent(response.choices[0]?.message?.content);
|
|
3550
|
+
}
|
|
3551
|
+
);
|
|
3552
|
+
}
|
|
3553
|
+
generateChatCompletion(messages, options = {}) {
|
|
3554
|
+
const model = options.model ?? this.defaultModel;
|
|
3555
|
+
return this.executeWithCache(
|
|
3556
|
+
{
|
|
3557
|
+
type: CACHE_KEY_TYPE_CHAT,
|
|
3558
|
+
model,
|
|
3559
|
+
messages: [...messages],
|
|
3560
|
+
config: options.generationConfig
|
|
3561
|
+
},
|
|
3562
|
+
async () => {
|
|
3563
|
+
const request = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(options.generationConfig).build();
|
|
3564
|
+
const response = await this.httpClient.postChatCompletion(request);
|
|
3565
|
+
return this.extractContent(response.choices[0]?.message?.content);
|
|
3566
|
+
}
|
|
3567
|
+
);
|
|
3568
|
+
}
|
|
3569
|
+
generateStructured(promptOrRequest, options) {
|
|
3570
|
+
if (typeof promptOrRequest === "string") {
|
|
3571
|
+
const model2 = options?.model ?? this.defaultModel;
|
|
3572
|
+
const jsonPrompt = StructuredPromptBuilder.for(promptOrRequest).withSchema(options?.schema).build();
|
|
3573
|
+
const request = GroqChatRequestBuilder.for(model2).withMessages([createUserMessage(jsonPrompt)]).withConfig({
|
|
3574
|
+
...options?.generationConfig,
|
|
3575
|
+
temperature: STRUCTURED_OUTPUT_TEMPERATURE
|
|
3576
|
+
}).build();
|
|
3577
|
+
return this.httpClient.postChatCompletion(request).then((response) => {
|
|
3578
|
+
const content = this.extractContent(response.choices[0]?.message?.content);
|
|
3579
|
+
return this.jsonParser.parse(content);
|
|
3580
|
+
});
|
|
3581
|
+
}
|
|
3582
|
+
const req = promptOrRequest;
|
|
3583
|
+
const model = req.model ?? (req.tier ? this.resolveModel(req.tier) : this.defaultModel);
|
|
3584
|
+
const schemaObj = req.schema;
|
|
3585
|
+
const messages = [];
|
|
3586
|
+
if (req.systemPrompt) {
|
|
3587
|
+
messages.push({ role: "system", content: req.systemPrompt });
|
|
3588
|
+
}
|
|
3589
|
+
for (const m of req.messages) {
|
|
3590
|
+
messages.push({ role: m.role, content: m.content });
|
|
3591
|
+
}
|
|
3592
|
+
const lastMsg = messages[messages.length - 1];
|
|
3593
|
+
if (lastMsg) {
|
|
3594
|
+
const structuredPrompt = StructuredPromptBuilder.for(lastMsg.content).withSchema(schemaObj).build();
|
|
3595
|
+
messages[messages.length - 1] = { ...lastMsg, content: structuredPrompt };
|
|
3596
|
+
}
|
|
3597
|
+
const groqReq = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig({
|
|
3598
|
+
temperature: req.temperature ?? STRUCTURED_OUTPUT_TEMPERATURE,
|
|
3599
|
+
maxTokens: req.maxTokens
|
|
3600
|
+
}).build();
|
|
3601
|
+
return this.httpClient.postChatCompletion(groqReq).then((response) => {
|
|
3602
|
+
const content = this.extractContent(response.choices[0]?.message?.content);
|
|
3603
|
+
const parsed = this.jsonParser.parse(content);
|
|
3604
|
+
const genResult = {
|
|
3605
|
+
text: content,
|
|
3606
|
+
model: response.model,
|
|
3607
|
+
providerId: this.id,
|
|
3608
|
+
finishReason: response.choices[0]?.finish_reason ?? "stop",
|
|
3609
|
+
usage: response.usage ? {
|
|
3610
|
+
inputTokens: response.usage.prompt_tokens,
|
|
3611
|
+
outputTokens: response.usage.completion_tokens,
|
|
3612
|
+
totalTokens: response.usage.total_tokens
|
|
3613
|
+
} : void 0
|
|
3614
|
+
};
|
|
3615
|
+
return { value: parsed, result: genResult };
|
|
3616
|
+
});
|
|
3617
|
+
}
|
|
3618
|
+
streamCompletion(prompt, callbacks, options = {}) {
|
|
3619
|
+
return this.streamChatCompletion([createUserMessage(prompt)], callbacks, options);
|
|
3620
|
+
}
|
|
3621
|
+
async streamChatCompletion(messages, callbacks, options = {}) {
|
|
3622
|
+
const model = options.model ?? this.defaultModel;
|
|
3623
|
+
const request = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(options.generationConfig).withStream(true).build();
|
|
3624
|
+
const parser = new StreamingResponseParser(
|
|
3625
|
+
{
|
|
3626
|
+
onChunk: (chunk) => callbacks.onChunk?.(chunk)
|
|
3627
|
+
},
|
|
3628
|
+
extractContentFromSsePayload
|
|
3629
|
+
);
|
|
3630
|
+
try {
|
|
3631
|
+
const stream = await this.httpClient.streamChatCompletion(request, {
|
|
3632
|
+
signal: options.signal
|
|
3633
|
+
});
|
|
3634
|
+
const fullText = await parser.parse(stream);
|
|
3635
|
+
callbacks.onComplete?.(fullText);
|
|
3636
|
+
return fullText;
|
|
3637
|
+
} catch (error) {
|
|
3638
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
3639
|
+
callbacks.onError?.(err);
|
|
3640
|
+
throw err;
|
|
3641
|
+
}
|
|
3642
|
+
}
|
|
3643
|
+
clearCache() {
|
|
3644
|
+
this.cache.clear();
|
|
3645
|
+
}
|
|
3646
|
+
// --- ITextProvider implementation ---
|
|
3647
|
+
resolveModel(tier) {
|
|
3648
|
+
return GROQ_TIERS[tier] ?? this.defaultModel;
|
|
3649
|
+
}
|
|
3650
|
+
async generate(request) {
|
|
3651
|
+
const messages = [];
|
|
3652
|
+
if (request.systemPrompt) {
|
|
3653
|
+
messages.push({ role: "system", content: request.systemPrompt });
|
|
3654
|
+
}
|
|
3655
|
+
for (const m of request.messages) {
|
|
3656
|
+
messages.push({ role: m.role, content: m.content });
|
|
3657
|
+
}
|
|
3658
|
+
const model = request.model ?? (request.tier ? this.resolveModel(request.tier) : this.defaultModel);
|
|
3659
|
+
const groqReq = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig({
|
|
3660
|
+
temperature: request.temperature,
|
|
3661
|
+
maxTokens: request.maxTokens
|
|
3662
|
+
}).build();
|
|
3663
|
+
const resp = await this.httpClient.postChatCompletion(groqReq);
|
|
3664
|
+
const content = resp.choices[0]?.message?.content ?? "";
|
|
3665
|
+
return {
|
|
3666
|
+
text: content,
|
|
3667
|
+
finishReason: resp.choices[0]?.finish_reason ?? "stop",
|
|
3668
|
+
model: resp.model,
|
|
3669
|
+
providerId: this.id,
|
|
3670
|
+
usage: resp.usage ? {
|
|
3671
|
+
inputTokens: resp.usage.prompt_tokens,
|
|
3672
|
+
outputTokens: resp.usage.completion_tokens,
|
|
3673
|
+
totalTokens: resp.usage.total_tokens
|
|
3674
|
+
} : void 0
|
|
3675
|
+
};
|
|
3676
|
+
}
|
|
3677
|
+
async stream(request, callbacks) {
|
|
3678
|
+
const messages = [];
|
|
3679
|
+
if (request.systemPrompt) {
|
|
3680
|
+
messages.push({ role: "system", content: request.systemPrompt });
|
|
3681
|
+
}
|
|
3682
|
+
for (const m of request.messages) {
|
|
3683
|
+
messages.push({ role: m.role, content: m.content });
|
|
3684
|
+
}
|
|
3685
|
+
const model = request.model ?? (request.tier ? this.resolveModel(request.tier) : this.defaultModel);
|
|
3686
|
+
const text = await this.streamChatCompletion(
|
|
3687
|
+
messages,
|
|
3688
|
+
{
|
|
3689
|
+
onChunk: callbacks.onChunk,
|
|
3690
|
+
onError: callbacks.onError
|
|
3691
|
+
},
|
|
3692
|
+
{
|
|
3693
|
+
model,
|
|
3694
|
+
signal: request.signal,
|
|
3695
|
+
generationConfig: {
|
|
3696
|
+
temperature: request.temperature,
|
|
3697
|
+
maxTokens: request.maxTokens
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
);
|
|
3701
|
+
const result = {
|
|
3702
|
+
text,
|
|
3703
|
+
finishReason: "stop",
|
|
3704
|
+
model,
|
|
3705
|
+
providerId: this.id
|
|
3706
|
+
};
|
|
3707
|
+
callbacks.onComplete?.(result);
|
|
3708
|
+
return result;
|
|
3709
|
+
}
|
|
3710
|
+
async countTokens(text) {
|
|
3711
|
+
return Math.max(1, Math.ceil(text.length / 4));
|
|
3712
|
+
}
|
|
3713
|
+
async estimateCost(_request) {
|
|
3714
|
+
return 0;
|
|
3715
|
+
}
|
|
3716
|
+
async healthCheck() {
|
|
3717
|
+
try {
|
|
3718
|
+
await this.generateCompletion("ping", {
|
|
3719
|
+
generationConfig: { maxTokens: 1 }
|
|
3720
|
+
});
|
|
3721
|
+
return "healthy";
|
|
3722
|
+
} catch {
|
|
3723
|
+
return "unavailable";
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
async executeWithCache(params, factory) {
|
|
3727
|
+
const key = this.cache.generateKey(params);
|
|
3728
|
+
const cached = this.cache.get(key);
|
|
3729
|
+
if (cached !== null) {
|
|
3730
|
+
return cached;
|
|
3731
|
+
}
|
|
3732
|
+
const result = await factory();
|
|
3733
|
+
this.cache.set(key, result);
|
|
3734
|
+
return result;
|
|
3735
|
+
}
|
|
3736
|
+
extractContent(content) {
|
|
3737
|
+
if (!content) {
|
|
3738
|
+
throw new GroqError(
|
|
3739
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
3740
|
+
"No content generated from Groq API"
|
|
3741
|
+
);
|
|
3742
|
+
}
|
|
3743
|
+
return content;
|
|
3744
|
+
}
|
|
3745
|
+
};
|
|
3746
|
+
|
|
3747
|
+
// src/core/calculations/random-base36-suffix.ts
|
|
3748
|
+
var BASE_36_RADIX = 36;
|
|
3749
|
+
var DECIMAL_OFFSET = 2;
|
|
3750
|
+
function generateRandomBase36Suffix(length, random = Math.random) {
|
|
3751
|
+
if (length <= 0) return "";
|
|
3752
|
+
const raw = random().toString(BASE_36_RADIX).slice(DECIMAL_OFFSET);
|
|
3753
|
+
if (raw.length >= length) return raw.slice(0, length);
|
|
3754
|
+
let result = raw;
|
|
3755
|
+
while (result.length < length) {
|
|
3756
|
+
result += random().toString(BASE_36_RADIX).slice(DECIMAL_OFFSET);
|
|
3757
|
+
}
|
|
3758
|
+
return result.slice(0, length);
|
|
3759
|
+
}
|
|
3760
|
+
|
|
3761
|
+
// src/chat/utils/chat-id-generator.ts
|
|
3762
|
+
var ID_PART_DELIMITER = "-";
|
|
3763
|
+
var ChatIdGenerator = class {
|
|
3764
|
+
counter = 0;
|
|
3765
|
+
randomLength;
|
|
3766
|
+
constructor(randomLength = CHAT_MESSAGE_ID_SUFFIX_LENGTH) {
|
|
3767
|
+
this.randomLength = randomLength;
|
|
3768
|
+
}
|
|
3769
|
+
next(sender) {
|
|
3770
|
+
this.counter += 1;
|
|
3771
|
+
const random = generateRandomBase36Suffix(this.randomLength);
|
|
3772
|
+
return [
|
|
3773
|
+
MESSAGE_ID_PREFIX,
|
|
3774
|
+
Date.now(),
|
|
3775
|
+
sender,
|
|
3776
|
+
this.counter,
|
|
3777
|
+
random
|
|
3778
|
+
].join(ID_PART_DELIMITER);
|
|
3779
|
+
}
|
|
3780
|
+
};
|
|
3781
|
+
var chatIdGenerator = new ChatIdGenerator();
|
|
3782
|
+
|
|
3783
|
+
// src/chat/utils/message-formatter.ts
|
|
3784
|
+
var MessageFormatter = class {
|
|
3785
|
+
constructor(idGenerator = chatIdGenerator) {
|
|
3786
|
+
this.idGenerator = idGenerator;
|
|
3787
|
+
}
|
|
3788
|
+
idGenerator;
|
|
3789
|
+
/** Maps chat-domain history to neutral core messages; system senders are
|
|
3790
|
+
* dropped — the system prompt travels on the request's own slot. */
|
|
3791
|
+
toCoreMessages(messages) {
|
|
3792
|
+
const coreMessages = [];
|
|
3793
|
+
for (const message of messages) {
|
|
3794
|
+
if (message.sender === "system") continue;
|
|
3795
|
+
coreMessages.push({
|
|
3796
|
+
role: message.sender === "user" ? USER_ROLE : ASSISTANT_ROLE,
|
|
3797
|
+
content: message.content
|
|
3798
|
+
});
|
|
3799
|
+
}
|
|
3800
|
+
return coreMessages;
|
|
3801
|
+
}
|
|
3802
|
+
toChatMessage(content, sender) {
|
|
3803
|
+
return {
|
|
3804
|
+
id: this.idGenerator.next(sender),
|
|
3805
|
+
sender,
|
|
3806
|
+
content: content.trim(),
|
|
3807
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3808
|
+
type: "text"
|
|
3809
|
+
};
|
|
3810
|
+
}
|
|
3811
|
+
};
|
|
3812
|
+
var messageFormatter = new MessageFormatter();
|
|
3813
|
+
|
|
3814
|
+
// src/chat/utils/prompt-strategy.ts
|
|
3815
|
+
var DEFAULT_PROMPT_STRATEGY = {
|
|
3816
|
+
resolve: (config) => {
|
|
3817
|
+
if (config.systemPrompt && config.systemPrompt.length > 0) {
|
|
3818
|
+
return config.systemPrompt;
|
|
3819
|
+
}
|
|
3820
|
+
return void 0;
|
|
3821
|
+
}
|
|
3822
|
+
};
|
|
3823
|
+
|
|
3824
|
+
// src/chat/services/chat.service.ts
|
|
3825
|
+
var DEFAULT_CONFIG = {
|
|
3826
|
+
temperature: 0.8,
|
|
3827
|
+
maxTokens: 500
|
|
3828
|
+
};
|
|
3829
|
+
var ChatService = class {
|
|
3830
|
+
constructor(engine) {
|
|
3831
|
+
this.engine = engine;
|
|
3832
|
+
}
|
|
3833
|
+
engine;
|
|
3834
|
+
config = DEFAULT_CONFIG;
|
|
3835
|
+
promptStrategy = DEFAULT_PROMPT_STRATEGY;
|
|
3836
|
+
storage = null;
|
|
3837
|
+
initialize(config) {
|
|
3838
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
3839
|
+
}
|
|
3840
|
+
updateConfig(config) {
|
|
3841
|
+
this.config = { ...this.config, ...config };
|
|
3842
|
+
}
|
|
3843
|
+
setPromptStrategy(strategy) {
|
|
3844
|
+
this.promptStrategy = strategy;
|
|
3845
|
+
}
|
|
3846
|
+
setStorage(storage) {
|
|
3847
|
+
this.storage = storage;
|
|
3848
|
+
}
|
|
3849
|
+
async getConversation(conversationId) {
|
|
3850
|
+
const storage = this.requireStorage();
|
|
3851
|
+
const messages = await storage.getMessages(conversationId);
|
|
3852
|
+
if (messages.length === 0) return null;
|
|
3853
|
+
const last = messages[messages.length - 1];
|
|
3854
|
+
const first = messages[0];
|
|
3855
|
+
const companionId = String(first.metadata?.["companionId"] ?? "unknown");
|
|
3856
|
+
const companionName = String(first.metadata?.["companionName"] ?? "Unknown");
|
|
3857
|
+
return {
|
|
3858
|
+
id: conversationId,
|
|
3859
|
+
companionId,
|
|
3860
|
+
companionName,
|
|
3861
|
+
lastMessage: last,
|
|
3862
|
+
messageCount: messages.length,
|
|
3863
|
+
updatedAt: last.timestamp
|
|
3864
|
+
};
|
|
3865
|
+
}
|
|
3866
|
+
async getConversations() {
|
|
3867
|
+
if (this.storage && "getConversations" in this.storage && typeof this.storage.getConversations === "function") {
|
|
3868
|
+
return this.storage.getConversations();
|
|
3869
|
+
}
|
|
3870
|
+
return [];
|
|
3871
|
+
}
|
|
3872
|
+
async sendMessage(input, signal) {
|
|
3873
|
+
const userMessage = {
|
|
3874
|
+
...messageFormatter.toChatMessage(input.text, "user"),
|
|
3875
|
+
type: input.type ?? "text",
|
|
3876
|
+
...input.imageUrl !== void 0 ? { imageUrl: input.imageUrl } : {}
|
|
3877
|
+
};
|
|
3878
|
+
const aiResponse = await this.generateAIResponse(
|
|
3879
|
+
input.companionId,
|
|
3880
|
+
input.text,
|
|
3881
|
+
[],
|
|
3882
|
+
signal
|
|
3883
|
+
);
|
|
3884
|
+
return { userMessage, aiResponse };
|
|
3885
|
+
}
|
|
3886
|
+
async generateAIResponse(companionId, userMessage, context = [], signal) {
|
|
3887
|
+
const result = await this.run({
|
|
3888
|
+
...this.buildRequest(userMessage, context, signal)
|
|
3889
|
+
});
|
|
3890
|
+
return {
|
|
3891
|
+
...messageFormatter.toChatMessage(result.text, "assistant"),
|
|
3892
|
+
metadata: {
|
|
3893
|
+
companionId,
|
|
3894
|
+
model: result.model,
|
|
3895
|
+
usage: {
|
|
3896
|
+
input_tokens: result.usage?.inputTokens,
|
|
3897
|
+
output_tokens: result.usage?.outputTokens,
|
|
3898
|
+
total_tokens: result.usage?.totalTokens
|
|
3899
|
+
},
|
|
3900
|
+
finishReason: result.finishReason
|
|
3901
|
+
}
|
|
3902
|
+
};
|
|
3903
|
+
}
|
|
3904
|
+
async generateStreamingResponse(userMessage, context, onChunk, signal) {
|
|
3905
|
+
const request = this.buildRequest(userMessage, context, signal);
|
|
3906
|
+
const result = await this.runStream(request, { onChunk });
|
|
3907
|
+
return result.text;
|
|
3908
|
+
}
|
|
3909
|
+
buildRequest(userMessage, context, signal) {
|
|
3910
|
+
const messages = messageFormatter.toCoreMessages(context);
|
|
3911
|
+
messages.push({ role: "user", content: userMessage });
|
|
3912
|
+
return {
|
|
3913
|
+
messages,
|
|
3914
|
+
systemPrompt: this.resolveSystemPrompt(),
|
|
3915
|
+
model: this.config.model,
|
|
3916
|
+
tier: this.config.tier,
|
|
3917
|
+
temperature: this.config.temperature,
|
|
3918
|
+
maxTokens: this.config.maxTokens,
|
|
3919
|
+
...signal !== void 0 ? { signal } : {}
|
|
3920
|
+
};
|
|
3921
|
+
}
|
|
3922
|
+
resolveSystemPrompt() {
|
|
3923
|
+
const prompt = this.promptStrategy.resolve(this.config);
|
|
3924
|
+
return prompt && prompt.length > 0 ? prompt : void 0;
|
|
3925
|
+
}
|
|
3926
|
+
async run(request) {
|
|
3927
|
+
if (this.engine instanceof ProviderFactory) {
|
|
3928
|
+
return this.engine.chat(request);
|
|
3929
|
+
}
|
|
3930
|
+
return this.engine.generate(request);
|
|
3931
|
+
}
|
|
3932
|
+
async runStream(request, callbacks) {
|
|
3933
|
+
if (this.engine instanceof ProviderFactory) {
|
|
3934
|
+
return this.engine.chatStream(request, callbacks);
|
|
3935
|
+
}
|
|
3936
|
+
return this.engine.stream(request, callbacks);
|
|
3937
|
+
}
|
|
3938
|
+
requireStorage() {
|
|
3939
|
+
if (!this.storage) {
|
|
3940
|
+
throw new AIError(
|
|
3941
|
+
"MISSING_CONFIG" /* MISSING_CONFIG */,
|
|
3942
|
+
"ChatService.getConversation requires setStorage() to be called first."
|
|
3943
|
+
);
|
|
3944
|
+
}
|
|
3945
|
+
return this.storage;
|
|
3946
|
+
}
|
|
3947
|
+
};
|
|
3948
|
+
|
|
3949
|
+
// src/providers/groq/groq-container.ts
|
|
3950
|
+
var container = null;
|
|
3951
|
+
function configureProvider(config) {
|
|
3952
|
+
const configStore = new GroqConfigStore();
|
|
3953
|
+
const transport = new GroqHttpTransport(configStore);
|
|
3954
|
+
const httpClient = new GroqHttpClient({ configStore, transport });
|
|
3955
|
+
httpClient.initialize(config);
|
|
3956
|
+
const textGeneration = new TextGenerationService(
|
|
3957
|
+
httpClient,
|
|
3958
|
+
new CacheManager(),
|
|
3959
|
+
config.textModel
|
|
3960
|
+
);
|
|
3961
|
+
const chat = new ChatService(textGeneration);
|
|
3962
|
+
container = { groqHttpClient: httpClient, textGeneration, chat };
|
|
3963
|
+
return container;
|
|
3964
|
+
}
|
|
3965
|
+
function getProvider() {
|
|
3966
|
+
return container;
|
|
3967
|
+
}
|
|
3968
|
+
function resetProvider() {
|
|
3969
|
+
container?.groqHttpClient.reset();
|
|
3970
|
+
container = null;
|
|
3971
|
+
}
|
|
3972
|
+
|
|
2533
3973
|
exports.ANTHROPIC_API_VERSION = ANTHROPIC_API_VERSION;
|
|
2534
3974
|
exports.ANTHROPIC_DEFAULT_MAX_TOKENS = ANTHROPIC_DEFAULT_MAX_TOKENS;
|
|
2535
3975
|
exports.ANTHROPIC_MODELS = ANTHROPIC_MODELS;
|
|
2536
3976
|
exports.ANTHROPIC_TIERS = ANTHROPIC_TIERS;
|
|
3977
|
+
exports.API_ENDPOINTS = API_ENDPOINTS;
|
|
2537
3978
|
exports.AnthropicHttpTransport = AnthropicHttpTransport;
|
|
2538
3979
|
exports.AnthropicProvider = AnthropicProvider;
|
|
2539
3980
|
exports.AnthropicRequestBuilder = AnthropicRequestBuilder;
|
|
3981
|
+
exports.AuthenticationError = AuthenticationError;
|
|
2540
3982
|
exports.BaseProvider = BaseProvider;
|
|
3983
|
+
exports.CancellationError = CancellationError;
|
|
3984
|
+
exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
|
|
3985
|
+
exports.DEFAULT_GENERATION_CONFIG = DEFAULT_GENERATION_CONFIG;
|
|
3986
|
+
exports.DEFAULT_MODELS = DEFAULT_MODELS;
|
|
2541
3987
|
exports.FalProvider = FalProvider;
|
|
2542
3988
|
exports.GEMINI_TIERS = GEMINI_TIERS;
|
|
2543
3989
|
exports.GROQ_MODELS = GROQ_MODELS;
|
|
2544
3990
|
exports.GROQ_TIERS = GROQ_TIERS;
|
|
2545
3991
|
exports.GeminiProvider = GeminiProvider;
|
|
3992
|
+
exports.GenerationFailedError = GenerationFailedError;
|
|
2546
3993
|
exports.GroqChatRequestBuilder = GroqChatRequestBuilder;
|
|
3994
|
+
exports.GroqConfigStore = GroqConfigStore;
|
|
2547
3995
|
exports.GroqHttpClient = GroqHttpClient;
|
|
2548
3996
|
exports.GroqHttpTransport = GroqHttpTransport;
|
|
2549
3997
|
exports.GroqProvider = GroqProvider;
|
|
2550
3998
|
exports.ProviderError = ProviderError;
|
|
2551
3999
|
exports.ProviderFactory = ProviderFactory;
|
|
2552
4000
|
exports.PrunaProvider = PrunaProvider;
|
|
4001
|
+
exports.TIMEOUTS = TIMEOUTS;
|
|
4002
|
+
exports.TextGenerationService = TextGenerationService;
|
|
4003
|
+
exports.TimeoutError = TimeoutError;
|
|
4004
|
+
exports.ValidationError = ValidationError;
|
|
4005
|
+
exports.configureProvider = configureProvider;
|
|
2553
4006
|
exports.consumeAnthropicStream = consumeAnthropicStream;
|
|
2554
4007
|
exports.consumeGroqStream = consumeGroqStream;
|
|
2555
4008
|
exports.createAI = createAI;
|
|
4009
|
+
exports.createAssistantMessage = createAssistantMessage;
|
|
2556
4010
|
exports.createFalProvider = createFalProvider;
|
|
2557
4011
|
exports.createGeminiProvider = createGeminiProvider;
|
|
4012
|
+
exports.createMessage = createMessage;
|
|
2558
4013
|
exports.createPrunaProvider = createPrunaProvider;
|
|
4014
|
+
exports.createSystemMessage = createSystemMessage;
|
|
4015
|
+
exports.createUserMessage = createUserMessage;
|
|
2559
4016
|
exports.defaultEffortForModel = defaultEffortForModel;
|
|
2560
4017
|
exports.extractContentFromSsePayload = extractContentFromSsePayload;
|
|
4018
|
+
exports.extractTextFromMessages = extractTextFromMessages;
|
|
4019
|
+
exports.formatMessagesForDisplay = formatMessagesForDisplay;
|
|
4020
|
+
exports.generateImageThenVideo = generateImageThenVideo;
|
|
4021
|
+
exports.generatePruna = generate;
|
|
2561
4022
|
exports.generateWithPruna = generateWithPruna;
|
|
4023
|
+
exports.getProvider = getProvider;
|
|
2562
4024
|
exports.isMediaProvider = isMediaProvider;
|
|
2563
4025
|
exports.isTextProvider = isTextProvider;
|
|
2564
4026
|
exports.mapAnthropicStopReason = mapAnthropicStopReason;
|
|
4027
|
+
exports.pollForResult = pollForResult;
|
|
4028
|
+
exports.promptToMessages = promptToMessages;
|
|
4029
|
+
exports.requestStructuredJson = requestStructuredJson;
|
|
4030
|
+
exports.resetProvider = resetProvider;
|
|
4031
|
+
exports.submitPrediction = submitPrediction;
|
|
2565
4032
|
exports.toGroqMessages = toGroqMessages;
|
|
4033
|
+
exports.uploadImage = uploadImage;
|
|
2566
4034
|
//# sourceMappingURL=index.cjs.map
|
|
2567
4035
|
//# sourceMappingURL=index.cjs.map
|