@reverbia/sdk 1.0.0-next.20260109150925 → 1.0.0-next.20260109181949
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/expo/index.cjs +51 -27
- package/dist/expo/index.d.mts +37 -8
- package/dist/expo/index.d.ts +37 -8
- package/dist/expo/index.mjs +51 -27
- package/dist/react/index.cjs +51 -27
- package/dist/react/index.d.mts +37 -8
- package/dist/react/index.d.ts +37 -8
- package/dist/react/index.mjs +51 -27
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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 =
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
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
|
|
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
|
});
|
|
@@ -3868,7 +3891,8 @@ function useMemoryStorage(options) {
|
|
|
3868
3891
|
content: [{ type: "text", text: m.content }]
|
|
3869
3892
|
}))
|
|
3870
3893
|
],
|
|
3871
|
-
model: model || completionsModel
|
|
3894
|
+
model: model || completionsModel,
|
|
3895
|
+
tool_choice: "none"
|
|
3872
3896
|
},
|
|
3873
3897
|
headers: {
|
|
3874
3898
|
Authorization: `Bearer ${token}`
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -906,20 +906,49 @@ interface BaseUseChatStorageOptions {
|
|
|
906
906
|
*/
|
|
907
907
|
interface BaseSendMessageWithStorageArgs {
|
|
908
908
|
/**
|
|
909
|
-
* The
|
|
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
|
-
|
|
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.
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -906,20 +906,49 @@ interface BaseUseChatStorageOptions {
|
|
|
906
906
|
*/
|
|
907
907
|
interface BaseSendMessageWithStorageArgs {
|
|
908
908
|
/**
|
|
909
|
-
* The
|
|
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
|
-
|
|
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.
|
package/dist/expo/index.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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 =
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
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
|
|
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
|
});
|
|
@@ -3832,7 +3855,8 @@ function useMemoryStorage(options) {
|
|
|
3832
3855
|
content: [{ type: "text", text: m.content }]
|
|
3833
3856
|
}))
|
|
3834
3857
|
],
|
|
3835
|
-
model: model || completionsModel
|
|
3858
|
+
model: model || completionsModel,
|
|
3859
|
+
tool_choice: "none"
|
|
3836
3860
|
},
|
|
3837
3861
|
headers: {
|
|
3838
3862
|
Authorization: `Bearer ${token}`
|
package/dist/react/index.cjs
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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 =
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
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
|
|
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
|
});
|
|
@@ -4494,7 +4517,8 @@ function useMemoryStorage(options) {
|
|
|
4494
4517
|
content: [{ type: "text", text: m.content }]
|
|
4495
4518
|
}))
|
|
4496
4519
|
],
|
|
4497
|
-
model: model || completionsModel
|
|
4520
|
+
model: model || completionsModel,
|
|
4521
|
+
tool_choice: "none"
|
|
4498
4522
|
},
|
|
4499
4523
|
headers: {
|
|
4500
4524
|
Authorization: `Bearer ${token}`
|
package/dist/react/index.d.mts
CHANGED
|
@@ -1552,20 +1552,49 @@ interface BaseUseChatStorageOptions {
|
|
|
1552
1552
|
*/
|
|
1553
1553
|
interface BaseSendMessageWithStorageArgs {
|
|
1554
1554
|
/**
|
|
1555
|
-
* The
|
|
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
|
-
|
|
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.
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1552,20 +1552,49 @@ interface BaseUseChatStorageOptions {
|
|
|
1552
1552
|
*/
|
|
1553
1553
|
interface BaseSendMessageWithStorageArgs {
|
|
1554
1554
|
/**
|
|
1555
|
-
* The
|
|
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
|
-
|
|
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.
|
package/dist/react/index.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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 =
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
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
|
|
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
|
});
|
|
@@ -4372,7 +4395,8 @@ function useMemoryStorage(options) {
|
|
|
4372
4395
|
content: [{ type: "text", text: m.content }]
|
|
4373
4396
|
}))
|
|
4374
4397
|
],
|
|
4375
|
-
model: model || completionsModel
|
|
4398
|
+
model: model || completionsModel,
|
|
4399
|
+
tool_choice: "none"
|
|
4376
4400
|
},
|
|
4377
4401
|
headers: {
|
|
4378
4402
|
Authorization: `Bearer ${token}`
|