@reverbia/sdk 1.0.0-next.20260110224403 → 1.0.0-next.20260111125102
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 +514 -47
- package/dist/react/index.d.mts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.mjs +514 -47
- 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,19 +3032,70 @@ 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) {
|
|
@@ -2899,7 +3105,7 @@ function storedToLlmapiMessage(stored) {
|
|
|
2899
3105
|
let textContent = stored.content;
|
|
2900
3106
|
const fileUrlMap = /* @__PURE__ */ new Map();
|
|
2901
3107
|
const imageParts = [];
|
|
2902
|
-
if (stored.files?.length) {
|
|
3108
|
+
if (stored.role !== "assistant" && stored.files?.length) {
|
|
2903
3109
|
for (const file of stored.files) {
|
|
2904
3110
|
if (file.url) {
|
|
2905
3111
|
imageParts.push({
|
|
@@ -2914,6 +3120,12 @@ function storedToLlmapiMessage(stored) {
|
|
|
2914
3120
|
fileUrlMap.set(file.id, file.sourceUrl);
|
|
2915
3121
|
}
|
|
2916
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);
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
2917
3129
|
}
|
|
2918
3130
|
textContent = textContent.replace(
|
|
2919
3131
|
/__SDKFILE__([a-f0-9-]+)__/g,
|
|
@@ -3041,30 +3253,67 @@ function useChatStorage(options) {
|
|
|
3041
3253
|
const blobManager = blobManagerRef.current;
|
|
3042
3254
|
const resolvedMessages = await Promise.all(
|
|
3043
3255
|
messages.map(async (msg) => {
|
|
3044
|
-
const fileIds = extractFileIds(msg.content);
|
|
3256
|
+
const fileIds = [...new Set(extractFileIds(msg.content))];
|
|
3045
3257
|
if (fileIds.length === 0) {
|
|
3046
3258
|
return msg;
|
|
3047
3259
|
}
|
|
3260
|
+
console.log(
|
|
3261
|
+
`[getMessages] Found ${fileIds.length} placeholder(s) in message ${msg.uniqueId}:`,
|
|
3262
|
+
fileIds
|
|
3263
|
+
);
|
|
3048
3264
|
let resolvedContent = msg.content;
|
|
3049
3265
|
for (const fileId of fileIds) {
|
|
3266
|
+
const placeholder = createFilePlaceholder(fileId);
|
|
3267
|
+
console.log(
|
|
3268
|
+
`[getMessages] Resolving placeholder: ${placeholder} (fileId: ${fileId})`
|
|
3269
|
+
);
|
|
3050
3270
|
let url = blobManager.getUrl(fileId);
|
|
3051
3271
|
if (!url) {
|
|
3272
|
+
console.log(
|
|
3273
|
+
`[getMessages] No cached URL for ${fileId}, reading from OPFS...`
|
|
3274
|
+
);
|
|
3052
3275
|
const result = await readEncryptedFile(fileId, encryptionKey);
|
|
3053
3276
|
if (result) {
|
|
3054
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
|
+
);
|
|
3055
3286
|
}
|
|
3287
|
+
} else {
|
|
3288
|
+
console.log(
|
|
3289
|
+
`[getMessages] Using cached blob URL for ${fileId}:`,
|
|
3290
|
+
url
|
|
3291
|
+
);
|
|
3056
3292
|
}
|
|
3057
3293
|
if (url) {
|
|
3058
|
-
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
|
+
);
|
|
3059
3304
|
resolvedContent = resolvedContent.replace(
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3305
|
+
placeholderRegex,
|
|
3306
|
+
replacement
|
|
3307
|
+
);
|
|
3308
|
+
} else {
|
|
3309
|
+
console.warn(
|
|
3310
|
+
`[getMessages] No URL available for ${fileId}, placeholder ${placeholder} will remain in content`
|
|
3065
3311
|
);
|
|
3066
3312
|
}
|
|
3067
3313
|
}
|
|
3314
|
+
console.log(
|
|
3315
|
+
`[getMessages] Resolved content length: ${resolvedContent.length}, original length: ${msg.content.length}`
|
|
3316
|
+
);
|
|
3068
3317
|
return { ...msg, content: resolvedContent };
|
|
3069
3318
|
})
|
|
3070
3319
|
);
|
|
@@ -3204,16 +3453,42 @@ function useChatStorage(options) {
|
|
|
3204
3453
|
const { replaceUrls = true } = options2 ?? {};
|
|
3205
3454
|
try {
|
|
3206
3455
|
const MCP_IMAGE_URL_PATTERN = new RegExp(
|
|
3207
|
-
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s)]*`,
|
|
3456
|
+
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s"'<>)]*`,
|
|
3208
3457
|
"g"
|
|
3209
3458
|
);
|
|
3210
3459
|
const urlMatches = content.match(MCP_IMAGE_URL_PATTERN);
|
|
3211
3460
|
if (!urlMatches || urlMatches.length === 0) {
|
|
3212
3461
|
return { processedFiles: [], cleanedContent: content };
|
|
3213
3462
|
}
|
|
3214
|
-
const
|
|
3463
|
+
const cleanedUrls = urlMatches.map((url) => url.replace(/["']+$/, ""));
|
|
3464
|
+
const uniqueUrls = [...new Set(cleanedUrls)];
|
|
3215
3465
|
const processedFiles = [];
|
|
3216
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
|
+
});
|
|
3217
3492
|
const results = await Promise.allSettled(
|
|
3218
3493
|
uniqueUrls.map(async (imageUrl) => {
|
|
3219
3494
|
const controller = new AbortController();
|
|
@@ -3245,27 +3520,85 @@ function useChatStorage(options) {
|
|
|
3245
3520
|
);
|
|
3246
3521
|
const replaceUrlWithPlaceholder = (imageUrl, fileId) => {
|
|
3247
3522
|
const escapedUrl = imageUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3248
|
-
const placeholder =
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
markdownImagePattern,
|
|
3523
|
+
const placeholder = createFilePlaceholder(fileId);
|
|
3524
|
+
let replacementCount = 0;
|
|
3525
|
+
console.log(
|
|
3526
|
+
`[extractAndStoreMCPImages] Replacing URL with placeholder:`,
|
|
3527
|
+
imageUrl,
|
|
3528
|
+
"->",
|
|
3255
3529
|
placeholder
|
|
3256
3530
|
);
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3531
|
+
const htmlImgPatternDouble = new RegExp(
|
|
3532
|
+
`<img[^>]*src="${escapedUrl}"[^>]*>`,
|
|
3533
|
+
"gi"
|
|
3534
|
+
);
|
|
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"
|
|
3260
3552
|
);
|
|
3261
|
-
const
|
|
3262
|
-
|
|
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]*\\)`,
|
|
3263
3569
|
"g"
|
|
3264
3570
|
);
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
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
|
|
3268
3600
|
);
|
|
3601
|
+
return replacementCount;
|
|
3269
3602
|
};
|
|
3270
3603
|
results.forEach((result, i) => {
|
|
3271
3604
|
const imageUrl = uniqueUrls[i];
|
|
@@ -3279,7 +3612,29 @@ function useChatStorage(options) {
|
|
|
3279
3612
|
sourceUrl: imageUrl
|
|
3280
3613
|
});
|
|
3281
3614
|
if (replaceUrls && imageUrl) {
|
|
3282
|
-
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
|
+
}
|
|
3283
3638
|
}
|
|
3284
3639
|
} else {
|
|
3285
3640
|
console.error(
|
|
@@ -3312,17 +3667,43 @@ function useChatStorage(options) {
|
|
|
3312
3667
|
return { processedFiles: [], cleanedContent: content };
|
|
3313
3668
|
}
|
|
3314
3669
|
const MCP_IMAGE_URL_PATTERN = new RegExp(
|
|
3315
|
-
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s)]*`,
|
|
3670
|
+
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s"'<>)]*`,
|
|
3316
3671
|
"g"
|
|
3317
3672
|
);
|
|
3318
3673
|
const urlMatches = content.match(MCP_IMAGE_URL_PATTERN);
|
|
3319
3674
|
if (!urlMatches || urlMatches.length === 0) {
|
|
3320
3675
|
return { processedFiles: [], cleanedContent: content };
|
|
3321
3676
|
}
|
|
3322
|
-
const
|
|
3677
|
+
const cleanedUrls = urlMatches.map((url) => url.replace(/["']+$/, ""));
|
|
3678
|
+
const uniqueUrls = [...new Set(cleanedUrls)];
|
|
3323
3679
|
const encryptionKey = await getEncryptionKey(address);
|
|
3324
3680
|
const processedFiles = [];
|
|
3325
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
|
+
});
|
|
3326
3707
|
const results = await Promise.allSettled(
|
|
3327
3708
|
uniqueUrls.map(async (imageUrl) => {
|
|
3328
3709
|
const controller = new AbortController();
|
|
@@ -3364,12 +3745,98 @@ function useChatStorage(options) {
|
|
|
3364
3745
|
});
|
|
3365
3746
|
const placeholder = createFilePlaceholder(fileId);
|
|
3366
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
|
+
}
|
|
3367
3791
|
const markdownImagePattern = new RegExp(
|
|
3368
3792
|
`!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
|
|
3369
3793
|
"g"
|
|
3370
3794
|
);
|
|
3371
|
-
|
|
3372
|
-
|
|
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
|
+
}
|
|
3373
3840
|
} else {
|
|
3374
3841
|
console.error("[extractAndStoreEncryptedMCPImages] Failed:", result.reason);
|
|
3375
3842
|
}
|