@smart-cloud/ai-kit-ui 1.4.14 → 1.4.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smart-cloud/ai-kit-ui",
3
- "version": "1.4.14",
3
+ "version": "1.4.16",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "@emotion/cache": "^11.14.0",
23
23
  "@emotion/react": "^11.14.0",
24
24
  "@mantine/colors-generator": "^8.3.18",
25
- "@smart-cloud/ai-kit-core": "^1.4.9",
25
+ "@smart-cloud/ai-kit-core": "^1.4.11",
26
26
  "@smart-cloud/wpsuite-core": "^2.2.11",
27
27
  "@tabler/icons-react": "^3.41.1",
28
28
  "chroma-js": "^3.2.0",
@@ -65,8 +65,9 @@ const USE_AUDIO = false; // Set to true to enable audio recording feature (requi
65
65
  // New: history storage support
66
66
  const DEFAULT_PRESERVATION_TIME_DAYS = 1;
67
67
  const DEFAULT_HISTORY_STORAGE: HistoryStorageMode = "localstorage";
68
- const HISTORY_STORAGE_KEY = `ai-kit-chatbot-history-v1:${typeof window !== "undefined" ? window.location.hostname : "unknown"
69
- }`;
68
+ const HISTORY_STORAGE_KEY = `ai-kit-chatbot-history-v1:${
69
+ typeof window !== "undefined" ? window.location.hostname : "unknown"
70
+ }`;
70
71
 
71
72
  export const DEFAULT_CHATBOT_LABELS: Required<AiChatbotLabels> = {
72
73
  modalTitle: "AI Assistant",
@@ -126,6 +127,9 @@ type ChatResponse = {
126
127
  modelId?: string;
127
128
  requestId?: string;
128
129
  messageId?: string;
130
+ outputTokens?: number;
131
+ maxTokens?: number;
132
+ stopReason?: string;
129
133
  };
130
134
  };
131
135
 
@@ -222,7 +226,7 @@ const formatStatusEvent = (
222
226
  case "backend:response":
223
227
  return I18n.get(
224
228
  labels.assistantThinkingLabel ??
225
- DEFAULT_CHATBOT_LABELS.assistantThinkingLabel,
229
+ DEFAULT_CHATBOT_LABELS.assistantThinkingLabel,
226
230
  );
227
231
  case "done":
228
232
  return msg || I18n.get("Done.");
@@ -305,6 +309,7 @@ const AiChatbotBase: FC<AiChatbotProps & AiKitShellInjectedProps> = (props) => {
305
309
  placeholder,
306
310
  maxImages,
307
311
  maxImageBytes,
312
+ maxTokens,
308
313
 
309
314
  // New
310
315
  historyStorage = DEFAULT_HISTORY_STORAGE,
@@ -963,9 +968,9 @@ const AiChatbotBase: FC<AiChatbotProps & AiKitShellInjectedProps> = (props) => {
963
968
  blob instanceof File
964
969
  ? blob
965
970
  : new File([blob], attachment.name || "attachment", {
966
- type:
967
- attachment.type || blob.type || "application/octet-stream",
968
- });
971
+ type:
972
+ attachment.type || blob.type || "application/octet-stream",
973
+ });
969
974
 
970
975
  const objectUrl = createObjectUrl(file);
971
976
  if (!objectUrl) continue;
@@ -1054,7 +1059,7 @@ const AiChatbotBase: FC<AiChatbotProps & AiKitShellInjectedProps> = (props) => {
1054
1059
  try {
1055
1060
  const activeSessionId =
1056
1061
  sessionRef.current &&
1057
- Date.now() - sessionRef.current.storedAt <
1062
+ Date.now() - sessionRef.current.storedAt <
1058
1063
  emptyHistoryAfterDays * TWENTY_FOUR_HOURS_MS
1059
1064
  ? sessionRef.current.id
1060
1065
  : undefined;
@@ -1148,7 +1153,7 @@ const AiChatbotBase: FC<AiChatbotProps & AiKitShellInjectedProps> = (props) => {
1148
1153
  try {
1149
1154
  const activeSessionId =
1150
1155
  sessionRef.current &&
1151
- Date.now() - sessionRef.current.storedAt <
1156
+ Date.now() - sessionRef.current.storedAt <
1152
1157
  emptyHistoryAfterDays * TWENTY_FOUR_HOURS_MS
1153
1158
  ? sessionRef.current.id
1154
1159
  : undefined;
@@ -1160,6 +1165,7 @@ const AiChatbotBase: FC<AiChatbotProps & AiKitShellInjectedProps> = (props) => {
1160
1165
  message: trimmed || undefined,
1161
1166
  audio: selectedAudio?.blob,
1162
1167
  images: selectedImages.map((img) => img.file),
1168
+ maxTokens,
1163
1169
  },
1164
1170
  {
1165
1171
  signal,
@@ -1187,10 +1193,25 @@ const AiChatbotBase: FC<AiChatbotProps & AiKitShellInjectedProps> = (props) => {
1187
1193
  };
1188
1194
  }
1189
1195
 
1196
+ const resultText =
1197
+ typeof res.result === "string" ? res.result.trim() : "";
1198
+ if (!resultText) {
1199
+ throw new Error(I18n.get(ai.error ?? labels.emptyResponseLabel));
1200
+ }
1201
+
1202
+ if (res.metadata?.stopReason === "max_tokens") {
1203
+ console.warn("Chat response hit the backend output token limit", {
1204
+ maxTokens: res.metadata?.maxTokens,
1205
+ requestId: res.metadata?.requestId,
1206
+ modelId: res.metadata?.modelId,
1207
+ outputTokens: res.metadata?.outputTokens,
1208
+ });
1209
+ }
1210
+
1190
1211
  const assistantMessage: ChatMessage = {
1191
1212
  id: res.metadata?.messageId || createMessageId("assistant"),
1192
1213
  role: "assistant",
1193
- content: res.result || "",
1214
+ content: resultText,
1194
1215
  citations: res.citations,
1195
1216
  createdAt: Date.now(),
1196
1217
  };
@@ -1776,53 +1797,53 @@ const AiChatbotBase: FC<AiChatbotProps & AiKitShellInjectedProps> = (props) => {
1776
1797
  att.mediaType === "image" ||
1777
1798
  (!att.mediaType && att.type.startsWith("image/")),
1778
1799
  ).length > 0 && (
1779
- <Group
1780
- className="ai-thumbs ai-message-thumbs"
1781
- gap="xs"
1782
- >
1783
- {msg.attachments
1784
- .filter(
1785
- (att) =>
1786
- att.mediaType === "image" ||
1787
- (!att.mediaType &&
1788
- att.type.startsWith("image/")),
1789
- )
1790
- .map((attachment) => (
1791
- <button
1792
- key={attachment.id}
1793
- type="button"
1794
- className="thumb"
1795
- style={{
1796
- backgroundImage: attachment.objectUrl
1797
- ? `url(${attachment.objectUrl})`
1798
- : undefined,
1799
- backgroundSize: "cover",
1800
- backgroundPosition: "center",
1801
- backgroundRepeat: "no-repeat",
1802
- }}
1803
- onClick={() =>
1804
- openAttachmentPreview(
1805
- attachment.objectUrl,
1806
- attachment.name,
1807
- )
1808
- }
1809
- disabled={!attachment.objectUrl}
1810
- title={
1811
- attachment.name || I18n.get("View image")
1812
- }
1813
- aria-label={
1814
- attachment.name || I18n.get("View image")
1815
- }
1816
- >
1817
- {!attachment.objectUrl && (
1818
- <Text size="xs" c="dimmed">
1819
- {I18n.get("Image no longer available")}
1820
- </Text>
1821
- )}
1822
- </button>
1823
- ))}
1824
- </Group>
1825
- )}
1800
+ <Group
1801
+ className="ai-thumbs ai-message-thumbs"
1802
+ gap="xs"
1803
+ >
1804
+ {msg.attachments
1805
+ .filter(
1806
+ (att) =>
1807
+ att.mediaType === "image" ||
1808
+ (!att.mediaType &&
1809
+ att.type.startsWith("image/")),
1810
+ )
1811
+ .map((attachment) => (
1812
+ <button
1813
+ key={attachment.id}
1814
+ type="button"
1815
+ className="thumb"
1816
+ style={{
1817
+ backgroundImage: attachment.objectUrl
1818
+ ? `url(${attachment.objectUrl})`
1819
+ : undefined,
1820
+ backgroundSize: "cover",
1821
+ backgroundPosition: "center",
1822
+ backgroundRepeat: "no-repeat",
1823
+ }}
1824
+ onClick={() =>
1825
+ openAttachmentPreview(
1826
+ attachment.objectUrl,
1827
+ attachment.name,
1828
+ )
1829
+ }
1830
+ disabled={!attachment.objectUrl}
1831
+ title={
1832
+ attachment.name || I18n.get("View image")
1833
+ }
1834
+ aria-label={
1835
+ attachment.name || I18n.get("View image")
1836
+ }
1837
+ >
1838
+ {!attachment.objectUrl && (
1839
+ <Text size="xs" c="dimmed">
1840
+ {I18n.get("Image no longer available")}
1841
+ </Text>
1842
+ )}
1843
+ </button>
1844
+ ))}
1845
+ </Group>
1846
+ )}
1826
1847
 
1827
1848
  {/* Audio attachments */}
1828
1849
  {msg.attachments