@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.cjs
CHANGED
|
@@ -1014,14 +1014,128 @@ function validateToken(token) {
|
|
|
1014
1014
|
}
|
|
1015
1015
|
return { valid: true };
|
|
1016
1016
|
}
|
|
1017
|
-
function
|
|
1017
|
+
function parseReasoningTags(content, previousPartialTag = "") {
|
|
1018
|
+
const OPENING_TAG = "<think>";
|
|
1019
|
+
const CLOSING_TAG = "</think>";
|
|
1020
|
+
const OPENING_TAG_LEN = OPENING_TAG.length;
|
|
1021
|
+
const CLOSING_TAG_LEN = CLOSING_TAG.length;
|
|
1022
|
+
const fullContent = previousPartialTag + content;
|
|
1023
|
+
let messageContent = "";
|
|
1024
|
+
let reasoningContent = "";
|
|
1025
|
+
let partialTag = "";
|
|
1026
|
+
let i = 0;
|
|
1027
|
+
let insideReasoning = false;
|
|
1028
|
+
if (previousPartialTag) {
|
|
1029
|
+
if (previousPartialTag === OPENING_TAG) {
|
|
1030
|
+
insideReasoning = true;
|
|
1031
|
+
i = OPENING_TAG_LEN;
|
|
1032
|
+
} else if (OPENING_TAG.startsWith(previousPartialTag)) {
|
|
1033
|
+
if (fullContent.startsWith(OPENING_TAG)) {
|
|
1034
|
+
insideReasoning = true;
|
|
1035
|
+
i = OPENING_TAG_LEN;
|
|
1036
|
+
} else if (OPENING_TAG.startsWith(fullContent.slice(0, Math.min(OPENING_TAG_LEN, fullContent.length)))) {
|
|
1037
|
+
return {
|
|
1038
|
+
messageContent: "",
|
|
1039
|
+
reasoningContent: "",
|
|
1040
|
+
partialTag: fullContent.slice(0, Math.min(OPENING_TAG_LEN, fullContent.length))
|
|
1041
|
+
};
|
|
1042
|
+
} else {
|
|
1043
|
+
messageContent = previousPartialTag;
|
|
1044
|
+
i = previousPartialTag.length;
|
|
1045
|
+
}
|
|
1046
|
+
} else if (CLOSING_TAG.startsWith(previousPartialTag)) {
|
|
1047
|
+
if (fullContent.startsWith(CLOSING_TAG)) {
|
|
1048
|
+
i = CLOSING_TAG_LEN;
|
|
1049
|
+
insideReasoning = false;
|
|
1050
|
+
} else if (CLOSING_TAG.startsWith(fullContent.slice(0, Math.min(CLOSING_TAG_LEN, fullContent.length)))) {
|
|
1051
|
+
return {
|
|
1052
|
+
messageContent: "",
|
|
1053
|
+
reasoningContent: "",
|
|
1054
|
+
partialTag: fullContent.slice(0, Math.min(CLOSING_TAG_LEN, fullContent.length))
|
|
1055
|
+
};
|
|
1056
|
+
} else {
|
|
1057
|
+
reasoningContent = previousPartialTag;
|
|
1058
|
+
i = previousPartialTag.length;
|
|
1059
|
+
insideReasoning = true;
|
|
1060
|
+
}
|
|
1061
|
+
} else {
|
|
1062
|
+
if (insideReasoning) {
|
|
1063
|
+
reasoningContent = previousPartialTag;
|
|
1064
|
+
} else {
|
|
1065
|
+
messageContent = previousPartialTag;
|
|
1066
|
+
}
|
|
1067
|
+
i = previousPartialTag.length;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
while (i < fullContent.length) {
|
|
1071
|
+
if (insideReasoning) {
|
|
1072
|
+
const closeIndex = fullContent.indexOf(CLOSING_TAG, i);
|
|
1073
|
+
if (closeIndex === -1) {
|
|
1074
|
+
const remaining = fullContent.slice(i);
|
|
1075
|
+
if (remaining.length < CLOSING_TAG_LEN) {
|
|
1076
|
+
const potentialClose = remaining;
|
|
1077
|
+
if (CLOSING_TAG.startsWith(potentialClose)) {
|
|
1078
|
+
partialTag = potentialClose;
|
|
1079
|
+
} else {
|
|
1080
|
+
reasoningContent += remaining;
|
|
1081
|
+
}
|
|
1082
|
+
} else {
|
|
1083
|
+
reasoningContent += remaining;
|
|
1084
|
+
}
|
|
1085
|
+
break;
|
|
1086
|
+
}
|
|
1087
|
+
const contentBeforeClose = fullContent.slice(i, closeIndex);
|
|
1088
|
+
if (contentBeforeClose) {
|
|
1089
|
+
reasoningContent += contentBeforeClose;
|
|
1090
|
+
}
|
|
1091
|
+
i = closeIndex + CLOSING_TAG_LEN;
|
|
1092
|
+
insideReasoning = false;
|
|
1093
|
+
} else {
|
|
1094
|
+
const openIndex = fullContent.indexOf(OPENING_TAG, i);
|
|
1095
|
+
if (openIndex === -1) {
|
|
1096
|
+
const remaining = fullContent.slice(i);
|
|
1097
|
+
if (remaining.length < OPENING_TAG_LEN) {
|
|
1098
|
+
const potentialOpen = remaining;
|
|
1099
|
+
if (OPENING_TAG.startsWith(potentialOpen)) {
|
|
1100
|
+
partialTag = potentialOpen;
|
|
1101
|
+
} else {
|
|
1102
|
+
messageContent += remaining;
|
|
1103
|
+
}
|
|
1104
|
+
} else {
|
|
1105
|
+
messageContent += remaining;
|
|
1106
|
+
}
|
|
1107
|
+
break;
|
|
1108
|
+
}
|
|
1109
|
+
messageContent += fullContent.slice(i, openIndex);
|
|
1110
|
+
i = openIndex + OPENING_TAG_LEN;
|
|
1111
|
+
insideReasoning = true;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
if (messageContent.includes(OPENING_TAG) || messageContent.includes(CLOSING_TAG)) {
|
|
1115
|
+
console.warn("[parseReasoningTags] Warning: Tag found in messageContent, removing");
|
|
1116
|
+
messageContent = messageContent.replace(new RegExp(OPENING_TAG.replace(/[<>]/g, "\\$&"), "g"), "");
|
|
1117
|
+
messageContent = messageContent.replace(new RegExp(CLOSING_TAG.replace(/[<>]/g, "\\$&"), "g"), "");
|
|
1118
|
+
}
|
|
1119
|
+
if (reasoningContent.includes(OPENING_TAG) || reasoningContent.includes(CLOSING_TAG)) {
|
|
1120
|
+
console.warn("[parseReasoningTags] Warning: Tag found in reasoningContent, removing");
|
|
1121
|
+
reasoningContent = reasoningContent.replace(new RegExp(OPENING_TAG.replace(/[<>]/g, "\\$&"), "g"), "");
|
|
1122
|
+
reasoningContent = reasoningContent.replace(new RegExp(CLOSING_TAG.replace(/[<>]/g, "\\$&"), "g"), "");
|
|
1123
|
+
}
|
|
1124
|
+
return {
|
|
1125
|
+
messageContent,
|
|
1126
|
+
reasoningContent,
|
|
1127
|
+
partialTag
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
function createStreamAccumulator(initialModel) {
|
|
1018
1131
|
return {
|
|
1019
1132
|
content: "",
|
|
1020
1133
|
thinking: "",
|
|
1021
1134
|
responseId: "",
|
|
1022
|
-
responseModel: "",
|
|
1135
|
+
responseModel: initialModel || "",
|
|
1023
1136
|
usage: {},
|
|
1024
|
-
toolCalls: /* @__PURE__ */ new Map()
|
|
1137
|
+
toolCalls: /* @__PURE__ */ new Map(),
|
|
1138
|
+
partialReasoningTag: ""
|
|
1025
1139
|
};
|
|
1026
1140
|
}
|
|
1027
1141
|
function createErrorResult(message, onError) {
|
|
@@ -1191,7 +1305,7 @@ var ResponsesStrategy = class {
|
|
|
1191
1305
|
const delta = typedChunk.delta;
|
|
1192
1306
|
if (delta) {
|
|
1193
1307
|
const deltaText = typeof delta === "string" ? delta : delta.OfString;
|
|
1194
|
-
if (deltaText) {
|
|
1308
|
+
if (deltaText && deltaText.trim().length > 0) {
|
|
1195
1309
|
accumulator.content += deltaText;
|
|
1196
1310
|
result.content = deltaText;
|
|
1197
1311
|
}
|
|
@@ -1318,8 +1432,21 @@ var CompletionsStrategy = class {
|
|
|
1318
1432
|
const choice = typedChunk.choices[0];
|
|
1319
1433
|
if (choice.delta) {
|
|
1320
1434
|
if (choice.delta.content) {
|
|
1321
|
-
|
|
1322
|
-
|
|
1435
|
+
const parseResult = parseReasoningTags(
|
|
1436
|
+
choice.delta.content,
|
|
1437
|
+
accumulator.partialReasoningTag || ""
|
|
1438
|
+
);
|
|
1439
|
+
accumulator.content += parseResult.messageContent;
|
|
1440
|
+
accumulator.thinking += parseResult.reasoningContent;
|
|
1441
|
+
accumulator.partialReasoningTag = parseResult.partialTag;
|
|
1442
|
+
const willEmitMessage = parseResult.messageContent && parseResult.messageContent.trim().length > 0;
|
|
1443
|
+
const willEmitReasoning = parseResult.reasoningContent && parseResult.reasoningContent.trim().length > 0;
|
|
1444
|
+
if (willEmitMessage) {
|
|
1445
|
+
result.content = parseResult.messageContent;
|
|
1446
|
+
}
|
|
1447
|
+
if (willEmitReasoning) {
|
|
1448
|
+
result.thinking = parseResult.reasoningContent;
|
|
1449
|
+
}
|
|
1323
1450
|
}
|
|
1324
1451
|
if (choice.delta.tool_calls) {
|
|
1325
1452
|
for (const toolCallDelta of choice.delta.tool_calls) {
|
|
@@ -1348,8 +1475,19 @@ var CompletionsStrategy = class {
|
|
|
1348
1475
|
}
|
|
1349
1476
|
if (choice.message) {
|
|
1350
1477
|
if (choice.message.content) {
|
|
1351
|
-
|
|
1352
|
-
|
|
1478
|
+
const parseResult = parseReasoningTags(
|
|
1479
|
+
choice.message.content,
|
|
1480
|
+
accumulator.partialReasoningTag || ""
|
|
1481
|
+
);
|
|
1482
|
+
accumulator.content = parseResult.messageContent;
|
|
1483
|
+
accumulator.thinking += parseResult.reasoningContent;
|
|
1484
|
+
accumulator.partialReasoningTag = parseResult.partialTag;
|
|
1485
|
+
if (parseResult.messageContent && parseResult.messageContent.trim().length > 0) {
|
|
1486
|
+
result.content = parseResult.messageContent;
|
|
1487
|
+
}
|
|
1488
|
+
if (parseResult.reasoningContent && parseResult.reasoningContent.trim().length > 0) {
|
|
1489
|
+
result.thinking = parseResult.reasoningContent;
|
|
1490
|
+
}
|
|
1353
1491
|
}
|
|
1354
1492
|
if (choice.message.tool_calls) {
|
|
1355
1493
|
for (let i = 0; i < choice.message.tool_calls.length; i++) {
|
|
@@ -1377,6 +1515,23 @@ var CompletionsStrategy = class {
|
|
|
1377
1515
|
}
|
|
1378
1516
|
buildFinalResponse(accumulator) {
|
|
1379
1517
|
const output = [];
|
|
1518
|
+
let finalContent = accumulator.content;
|
|
1519
|
+
let finalThinking = accumulator.thinking;
|
|
1520
|
+
if (accumulator.partialReasoningTag) {
|
|
1521
|
+
const finalParse = parseReasoningTags("", accumulator.partialReasoningTag);
|
|
1522
|
+
finalContent += finalParse.messageContent;
|
|
1523
|
+
if (finalParse.reasoningContent) {
|
|
1524
|
+
finalThinking += finalParse.reasoningContent;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
if (finalThinking) {
|
|
1528
|
+
output.push({
|
|
1529
|
+
type: "reasoning",
|
|
1530
|
+
role: "assistant",
|
|
1531
|
+
content: [{ type: "output_text", text: finalThinking }],
|
|
1532
|
+
status: "completed"
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1380
1535
|
if (accumulator.toolCalls.size > 0) {
|
|
1381
1536
|
for (const toolCall of accumulator.toolCalls.values()) {
|
|
1382
1537
|
output.push({
|
|
@@ -1391,7 +1546,7 @@ var CompletionsStrategy = class {
|
|
|
1391
1546
|
output.push({
|
|
1392
1547
|
type: "message",
|
|
1393
1548
|
role: "assistant",
|
|
1394
|
-
content: [{ type: "output_text", text:
|
|
1549
|
+
content: [{ type: "output_text", text: finalContent }],
|
|
1395
1550
|
status: "completed"
|
|
1396
1551
|
});
|
|
1397
1552
|
return {
|
|
@@ -1571,7 +1726,7 @@ function useChat(options) {
|
|
|
1571
1726
|
sseError = error instanceof Error ? error : new Error(String(error));
|
|
1572
1727
|
}
|
|
1573
1728
|
});
|
|
1574
|
-
const accumulator = createStreamAccumulator();
|
|
1729
|
+
const accumulator = createStreamAccumulator(model || void 0);
|
|
1575
1730
|
try {
|
|
1576
1731
|
for await (const chunk of sseResult.stream) {
|
|
1577
1732
|
if (isDoneMarker(chunk)) {
|
|
@@ -1766,7 +1921,7 @@ Executing tool: ${toolInfo}
|
|
|
1766
1921
|
sseError = error instanceof Error ? error : new Error(String(error));
|
|
1767
1922
|
}
|
|
1768
1923
|
});
|
|
1769
|
-
const continuationAccumulator = createStreamAccumulator();
|
|
1924
|
+
const continuationAccumulator = createStreamAccumulator(model || void 0);
|
|
1770
1925
|
try {
|
|
1771
1926
|
for await (const chunk of continuationResult.stream) {
|
|
1772
1927
|
if (isDoneMarker(chunk)) {
|
|
@@ -3013,44 +3168,80 @@ var BlobUrlManager = class {
|
|
|
3013
3168
|
// src/react/useChatStorage.ts
|
|
3014
3169
|
function replaceUrlWithMCPPlaceholder(content, url, fileId) {
|
|
3015
3170
|
const escapedUrl = url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3016
|
-
const placeholder =
|
|
3171
|
+
const placeholder = createFilePlaceholder(fileId);
|
|
3017
3172
|
let result = content;
|
|
3173
|
+
console.log(
|
|
3174
|
+
`[replaceUrlWithMCPPlaceholder] Replacing URL with placeholder:`,
|
|
3175
|
+
url,
|
|
3176
|
+
"->",
|
|
3177
|
+
placeholder
|
|
3178
|
+
);
|
|
3179
|
+
const htmlImgPatternDouble = new RegExp(
|
|
3180
|
+
`<img[^>]*src="${escapedUrl}"[^>]*>`,
|
|
3181
|
+
"gi"
|
|
3182
|
+
);
|
|
3183
|
+
const doubleMatches = result.match(htmlImgPatternDouble);
|
|
3184
|
+
if (doubleMatches) {
|
|
3185
|
+
console.log(
|
|
3186
|
+
`[replaceUrlWithMCPPlaceholder] Replacing ${doubleMatches.length} HTML img tag(s) with double quotes:`,
|
|
3187
|
+
doubleMatches,
|
|
3188
|
+
"->",
|
|
3189
|
+
placeholder
|
|
3190
|
+
);
|
|
3191
|
+
}
|
|
3192
|
+
result = result.replace(htmlImgPatternDouble, placeholder);
|
|
3193
|
+
const htmlImgPatternSingle = new RegExp(
|
|
3194
|
+
`<img[^>]*src='${escapedUrl}'[^>]*>`,
|
|
3195
|
+
"gi"
|
|
3196
|
+
);
|
|
3197
|
+
const singleMatches = result.match(htmlImgPatternSingle);
|
|
3198
|
+
if (singleMatches) {
|
|
3199
|
+
console.log(
|
|
3200
|
+
`[replaceUrlWithMCPPlaceholder] Replacing ${singleMatches.length} HTML img tag(s) with single quotes:`,
|
|
3201
|
+
singleMatches,
|
|
3202
|
+
"->",
|
|
3203
|
+
placeholder
|
|
3204
|
+
);
|
|
3205
|
+
}
|
|
3206
|
+
result = result.replace(htmlImgPatternSingle, placeholder);
|
|
3018
3207
|
const markdownImagePattern = new RegExp(
|
|
3019
3208
|
`!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
|
|
3020
3209
|
"g"
|
|
3021
3210
|
);
|
|
3211
|
+
const markdownMatches = result.match(markdownImagePattern);
|
|
3212
|
+
if (markdownMatches) {
|
|
3213
|
+
console.log(
|
|
3214
|
+
`[replaceUrlWithMCPPlaceholder] Replacing ${markdownMatches.length} markdown image(s):`,
|
|
3215
|
+
markdownMatches,
|
|
3216
|
+
"->",
|
|
3217
|
+
placeholder
|
|
3218
|
+
);
|
|
3219
|
+
}
|
|
3022
3220
|
result = result.replace(markdownImagePattern, placeholder);
|
|
3023
|
-
|
|
3024
|
-
const
|
|
3025
|
-
|
|
3026
|
-
|
|
3221
|
+
const rawUrlPattern = new RegExp(escapedUrl, "g");
|
|
3222
|
+
const rawMatches = result.match(rawUrlPattern);
|
|
3223
|
+
if (rawMatches) {
|
|
3224
|
+
console.log(
|
|
3225
|
+
`[replaceUrlWithMCPPlaceholder] Replacing ${rawMatches.length} raw URL(s):`,
|
|
3226
|
+
rawMatches,
|
|
3227
|
+
"->",
|
|
3228
|
+
placeholder
|
|
3229
|
+
);
|
|
3230
|
+
}
|
|
3231
|
+
result = result.replace(rawUrlPattern, placeholder);
|
|
3232
|
+
console.log(
|
|
3233
|
+
`[replaceUrlWithMCPPlaceholder] Final result length: ${result.length}, original length: ${content.length}`
|
|
3027
3234
|
);
|
|
3028
|
-
result = result.replace(orphanedMarkdownPattern, placeholder);
|
|
3029
3235
|
return result;
|
|
3030
3236
|
}
|
|
3031
3237
|
function findFileIdBySourceUrl(files, sourceUrl) {
|
|
3032
3238
|
return files?.find((f) => f.sourceUrl === sourceUrl)?.id;
|
|
3033
3239
|
}
|
|
3034
|
-
|
|
3035
|
-
try {
|
|
3036
|
-
const controller = new AbortController();
|
|
3037
|
-
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
3038
|
-
const response = await fetch(url, {
|
|
3039
|
-
method: "GET",
|
|
3040
|
-
headers: { Range: "bytes=0-0" },
|
|
3041
|
-
signal: controller.signal
|
|
3042
|
-
});
|
|
3043
|
-
clearTimeout(timeoutId);
|
|
3044
|
-
return response.ok || response.status === 206;
|
|
3045
|
-
} catch {
|
|
3046
|
-
return false;
|
|
3047
|
-
}
|
|
3048
|
-
}
|
|
3049
|
-
async function storedToLlmapiMessage(stored) {
|
|
3240
|
+
function storedToLlmapiMessage(stored) {
|
|
3050
3241
|
let textContent = stored.content;
|
|
3051
3242
|
const fileUrlMap = /* @__PURE__ */ new Map();
|
|
3052
3243
|
const imageParts = [];
|
|
3053
|
-
if (stored.files?.length) {
|
|
3244
|
+
if (stored.role !== "assistant" && stored.files?.length) {
|
|
3054
3245
|
for (const file of stored.files) {
|
|
3055
3246
|
if (file.url) {
|
|
3056
3247
|
imageParts.push({
|
|
@@ -3058,14 +3249,17 @@ async function storedToLlmapiMessage(stored) {
|
|
|
3058
3249
|
image_url: { url: file.url }
|
|
3059
3250
|
});
|
|
3060
3251
|
} else if (file.sourceUrl) {
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3252
|
+
imageParts.push({
|
|
3253
|
+
type: "image_url",
|
|
3254
|
+
image_url: { url: file.sourceUrl }
|
|
3255
|
+
});
|
|
3256
|
+
fileUrlMap.set(file.id, file.sourceUrl);
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
} else if (stored.role === "assistant" && stored.files?.length) {
|
|
3260
|
+
for (const file of stored.files) {
|
|
3261
|
+
if (file.sourceUrl) {
|
|
3262
|
+
fileUrlMap.set(file.id, file.sourceUrl);
|
|
3069
3263
|
}
|
|
3070
3264
|
}
|
|
3071
3265
|
}
|
|
@@ -3199,26 +3393,63 @@ function useChatStorage(options) {
|
|
|
3199
3393
|
if (fileIds.length === 0) {
|
|
3200
3394
|
return msg;
|
|
3201
3395
|
}
|
|
3396
|
+
console.log(
|
|
3397
|
+
`[getMessages] Found ${fileIds.length} placeholder(s) in message ${msg.uniqueId}:`,
|
|
3398
|
+
fileIds
|
|
3399
|
+
);
|
|
3202
3400
|
let resolvedContent = msg.content;
|
|
3203
3401
|
for (const fileId of fileIds) {
|
|
3402
|
+
const placeholder = createFilePlaceholder(fileId);
|
|
3403
|
+
console.log(
|
|
3404
|
+
`[getMessages] Resolving placeholder: ${placeholder} (fileId: ${fileId})`
|
|
3405
|
+
);
|
|
3204
3406
|
let url = blobManager.getUrl(fileId);
|
|
3205
3407
|
if (!url) {
|
|
3408
|
+
console.log(
|
|
3409
|
+
`[getMessages] No cached URL for ${fileId}, reading from OPFS...`
|
|
3410
|
+
);
|
|
3206
3411
|
const result = await readEncryptedFile(fileId, encryptionKey);
|
|
3207
3412
|
if (result) {
|
|
3208
3413
|
url = blobManager.createUrl(fileId, result.blob);
|
|
3414
|
+
console.log(
|
|
3415
|
+
`[getMessages] Created blob URL for ${fileId}:`,
|
|
3416
|
+
url
|
|
3417
|
+
);
|
|
3418
|
+
} else {
|
|
3419
|
+
console.warn(
|
|
3420
|
+
`[getMessages] Failed to read file ${fileId} from OPFS`
|
|
3421
|
+
);
|
|
3209
3422
|
}
|
|
3423
|
+
} else {
|
|
3424
|
+
console.log(
|
|
3425
|
+
`[getMessages] Using cached blob URL for ${fileId}:`,
|
|
3426
|
+
url
|
|
3427
|
+
);
|
|
3210
3428
|
}
|
|
3211
3429
|
if (url) {
|
|
3212
|
-
const
|
|
3430
|
+
const placeholderRegex = new RegExp(
|
|
3431
|
+
placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
|
|
3432
|
+
"g"
|
|
3433
|
+
);
|
|
3434
|
+
const matches = resolvedContent.match(placeholderRegex);
|
|
3435
|
+
const replacement = ``;
|
|
3436
|
+
console.log(
|
|
3437
|
+
`[getMessages] Replacing ${matches?.length || 0} instance(s) of ${placeholder} with:`,
|
|
3438
|
+
replacement
|
|
3439
|
+
);
|
|
3213
3440
|
resolvedContent = resolvedContent.replace(
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3441
|
+
placeholderRegex,
|
|
3442
|
+
replacement
|
|
3443
|
+
);
|
|
3444
|
+
} else {
|
|
3445
|
+
console.warn(
|
|
3446
|
+
`[getMessages] No URL available for ${fileId}, placeholder ${placeholder} will remain in content`
|
|
3219
3447
|
);
|
|
3220
3448
|
}
|
|
3221
3449
|
}
|
|
3450
|
+
console.log(
|
|
3451
|
+
`[getMessages] Resolved content length: ${resolvedContent.length}, original length: ${msg.content.length}`
|
|
3452
|
+
);
|
|
3222
3453
|
return { ...msg, content: resolvedContent };
|
|
3223
3454
|
})
|
|
3224
3455
|
);
|
|
@@ -3358,16 +3589,42 @@ function useChatStorage(options) {
|
|
|
3358
3589
|
const { replaceUrls = true } = options2 ?? {};
|
|
3359
3590
|
try {
|
|
3360
3591
|
const MCP_IMAGE_URL_PATTERN = new RegExp(
|
|
3361
|
-
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s)]*`,
|
|
3592
|
+
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s"'<>)]*`,
|
|
3362
3593
|
"g"
|
|
3363
3594
|
);
|
|
3364
3595
|
const urlMatches = content.match(MCP_IMAGE_URL_PATTERN);
|
|
3365
3596
|
if (!urlMatches || urlMatches.length === 0) {
|
|
3366
3597
|
return { processedFiles: [], cleanedContent: content };
|
|
3367
3598
|
}
|
|
3368
|
-
const
|
|
3599
|
+
const cleanedUrls = urlMatches.map((url) => url.replace(/["']+$/, ""));
|
|
3600
|
+
const uniqueUrls = [...new Set(cleanedUrls)];
|
|
3369
3601
|
const processedFiles = [];
|
|
3370
3602
|
let cleanedContent = content;
|
|
3603
|
+
const urlOccurrenceCounts = /* @__PURE__ */ new Map();
|
|
3604
|
+
uniqueUrls.forEach((url) => {
|
|
3605
|
+
const escapedUrl = url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3606
|
+
const htmlDoublePattern = new RegExp(
|
|
3607
|
+
`<img[^>]*src="${escapedUrl}"[^>]*>`,
|
|
3608
|
+
"gi"
|
|
3609
|
+
);
|
|
3610
|
+
const htmlSinglePattern = new RegExp(
|
|
3611
|
+
`<img[^>]*src='${escapedUrl}'[^>]*>`,
|
|
3612
|
+
"gi"
|
|
3613
|
+
);
|
|
3614
|
+
const markdownPattern = new RegExp(
|
|
3615
|
+
`!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
|
|
3616
|
+
"g"
|
|
3617
|
+
);
|
|
3618
|
+
const rawPattern = new RegExp(escapedUrl, "g");
|
|
3619
|
+
const htmlDoubleMatches = content.match(htmlDoublePattern)?.length || 0;
|
|
3620
|
+
const htmlSingleMatches = content.match(htmlSinglePattern)?.length || 0;
|
|
3621
|
+
const markdownMatches = content.match(markdownPattern)?.length || 0;
|
|
3622
|
+
const rawMatches = (content.match(rawPattern)?.length || 0) - htmlDoubleMatches - htmlSingleMatches - markdownMatches;
|
|
3623
|
+
urlOccurrenceCounts.set(
|
|
3624
|
+
url,
|
|
3625
|
+
htmlDoubleMatches + htmlSingleMatches + markdownMatches + rawMatches
|
|
3626
|
+
);
|
|
3627
|
+
});
|
|
3371
3628
|
const results = await Promise.allSettled(
|
|
3372
3629
|
uniqueUrls.map(async (imageUrl) => {
|
|
3373
3630
|
const controller = new AbortController();
|
|
@@ -3399,27 +3656,85 @@ function useChatStorage(options) {
|
|
|
3399
3656
|
);
|
|
3400
3657
|
const replaceUrlWithPlaceholder = (imageUrl, fileId) => {
|
|
3401
3658
|
const escapedUrl = imageUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3402
|
-
const placeholder =
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
markdownImagePattern,
|
|
3659
|
+
const placeholder = createFilePlaceholder(fileId);
|
|
3660
|
+
let replacementCount = 0;
|
|
3661
|
+
console.log(
|
|
3662
|
+
`[extractAndStoreMCPImages] Replacing URL with placeholder:`,
|
|
3663
|
+
imageUrl,
|
|
3664
|
+
"->",
|
|
3409
3665
|
placeholder
|
|
3410
3666
|
);
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3667
|
+
const htmlImgPatternDouble = new RegExp(
|
|
3668
|
+
`<img[^>]*src="${escapedUrl}"[^>]*>`,
|
|
3669
|
+
"gi"
|
|
3414
3670
|
);
|
|
3415
|
-
const
|
|
3416
|
-
|
|
3671
|
+
const doubleMatches = cleanedContent.match(htmlImgPatternDouble);
|
|
3672
|
+
if (doubleMatches) {
|
|
3673
|
+
console.log(
|
|
3674
|
+
`[extractAndStoreMCPImages] Replacing ${doubleMatches.length} HTML img tag(s) with double quotes:`,
|
|
3675
|
+
doubleMatches,
|
|
3676
|
+
"->",
|
|
3677
|
+
placeholder
|
|
3678
|
+
);
|
|
3679
|
+
replacementCount += doubleMatches.length;
|
|
3680
|
+
cleanedContent = cleanedContent.replace(
|
|
3681
|
+
htmlImgPatternDouble,
|
|
3682
|
+
placeholder
|
|
3683
|
+
);
|
|
3684
|
+
}
|
|
3685
|
+
const htmlImgPatternSingle = new RegExp(
|
|
3686
|
+
`<img[^>]*src='${escapedUrl}'[^>]*>`,
|
|
3687
|
+
"gi"
|
|
3688
|
+
);
|
|
3689
|
+
const singleMatches = cleanedContent.match(htmlImgPatternSingle);
|
|
3690
|
+
if (singleMatches) {
|
|
3691
|
+
console.log(
|
|
3692
|
+
`[extractAndStoreMCPImages] Replacing ${singleMatches.length} HTML img tag(s) with single quotes:`,
|
|
3693
|
+
singleMatches,
|
|
3694
|
+
"->",
|
|
3695
|
+
placeholder
|
|
3696
|
+
);
|
|
3697
|
+
replacementCount += singleMatches.length;
|
|
3698
|
+
cleanedContent = cleanedContent.replace(
|
|
3699
|
+
htmlImgPatternSingle,
|
|
3700
|
+
placeholder
|
|
3701
|
+
);
|
|
3702
|
+
}
|
|
3703
|
+
const markdownImagePattern = new RegExp(
|
|
3704
|
+
`!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
|
|
3417
3705
|
"g"
|
|
3418
3706
|
);
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3707
|
+
const markdownMatches = cleanedContent.match(markdownImagePattern);
|
|
3708
|
+
if (markdownMatches) {
|
|
3709
|
+
console.log(
|
|
3710
|
+
`[extractAndStoreMCPImages] Replacing ${markdownMatches.length} markdown image(s):`,
|
|
3711
|
+
markdownMatches,
|
|
3712
|
+
"->",
|
|
3713
|
+
placeholder
|
|
3714
|
+
);
|
|
3715
|
+
replacementCount += markdownMatches.length;
|
|
3716
|
+
cleanedContent = cleanedContent.replace(
|
|
3717
|
+
markdownImagePattern,
|
|
3718
|
+
placeholder
|
|
3719
|
+
);
|
|
3720
|
+
}
|
|
3721
|
+
const rawUrlPattern = new RegExp(escapedUrl, "g");
|
|
3722
|
+
const rawMatches = cleanedContent.match(rawUrlPattern);
|
|
3723
|
+
if (rawMatches) {
|
|
3724
|
+
console.log(
|
|
3725
|
+
`[extractAndStoreMCPImages] Replacing ${rawMatches.length} raw URL(s):`,
|
|
3726
|
+
rawMatches,
|
|
3727
|
+
"->",
|
|
3728
|
+
placeholder
|
|
3729
|
+
);
|
|
3730
|
+
replacementCount += rawMatches.length;
|
|
3731
|
+
cleanedContent = cleanedContent.replace(rawUrlPattern, placeholder);
|
|
3732
|
+
}
|
|
3733
|
+
console.log(
|
|
3734
|
+
`[extractAndStoreMCPImages] Total replacements made: ${replacementCount} for URL:`,
|
|
3735
|
+
imageUrl
|
|
3422
3736
|
);
|
|
3737
|
+
return replacementCount;
|
|
3423
3738
|
};
|
|
3424
3739
|
results.forEach((result, i) => {
|
|
3425
3740
|
const imageUrl = uniqueUrls[i];
|
|
@@ -3433,7 +3748,29 @@ function useChatStorage(options) {
|
|
|
3433
3748
|
sourceUrl: imageUrl
|
|
3434
3749
|
});
|
|
3435
3750
|
if (replaceUrls && imageUrl) {
|
|
3436
|
-
replaceUrlWithPlaceholder(
|
|
3751
|
+
const replacementCount = replaceUrlWithPlaceholder(
|
|
3752
|
+
imageUrl,
|
|
3753
|
+
fileId
|
|
3754
|
+
);
|
|
3755
|
+
const expectedCount = urlOccurrenceCounts.get(imageUrl) || 0;
|
|
3756
|
+
if (replacementCount < expectedCount) {
|
|
3757
|
+
console.warn(
|
|
3758
|
+
`[extractAndStoreMCPImages] Not all instances of URL replaced. Expected ${expectedCount}, replaced ${replacementCount}:`,
|
|
3759
|
+
imageUrl
|
|
3760
|
+
);
|
|
3761
|
+
}
|
|
3762
|
+
const escapedUrl = imageUrl.replace(
|
|
3763
|
+
/[.*+?^${}()|[\]\\]/g,
|
|
3764
|
+
"\\$&"
|
|
3765
|
+
);
|
|
3766
|
+
const remainingPattern = new RegExp(escapedUrl, "g");
|
|
3767
|
+
const remainingMatches = cleanedContent.match(remainingPattern);
|
|
3768
|
+
if (remainingMatches && remainingMatches.length > 0) {
|
|
3769
|
+
console.warn(
|
|
3770
|
+
`[extractAndStoreMCPImages] Found ${remainingMatches.length} remaining instance(s) of URL after replacement:`,
|
|
3771
|
+
imageUrl
|
|
3772
|
+
);
|
|
3773
|
+
}
|
|
3437
3774
|
}
|
|
3438
3775
|
} else {
|
|
3439
3776
|
console.error(
|
|
@@ -3466,17 +3803,43 @@ function useChatStorage(options) {
|
|
|
3466
3803
|
return { processedFiles: [], cleanedContent: content };
|
|
3467
3804
|
}
|
|
3468
3805
|
const MCP_IMAGE_URL_PATTERN = new RegExp(
|
|
3469
|
-
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s)]*`,
|
|
3806
|
+
`https://${MCP_R2_DOMAIN.replace(/\./g, "\\.")}[^\\s"'<>)]*`,
|
|
3470
3807
|
"g"
|
|
3471
3808
|
);
|
|
3472
3809
|
const urlMatches = content.match(MCP_IMAGE_URL_PATTERN);
|
|
3473
3810
|
if (!urlMatches || urlMatches.length === 0) {
|
|
3474
3811
|
return { processedFiles: [], cleanedContent: content };
|
|
3475
3812
|
}
|
|
3476
|
-
const
|
|
3813
|
+
const cleanedUrls = urlMatches.map((url) => url.replace(/["']+$/, ""));
|
|
3814
|
+
const uniqueUrls = [...new Set(cleanedUrls)];
|
|
3477
3815
|
const encryptionKey = await getEncryptionKey(address);
|
|
3478
3816
|
const processedFiles = [];
|
|
3479
3817
|
let cleanedContent = content;
|
|
3818
|
+
const urlOccurrenceCounts = /* @__PURE__ */ new Map();
|
|
3819
|
+
uniqueUrls.forEach((url) => {
|
|
3820
|
+
const escapedUrl = url.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3821
|
+
const htmlDoublePattern = new RegExp(
|
|
3822
|
+
`<img[^>]*src="${escapedUrl}"[^>]*>`,
|
|
3823
|
+
"gi"
|
|
3824
|
+
);
|
|
3825
|
+
const htmlSinglePattern = new RegExp(
|
|
3826
|
+
`<img[^>]*src='${escapedUrl}'[^>]*>`,
|
|
3827
|
+
"gi"
|
|
3828
|
+
);
|
|
3829
|
+
const markdownPattern = new RegExp(
|
|
3830
|
+
`!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
|
|
3831
|
+
"g"
|
|
3832
|
+
);
|
|
3833
|
+
const rawPattern = new RegExp(escapedUrl, "g");
|
|
3834
|
+
const htmlDoubleMatches = content.match(htmlDoublePattern)?.length || 0;
|
|
3835
|
+
const htmlSingleMatches = content.match(htmlSinglePattern)?.length || 0;
|
|
3836
|
+
const markdownMatches = content.match(markdownPattern)?.length || 0;
|
|
3837
|
+
const rawMatches = (content.match(rawPattern)?.length || 0) - htmlDoubleMatches - htmlSingleMatches - markdownMatches;
|
|
3838
|
+
urlOccurrenceCounts.set(
|
|
3839
|
+
url,
|
|
3840
|
+
htmlDoubleMatches + htmlSingleMatches + markdownMatches + rawMatches
|
|
3841
|
+
);
|
|
3842
|
+
});
|
|
3480
3843
|
const results = await Promise.allSettled(
|
|
3481
3844
|
uniqueUrls.map(async (imageUrl) => {
|
|
3482
3845
|
const controller = new AbortController();
|
|
@@ -3518,12 +3881,98 @@ function useChatStorage(options) {
|
|
|
3518
3881
|
});
|
|
3519
3882
|
const placeholder = createFilePlaceholder(fileId);
|
|
3520
3883
|
const escapedUrl = imageUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3884
|
+
let replacementCount = 0;
|
|
3885
|
+
console.log(
|
|
3886
|
+
`[extractAndStoreEncryptedMCPImages] Replacing URL with placeholder:`,
|
|
3887
|
+
imageUrl,
|
|
3888
|
+
"->",
|
|
3889
|
+
placeholder
|
|
3890
|
+
);
|
|
3891
|
+
const htmlImgPatternDouble = new RegExp(
|
|
3892
|
+
`<img[^>]*src="${escapedUrl}"[^>]*>`,
|
|
3893
|
+
"gi"
|
|
3894
|
+
);
|
|
3895
|
+
const doubleMatches = cleanedContent.match(htmlImgPatternDouble);
|
|
3896
|
+
if (doubleMatches) {
|
|
3897
|
+
console.log(
|
|
3898
|
+
`[extractAndStoreEncryptedMCPImages] Replacing ${doubleMatches.length} HTML img tag(s) with double quotes:`,
|
|
3899
|
+
doubleMatches,
|
|
3900
|
+
"->",
|
|
3901
|
+
placeholder
|
|
3902
|
+
);
|
|
3903
|
+
replacementCount += doubleMatches.length;
|
|
3904
|
+
cleanedContent = cleanedContent.replace(
|
|
3905
|
+
htmlImgPatternDouble,
|
|
3906
|
+
placeholder
|
|
3907
|
+
);
|
|
3908
|
+
}
|
|
3909
|
+
const htmlImgPatternSingle = new RegExp(
|
|
3910
|
+
`<img[^>]*src='${escapedUrl}'[^>]*>`,
|
|
3911
|
+
"gi"
|
|
3912
|
+
);
|
|
3913
|
+
const singleMatches = cleanedContent.match(htmlImgPatternSingle);
|
|
3914
|
+
if (singleMatches) {
|
|
3915
|
+
console.log(
|
|
3916
|
+
`[extractAndStoreEncryptedMCPImages] Replacing ${singleMatches.length} HTML img tag(s) with single quotes:`,
|
|
3917
|
+
singleMatches,
|
|
3918
|
+
"->",
|
|
3919
|
+
placeholder
|
|
3920
|
+
);
|
|
3921
|
+
replacementCount += singleMatches.length;
|
|
3922
|
+
cleanedContent = cleanedContent.replace(
|
|
3923
|
+
htmlImgPatternSingle,
|
|
3924
|
+
placeholder
|
|
3925
|
+
);
|
|
3926
|
+
}
|
|
3521
3927
|
const markdownImagePattern = new RegExp(
|
|
3522
3928
|
`!\\[[^\\]]*\\]\\([\\s]*${escapedUrl}[\\s]*\\)`,
|
|
3523
3929
|
"g"
|
|
3524
3930
|
);
|
|
3525
|
-
|
|
3526
|
-
|
|
3931
|
+
const markdownMatches = cleanedContent.match(markdownImagePattern);
|
|
3932
|
+
if (markdownMatches) {
|
|
3933
|
+
console.log(
|
|
3934
|
+
`[extractAndStoreEncryptedMCPImages] Replacing ${markdownMatches.length} markdown image(s):`,
|
|
3935
|
+
markdownMatches,
|
|
3936
|
+
"->",
|
|
3937
|
+
placeholder
|
|
3938
|
+
);
|
|
3939
|
+
replacementCount += markdownMatches.length;
|
|
3940
|
+
cleanedContent = cleanedContent.replace(
|
|
3941
|
+
markdownImagePattern,
|
|
3942
|
+
placeholder
|
|
3943
|
+
);
|
|
3944
|
+
}
|
|
3945
|
+
const rawUrlPattern = new RegExp(escapedUrl, "g");
|
|
3946
|
+
const rawMatches = cleanedContent.match(rawUrlPattern);
|
|
3947
|
+
if (rawMatches) {
|
|
3948
|
+
console.log(
|
|
3949
|
+
`[extractAndStoreEncryptedMCPImages] Replacing ${rawMatches.length} raw URL(s):`,
|
|
3950
|
+
rawMatches,
|
|
3951
|
+
"->",
|
|
3952
|
+
placeholder
|
|
3953
|
+
);
|
|
3954
|
+
replacementCount += rawMatches.length;
|
|
3955
|
+
cleanedContent = cleanedContent.replace(rawUrlPattern, placeholder);
|
|
3956
|
+
}
|
|
3957
|
+
console.log(
|
|
3958
|
+
`[extractAndStoreEncryptedMCPImages] Total replacements made: ${replacementCount} for URL:`,
|
|
3959
|
+
imageUrl
|
|
3960
|
+
);
|
|
3961
|
+
const expectedCount = urlOccurrenceCounts.get(imageUrl) || 0;
|
|
3962
|
+
if (replacementCount < expectedCount) {
|
|
3963
|
+
console.warn(
|
|
3964
|
+
`[extractAndStoreEncryptedMCPImages] Not all instances of URL replaced. Expected ${expectedCount}, replaced ${replacementCount}:`,
|
|
3965
|
+
imageUrl
|
|
3966
|
+
);
|
|
3967
|
+
}
|
|
3968
|
+
const remainingPattern = new RegExp(escapedUrl, "g");
|
|
3969
|
+
const remainingMatches = cleanedContent.match(remainingPattern);
|
|
3970
|
+
if (remainingMatches && remainingMatches.length > 0) {
|
|
3971
|
+
console.warn(
|
|
3972
|
+
`[extractAndStoreEncryptedMCPImages] Found ${remainingMatches.length} remaining instance(s) of URL after replacement:`,
|
|
3973
|
+
imageUrl
|
|
3974
|
+
);
|
|
3975
|
+
}
|
|
3527
3976
|
} else {
|
|
3528
3977
|
console.error("[extractAndStoreEncryptedMCPImages] Failed:", result.reason);
|
|
3529
3978
|
}
|
|
@@ -3588,9 +4037,7 @@ function useChatStorage(options) {
|
|
|
3588
4037
|
const storedMessages = await getMessagesOp(storageCtx, convId);
|
|
3589
4038
|
const validMessages = storedMessages.filter((msg) => !msg.error);
|
|
3590
4039
|
const limitedMessages = validMessages.slice(-maxHistoryMessages);
|
|
3591
|
-
const historyMessages =
|
|
3592
|
-
limitedMessages.map(storedToLlmapiMessage)
|
|
3593
|
-
);
|
|
4040
|
+
const historyMessages = limitedMessages.map(storedToLlmapiMessage);
|
|
3594
4041
|
messagesToSend = [...historyMessages, ...messages];
|
|
3595
4042
|
} else {
|
|
3596
4043
|
messagesToSend = [...messages];
|