@thorprovider/medusa-extended 1.11.2 → 1.11.5

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/index.mjs CHANGED
@@ -449,6 +449,89 @@ var DropshipperClient = class {
449
449
  body
450
450
  );
451
451
  }
452
+ /**
453
+ * Stream the AI assistant's reply.
454
+ *
455
+ * Unlike `chatAssistant`, this surfaces the model's progress: the backend
456
+ * resolves the intent first and then streams the answer token by token
457
+ * (catalog searches) or returns the full answer in one shot (greetings/other).
458
+ * The response is normalized into a single `ReadableStream<ChatStreamEvent>`
459
+ * so callers can show a live "thinking" label and render text incrementally.
460
+ *
461
+ * `POST /admin/thor/dropshipper/ai/chat`
462
+ */
463
+ async chatAssistantStream(body) {
464
+ const url = `${this.baseUrl}/admin/thor/dropshipper/ai/chat`;
465
+ this.logger.debug("[dropshipper] POST /admin/thor/dropshipper/ai/chat (stream)");
466
+ const init = {
467
+ method: "POST",
468
+ headers: {
469
+ Authorization: `Bearer ${this.token}`,
470
+ "Content-Type": "application/json",
471
+ Accept: "text/event-stream"
472
+ },
473
+ body: JSON.stringify(body)
474
+ };
475
+ let response;
476
+ try {
477
+ response = await fetchBackendWithResilience(url, init, {
478
+ timeoutMs: 6e4,
479
+ maxRetries: 1
480
+ });
481
+ } catch (networkError) {
482
+ throw new ProviderAPIError3(
483
+ `[dropshipper] Network error on POST /admin/thor/dropshipper/ai/chat: ${networkError.message}`,
484
+ "NETWORK_ERROR",
485
+ networkError
486
+ );
487
+ }
488
+ if (!response.ok) {
489
+ let message = `HTTP ${response.status}`;
490
+ let errorCode;
491
+ let requestId;
492
+ let details;
493
+ try {
494
+ const json = await response.json();
495
+ message = json?.message ?? message;
496
+ errorCode = json?.error_code ?? json?.type;
497
+ requestId = json?.request_id;
498
+ details = json?.details;
499
+ } catch {
500
+ }
501
+ this.logger.error(
502
+ `[dropshipper] POST /admin/thor/dropshipper/ai/chat failed status=${response.status} message=${message}` + (errorCode ? ` error_code=${errorCode}` : "") + (requestId ? ` request_id=${requestId}` : "") + (details ? ` details=${details}` : "")
503
+ );
504
+ throw new ProviderAPIError3(
505
+ `[dropshipper] POST /admin/thor/dropshipper/ai/chat failed: ${message}`,
506
+ `DROPSHIPPER_API_${response.status}`,
507
+ response.status,
508
+ {
509
+ message,
510
+ status: response.status,
511
+ errorCode,
512
+ requestId,
513
+ details
514
+ }
515
+ );
516
+ }
517
+ const contentType = response.headers.get("content-type") ?? "";
518
+ if (contentType.includes("text/event-stream") && response.body) {
519
+ return mapUiMessageStreamToEvents(response.body, this.logger);
520
+ }
521
+ const data = await response.json();
522
+ return new ReadableStream({
523
+ start(controller) {
524
+ controller.enqueue({ type: "start", intent: data.intent });
525
+ controller.enqueue({ type: "text-delta", delta: data.answer });
526
+ controller.enqueue({
527
+ type: "finish",
528
+ intent: data.intent,
529
+ sources: data.sources ?? []
530
+ });
531
+ controller.close();
532
+ }
533
+ });
534
+ }
452
535
  // -------------------------------------------------------------------------
453
536
  // Notifications
454
537
  // -------------------------------------------------------------------------
@@ -1607,6 +1690,103 @@ var DropshipperClient = class {
1607
1690
  );
1608
1691
  }
1609
1692
  };
1693
+ async function* parseSse(stream, logger) {
1694
+ const reader = stream.getReader();
1695
+ const decoder = new TextDecoder();
1696
+ let buffer = "";
1697
+ let frameIndex = 0;
1698
+ try {
1699
+ while (true) {
1700
+ const { done, value } = await reader.read();
1701
+ if (done) break;
1702
+ buffer += decoder.decode(value, { stream: true });
1703
+ const lines = buffer.split(/\r?\n/);
1704
+ buffer = lines.pop() ?? "";
1705
+ for (const line of lines) {
1706
+ const trimmed = line.trim();
1707
+ if (!trimmed.startsWith("data:")) continue;
1708
+ const payload = trimmed.slice(5).trim();
1709
+ if (!payload || payload === "[DONE]") continue;
1710
+ frameIndex += 1;
1711
+ try {
1712
+ yield JSON.parse(payload);
1713
+ } catch (err) {
1714
+ logger?.warn(
1715
+ `[dropshipper] sse-malformed-frame frame=${frameIndex} payload=${payload.slice(0, 200)}`
1716
+ );
1717
+ }
1718
+ }
1719
+ }
1720
+ const tail = buffer.trim();
1721
+ if (tail.startsWith("data:")) {
1722
+ const payload = tail.slice(5).trim();
1723
+ if (payload && payload !== "[DONE]") {
1724
+ frameIndex += 1;
1725
+ try {
1726
+ yield JSON.parse(payload);
1727
+ } catch (err) {
1728
+ logger?.warn(
1729
+ `[dropshipper] sse-malformed-frame frame=${frameIndex} payload=${payload.slice(0, 200)}`
1730
+ );
1731
+ }
1732
+ }
1733
+ }
1734
+ } finally {
1735
+ reader.releaseLock();
1736
+ }
1737
+ }
1738
+ function mapUiMessageStreamToEvents(stream, logger) {
1739
+ return new ReadableStream({
1740
+ async start(controller) {
1741
+ let eventCount = 0;
1742
+ for await (const raw of parseSse(stream, logger)) {
1743
+ const chunk = raw;
1744
+ switch (chunk.type) {
1745
+ case "start":
1746
+ controller.enqueue({
1747
+ type: "start",
1748
+ intent: chunk.messageMetadata?.intent
1749
+ });
1750
+ eventCount += 1;
1751
+ break;
1752
+ case "text-delta":
1753
+ if (chunk.delta !== void 0) {
1754
+ controller.enqueue({ type: "text-delta", delta: chunk.delta });
1755
+ eventCount += 1;
1756
+ }
1757
+ break;
1758
+ case "finish":
1759
+ controller.enqueue({
1760
+ type: "finish",
1761
+ intent: chunk.messageMetadata?.intent ?? "other",
1762
+ sources: chunk.messageMetadata?.sources ?? []
1763
+ });
1764
+ eventCount += 1;
1765
+ break;
1766
+ case "error":
1767
+ logger?.warn(
1768
+ `[dropshipper] chat-stream-error errorText=${chunk.errorText}`
1769
+ );
1770
+ controller.enqueue({
1771
+ type: "error",
1772
+ errorText: chunk.errorText ?? "Error inesperado del asistente."
1773
+ });
1774
+ eventCount += 1;
1775
+ break;
1776
+ default:
1777
+ logger?.debug(
1778
+ `[dropshipper] chat-stream-unknown-frame type=${chunk.type}`
1779
+ );
1780
+ }
1781
+ }
1782
+ logger?.debug(`[dropshipper] chat-stream-completed events=${eventCount}`);
1783
+ controller.close();
1784
+ },
1785
+ cancel() {
1786
+ stream.cancel?.();
1787
+ }
1788
+ });
1789
+ }
1610
1790
  export {
1611
1791
  DropshipperClient,
1612
1792
  MedusaAdminClient