@copilotz/chat-adapter 0.9.43 → 0.9.44

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.js CHANGED
@@ -1638,6 +1638,17 @@ var getStreamEventPayload = (event) => {
1638
1638
  if (!isRecord2(event)) return event;
1639
1639
  return "payload" in event ? event.payload : event;
1640
1640
  };
1641
+ var getLlmAttemptId = (event) => {
1642
+ if (!isRecord2(event)) return null;
1643
+ const metadata = isRecord2(event.metadata) ? event.metadata : {};
1644
+ if (typeof metadata.llmAttemptId === "string" && metadata.llmAttemptId.trim().length > 0) {
1645
+ return metadata.llmAttemptId.trim();
1646
+ }
1647
+ if (event.subjectType === "llm_attempt" && typeof event.subjectId === "string" && event.subjectId.trim().length > 0) {
1648
+ return event.subjectId.trim();
1649
+ }
1650
+ return null;
1651
+ };
1641
1652
  var isTerminalEmptyLlmResultEvent = (event) => {
1642
1653
  if (!isRecord2(event) || event.type !== "LLM_RESULT") return false;
1643
1654
  const payload = getStreamEventPayload(event);
@@ -1661,40 +1672,9 @@ var isSameThreadIdentity = (owner, current) => {
1661
1672
  return ownerValues.some((value) => currentValues.has(value));
1662
1673
  };
1663
1674
 
1664
- // src/useCopilotzChat.ts
1665
- var nowTs = () => Date.now();
1666
- var generateId = () => globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
1667
- var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError" || typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
1668
- var getEventPayload = (event) => getStreamEventPayload(event);
1669
- var getEventSenderType = (payload) => payload?.senderType || payload?.sender?.type;
1670
- var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1671
- var normalizeThreadTag = (value) => {
1672
- if (!isRecord3(value)) return null;
1673
- const id = typeof value.id === "string" ? value.id.trim() : "";
1674
- const name = typeof value.name === "string" ? value.name.trim() : "";
1675
- const color = typeof value.color === "string" && value.color.trim() ? value.color.trim() : void 0;
1676
- if (!id || !name) return null;
1677
- return color ? { id, name, color } : { id, name };
1678
- };
1679
- var getThreadTagsFromMetadata = (metadata) => {
1680
- if (!isRecord3(metadata) || !isRecord3(metadata.public)) return [];
1681
- const tags = metadata.public.tags;
1682
- if (!Array.isArray(tags)) return [];
1683
- return tags.map(normalizeThreadTag).filter((tag) => !!tag);
1684
- };
1685
- var patchMetadataPublicTags = (metadata, tags) => ({
1686
- ...metadata ?? {},
1687
- public: {
1688
- ...isRecord3(metadata?.public) ? metadata.public : {},
1689
- tags
1690
- }
1691
- });
1692
- var THREAD_MESSAGES_PAGE_SIZE = 50;
1693
- var createEmptyMessagePageInfo = () => ({
1694
- hasMoreBefore: false,
1695
- oldestMessageId: null,
1696
- newestMessageId: null
1697
- });
1675
+ // src/messageReconciliation.ts
1676
+ var CLIENT_MESSAGE_ID_METADATA_KEY = "clientMessageId";
1677
+ var LLM_ATTEMPT_ID_METADATA_KEY = "llmAttemptId";
1698
1678
  var stringifyForCompare = (value) => {
1699
1679
  if (value === void 0) return "";
1700
1680
  try {
@@ -1719,6 +1699,36 @@ var getMessageSignature = (message) => JSON.stringify({
1719
1699
  agentId: message.sender.agentId
1720
1700
  } : null
1721
1701
  });
1702
+ var getMetadataString = (message, key) => {
1703
+ const value = message.metadata?.[key];
1704
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
1705
+ };
1706
+ var getCorrelationKeys = (message) => {
1707
+ const clientMessageId = getMetadataString(
1708
+ message,
1709
+ CLIENT_MESSAGE_ID_METADATA_KEY
1710
+ );
1711
+ const llmAttemptId = getMetadataString(
1712
+ message,
1713
+ LLM_ATTEMPT_ID_METADATA_KEY
1714
+ );
1715
+ return [
1716
+ ...clientMessageId ? [`client-message:${message.role}:${clientMessageId}`] : [],
1717
+ ...llmAttemptId ? [`llm-attempt:${message.role}:${llmAttemptId}`] : []
1718
+ ];
1719
+ };
1720
+ var indexUniqueFreshCorrelations = (freshMessages) => {
1721
+ const messagesByCorrelation = /* @__PURE__ */ new Map();
1722
+ for (const message of freshMessages) {
1723
+ for (const key of getCorrelationKeys(message)) {
1724
+ messagesByCorrelation.set(
1725
+ key,
1726
+ messagesByCorrelation.has(key) ? null : message
1727
+ );
1728
+ }
1729
+ }
1730
+ return messagesByCorrelation;
1731
+ };
1722
1732
  var reconcileThreadMessages = (currentMessages, freshMessages) => {
1723
1733
  if (freshMessages.length === 0) {
1724
1734
  return { messages: currentMessages, changed: false };
@@ -1727,12 +1737,15 @@ var reconcileThreadMessages = (currentMessages, freshMessages) => {
1727
1737
  return { messages: freshMessages, changed: true };
1728
1738
  }
1729
1739
  const freshById = new Map(freshMessages.map((message) => [message.id, message]));
1740
+ const freshByCorrelation = indexUniqueFreshCorrelations(freshMessages);
1730
1741
  const seen = /* @__PURE__ */ new Set();
1731
1742
  let changed = false;
1732
1743
  const nextMessages = currentMessages.map((message) => {
1733
- const fresh = freshById.get(message.id);
1744
+ const exactMatch = freshById.get(message.id);
1745
+ const correlatedMatch = exactMatch ? null : getCorrelationKeys(message).map((key) => freshByCorrelation.get(key)).find((candidate) => candidate !== null && candidate !== void 0 && !seen.has(candidate.id));
1746
+ const fresh = exactMatch ?? correlatedMatch;
1734
1747
  if (!fresh) return message;
1735
- seen.add(message.id);
1748
+ seen.add(fresh.id);
1736
1749
  if (getMessageSignature(message) === getMessageSignature(fresh)) {
1737
1750
  return message;
1738
1751
  }
@@ -1750,6 +1763,41 @@ var reconcileThreadMessages = (currentMessages, freshMessages) => {
1750
1763
  }
1751
1764
  return changed ? { messages: nextMessages, changed } : { messages: currentMessages, changed: false };
1752
1765
  };
1766
+
1767
+ // src/useCopilotzChat.ts
1768
+ var nowTs = () => Date.now();
1769
+ var generateId = () => globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
1770
+ var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError" || typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
1771
+ var getEventPayload = (event) => getStreamEventPayload(event);
1772
+ var getEventSenderType = (payload) => payload?.senderType || payload?.sender?.type;
1773
+ var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1774
+ var normalizeThreadTag = (value) => {
1775
+ if (!isRecord3(value)) return null;
1776
+ const id = typeof value.id === "string" ? value.id.trim() : "";
1777
+ const name = typeof value.name === "string" ? value.name.trim() : "";
1778
+ const color = typeof value.color === "string" && value.color.trim() ? value.color.trim() : void 0;
1779
+ if (!id || !name) return null;
1780
+ return color ? { id, name, color } : { id, name };
1781
+ };
1782
+ var getThreadTagsFromMetadata = (metadata) => {
1783
+ if (!isRecord3(metadata) || !isRecord3(metadata.public)) return [];
1784
+ const tags = metadata.public.tags;
1785
+ if (!Array.isArray(tags)) return [];
1786
+ return tags.map(normalizeThreadTag).filter((tag) => !!tag);
1787
+ };
1788
+ var patchMetadataPublicTags = (metadata, tags) => ({
1789
+ ...metadata ?? {},
1790
+ public: {
1791
+ ...isRecord3(metadata?.public) ? metadata.public : {},
1792
+ tags
1793
+ }
1794
+ });
1795
+ var THREAD_MESSAGES_PAGE_SIZE = 50;
1796
+ var createEmptyMessagePageInfo = () => ({
1797
+ hasMoreBefore: false,
1798
+ oldestMessageId: null,
1799
+ newestMessageId: null
1800
+ });
1753
1801
  var createPendingAssistantActivity = () => ({
1754
1802
  items: [
1755
1803
  {
@@ -2453,7 +2501,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
2453
2501
  liveToolUpdatesRef.current.push(update);
2454
2502
  }
2455
2503
  };
2456
- const finalizeActiveAssistantTurn = (finalAnswer) => {
2504
+ const finalizeActiveAssistantTurn = (finalAnswer, llmAttemptId) => {
2457
2505
  if (!streamStillOwnsVisibleThread()) return;
2458
2506
  setMessages((prev) => {
2459
2507
  const currentIdx = prev.findIndex((message2) => message2.id === currentAssistantId && message2.role === "assistant");
@@ -2467,8 +2515,15 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
2467
2515
  })();
2468
2516
  if (fallbackIdx < 0) return prev;
2469
2517
  const message = prev[fallbackIdx];
2470
- const nextMessage = finalizeAssistantMessage(message, finalAnswer);
2471
- if (message.content === nextMessage.content && message.isStreaming === nextMessage.isStreaming && message.isComplete === nextMessage.isComplete && message.activity === nextMessage.activity) {
2518
+ const correlatedMessage = llmAttemptId ? {
2519
+ ...message,
2520
+ metadata: {
2521
+ ...message.metadata ?? {},
2522
+ [LLM_ATTEMPT_ID_METADATA_KEY]: llmAttemptId
2523
+ }
2524
+ } : message;
2525
+ const nextMessage = finalizeAssistantMessage(correlatedMessage, finalAnswer);
2526
+ if (message.content === nextMessage.content && message.isStreaming === nextMessage.isStreaming && message.isComplete === nextMessage.isComplete && message.activity === nextMessage.activity && message.metadata === nextMessage.metadata) {
2472
2527
  return prev;
2473
2528
  }
2474
2529
  const updated = [...prev];
@@ -2577,7 +2632,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
2577
2632
  }
2578
2633
  if (type === "LLM_RESULT") {
2579
2634
  const finalAnswer = typeof payload?.answer === "string" ? payload.answer : void 0;
2580
- finalizeActiveAssistantTurn(finalAnswer);
2635
+ finalizeActiveAssistantTurn(finalAnswer, getLlmAttemptId(event));
2581
2636
  if (isTerminalEmptyLlmResultEvent(event)) {
2582
2637
  finalizeStreamingPlaceholders();
2583
2638
  }
@@ -2762,13 +2817,17 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
2762
2817
  );
2763
2818
  const currentMetadata = threadMetadataMapRef.current[conversationKey];
2764
2819
  const pendingTitle = currentMetadata?.pendingTitle;
2820
+ const userMessageId = generateId();
2765
2821
  const userMessage = {
2766
- id: generateId(),
2822
+ id: userMessageId,
2767
2823
  role: "user",
2768
2824
  content,
2769
2825
  timestamp,
2770
2826
  attachments: attachments.length > 0 ? attachments : void 0,
2771
2827
  isComplete: true,
2828
+ metadata: {
2829
+ [CLIENT_MESSAGE_ID_METADATA_KEY]: userMessageId
2830
+ },
2772
2831
  sender: resolveUserSender({
2773
2832
  id: userId,
2774
2833
  name: getCurrentUserDisplayName(userName, userId)
@@ -2817,6 +2876,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
2817
2876
  userId,
2818
2877
  userName: getCurrentUserDisplayName(userName, userId),
2819
2878
  agentName: preferredAgentRef.current,
2879
+ metadata: userMessage.metadata,
2820
2880
  assistantMessageId: assistantPlaceholder.id,
2821
2881
  assistantSender,
2822
2882
  preserveActiveRun,