@reverbia/sdk 1.0.0-next.20260110221448 → 1.0.0-next.20260111110909
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 +167 -12
- package/dist/expo/index.mjs +167 -12
- package/dist/react/index.cjs +520 -73
- package/dist/react/index.d.mts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.mjs +520 -73
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -875,14 +875,128 @@ function validateToken(token) {
|
|
|
875
875
|
}
|
|
876
876
|
return { valid: true };
|
|
877
877
|
}
|
|
878
|
-
function
|
|
878
|
+
function parseReasoningTags(content, previousPartialTag = "") {
|
|
879
|
+
const OPENING_TAG = "<think>";
|
|
880
|
+
const CLOSING_TAG = "</think>";
|
|
881
|
+
const OPENING_TAG_LEN = OPENING_TAG.length;
|
|
882
|
+
const CLOSING_TAG_LEN = CLOSING_TAG.length;
|
|
883
|
+
const fullContent = previousPartialTag + content;
|
|
884
|
+
let messageContent = "";
|
|
885
|
+
let reasoningContent = "";
|
|
886
|
+
let partialTag = "";
|
|
887
|
+
let i = 0;
|
|
888
|
+
let insideReasoning = false;
|
|
889
|
+
if (previousPartialTag) {
|
|
890
|
+
if (previousPartialTag === OPENING_TAG) {
|
|
891
|
+
insideReasoning = true;
|
|
892
|
+
i = OPENING_TAG_LEN;
|
|
893
|
+
} else if (OPENING_TAG.startsWith(previousPartialTag)) {
|
|
894
|
+
if (fullContent.startsWith(OPENING_TAG)) {
|
|
895
|
+
insideReasoning = true;
|
|
896
|
+
i = OPENING_TAG_LEN;
|
|
897
|
+
} else if (OPENING_TAG.startsWith(fullContent.slice(0, Math.min(OPENING_TAG_LEN, fullContent.length)))) {
|
|
898
|
+
return {
|
|
899
|
+
messageContent: "",
|
|
900
|
+
reasoningContent: "",
|
|
901
|
+
partialTag: fullContent.slice(0, Math.min(OPENING_TAG_LEN, fullContent.length))
|
|
902
|
+
};
|
|
903
|
+
} else {
|
|
904
|
+
messageContent = previousPartialTag;
|
|
905
|
+
i = previousPartialTag.length;
|
|
906
|
+
}
|
|
907
|
+
} else if (CLOSING_TAG.startsWith(previousPartialTag)) {
|
|
908
|
+
if (fullContent.startsWith(CLOSING_TAG)) {
|
|
909
|
+
i = CLOSING_TAG_LEN;
|
|
910
|
+
insideReasoning = false;
|
|
911
|
+
} else if (CLOSING_TAG.startsWith(fullContent.slice(0, Math.min(CLOSING_TAG_LEN, fullContent.length)))) {
|
|
912
|
+
return {
|
|
913
|
+
messageContent: "",
|
|
914
|
+
reasoningContent: "",
|
|
915
|
+
partialTag: fullContent.slice(0, Math.min(CLOSING_TAG_LEN, fullContent.length))
|
|
916
|
+
};
|
|
917
|
+
} else {
|
|
918
|
+
reasoningContent = previousPartialTag;
|
|
919
|
+
i = previousPartialTag.length;
|
|
920
|
+
insideReasoning = true;
|
|
921
|
+
}
|
|
922
|
+
} else {
|
|
923
|
+
if (insideReasoning) {
|
|
924
|
+
reasoningContent = previousPartialTag;
|
|
925
|
+
} else {
|
|
926
|
+
messageContent = previousPartialTag;
|
|
927
|
+
}
|
|
928
|
+
i = previousPartialTag.length;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
while (i < fullContent.length) {
|
|
932
|
+
if (insideReasoning) {
|
|
933
|
+
const closeIndex = fullContent.indexOf(CLOSING_TAG, i);
|
|
934
|
+
if (closeIndex === -1) {
|
|
935
|
+
const remaining = fullContent.slice(i);
|
|
936
|
+
if (remaining.length < CLOSING_TAG_LEN) {
|
|
937
|
+
const potentialClose = remaining;
|
|
938
|
+
if (CLOSING_TAG.startsWith(potentialClose)) {
|
|
939
|
+
partialTag = potentialClose;
|
|
940
|
+
} else {
|
|
941
|
+
reasoningContent += remaining;
|
|
942
|
+
}
|
|
943
|
+
} else {
|
|
944
|
+
reasoningContent += remaining;
|
|
945
|
+
}
|
|
946
|
+
break;
|
|
947
|
+
}
|
|
948
|
+
const contentBeforeClose = fullContent.slice(i, closeIndex);
|
|
949
|
+
if (contentBeforeClose) {
|
|
950
|
+
reasoningContent += contentBeforeClose;
|
|
951
|
+
}
|
|
952
|
+
i = closeIndex + CLOSING_TAG_LEN;
|
|
953
|
+
insideReasoning = false;
|
|
954
|
+
} else {
|
|
955
|
+
const openIndex = fullContent.indexOf(OPENING_TAG, i);
|
|
956
|
+
if (openIndex === -1) {
|
|
957
|
+
const remaining = fullContent.slice(i);
|
|
958
|
+
if (remaining.length < OPENING_TAG_LEN) {
|
|
959
|
+
const potentialOpen = remaining;
|
|
960
|
+
if (OPENING_TAG.startsWith(potentialOpen)) {
|
|
961
|
+
partialTag = potentialOpen;
|
|
962
|
+
} else {
|
|
963
|
+
messageContent += remaining;
|
|
964
|
+
}
|
|
965
|
+
} else {
|
|
966
|
+
messageContent += remaining;
|
|
967
|
+
}
|
|
968
|
+
break;
|
|
969
|
+
}
|
|
970
|
+
messageContent += fullContent.slice(i, openIndex);
|
|
971
|
+
i = openIndex + OPENING_TAG_LEN;
|
|
972
|
+
insideReasoning = true;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
if (messageContent.includes(OPENING_TAG) || messageContent.includes(CLOSING_TAG)) {
|
|
976
|
+
console.warn("[parseReasoningTags] Warning: Tag found in messageContent, removing");
|
|
977
|
+
messageContent = messageContent.replace(new RegExp(OPENING_TAG.replace(/[<>]/g, "\\$&"), "g"), "");
|
|
978
|
+
messageContent = messageContent.replace(new RegExp(CLOSING_TAG.replace(/[<>]/g, "\\$&"), "g"), "");
|
|
979
|
+
}
|
|
980
|
+
if (reasoningContent.includes(OPENING_TAG) || reasoningContent.includes(CLOSING_TAG)) {
|
|
981
|
+
console.warn("[parseReasoningTags] Warning: Tag found in reasoningContent, removing");
|
|
982
|
+
reasoningContent = reasoningContent.replace(new RegExp(OPENING_TAG.replace(/[<>]/g, "\\$&"), "g"), "");
|
|
983
|
+
reasoningContent = reasoningContent.replace(new RegExp(CLOSING_TAG.replace(/[<>]/g, "\\$&"), "g"), "");
|
|
984
|
+
}
|
|
985
|
+
return {
|
|
986
|
+
messageContent,
|
|
987
|
+
reasoningContent,
|
|
988
|
+
partialTag
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
function createStreamAccumulator(initialModel) {
|
|
879
992
|
return {
|
|
880
993
|
content: "",
|
|
881
994
|
thinking: "",
|
|
882
995
|
responseId: "",
|
|
883
|
-
responseModel: "",
|
|
996
|
+
responseModel: initialModel || "",
|
|
884
997
|
usage: {},
|
|
885
|
-
toolCalls: /* @__PURE__ */ new Map()
|
|
998
|
+
toolCalls: /* @__PURE__ */ new Map(),
|
|
999
|
+
partialReasoningTag: ""
|
|
886
1000
|
};
|
|
887
1001
|
}
|
|
888
1002
|
function createErrorResult(message, onError) {
|
|
@@ -1052,7 +1166,7 @@ var ResponsesStrategy = class {
|
|
|
1052
1166
|
const delta = typedChunk.delta;
|
|
1053
1167
|
if (delta) {
|
|
1054
1168
|
const deltaText = typeof delta === "string" ? delta : delta.OfString;
|
|
1055
|
-
if (deltaText) {
|
|
1169
|
+
if (deltaText && deltaText.trim().length > 0) {
|
|
1056
1170
|
accumulator.content += deltaText;
|
|
1057
1171
|
result.content = deltaText;
|
|
1058
1172
|
}
|
|
@@ -1179,8 +1293,21 @@ var CompletionsStrategy = class {
|
|
|
1179
1293
|
const choice = typedChunk.choices[0];
|
|
1180
1294
|
if (choice.delta) {
|
|
1181
1295
|
if (choice.delta.content) {
|
|
1182
|
-
|
|
1183
|
-
|
|
1296
|
+
const parseResult = parseReasoningTags(
|
|
1297
|
+
choice.delta.content,
|
|
1298
|
+
accumulator.partialReasoningTag || ""
|
|
1299
|
+
);
|
|
1300
|
+
accumulator.content += parseResult.messageContent;
|
|
1301
|
+
accumulator.thinking += parseResult.reasoningContent;
|
|
1302
|
+
accumulator.partialReasoningTag = parseResult.partialTag;
|
|
1303
|
+
const willEmitMessage = parseResult.messageContent && parseResult.messageContent.trim().length > 0;
|
|
1304
|
+
const willEmitReasoning = parseResult.reasoningContent && parseResult.reasoningContent.trim().length > 0;
|
|
1305
|
+
if (willEmitMessage) {
|
|
1306
|
+
result.content = parseResult.messageContent;
|
|
1307
|
+
}
|
|
1308
|
+
if (willEmitReasoning) {
|
|
1309
|
+
result.thinking = parseResult.reasoningContent;
|
|
1310
|
+
}
|
|
1184
1311
|
}
|
|
1185
1312
|
if (choice.delta.tool_calls) {
|
|
1186
1313
|
for (const toolCallDelta of choice.delta.tool_calls) {
|
|
@@ -1209,8 +1336,19 @@ var CompletionsStrategy = class {
|
|
|
1209
1336
|
}
|
|
1210
1337
|
if (choice.message) {
|
|
1211
1338
|
if (choice.message.content) {
|
|
1212
|
-
|
|
1213
|
-
|
|
1339
|
+
const parseResult = parseReasoningTags(
|
|
1340
|
+
choice.message.content,
|
|
1341
|
+
accumulator.partialReasoningTag || ""
|
|
1342
|
+
);
|
|
1343
|
+
accumulator.content = parseResult.messageContent;
|
|
1344
|
+
accumulator.thinking += parseResult.reasoningContent;
|
|
1345
|
+
accumulator.partialReasoningTag = parseResult.partialTag;
|
|
1346
|
+
if (parseResult.messageContent && parseResult.messageContent.trim().length > 0) {
|
|
1347
|
+
result.content = parseResult.messageContent;
|
|
1348
|
+
}
|
|
1349
|
+
if (parseResult.reasoningContent && parseResult.reasoningContent.trim().length > 0) {
|
|
1350
|
+
result.thinking = parseResult.reasoningContent;
|
|
1351
|
+
}
|
|
1214
1352
|
}
|
|
1215
1353
|
if (choice.message.tool_calls) {
|
|
1216
1354
|
for (let i = 0; i < choice.message.tool_calls.length; i++) {
|
|
@@ -1238,6 +1376,23 @@ var CompletionsStrategy = class {
|
|
|
1238
1376
|
}
|
|
1239
1377
|
buildFinalResponse(accumulator) {
|
|
1240
1378
|
const output = [];
|
|
1379
|
+
let finalContent = accumulator.content;
|
|
1380
|
+
let finalThinking = accumulator.thinking;
|
|
1381
|
+
if (accumulator.partialReasoningTag) {
|
|
1382
|
+
const finalParse = parseReasoningTags("", accumulator.partialReasoningTag);
|
|
1383
|
+
finalContent += finalParse.messageContent;
|
|
1384
|
+
if (finalParse.reasoningContent) {
|
|
1385
|
+
finalThinking += finalParse.reasoningContent;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
if (finalThinking) {
|
|
1389
|
+
output.push({
|
|
1390
|
+
type: "reasoning",
|
|
1391
|
+
role: "assistant",
|
|
1392
|
+
content: [{ type: "output_text", text: finalThinking }],
|
|
1393
|
+
status: "completed"
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1241
1396
|
if (accumulator.toolCalls.size > 0) {
|
|
1242
1397
|
for (const toolCall of accumulator.toolCalls.values()) {
|
|
1243
1398
|
output.push({
|
|
@@ -1252,7 +1407,7 @@ var CompletionsStrategy = class {
|
|
|
1252
1407
|
output.push({
|
|
1253
1408
|
type: "message",
|
|
1254
1409
|
role: "assistant",
|
|
1255
|
-
content: [{ type: "output_text", text:
|
|
1410
|
+
content: [{ type: "output_text", text: finalContent }],
|
|
1256
1411
|
status: "completed"
|
|
1257
1412
|
});
|
|
1258
1413
|
return {
|
|
@@ -1432,7 +1587,7 @@ function useChat(options) {
|
|
|
1432
1587
|
sseError = error instanceof Error ? error : new Error(String(error));
|
|
1433
1588
|
}
|
|
1434
1589
|
});
|
|
1435
|
-
const accumulator = createStreamAccumulator();
|
|
1590
|
+
const accumulator = createStreamAccumulator(model || void 0);
|
|
1436
1591
|
try {
|
|
1437
1592
|
for await (const chunk of sseResult.stream) {
|
|
1438
1593
|
if (isDoneMarker(chunk)) {
|
|
@@ -1627,7 +1782,7 @@ Executing tool: ${toolInfo}
|
|
|
1627
1782
|
sseError = error instanceof Error ? error : new Error(String(error));
|
|
1628
1783
|
}
|
|
1629
1784
|
});
|
|
1630
|
-
const continuationAccumulator = createStreamAccumulator();
|
|
1785
|
+
const continuationAccumulator = createStreamAccumulator(model || void 0);
|
|
1631
1786
|
try {
|
|
1632
1787
|
for await (const chunk of continuationResult.stream) {
|
|
1633
1788
|
if (isDoneMarker(chunk)) {
|
|
@@ -2877,44 +3032,80 @@ var BlobUrlManager = class {
|
|
|
2877
3032
|
// src/react/useChatStorage.ts
|
|
2878
3033
|
function replaceUrlWithMCPPlaceholder(content, url, fileId) {
|
|
2879
3034
|
const escapedUrl = url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2880
|
-
const placeholder =
|
|
3035
|
+
const placeholder = createFilePlaceholder(fileId);
|
|
2881
3036
|
let result = content;
|
|
3037
|
+
console.log(
|
|
3038
|
+
`[replaceUrlWithMCPPlaceholder] Replacing URL with placeholder:`,
|
|
3039
|
+
url,
|
|
3040
|
+
"->",
|
|
3041
|
+
placeholder
|
|
3042
|
+
);
|
|
3043
|
+
const htmlImgPatternDouble = new RegExp(
|
|
3044
|
+
`<img[^>]*src="${escapedUrl}"[^>]*>`,
|
|
3045
|
+
"gi"
|
|
3046
|
+
);
|
|
3047
|
+
const doubleMatches = result.match(htmlImgPatternDouble);
|
|
3048
|
+
if (doubleMatches) {
|
|
3049
|
+
console.log(
|
|
3050
|
+
`[replaceUrlWithMCPPlaceholder] Replacing ${doubleMatches.length} HTML img tag(s) with double quotes:`,
|
|
3051
|
+
doubleMatches,
|
|
3052
|
+
"->",
|
|
3053
|
+
placeholder
|
|
3054
|
+
);
|
|
3055
|
+
}
|
|
3056
|
+
result = result.replace(htmlImgPatternDouble, placeholder);
|
|
3057
|
+
const htmlImgPatternSingle = new RegExp(
|
|
3058
|
+
`<img[^>]*src='${escapedUrl}'[^>]*>`,
|
|
3059
|
+
"gi"
|
|
3060
|
+
);
|
|
3061
|
+
const singleMatches = result.match(htmlImgPatternSingle);
|
|
3062
|
+
if (singleMatches) {
|
|
3063
|
+
console.log(
|
|
3064
|
+
`[replaceUrlWithMCPPlaceholder] Replacing ${singleMatches.length} HTML img tag(s) with single quotes:`,
|
|
3065
|
+
singleMatches,
|
|
3066
|
+
"->",
|
|
3067
|
+
placeholder
|
|
3068
|
+
);
|
|
3069
|
+
}
|
|
3070
|
+
result = result.replace(htmlImgPatternSingle, placeholder);
|
|
2882
3071
|
const markdownImagePattern = new RegExp(
|
|
2883
3072
|
`!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
|
|
2884
3073
|
"g"
|
|
2885
3074
|
);
|
|
3075
|
+
const markdownMatches = result.match(markdownImagePattern);
|
|
3076
|
+
if (markdownMatches) {
|
|
3077
|
+
console.log(
|
|
3078
|
+
`[replaceUrlWithMCPPlaceholder] Replacing ${markdownMatches.length} markdown image(s):`,
|
|
3079
|
+
markdownMatches,
|
|
3080
|
+
"->",
|
|
3081
|
+
placeholder
|
|
3082
|
+
);
|
|
3083
|
+
}
|
|
2886
3084
|
result = result.replace(markdownImagePattern, placeholder);
|
|
2887
|
-
|
|
2888
|
-
const
|
|
2889
|
-
|
|
2890
|
-
|
|
3085
|
+
const rawUrlPattern = new RegExp(escapedUrl, "g");
|
|
3086
|
+
const rawMatches = result.match(rawUrlPattern);
|
|
3087
|
+
if (rawMatches) {
|
|
3088
|
+
console.log(
|
|
3089
|
+
`[replaceUrlWithMCPPlaceholder] Replacing ${rawMatches.length} raw URL(s):`,
|
|
3090
|
+
rawMatches,
|
|
3091
|
+
"->",
|
|
3092
|
+
placeholder
|
|
3093
|
+
);
|
|
3094
|
+
}
|
|
3095
|
+
result = result.replace(rawUrlPattern, placeholder);
|
|
3096
|
+
console.log(
|
|
3097
|
+
`[replaceUrlWithMCPPlaceholder] Final result length: ${result.length}, original length: ${content.length}`
|
|
2891
3098
|
);
|
|
2892
|
-
result = result.replace(orphanedMarkdownPattern, placeholder);
|
|
2893
3099
|
return result;
|
|
2894
3100
|
}
|
|
2895
3101
|
function findFileIdBySourceUrl(files, sourceUrl) {
|
|
2896
3102
|
return files?.find((f) => f.sourceUrl === sourceUrl)?.id;
|
|
2897
3103
|
}
|
|
2898
|
-
|
|
2899
|
-
try {
|
|
2900
|
-
const controller = new AbortController();
|
|
2901
|
-
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
2902
|
-
const response = await fetch(url, {
|
|
2903
|
-
method: "GET",
|
|
2904
|
-
headers: { Range: "bytes=0-0" },
|
|
2905
|
-
signal: controller.signal
|
|
2906
|
-
});
|
|
2907
|
-
clearTimeout(timeoutId);
|
|
2908
|
-
return response.ok || response.status === 206;
|
|
2909
|
-
} catch {
|
|
2910
|
-
return false;
|
|
2911
|
-
}
|
|
2912
|
-
}
|
|
2913
|
-
async function storedToLlmapiMessage(stored) {
|
|
3104
|
+
function storedToLlmapiMessage(stored) {
|
|
2914
3105
|
let textContent = stored.content;
|
|
2915
3106
|
const fileUrlMap = /* @__PURE__ */ new Map();
|
|
2916
3107
|
const imageParts = [];
|
|
2917
|
-
if (stored.files?.length) {
|
|
3108
|
+
if (stored.role !== "assistant" && stored.files?.length) {
|
|
2918
3109
|
for (const file of stored.files) {
|
|
2919
3110
|
if (file.url) {
|
|
2920
3111
|
imageParts.push({
|
|
@@ -2922,14 +3113,17 @@ async function storedToLlmapiMessage(stored) {
|
|
|
2922
3113
|
image_url: { url: file.url }
|
|
2923
3114
|
});
|
|
2924
3115
|
} else if (file.sourceUrl) {
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
3116
|
+
imageParts.push({
|
|
3117
|
+
type: "image_url",
|
|
3118
|
+
image_url: { url: file.sourceUrl }
|
|
3119
|
+
});
|
|
3120
|
+
fileUrlMap.set(file.id, file.sourceUrl);
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
} else if (stored.role === "assistant" && stored.files?.length) {
|
|
3124
|
+
for (const file of stored.files) {
|
|
3125
|
+
if (file.sourceUrl) {
|
|
3126
|
+
fileUrlMap.set(file.id, file.sourceUrl);
|
|
2933
3127
|
}
|
|
2934
3128
|
}
|
|
2935
3129
|
}
|
|
@@ -3063,26 +3257,63 @@ function useChatStorage(options) {
|
|
|
3063
3257
|
if (fileIds.length === 0) {
|
|
3064
3258
|
return msg;
|
|
3065
3259
|
}
|
|
3260
|
+
console.log(
|
|
3261
|
+
`[getMessages] Found ${fileIds.length} placeholder(s) in message ${msg.uniqueId}:`,
|
|
3262
|
+
fileIds
|
|
3263
|
+
);
|
|
3066
3264
|
let resolvedContent = msg.content;
|
|
3067
3265
|
for (const fileId of fileIds) {
|
|
3266
|
+
const placeholder = createFilePlaceholder(fileId);
|
|
3267
|
+
console.log(
|
|
3268
|
+
`[getMessages] Resolving placeholder: ${placeholder} (fileId: ${fileId})`
|
|
3269
|
+
);
|
|
3068
3270
|
let url = blobManager.getUrl(fileId);
|
|
3069
3271
|
if (!url) {
|
|
3272
|
+
console.log(
|
|
3273
|
+
`[getMessages] No cached URL for ${fileId}, reading from OPFS...`
|
|
3274
|
+
);
|
|
3070
3275
|
const result = await readEncryptedFile(fileId, encryptionKey);
|
|
3071
3276
|
if (result) {
|
|
3072
3277
|
url = blobManager.createUrl(fileId, result.blob);
|
|
3278
|
+
console.log(
|
|
3279
|
+
`[getMessages] Created blob URL for ${fileId}:`,
|
|
3280
|
+
url
|
|
3281
|
+
);
|
|
3282
|
+
} else {
|
|
3283
|
+
console.warn(
|
|
3284
|
+
`[getMessages] Failed to read file ${fileId} from OPFS`
|
|
3285
|
+
);
|
|
3073
3286
|
}
|
|
3287
|
+
} else {
|
|
3288
|
+
console.log(
|
|
3289
|
+
`[getMessages] Using cached blob URL for ${fileId}:`,
|
|
3290
|
+
url
|
|
3291
|
+
);
|
|
3074
3292
|
}
|
|
3075
3293
|
if (url) {
|
|
3076
|
-
const
|
|
3294
|
+
const placeholderRegex = new RegExp(
|
|
3295
|
+
placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
|
|
3296
|
+
"g"
|
|
3297
|
+
);
|
|
3298
|
+
const matches = resolvedContent.match(placeholderRegex);
|
|
3299
|
+
const replacement = ``;
|
|
3300
|
+
console.log(
|
|
3301
|
+
`[getMessages] Replacing ${matches?.length || 0} instance(s) of ${placeholder} with:`,
|
|
3302
|
+
replacement
|
|
3303
|
+
);
|
|
3077
3304
|
resolvedContent = resolvedContent.replace(
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3305
|
+
placeholderRegex,
|
|
3306
|
+
replacement
|
|
3307
|
+
);
|
|
3308
|
+
} else {
|
|
3309
|
+
console.warn(
|
|
3310
|
+
`[getMessages] No URL available for ${fileId}, placeholder ${placeholder} will remain in content`
|
|
3083
3311
|
);
|
|
3084
3312
|
}
|
|
3085
3313
|
}
|
|
3314
|
+
console.log(
|
|
3315
|
+
`[getMessages] Resolved content length: ${resolvedContent.length}, original length: ${msg.content.length}`
|
|
3316
|
+
);
|
|
3086
3317
|
return { ...msg, content: resolvedContent };
|
|
3087
3318
|
})
|
|
3088
3319
|
);
|
|
@@ -3222,16 +3453,42 @@ function useChatStorage(options) {
|
|
|
3222
3453
|
const { replaceUrls = true } = options2 ?? {};
|
|
3223
3454
|
try {
|
|
3224
3455
|
const MCP_IMAGE_URL_PATTERN = new RegExp(
|
|
3225
|
-
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s)]*`,
|
|
3456
|
+
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s"'<>)]*`,
|
|
3226
3457
|
"g"
|
|
3227
3458
|
);
|
|
3228
3459
|
const urlMatches = content.match(MCP_IMAGE_URL_PATTERN);
|
|
3229
3460
|
if (!urlMatches || urlMatches.length === 0) {
|
|
3230
3461
|
return { processedFiles: [], cleanedContent: content };
|
|
3231
3462
|
}
|
|
3232
|
-
const
|
|
3463
|
+
const cleanedUrls = urlMatches.map((url) => url.replace(/["']+$/, ""));
|
|
3464
|
+
const uniqueUrls = [...new Set(cleanedUrls)];
|
|
3233
3465
|
const processedFiles = [];
|
|
3234
3466
|
let cleanedContent = content;
|
|
3467
|
+
const urlOccurrenceCounts = /* @__PURE__ */ new Map();
|
|
3468
|
+
uniqueUrls.forEach((url) => {
|
|
3469
|
+
const escapedUrl = url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3470
|
+
const htmlDoublePattern = new RegExp(
|
|
3471
|
+
`<img[^>]*src="${escapedUrl}"[^>]*>`,
|
|
3472
|
+
"gi"
|
|
3473
|
+
);
|
|
3474
|
+
const htmlSinglePattern = new RegExp(
|
|
3475
|
+
`<img[^>]*src='${escapedUrl}'[^>]*>`,
|
|
3476
|
+
"gi"
|
|
3477
|
+
);
|
|
3478
|
+
const markdownPattern = new RegExp(
|
|
3479
|
+
`!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
|
|
3480
|
+
"g"
|
|
3481
|
+
);
|
|
3482
|
+
const rawPattern = new RegExp(escapedUrl, "g");
|
|
3483
|
+
const htmlDoubleMatches = content.match(htmlDoublePattern)?.length || 0;
|
|
3484
|
+
const htmlSingleMatches = content.match(htmlSinglePattern)?.length || 0;
|
|
3485
|
+
const markdownMatches = content.match(markdownPattern)?.length || 0;
|
|
3486
|
+
const rawMatches = (content.match(rawPattern)?.length || 0) - htmlDoubleMatches - htmlSingleMatches - markdownMatches;
|
|
3487
|
+
urlOccurrenceCounts.set(
|
|
3488
|
+
url,
|
|
3489
|
+
htmlDoubleMatches + htmlSingleMatches + markdownMatches + rawMatches
|
|
3490
|
+
);
|
|
3491
|
+
});
|
|
3235
3492
|
const results = await Promise.allSettled(
|
|
3236
3493
|
uniqueUrls.map(async (imageUrl) => {
|
|
3237
3494
|
const controller = new AbortController();
|
|
@@ -3263,27 +3520,85 @@ function useChatStorage(options) {
|
|
|
3263
3520
|
);
|
|
3264
3521
|
const replaceUrlWithPlaceholder = (imageUrl, fileId) => {
|
|
3265
3522
|
const escapedUrl = imageUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3266
|
-
const placeholder =
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
markdownImagePattern,
|
|
3523
|
+
const placeholder = createFilePlaceholder(fileId);
|
|
3524
|
+
let replacementCount = 0;
|
|
3525
|
+
console.log(
|
|
3526
|
+
`[extractAndStoreMCPImages] Replacing URL with placeholder:`,
|
|
3527
|
+
imageUrl,
|
|
3528
|
+
"->",
|
|
3273
3529
|
placeholder
|
|
3274
3530
|
);
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3531
|
+
const htmlImgPatternDouble = new RegExp(
|
|
3532
|
+
`<img[^>]*src="${escapedUrl}"[^>]*>`,
|
|
3533
|
+
"gi"
|
|
3278
3534
|
);
|
|
3279
|
-
const
|
|
3280
|
-
|
|
3535
|
+
const doubleMatches = cleanedContent.match(htmlImgPatternDouble);
|
|
3536
|
+
if (doubleMatches) {
|
|
3537
|
+
console.log(
|
|
3538
|
+
`[extractAndStoreMCPImages] Replacing ${doubleMatches.length} HTML img tag(s) with double quotes:`,
|
|
3539
|
+
doubleMatches,
|
|
3540
|
+
"->",
|
|
3541
|
+
placeholder
|
|
3542
|
+
);
|
|
3543
|
+
replacementCount += doubleMatches.length;
|
|
3544
|
+
cleanedContent = cleanedContent.replace(
|
|
3545
|
+
htmlImgPatternDouble,
|
|
3546
|
+
placeholder
|
|
3547
|
+
);
|
|
3548
|
+
}
|
|
3549
|
+
const htmlImgPatternSingle = new RegExp(
|
|
3550
|
+
`<img[^>]*src='${escapedUrl}'[^>]*>`,
|
|
3551
|
+
"gi"
|
|
3552
|
+
);
|
|
3553
|
+
const singleMatches = cleanedContent.match(htmlImgPatternSingle);
|
|
3554
|
+
if (singleMatches) {
|
|
3555
|
+
console.log(
|
|
3556
|
+
`[extractAndStoreMCPImages] Replacing ${singleMatches.length} HTML img tag(s) with single quotes:`,
|
|
3557
|
+
singleMatches,
|
|
3558
|
+
"->",
|
|
3559
|
+
placeholder
|
|
3560
|
+
);
|
|
3561
|
+
replacementCount += singleMatches.length;
|
|
3562
|
+
cleanedContent = cleanedContent.replace(
|
|
3563
|
+
htmlImgPatternSingle,
|
|
3564
|
+
placeholder
|
|
3565
|
+
);
|
|
3566
|
+
}
|
|
3567
|
+
const markdownImagePattern = new RegExp(
|
|
3568
|
+
`!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
|
|
3281
3569
|
"g"
|
|
3282
3570
|
);
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3571
|
+
const markdownMatches = cleanedContent.match(markdownImagePattern);
|
|
3572
|
+
if (markdownMatches) {
|
|
3573
|
+
console.log(
|
|
3574
|
+
`[extractAndStoreMCPImages] Replacing ${markdownMatches.length} markdown image(s):`,
|
|
3575
|
+
markdownMatches,
|
|
3576
|
+
"->",
|
|
3577
|
+
placeholder
|
|
3578
|
+
);
|
|
3579
|
+
replacementCount += markdownMatches.length;
|
|
3580
|
+
cleanedContent = cleanedContent.replace(
|
|
3581
|
+
markdownImagePattern,
|
|
3582
|
+
placeholder
|
|
3583
|
+
);
|
|
3584
|
+
}
|
|
3585
|
+
const rawUrlPattern = new RegExp(escapedUrl, "g");
|
|
3586
|
+
const rawMatches = cleanedContent.match(rawUrlPattern);
|
|
3587
|
+
if (rawMatches) {
|
|
3588
|
+
console.log(
|
|
3589
|
+
`[extractAndStoreMCPImages] Replacing ${rawMatches.length} raw URL(s):`,
|
|
3590
|
+
rawMatches,
|
|
3591
|
+
"->",
|
|
3592
|
+
placeholder
|
|
3593
|
+
);
|
|
3594
|
+
replacementCount += rawMatches.length;
|
|
3595
|
+
cleanedContent = cleanedContent.replace(rawUrlPattern, placeholder);
|
|
3596
|
+
}
|
|
3597
|
+
console.log(
|
|
3598
|
+
`[extractAndStoreMCPImages] Total replacements made: ${replacementCount} for URL:`,
|
|
3599
|
+
imageUrl
|
|
3286
3600
|
);
|
|
3601
|
+
return replacementCount;
|
|
3287
3602
|
};
|
|
3288
3603
|
results.forEach((result, i) => {
|
|
3289
3604
|
const imageUrl = uniqueUrls[i];
|
|
@@ -3297,7 +3612,29 @@ function useChatStorage(options) {
|
|
|
3297
3612
|
sourceUrl: imageUrl
|
|
3298
3613
|
});
|
|
3299
3614
|
if (replaceUrls && imageUrl) {
|
|
3300
|
-
replaceUrlWithPlaceholder(
|
|
3615
|
+
const replacementCount = replaceUrlWithPlaceholder(
|
|
3616
|
+
imageUrl,
|
|
3617
|
+
fileId
|
|
3618
|
+
);
|
|
3619
|
+
const expectedCount = urlOccurrenceCounts.get(imageUrl) || 0;
|
|
3620
|
+
if (replacementCount < expectedCount) {
|
|
3621
|
+
console.warn(
|
|
3622
|
+
`[extractAndStoreMCPImages] Not all instances of URL replaced. Expected ${expectedCount}, replaced ${replacementCount}:`,
|
|
3623
|
+
imageUrl
|
|
3624
|
+
);
|
|
3625
|
+
}
|
|
3626
|
+
const escapedUrl = imageUrl.replace(
|
|
3627
|
+
/[.*+?^${}()|[\]\\]/g,
|
|
3628
|
+
"\\$&"
|
|
3629
|
+
);
|
|
3630
|
+
const remainingPattern = new RegExp(escapedUrl, "g");
|
|
3631
|
+
const remainingMatches = cleanedContent.match(remainingPattern);
|
|
3632
|
+
if (remainingMatches && remainingMatches.length > 0) {
|
|
3633
|
+
console.warn(
|
|
3634
|
+
`[extractAndStoreMCPImages] Found ${remainingMatches.length} remaining instance(s) of URL after replacement:`,
|
|
3635
|
+
imageUrl
|
|
3636
|
+
);
|
|
3637
|
+
}
|
|
3301
3638
|
}
|
|
3302
3639
|
} else {
|
|
3303
3640
|
console.error(
|
|
@@ -3330,17 +3667,43 @@ function useChatStorage(options) {
|
|
|
3330
3667
|
return { processedFiles: [], cleanedContent: content };
|
|
3331
3668
|
}
|
|
3332
3669
|
const MCP_IMAGE_URL_PATTERN = new RegExp(
|
|
3333
|
-
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s)]*`,
|
|
3670
|
+
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s"'<>)]*`,
|
|
3334
3671
|
"g"
|
|
3335
3672
|
);
|
|
3336
3673
|
const urlMatches = content.match(MCP_IMAGE_URL_PATTERN);
|
|
3337
3674
|
if (!urlMatches || urlMatches.length === 0) {
|
|
3338
3675
|
return { processedFiles: [], cleanedContent: content };
|
|
3339
3676
|
}
|
|
3340
|
-
const
|
|
3677
|
+
const cleanedUrls = urlMatches.map((url) => url.replace(/["']+$/, ""));
|
|
3678
|
+
const uniqueUrls = [...new Set(cleanedUrls)];
|
|
3341
3679
|
const encryptionKey = await getEncryptionKey(address);
|
|
3342
3680
|
const processedFiles = [];
|
|
3343
3681
|
let cleanedContent = content;
|
|
3682
|
+
const urlOccurrenceCounts = /* @__PURE__ */ new Map();
|
|
3683
|
+
uniqueUrls.forEach((url) => {
|
|
3684
|
+
const escapedUrl = url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3685
|
+
const htmlDoublePattern = new RegExp(
|
|
3686
|
+
`<img[^>]*src="${escapedUrl}"[^>]*>`,
|
|
3687
|
+
"gi"
|
|
3688
|
+
);
|
|
3689
|
+
const htmlSinglePattern = new RegExp(
|
|
3690
|
+
`<img[^>]*src='${escapedUrl}'[^>]*>`,
|
|
3691
|
+
"gi"
|
|
3692
|
+
);
|
|
3693
|
+
const markdownPattern = new RegExp(
|
|
3694
|
+
`!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
|
|
3695
|
+
"g"
|
|
3696
|
+
);
|
|
3697
|
+
const rawPattern = new RegExp(escapedUrl, "g");
|
|
3698
|
+
const htmlDoubleMatches = content.match(htmlDoublePattern)?.length || 0;
|
|
3699
|
+
const htmlSingleMatches = content.match(htmlSinglePattern)?.length || 0;
|
|
3700
|
+
const markdownMatches = content.match(markdownPattern)?.length || 0;
|
|
3701
|
+
const rawMatches = (content.match(rawPattern)?.length || 0) - htmlDoubleMatches - htmlSingleMatches - markdownMatches;
|
|
3702
|
+
urlOccurrenceCounts.set(
|
|
3703
|
+
url,
|
|
3704
|
+
htmlDoubleMatches + htmlSingleMatches + markdownMatches + rawMatches
|
|
3705
|
+
);
|
|
3706
|
+
});
|
|
3344
3707
|
const results = await Promise.allSettled(
|
|
3345
3708
|
uniqueUrls.map(async (imageUrl) => {
|
|
3346
3709
|
const controller = new AbortController();
|
|
@@ -3382,12 +3745,98 @@ function useChatStorage(options) {
|
|
|
3382
3745
|
});
|
|
3383
3746
|
const placeholder = createFilePlaceholder(fileId);
|
|
3384
3747
|
const escapedUrl = imageUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3748
|
+
let replacementCount = 0;
|
|
3749
|
+
console.log(
|
|
3750
|
+
`[extractAndStoreEncryptedMCPImages] Replacing URL with placeholder:`,
|
|
3751
|
+
imageUrl,
|
|
3752
|
+
"->",
|
|
3753
|
+
placeholder
|
|
3754
|
+
);
|
|
3755
|
+
const htmlImgPatternDouble = new RegExp(
|
|
3756
|
+
`<img[^>]*src="${escapedUrl}"[^>]*>`,
|
|
3757
|
+
"gi"
|
|
3758
|
+
);
|
|
3759
|
+
const doubleMatches = cleanedContent.match(htmlImgPatternDouble);
|
|
3760
|
+
if (doubleMatches) {
|
|
3761
|
+
console.log(
|
|
3762
|
+
`[extractAndStoreEncryptedMCPImages] Replacing ${doubleMatches.length} HTML img tag(s) with double quotes:`,
|
|
3763
|
+
doubleMatches,
|
|
3764
|
+
"->",
|
|
3765
|
+
placeholder
|
|
3766
|
+
);
|
|
3767
|
+
replacementCount += doubleMatches.length;
|
|
3768
|
+
cleanedContent = cleanedContent.replace(
|
|
3769
|
+
htmlImgPatternDouble,
|
|
3770
|
+
placeholder
|
|
3771
|
+
);
|
|
3772
|
+
}
|
|
3773
|
+
const htmlImgPatternSingle = new RegExp(
|
|
3774
|
+
`<img[^>]*src='${escapedUrl}'[^>]*>`,
|
|
3775
|
+
"gi"
|
|
3776
|
+
);
|
|
3777
|
+
const singleMatches = cleanedContent.match(htmlImgPatternSingle);
|
|
3778
|
+
if (singleMatches) {
|
|
3779
|
+
console.log(
|
|
3780
|
+
`[extractAndStoreEncryptedMCPImages] Replacing ${singleMatches.length} HTML img tag(s) with single quotes:`,
|
|
3781
|
+
singleMatches,
|
|
3782
|
+
"->",
|
|
3783
|
+
placeholder
|
|
3784
|
+
);
|
|
3785
|
+
replacementCount += singleMatches.length;
|
|
3786
|
+
cleanedContent = cleanedContent.replace(
|
|
3787
|
+
htmlImgPatternSingle,
|
|
3788
|
+
placeholder
|
|
3789
|
+
);
|
|
3790
|
+
}
|
|
3385
3791
|
const markdownImagePattern = new RegExp(
|
|
3386
3792
|
`!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
|
|
3387
3793
|
"g"
|
|
3388
3794
|
);
|
|
3389
|
-
|
|
3390
|
-
|
|
3795
|
+
const markdownMatches = cleanedContent.match(markdownImagePattern);
|
|
3796
|
+
if (markdownMatches) {
|
|
3797
|
+
console.log(
|
|
3798
|
+
`[extractAndStoreEncryptedMCPImages] Replacing ${markdownMatches.length} markdown image(s):`,
|
|
3799
|
+
markdownMatches,
|
|
3800
|
+
"->",
|
|
3801
|
+
placeholder
|
|
3802
|
+
);
|
|
3803
|
+
replacementCount += markdownMatches.length;
|
|
3804
|
+
cleanedContent = cleanedContent.replace(
|
|
3805
|
+
markdownImagePattern,
|
|
3806
|
+
placeholder
|
|
3807
|
+
);
|
|
3808
|
+
}
|
|
3809
|
+
const rawUrlPattern = new RegExp(escapedUrl, "g");
|
|
3810
|
+
const rawMatches = cleanedContent.match(rawUrlPattern);
|
|
3811
|
+
if (rawMatches) {
|
|
3812
|
+
console.log(
|
|
3813
|
+
`[extractAndStoreEncryptedMCPImages] Replacing ${rawMatches.length} raw URL(s):`,
|
|
3814
|
+
rawMatches,
|
|
3815
|
+
"->",
|
|
3816
|
+
placeholder
|
|
3817
|
+
);
|
|
3818
|
+
replacementCount += rawMatches.length;
|
|
3819
|
+
cleanedContent = cleanedContent.replace(rawUrlPattern, placeholder);
|
|
3820
|
+
}
|
|
3821
|
+
console.log(
|
|
3822
|
+
`[extractAndStoreEncryptedMCPImages] Total replacements made: ${replacementCount} for URL:`,
|
|
3823
|
+
imageUrl
|
|
3824
|
+
);
|
|
3825
|
+
const expectedCount = urlOccurrenceCounts.get(imageUrl) || 0;
|
|
3826
|
+
if (replacementCount < expectedCount) {
|
|
3827
|
+
console.warn(
|
|
3828
|
+
`[extractAndStoreEncryptedMCPImages] Not all instances of URL replaced. Expected ${expectedCount}, replaced ${replacementCount}:`,
|
|
3829
|
+
imageUrl
|
|
3830
|
+
);
|
|
3831
|
+
}
|
|
3832
|
+
const remainingPattern = new RegExp(escapedUrl, "g");
|
|
3833
|
+
const remainingMatches = cleanedContent.match(remainingPattern);
|
|
3834
|
+
if (remainingMatches && remainingMatches.length > 0) {
|
|
3835
|
+
console.warn(
|
|
3836
|
+
`[extractAndStoreEncryptedMCPImages] Found ${remainingMatches.length} remaining instance(s) of URL after replacement:`,
|
|
3837
|
+
imageUrl
|
|
3838
|
+
);
|
|
3839
|
+
}
|
|
3391
3840
|
} else {
|
|
3392
3841
|
console.error("[extractAndStoreEncryptedMCPImages] Failed:", result.reason);
|
|
3393
3842
|
}
|
|
@@ -3452,9 +3901,7 @@ function useChatStorage(options) {
|
|
|
3452
3901
|
const storedMessages = await getMessagesOp(storageCtx, convId);
|
|
3453
3902
|
const validMessages = storedMessages.filter((msg) => !msg.error);
|
|
3454
3903
|
const limitedMessages = validMessages.slice(-maxHistoryMessages);
|
|
3455
|
-
const historyMessages =
|
|
3456
|
-
limitedMessages.map(storedToLlmapiMessage)
|
|
3457
|
-
);
|
|
3904
|
+
const historyMessages = limitedMessages.map(storedToLlmapiMessage);
|
|
3458
3905
|
messagesToSend = [...historyMessages, ...messages];
|
|
3459
3906
|
} else {
|
|
3460
3907
|
messagesToSend = [...messages];
|