@reverbia/sdk 1.0.0-next.20260109150925 → 1.0.0-next.20260109180912

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.
@@ -1303,6 +1303,36 @@ function finalizeThoughtProcess(thoughtProcess) {
1303
1303
  (phase, idx) => idx === thoughtProcess.length - 1 ? { ...phase, status: "completed" } : phase
1304
1304
  );
1305
1305
  }
1306
+ function extractUserMessageFromMessages(messages) {
1307
+ if (!messages || messages.length === 0) {
1308
+ return null;
1309
+ }
1310
+ const userMessages = messages.filter((m) => m.role === "user");
1311
+ const lastUserMessage = userMessages[userMessages.length - 1];
1312
+ if (!lastUserMessage || !lastUserMessage.content) {
1313
+ return null;
1314
+ }
1315
+ const textParts = [];
1316
+ const files = [];
1317
+ for (const part of lastUserMessage.content) {
1318
+ if (part.type === "text" && part.text) {
1319
+ textParts.push(part.text);
1320
+ } else if (part.type === "image_url" && part.image_url?.url) {
1321
+ files.push({
1322
+ id: `img_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
1323
+ name: "image",
1324
+ type: "image/unknown",
1325
+ size: 0,
1326
+ url: part.image_url.url
1327
+ });
1328
+ }
1329
+ }
1330
+ const content = textParts.join("\n");
1331
+ return {
1332
+ content,
1333
+ files: files.length > 0 ? files : void 0
1334
+ };
1335
+ }
1306
1336
 
1307
1337
  // src/lib/db/chat/operations.ts
1308
1338
  var import_watermelondb3 = require("@nozbe/watermelondb");
@@ -1679,9 +1709,8 @@ function useChatStorage(options) {
1679
1709
  const sendMessage = (0, import_react2.useCallback)(
1680
1710
  async (args) => {
1681
1711
  const {
1682
- content,
1712
+ messages,
1683
1713
  model,
1684
- messages: providedMessages,
1685
1714
  includeHistory = true,
1686
1715
  maxHistoryMessages = 50,
1687
1716
  files,
@@ -1702,6 +1731,15 @@ function useChatStorage(options) {
1702
1731
  reasoning,
1703
1732
  thinking
1704
1733
  } = args;
1734
+ const extracted = extractUserMessageFromMessages(messages);
1735
+ if (!extracted || !extracted.content) {
1736
+ return {
1737
+ data: null,
1738
+ error: "No user message found in messages array"
1739
+ };
1740
+ }
1741
+ const contentForStorage = extracted.content;
1742
+ const filesForStorage = files ?? extracted.files;
1705
1743
  let convId;
1706
1744
  try {
1707
1745
  convId = await ensureConversation();
@@ -1712,33 +1750,18 @@ function useChatStorage(options) {
1712
1750
  };
1713
1751
  }
1714
1752
  let messagesToSend = [];
1715
- if (includeHistory && !providedMessages) {
1753
+ if (includeHistory) {
1716
1754
  const storedMessages = await getMessages(convId);
1717
1755
  const validMessages = storedMessages.filter((msg) => !msg.error);
1718
1756
  const limitedMessages = validMessages.slice(-maxHistoryMessages);
1719
- messagesToSend = limitedMessages.map(storedToLlmapiMessage);
1720
- } else if (providedMessages) {
1721
- messagesToSend = providedMessages;
1722
- }
1723
- const userMessageContent = [
1724
- { type: "text", text: content }
1725
- ];
1726
- if (files?.length) {
1727
- for (const file of files) {
1728
- if (file.url) {
1729
- userMessageContent.push({
1730
- type: "image_url",
1731
- image_url: { url: file.url }
1732
- });
1733
- }
1734
- }
1757
+ messagesToSend = [
1758
+ ...limitedMessages.map(storedToLlmapiMessage),
1759
+ ...messages
1760
+ ];
1761
+ } else {
1762
+ messagesToSend = [...messages];
1735
1763
  }
1736
- const userMessage = {
1737
- role: "user",
1738
- content: userMessageContent
1739
- };
1740
- messagesToSend.push(userMessage);
1741
- const sanitizedFiles = files?.map((file) => ({
1764
+ const sanitizedFiles = filesForStorage?.map((file) => ({
1742
1765
  id: file.id,
1743
1766
  name: file.name,
1744
1767
  type: file.type,
@@ -1751,7 +1774,7 @@ function useChatStorage(options) {
1751
1774
  storedUserMessage = await createMessageOp(storageCtx, {
1752
1775
  conversationId: convId,
1753
1776
  role: "user",
1754
- content,
1777
+ content: contentForStorage,
1755
1778
  files: sanitizedFiles,
1756
1779
  model
1757
1780
  });
@@ -906,20 +906,49 @@ interface BaseUseChatStorageOptions {
906
906
  */
907
907
  interface BaseSendMessageWithStorageArgs {
908
908
  /**
909
- * The text content of the message to send to the AI.
909
+ * The message array to send to the AI.
910
+ *
911
+ * Uses the modern array format that supports multimodal content (text, images, files).
912
+ * The last user message in this array will be extracted and stored in the database.
913
+ *
914
+ * When `includeHistory` is true (default), conversation history is prepended.
915
+ * When `includeHistory` is false, only these messages are sent.
916
+ *
917
+ * @example
918
+ * ```ts
919
+ * // Simple usage
920
+ * sendMessage({
921
+ * messages: [
922
+ * { role: "user", content: [{ type: "text", text: "Hello!" }] }
923
+ * ]
924
+ * })
925
+ *
926
+ * // With system prompt and history disabled
927
+ * sendMessage({
928
+ * messages: [
929
+ * { role: "system", content: [{ type: "text", text: "You are helpful" }] },
930
+ * { role: "user", content: [{ type: "text", text: "Question" }] },
931
+ * ],
932
+ * includeHistory: false
933
+ * })
934
+ *
935
+ * // With images
936
+ * sendMessage({
937
+ * messages: [
938
+ * { role: "user", content: [
939
+ * { type: "text", text: "What's in this image?" },
940
+ * { type: "image_url", image_url: { url: "data:image/png;base64,..." } }
941
+ * ]}
942
+ * ]
943
+ * })
944
+ * ```
910
945
  */
911
- content: string;
946
+ messages: LlmapiMessage[];
912
947
  /**
913
948
  * The model identifier to use for this request (e.g., "gpt-4o", "claude-sonnet-4-20250514").
914
949
  * If not specified, uses the default model configured on the server.
915
950
  */
916
951
  model?: string;
917
- /**
918
- * Pre-built message array to send instead of using conversation history.
919
- * When provided, `includeHistory` is ignored and these messages are used directly.
920
- * Useful for custom message construction or when you need full control over context.
921
- */
922
- messages?: LlmapiMessage[];
923
952
  /**
924
953
  * Whether to automatically include previous messages from the conversation as context.
925
954
  * When true, fetches stored messages and prepends them to the request.
@@ -906,20 +906,49 @@ interface BaseUseChatStorageOptions {
906
906
  */
907
907
  interface BaseSendMessageWithStorageArgs {
908
908
  /**
909
- * The text content of the message to send to the AI.
909
+ * The message array to send to the AI.
910
+ *
911
+ * Uses the modern array format that supports multimodal content (text, images, files).
912
+ * The last user message in this array will be extracted and stored in the database.
913
+ *
914
+ * When `includeHistory` is true (default), conversation history is prepended.
915
+ * When `includeHistory` is false, only these messages are sent.
916
+ *
917
+ * @example
918
+ * ```ts
919
+ * // Simple usage
920
+ * sendMessage({
921
+ * messages: [
922
+ * { role: "user", content: [{ type: "text", text: "Hello!" }] }
923
+ * ]
924
+ * })
925
+ *
926
+ * // With system prompt and history disabled
927
+ * sendMessage({
928
+ * messages: [
929
+ * { role: "system", content: [{ type: "text", text: "You are helpful" }] },
930
+ * { role: "user", content: [{ type: "text", text: "Question" }] },
931
+ * ],
932
+ * includeHistory: false
933
+ * })
934
+ *
935
+ * // With images
936
+ * sendMessage({
937
+ * messages: [
938
+ * { role: "user", content: [
939
+ * { type: "text", text: "What's in this image?" },
940
+ * { type: "image_url", image_url: { url: "data:image/png;base64,..." } }
941
+ * ]}
942
+ * ]
943
+ * })
944
+ * ```
910
945
  */
911
- content: string;
946
+ messages: LlmapiMessage[];
912
947
  /**
913
948
  * The model identifier to use for this request (e.g., "gpt-4o", "claude-sonnet-4-20250514").
914
949
  * If not specified, uses the default model configured on the server.
915
950
  */
916
951
  model?: string;
917
- /**
918
- * Pre-built message array to send instead of using conversation history.
919
- * When provided, `includeHistory` is ignored and these messages are used directly.
920
- * Useful for custom message construction or when you need full control over context.
921
- */
922
- messages?: LlmapiMessage[];
923
952
  /**
924
953
  * Whether to automatically include previous messages from the conversation as context.
925
954
  * When true, fetches stored messages and prepends them to the request.
@@ -1267,6 +1267,36 @@ function finalizeThoughtProcess(thoughtProcess) {
1267
1267
  (phase, idx) => idx === thoughtProcess.length - 1 ? { ...phase, status: "completed" } : phase
1268
1268
  );
1269
1269
  }
1270
+ function extractUserMessageFromMessages(messages) {
1271
+ if (!messages || messages.length === 0) {
1272
+ return null;
1273
+ }
1274
+ const userMessages = messages.filter((m) => m.role === "user");
1275
+ const lastUserMessage = userMessages[userMessages.length - 1];
1276
+ if (!lastUserMessage || !lastUserMessage.content) {
1277
+ return null;
1278
+ }
1279
+ const textParts = [];
1280
+ const files = [];
1281
+ for (const part of lastUserMessage.content) {
1282
+ if (part.type === "text" && part.text) {
1283
+ textParts.push(part.text);
1284
+ } else if (part.type === "image_url" && part.image_url?.url) {
1285
+ files.push({
1286
+ id: `img_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
1287
+ name: "image",
1288
+ type: "image/unknown",
1289
+ size: 0,
1290
+ url: part.image_url.url
1291
+ });
1292
+ }
1293
+ }
1294
+ const content = textParts.join("\n");
1295
+ return {
1296
+ content,
1297
+ files: files.length > 0 ? files : void 0
1298
+ };
1299
+ }
1270
1300
 
1271
1301
  // src/lib/db/chat/operations.ts
1272
1302
  import { Q } from "@nozbe/watermelondb";
@@ -1643,9 +1673,8 @@ function useChatStorage(options) {
1643
1673
  const sendMessage = useCallback2(
1644
1674
  async (args) => {
1645
1675
  const {
1646
- content,
1676
+ messages,
1647
1677
  model,
1648
- messages: providedMessages,
1649
1678
  includeHistory = true,
1650
1679
  maxHistoryMessages = 50,
1651
1680
  files,
@@ -1666,6 +1695,15 @@ function useChatStorage(options) {
1666
1695
  reasoning,
1667
1696
  thinking
1668
1697
  } = args;
1698
+ const extracted = extractUserMessageFromMessages(messages);
1699
+ if (!extracted || !extracted.content) {
1700
+ return {
1701
+ data: null,
1702
+ error: "No user message found in messages array"
1703
+ };
1704
+ }
1705
+ const contentForStorage = extracted.content;
1706
+ const filesForStorage = files ?? extracted.files;
1669
1707
  let convId;
1670
1708
  try {
1671
1709
  convId = await ensureConversation();
@@ -1676,33 +1714,18 @@ function useChatStorage(options) {
1676
1714
  };
1677
1715
  }
1678
1716
  let messagesToSend = [];
1679
- if (includeHistory && !providedMessages) {
1717
+ if (includeHistory) {
1680
1718
  const storedMessages = await getMessages(convId);
1681
1719
  const validMessages = storedMessages.filter((msg) => !msg.error);
1682
1720
  const limitedMessages = validMessages.slice(-maxHistoryMessages);
1683
- messagesToSend = limitedMessages.map(storedToLlmapiMessage);
1684
- } else if (providedMessages) {
1685
- messagesToSend = providedMessages;
1686
- }
1687
- const userMessageContent = [
1688
- { type: "text", text: content }
1689
- ];
1690
- if (files?.length) {
1691
- for (const file of files) {
1692
- if (file.url) {
1693
- userMessageContent.push({
1694
- type: "image_url",
1695
- image_url: { url: file.url }
1696
- });
1697
- }
1698
- }
1721
+ messagesToSend = [
1722
+ ...limitedMessages.map(storedToLlmapiMessage),
1723
+ ...messages
1724
+ ];
1725
+ } else {
1726
+ messagesToSend = [...messages];
1699
1727
  }
1700
- const userMessage = {
1701
- role: "user",
1702
- content: userMessageContent
1703
- };
1704
- messagesToSend.push(userMessage);
1705
- const sanitizedFiles = files?.map((file) => ({
1728
+ const sanitizedFiles = filesForStorage?.map((file) => ({
1706
1729
  id: file.id,
1707
1730
  name: file.name,
1708
1731
  type: file.type,
@@ -1715,7 +1738,7 @@ function useChatStorage(options) {
1715
1738
  storedUserMessage = await createMessageOp(storageCtx, {
1716
1739
  conversationId: convId,
1717
1740
  role: "user",
1718
- content,
1741
+ content: contentForStorage,
1719
1742
  files: sanitizedFiles,
1720
1743
  model
1721
1744
  });
@@ -2575,6 +2575,36 @@ function finalizeThoughtProcess(thoughtProcess) {
2575
2575
  (phase, idx) => idx === thoughtProcess.length - 1 ? { ...phase, status: "completed" } : phase
2576
2576
  );
2577
2577
  }
2578
+ function extractUserMessageFromMessages(messages) {
2579
+ if (!messages || messages.length === 0) {
2580
+ return null;
2581
+ }
2582
+ const userMessages = messages.filter((m) => m.role === "user");
2583
+ const lastUserMessage = userMessages[userMessages.length - 1];
2584
+ if (!lastUserMessage || !lastUserMessage.content) {
2585
+ return null;
2586
+ }
2587
+ const textParts = [];
2588
+ const files = [];
2589
+ for (const part of lastUserMessage.content) {
2590
+ if (part.type === "text" && part.text) {
2591
+ textParts.push(part.text);
2592
+ } else if (part.type === "image_url" && part.image_url?.url) {
2593
+ files.push({
2594
+ id: `img_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
2595
+ name: "image",
2596
+ type: "image/unknown",
2597
+ size: 0,
2598
+ url: part.image_url.url
2599
+ });
2600
+ }
2601
+ }
2602
+ const content = textParts.join("\n");
2603
+ return {
2604
+ content,
2605
+ files: files.length > 0 ? files : void 0
2606
+ };
2607
+ }
2578
2608
 
2579
2609
  // src/lib/db/chat/operations.ts
2580
2610
  var import_watermelondb3 = require("@nozbe/watermelondb");
@@ -3097,9 +3127,8 @@ function useChatStorage(options) {
3097
3127
  const sendMessage = (0, import_react2.useCallback)(
3098
3128
  async (args) => {
3099
3129
  const {
3100
- content,
3130
+ messages,
3101
3131
  model,
3102
- messages: providedMessages,
3103
3132
  includeHistory = true,
3104
3133
  maxHistoryMessages = 50,
3105
3134
  files,
@@ -3123,6 +3152,15 @@ function useChatStorage(options) {
3123
3152
  apiType: requestApiType,
3124
3153
  writeFile
3125
3154
  } = args;
3155
+ const extracted = extractUserMessageFromMessages(messages);
3156
+ if (!extracted || !extracted.content) {
3157
+ return {
3158
+ data: null,
3159
+ error: "No user message found in messages array"
3160
+ };
3161
+ }
3162
+ const contentForStorage = extracted.content;
3163
+ const filesForStorage = files ?? extracted.files;
3126
3164
  let convId;
3127
3165
  try {
3128
3166
  convId = await ensureConversation();
@@ -3133,33 +3171,18 @@ function useChatStorage(options) {
3133
3171
  };
3134
3172
  }
3135
3173
  let messagesToSend = [];
3136
- if (includeHistory && !providedMessages) {
3174
+ if (includeHistory) {
3137
3175
  const storedMessages = await getMessages(convId);
3138
3176
  const validMessages = storedMessages.filter((msg) => !msg.error);
3139
3177
  const limitedMessages = validMessages.slice(-maxHistoryMessages);
3140
- messagesToSend = limitedMessages.map(storedToLlmapiMessage);
3141
- } else if (providedMessages) {
3142
- messagesToSend = providedMessages;
3143
- }
3144
- const userMessageContent = [
3145
- { type: "text", text: content }
3146
- ];
3147
- if (files && files.length > 0) {
3148
- for (const file of files) {
3149
- if (file.url && file.type.startsWith("image/")) {
3150
- userMessageContent.push({
3151
- type: "image_url",
3152
- image_url: { url: file.url }
3153
- });
3154
- }
3155
- }
3178
+ messagesToSend = [
3179
+ ...limitedMessages.map(storedToLlmapiMessage),
3180
+ ...messages
3181
+ ];
3182
+ } else {
3183
+ messagesToSend = [...messages];
3156
3184
  }
3157
- const userMessage = {
3158
- role: "user",
3159
- content: userMessageContent
3160
- };
3161
- messagesToSend.push(userMessage);
3162
- const sanitizedFiles = files?.map((file) => ({
3185
+ const sanitizedFiles = filesForStorage?.map((file) => ({
3163
3186
  id: file.id,
3164
3187
  name: file.name,
3165
3188
  type: file.type,
@@ -3172,7 +3195,7 @@ function useChatStorage(options) {
3172
3195
  storedUserMessage = await createMessageOp(storageCtx, {
3173
3196
  conversationId: convId,
3174
3197
  role: "user",
3175
- content,
3198
+ content: contentForStorage,
3176
3199
  files: sanitizedFiles,
3177
3200
  model
3178
3201
  });
@@ -1552,20 +1552,49 @@ interface BaseUseChatStorageOptions {
1552
1552
  */
1553
1553
  interface BaseSendMessageWithStorageArgs {
1554
1554
  /**
1555
- * The text content of the message to send to the AI.
1555
+ * The message array to send to the AI.
1556
+ *
1557
+ * Uses the modern array format that supports multimodal content (text, images, files).
1558
+ * The last user message in this array will be extracted and stored in the database.
1559
+ *
1560
+ * When `includeHistory` is true (default), conversation history is prepended.
1561
+ * When `includeHistory` is false, only these messages are sent.
1562
+ *
1563
+ * @example
1564
+ * ```ts
1565
+ * // Simple usage
1566
+ * sendMessage({
1567
+ * messages: [
1568
+ * { role: "user", content: [{ type: "text", text: "Hello!" }] }
1569
+ * ]
1570
+ * })
1571
+ *
1572
+ * // With system prompt and history disabled
1573
+ * sendMessage({
1574
+ * messages: [
1575
+ * { role: "system", content: [{ type: "text", text: "You are helpful" }] },
1576
+ * { role: "user", content: [{ type: "text", text: "Question" }] },
1577
+ * ],
1578
+ * includeHistory: false
1579
+ * })
1580
+ *
1581
+ * // With images
1582
+ * sendMessage({
1583
+ * messages: [
1584
+ * { role: "user", content: [
1585
+ * { type: "text", text: "What's in this image?" },
1586
+ * { type: "image_url", image_url: { url: "data:image/png;base64,..." } }
1587
+ * ]}
1588
+ * ]
1589
+ * })
1590
+ * ```
1556
1591
  */
1557
- content: string;
1592
+ messages: LlmapiMessage[];
1558
1593
  /**
1559
1594
  * The model identifier to use for this request (e.g., "gpt-4o", "claude-sonnet-4-20250514").
1560
1595
  * If not specified, uses the default model configured on the server.
1561
1596
  */
1562
1597
  model?: string;
1563
- /**
1564
- * Pre-built message array to send instead of using conversation history.
1565
- * When provided, `includeHistory` is ignored and these messages are used directly.
1566
- * Useful for custom message construction or when you need full control over context.
1567
- */
1568
- messages?: LlmapiMessage[];
1569
1598
  /**
1570
1599
  * Whether to automatically include previous messages from the conversation as context.
1571
1600
  * When true, fetches stored messages and prepends them to the request.
@@ -1552,20 +1552,49 @@ interface BaseUseChatStorageOptions {
1552
1552
  */
1553
1553
  interface BaseSendMessageWithStorageArgs {
1554
1554
  /**
1555
- * The text content of the message to send to the AI.
1555
+ * The message array to send to the AI.
1556
+ *
1557
+ * Uses the modern array format that supports multimodal content (text, images, files).
1558
+ * The last user message in this array will be extracted and stored in the database.
1559
+ *
1560
+ * When `includeHistory` is true (default), conversation history is prepended.
1561
+ * When `includeHistory` is false, only these messages are sent.
1562
+ *
1563
+ * @example
1564
+ * ```ts
1565
+ * // Simple usage
1566
+ * sendMessage({
1567
+ * messages: [
1568
+ * { role: "user", content: [{ type: "text", text: "Hello!" }] }
1569
+ * ]
1570
+ * })
1571
+ *
1572
+ * // With system prompt and history disabled
1573
+ * sendMessage({
1574
+ * messages: [
1575
+ * { role: "system", content: [{ type: "text", text: "You are helpful" }] },
1576
+ * { role: "user", content: [{ type: "text", text: "Question" }] },
1577
+ * ],
1578
+ * includeHistory: false
1579
+ * })
1580
+ *
1581
+ * // With images
1582
+ * sendMessage({
1583
+ * messages: [
1584
+ * { role: "user", content: [
1585
+ * { type: "text", text: "What's in this image?" },
1586
+ * { type: "image_url", image_url: { url: "data:image/png;base64,..." } }
1587
+ * ]}
1588
+ * ]
1589
+ * })
1590
+ * ```
1556
1591
  */
1557
- content: string;
1592
+ messages: LlmapiMessage[];
1558
1593
  /**
1559
1594
  * The model identifier to use for this request (e.g., "gpt-4o", "claude-sonnet-4-20250514").
1560
1595
  * If not specified, uses the default model configured on the server.
1561
1596
  */
1562
1597
  model?: string;
1563
- /**
1564
- * Pre-built message array to send instead of using conversation history.
1565
- * When provided, `includeHistory` is ignored and these messages are used directly.
1566
- * Useful for custom message construction or when you need full control over context.
1567
- */
1568
- messages?: LlmapiMessage[];
1569
1598
  /**
1570
1599
  * Whether to automatically include previous messages from the conversation as context.
1571
1600
  * When true, fetches stored messages and prepends them to the request.
@@ -2448,6 +2448,36 @@ function finalizeThoughtProcess(thoughtProcess) {
2448
2448
  (phase, idx) => idx === thoughtProcess.length - 1 ? { ...phase, status: "completed" } : phase
2449
2449
  );
2450
2450
  }
2451
+ function extractUserMessageFromMessages(messages) {
2452
+ if (!messages || messages.length === 0) {
2453
+ return null;
2454
+ }
2455
+ const userMessages = messages.filter((m) => m.role === "user");
2456
+ const lastUserMessage = userMessages[userMessages.length - 1];
2457
+ if (!lastUserMessage || !lastUserMessage.content) {
2458
+ return null;
2459
+ }
2460
+ const textParts = [];
2461
+ const files = [];
2462
+ for (const part of lastUserMessage.content) {
2463
+ if (part.type === "text" && part.text) {
2464
+ textParts.push(part.text);
2465
+ } else if (part.type === "image_url" && part.image_url?.url) {
2466
+ files.push({
2467
+ id: `img_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
2468
+ name: "image",
2469
+ type: "image/unknown",
2470
+ size: 0,
2471
+ url: part.image_url.url
2472
+ });
2473
+ }
2474
+ }
2475
+ const content = textParts.join("\n");
2476
+ return {
2477
+ content,
2478
+ files: files.length > 0 ? files : void 0
2479
+ };
2480
+ }
2451
2481
 
2452
2482
  // src/lib/db/chat/operations.ts
2453
2483
  import { Q } from "@nozbe/watermelondb";
@@ -2970,9 +3000,8 @@ function useChatStorage(options) {
2970
3000
  const sendMessage = useCallback2(
2971
3001
  async (args) => {
2972
3002
  const {
2973
- content,
3003
+ messages,
2974
3004
  model,
2975
- messages: providedMessages,
2976
3005
  includeHistory = true,
2977
3006
  maxHistoryMessages = 50,
2978
3007
  files,
@@ -2996,6 +3025,15 @@ function useChatStorage(options) {
2996
3025
  apiType: requestApiType,
2997
3026
  writeFile
2998
3027
  } = args;
3028
+ const extracted = extractUserMessageFromMessages(messages);
3029
+ if (!extracted || !extracted.content) {
3030
+ return {
3031
+ data: null,
3032
+ error: "No user message found in messages array"
3033
+ };
3034
+ }
3035
+ const contentForStorage = extracted.content;
3036
+ const filesForStorage = files ?? extracted.files;
2999
3037
  let convId;
3000
3038
  try {
3001
3039
  convId = await ensureConversation();
@@ -3006,33 +3044,18 @@ function useChatStorage(options) {
3006
3044
  };
3007
3045
  }
3008
3046
  let messagesToSend = [];
3009
- if (includeHistory && !providedMessages) {
3047
+ if (includeHistory) {
3010
3048
  const storedMessages = await getMessages(convId);
3011
3049
  const validMessages = storedMessages.filter((msg) => !msg.error);
3012
3050
  const limitedMessages = validMessages.slice(-maxHistoryMessages);
3013
- messagesToSend = limitedMessages.map(storedToLlmapiMessage);
3014
- } else if (providedMessages) {
3015
- messagesToSend = providedMessages;
3016
- }
3017
- const userMessageContent = [
3018
- { type: "text", text: content }
3019
- ];
3020
- if (files && files.length > 0) {
3021
- for (const file of files) {
3022
- if (file.url && file.type.startsWith("image/")) {
3023
- userMessageContent.push({
3024
- type: "image_url",
3025
- image_url: { url: file.url }
3026
- });
3027
- }
3028
- }
3051
+ messagesToSend = [
3052
+ ...limitedMessages.map(storedToLlmapiMessage),
3053
+ ...messages
3054
+ ];
3055
+ } else {
3056
+ messagesToSend = [...messages];
3029
3057
  }
3030
- const userMessage = {
3031
- role: "user",
3032
- content: userMessageContent
3033
- };
3034
- messagesToSend.push(userMessage);
3035
- const sanitizedFiles = files?.map((file) => ({
3058
+ const sanitizedFiles = filesForStorage?.map((file) => ({
3036
3059
  id: file.id,
3037
3060
  name: file.name,
3038
3061
  type: file.type,
@@ -3045,7 +3068,7 @@ function useChatStorage(options) {
3045
3068
  storedUserMessage = await createMessageOp(storageCtx, {
3046
3069
  conversationId: convId,
3047
3070
  role: "user",
3048
- content,
3071
+ content: contentForStorage,
3049
3072
  files: sanitizedFiles,
3050
3073
  model
3051
3074
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reverbia/sdk",
3
- "version": "1.0.0-next.20260109150925",
3
+ "version": "1.0.0-next.20260109180912",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",