llmasaservice-ui 0.12.2 → 0.12.4
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/index.css +58 -0
- package/dist/index.js +88 -16
- package/dist/index.mjs +88 -16
- package/package.json +1 -1
- package/src/ChatPanel.css +69 -0
- package/src/ChatPanel.tsx +107 -31
- package/test_duplication_fix.js +52 -0
- package/test_response_cleaning.js +0 -0
- package/test_tag_extraction.js +125 -0
- package/test_thinking_extraction.js +0 -0
- package/test_thinking_tag.js +0 -0
package/dist/index.css
CHANGED
|
@@ -395,6 +395,7 @@
|
|
|
395
395
|
display: flex;
|
|
396
396
|
align-items: center;
|
|
397
397
|
justify-content: center;
|
|
398
|
+
margin-top: 4px;
|
|
398
399
|
font-size: 10px;
|
|
399
400
|
color: #666;
|
|
400
401
|
opacity: 0.7;
|
|
@@ -720,3 +721,60 @@
|
|
|
720
721
|
.dark-theme .tool-status {
|
|
721
722
|
color: #999;
|
|
722
723
|
}
|
|
724
|
+
.reasoning-section,
|
|
725
|
+
.searching-section {
|
|
726
|
+
margin: 1rem 0;
|
|
727
|
+
padding: 0.75rem;
|
|
728
|
+
border-radius: var(--border-radius);
|
|
729
|
+
border-left: 4px solid;
|
|
730
|
+
background-color: var(--reasoning-background-color, #f8f9fa);
|
|
731
|
+
}
|
|
732
|
+
.reasoning-section {
|
|
733
|
+
border-left-color: var(--reasoning-border-color, #007bff);
|
|
734
|
+
background-color: var(--reasoning-background-color, #f0f8ff);
|
|
735
|
+
}
|
|
736
|
+
.searching-section {
|
|
737
|
+
border-left-color: var(--searching-border-color, #28a745);
|
|
738
|
+
background-color: var(--searching-background-color, #f0fff0);
|
|
739
|
+
}
|
|
740
|
+
.reasoning-header,
|
|
741
|
+
.searching-header {
|
|
742
|
+
font-weight: 600;
|
|
743
|
+
font-size: 0.9rem;
|
|
744
|
+
margin-bottom: 0.5rem;
|
|
745
|
+
color: var(--prompt-text-color);
|
|
746
|
+
opacity: 0.8;
|
|
747
|
+
}
|
|
748
|
+
.reasoning-content,
|
|
749
|
+
.searching-content {
|
|
750
|
+
font-size: 0.85rem;
|
|
751
|
+
line-height: 1.4;
|
|
752
|
+
color: var(--prompt-text-color);
|
|
753
|
+
opacity: 0.9;
|
|
754
|
+
font-style: italic;
|
|
755
|
+
}
|
|
756
|
+
.dark-theme .reasoning-section {
|
|
757
|
+
background-color: var(--reasoning-background-color-dark, #1a1a2e);
|
|
758
|
+
border-left-color: var(--reasoning-border-color-dark, #4a9eff);
|
|
759
|
+
}
|
|
760
|
+
.dark-theme .searching-section {
|
|
761
|
+
background-color: var(--searching-background-color-dark, #1a2e1a);
|
|
762
|
+
border-left-color: var(--searching-border-color-dark, #4ade80);
|
|
763
|
+
}
|
|
764
|
+
.dark-theme .reasoning-header,
|
|
765
|
+
.dark-theme .searching-header,
|
|
766
|
+
.dark-theme .reasoning-content,
|
|
767
|
+
.dark-theme .searching-content {
|
|
768
|
+
color: var(--response-text-color);
|
|
769
|
+
}
|
|
770
|
+
.streaming-response {
|
|
771
|
+
animation: fadeIn 0.3s ease-in-out;
|
|
772
|
+
}
|
|
773
|
+
@keyframes fadeIn {
|
|
774
|
+
from {
|
|
775
|
+
opacity: 0;
|
|
776
|
+
}
|
|
777
|
+
to {
|
|
778
|
+
opacity: 1;
|
|
779
|
+
}
|
|
780
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -272,30 +272,35 @@ var ChatPanel = ({
|
|
|
272
272
|
const [iframeUrl, setIframeUrl] = (0, import_react3.useState)(null);
|
|
273
273
|
const responseAreaRef = (0, import_react3.useRef)(null);
|
|
274
274
|
const extractLastThinkingTag = (text) => {
|
|
275
|
-
var _a2, _b;
|
|
275
|
+
var _a2, _b, _c, _d;
|
|
276
|
+
console.log("extractLastThinkingTag called with:", (text == null ? void 0 : text.length) ? `${text.substring(0, 100)}...` : "empty");
|
|
276
277
|
if (!text) return "Thinking";
|
|
277
|
-
const reasoningRegex = /<reasoning>(
|
|
278
|
-
const searchingRegex = /<searching>(
|
|
278
|
+
const reasoningRegex = /<reasoning>([\s\S]*?)<\/reasoning>/gi;
|
|
279
|
+
const searchingRegex = /<searching>([\s\S]*?)<\/searching>/gi;
|
|
279
280
|
const allMatches = [];
|
|
280
281
|
let reasoningMatch;
|
|
281
282
|
while ((reasoningMatch = reasoningRegex.exec(text)) !== null) {
|
|
283
|
+
console.log("Found reasoning match:", ((_a2 = reasoningMatch[1]) == null ? void 0 : _a2.substring(0, 50)) + "...");
|
|
282
284
|
allMatches.push({
|
|
283
|
-
content: ((
|
|
285
|
+
content: ((_b = reasoningMatch[1]) == null ? void 0 : _b.trim()) || "",
|
|
284
286
|
index: reasoningMatch.index,
|
|
285
287
|
type: "reasoning"
|
|
286
288
|
});
|
|
287
289
|
}
|
|
288
290
|
let searchingMatch;
|
|
289
291
|
while ((searchingMatch = searchingRegex.exec(text)) !== null) {
|
|
292
|
+
console.log("Found searching match:", ((_c = searchingMatch[1]) == null ? void 0 : _c.substring(0, 50)) + "...");
|
|
290
293
|
allMatches.push({
|
|
291
|
-
content: ((
|
|
294
|
+
content: ((_d = searchingMatch[1]) == null ? void 0 : _d.trim()) || "",
|
|
292
295
|
index: searchingMatch.index,
|
|
293
296
|
type: "searching"
|
|
294
297
|
});
|
|
295
298
|
}
|
|
299
|
+
console.log("Total matches found:", allMatches.length);
|
|
296
300
|
if (allMatches.length > 0) {
|
|
297
301
|
const lastMatch = allMatches.sort((a, b) => b.index - a.index)[0];
|
|
298
302
|
let content = (lastMatch == null ? void 0 : lastMatch.content) || "Thinking";
|
|
303
|
+
console.log("Last match content:", content == null ? void 0 : content.substring(0, 100));
|
|
299
304
|
content = content.replace(/\*\*(.*?)\*\*/g, "$1");
|
|
300
305
|
content = content.replace(/\*(.*?)\*/g, "$1");
|
|
301
306
|
content = content.replace(/\n+/g, " ");
|
|
@@ -304,16 +309,46 @@ var ChatPanel = ({
|
|
|
304
309
|
if (content.length > 80) {
|
|
305
310
|
content = content.substring(0, 77) + "...";
|
|
306
311
|
}
|
|
312
|
+
console.log("Final extracted content:", content);
|
|
307
313
|
return content || "Thinking";
|
|
308
314
|
}
|
|
315
|
+
console.log("No matches found, returning 'Thinking'");
|
|
309
316
|
return "Thinking";
|
|
310
317
|
};
|
|
311
|
-
const
|
|
318
|
+
const processResponseContent = (text, isStreaming = false) => {
|
|
312
319
|
if (!text) return "";
|
|
313
|
-
let
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
320
|
+
let processedText = text;
|
|
321
|
+
processedText = processedText.replace(
|
|
322
|
+
/<reasoning>([\s\S]*?)<\/reasoning>/gi,
|
|
323
|
+
(match, content) => {
|
|
324
|
+
const trimmedContent = content.trim();
|
|
325
|
+
if (!trimmedContent) return "";
|
|
326
|
+
return `
|
|
327
|
+
|
|
328
|
+
<div class="reasoning-section">
|
|
329
|
+
<div class="reasoning-header">\u{1F914} Reasoning</div>
|
|
330
|
+
<div class="reasoning-content">${trimmedContent}</div>
|
|
331
|
+
</div>
|
|
332
|
+
|
|
333
|
+
`;
|
|
334
|
+
}
|
|
335
|
+
);
|
|
336
|
+
processedText = processedText.replace(
|
|
337
|
+
/<searching>([\s\S]*?)<\/searching>/gi,
|
|
338
|
+
(match, content) => {
|
|
339
|
+
const trimmedContent = content.trim();
|
|
340
|
+
if (!trimmedContent) return "";
|
|
341
|
+
return `
|
|
342
|
+
|
|
343
|
+
<div class="searching-section">
|
|
344
|
+
<div class="searching-header">\u{1F50D} Searching</div>
|
|
345
|
+
<div class="searching-content">${trimmedContent}</div>
|
|
346
|
+
</div>
|
|
347
|
+
|
|
348
|
+
`;
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
return processedText;
|
|
317
352
|
};
|
|
318
353
|
const getBrowserInfo = () => {
|
|
319
354
|
try {
|
|
@@ -465,6 +500,16 @@ var ChatPanel = ({
|
|
|
465
500
|
};
|
|
466
501
|
})
|
|
467
502
|
});
|
|
503
|
+
(0, import_react3.useEffect)(() => {
|
|
504
|
+
console.log("Streaming state changed:", {
|
|
505
|
+
isLoading,
|
|
506
|
+
idle,
|
|
507
|
+
responseLength: (response == null ? void 0 : response.length) || 0,
|
|
508
|
+
lastCallId,
|
|
509
|
+
hasResponse: !!response,
|
|
510
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
511
|
+
});
|
|
512
|
+
}, [isLoading, idle, response, lastCallId]);
|
|
468
513
|
(0, import_react3.useEffect)(() => {
|
|
469
514
|
setShowEmailPanel(customerEmailCaptureMode !== "HIDE");
|
|
470
515
|
if (customerEmailCaptureMode === "REQUIRED") {
|
|
@@ -887,6 +932,14 @@ var ChatPanel = ({
|
|
|
887
932
|
});
|
|
888
933
|
(0, import_react3.useEffect)(() => {
|
|
889
934
|
if (response && response.length > 0) {
|
|
935
|
+
console.log("Response updated:", {
|
|
936
|
+
length: response.length,
|
|
937
|
+
isLoading,
|
|
938
|
+
idle,
|
|
939
|
+
hasReasoningTags: response.includes("<reasoning>"),
|
|
940
|
+
hasSearchingTags: response.includes("<searching>"),
|
|
941
|
+
preview: response.substring(0, 200) + "..."
|
|
942
|
+
});
|
|
890
943
|
setIsLoading(false);
|
|
891
944
|
let newResponse = response;
|
|
892
945
|
const toolRequests = [];
|
|
@@ -958,6 +1011,12 @@ var ChatPanel = ({
|
|
|
958
1011
|
} else {
|
|
959
1012
|
setPendingToolRequests([]);
|
|
960
1013
|
}
|
|
1014
|
+
console.log("Storing raw response to history:", {
|
|
1015
|
+
originalLength: newResponse.length,
|
|
1016
|
+
hasReasoningTags: newResponse.includes("<reasoning>"),
|
|
1017
|
+
hasSearchingTags: newResponse.includes("<searching>"),
|
|
1018
|
+
preview: newResponse.substring(0, 200) + "..."
|
|
1019
|
+
});
|
|
961
1020
|
setHistory((prevHistory) => {
|
|
962
1021
|
const existingEntry = prevHistory[lastKey != null ? lastKey : ""] || {
|
|
963
1022
|
content: "",
|
|
@@ -966,7 +1025,8 @@ var ChatPanel = ({
|
|
|
966
1025
|
return __spreadProps(__spreadValues({}, prevHistory), {
|
|
967
1026
|
[lastKey != null ? lastKey : ""]: __spreadProps(__spreadValues({}, existingEntry), {
|
|
968
1027
|
// This preserves toolCalls and toolResponses
|
|
969
|
-
content:
|
|
1028
|
+
content: newResponse,
|
|
1029
|
+
// Store raw response without processing
|
|
970
1030
|
callId: lastCallId
|
|
971
1031
|
})
|
|
972
1032
|
});
|
|
@@ -1184,7 +1244,7 @@ var ChatPanel = ({
|
|
|
1184
1244
|
setHistory((prevHistory) => {
|
|
1185
1245
|
return __spreadProps(__spreadValues({}, prevHistory), {
|
|
1186
1246
|
[lastKey != null ? lastKey : ""]: {
|
|
1187
|
-
content:
|
|
1247
|
+
content: processResponseContent(response) + "\n\n(response cancelled)",
|
|
1188
1248
|
callId: lastCallId
|
|
1189
1249
|
}
|
|
1190
1250
|
});
|
|
@@ -1212,7 +1272,7 @@ var ChatPanel = ({
|
|
|
1212
1272
|
messagesAndHistory.push({ role: "user", content: promptToSend });
|
|
1213
1273
|
messagesAndHistory.push({
|
|
1214
1274
|
role: "assistant",
|
|
1215
|
-
content:
|
|
1275
|
+
content: processResponseContent(response2.content)
|
|
1216
1276
|
});
|
|
1217
1277
|
});
|
|
1218
1278
|
let nextPromptToSend = suggestion != null ? suggestion : nextPrompt;
|
|
@@ -1579,7 +1639,19 @@ var ChatPanel = ({
|
|
|
1579
1639
|
var _a2, _b;
|
|
1580
1640
|
const isLastEntry = index === Object.keys(history).length - 1;
|
|
1581
1641
|
const hasToolData = !!((((_a2 = historyEntry == null ? void 0 : historyEntry.toolCalls) == null ? void 0 : _a2.length) || 0) > 0 || (((_b = historyEntry == null ? void 0 : historyEntry.toolResponses) == null ? void 0 : _b.length) || 0) > 0);
|
|
1582
|
-
return /* @__PURE__ */ import_react3.default.createElement("div", { className: "history-entry", key: index }, hideInitialPrompt && index === 0 ? null : /* @__PURE__ */ import_react3.default.createElement("div", { className: "prompt" }, formatPromptForDisplay(prompt)), /* @__PURE__ */ import_react3.default.createElement("div", { className: "response" }, index === Object.keys(history).length - 1 && isLoading
|
|
1642
|
+
return /* @__PURE__ */ import_react3.default.createElement("div", { className: "history-entry", key: index }, hideInitialPrompt && index === 0 ? null : /* @__PURE__ */ import_react3.default.createElement("div", { className: "prompt" }, formatPromptForDisplay(prompt)), /* @__PURE__ */ import_react3.default.createElement("div", { className: "response" }, index === Object.keys(history).length - 1 && isLoading ? /* @__PURE__ */ import_react3.default.createElement("div", { className: "streaming-response" }, response && response.length > 0 ? /* @__PURE__ */ import_react3.default.createElement(
|
|
1643
|
+
import_react_markdown.default,
|
|
1644
|
+
{
|
|
1645
|
+
className: markdownClass,
|
|
1646
|
+
remarkPlugins: [import_remark_gfm.default],
|
|
1647
|
+
rehypePlugins: [import_rehype_raw.default],
|
|
1648
|
+
components: {
|
|
1649
|
+
/*a: CustomLink,*/
|
|
1650
|
+
code: CodeBlock
|
|
1651
|
+
}
|
|
1652
|
+
},
|
|
1653
|
+
processResponseContent(response, true)
|
|
1654
|
+
) : /* @__PURE__ */ import_react3.default.createElement("div", { className: "loading-text" }, extractLastThinkingTag(response || ""), "\xA0", /* @__PURE__ */ import_react3.default.createElement("div", { className: "dot" }), /* @__PURE__ */ import_react3.default.createElement("div", { className: "dot" }), /* @__PURE__ */ import_react3.default.createElement("div", { className: "dot" }))) : /* @__PURE__ */ import_react3.default.createElement(
|
|
1583
1655
|
import_react_markdown.default,
|
|
1584
1656
|
{
|
|
1585
1657
|
className: markdownClass,
|
|
@@ -1590,7 +1662,7 @@ var ChatPanel = ({
|
|
|
1590
1662
|
code: CodeBlock
|
|
1591
1663
|
}
|
|
1592
1664
|
},
|
|
1593
|
-
historyEntry.content
|
|
1665
|
+
processResponseContent(historyEntry.content)
|
|
1594
1666
|
), isLastEntry && pendingToolRequests.length > 0 && /* @__PURE__ */ import_react3.default.createElement("div", { className: "approve-tools-panel" }, getUniqueToolNames(pendingToolRequests).map(
|
|
1595
1667
|
(toolName) => {
|
|
1596
1668
|
const tool = toolList.find(
|
|
@@ -1627,7 +1699,7 @@ var ChatPanel = ({
|
|
|
1627
1699
|
{
|
|
1628
1700
|
className: "copy-button",
|
|
1629
1701
|
onClick: () => {
|
|
1630
|
-
copyToClipboard(historyEntry.content);
|
|
1702
|
+
copyToClipboard(processResponseContent(historyEntry.content));
|
|
1631
1703
|
},
|
|
1632
1704
|
disabled: isDisabledDueToNoEmail()
|
|
1633
1705
|
},
|
package/dist/index.mjs
CHANGED
|
@@ -244,30 +244,35 @@ var ChatPanel = ({
|
|
|
244
244
|
const [iframeUrl, setIframeUrl] = useState2(null);
|
|
245
245
|
const responseAreaRef = useRef(null);
|
|
246
246
|
const extractLastThinkingTag = (text) => {
|
|
247
|
-
var _a2, _b;
|
|
247
|
+
var _a2, _b, _c, _d;
|
|
248
|
+
console.log("extractLastThinkingTag called with:", (text == null ? void 0 : text.length) ? `${text.substring(0, 100)}...` : "empty");
|
|
248
249
|
if (!text) return "Thinking";
|
|
249
|
-
const reasoningRegex = /<reasoning>(
|
|
250
|
-
const searchingRegex = /<searching>(
|
|
250
|
+
const reasoningRegex = /<reasoning>([\s\S]*?)<\/reasoning>/gi;
|
|
251
|
+
const searchingRegex = /<searching>([\s\S]*?)<\/searching>/gi;
|
|
251
252
|
const allMatches = [];
|
|
252
253
|
let reasoningMatch;
|
|
253
254
|
while ((reasoningMatch = reasoningRegex.exec(text)) !== null) {
|
|
255
|
+
console.log("Found reasoning match:", ((_a2 = reasoningMatch[1]) == null ? void 0 : _a2.substring(0, 50)) + "...");
|
|
254
256
|
allMatches.push({
|
|
255
|
-
content: ((
|
|
257
|
+
content: ((_b = reasoningMatch[1]) == null ? void 0 : _b.trim()) || "",
|
|
256
258
|
index: reasoningMatch.index,
|
|
257
259
|
type: "reasoning"
|
|
258
260
|
});
|
|
259
261
|
}
|
|
260
262
|
let searchingMatch;
|
|
261
263
|
while ((searchingMatch = searchingRegex.exec(text)) !== null) {
|
|
264
|
+
console.log("Found searching match:", ((_c = searchingMatch[1]) == null ? void 0 : _c.substring(0, 50)) + "...");
|
|
262
265
|
allMatches.push({
|
|
263
|
-
content: ((
|
|
266
|
+
content: ((_d = searchingMatch[1]) == null ? void 0 : _d.trim()) || "",
|
|
264
267
|
index: searchingMatch.index,
|
|
265
268
|
type: "searching"
|
|
266
269
|
});
|
|
267
270
|
}
|
|
271
|
+
console.log("Total matches found:", allMatches.length);
|
|
268
272
|
if (allMatches.length > 0) {
|
|
269
273
|
const lastMatch = allMatches.sort((a, b) => b.index - a.index)[0];
|
|
270
274
|
let content = (lastMatch == null ? void 0 : lastMatch.content) || "Thinking";
|
|
275
|
+
console.log("Last match content:", content == null ? void 0 : content.substring(0, 100));
|
|
271
276
|
content = content.replace(/\*\*(.*?)\*\*/g, "$1");
|
|
272
277
|
content = content.replace(/\*(.*?)\*/g, "$1");
|
|
273
278
|
content = content.replace(/\n+/g, " ");
|
|
@@ -276,16 +281,46 @@ var ChatPanel = ({
|
|
|
276
281
|
if (content.length > 80) {
|
|
277
282
|
content = content.substring(0, 77) + "...";
|
|
278
283
|
}
|
|
284
|
+
console.log("Final extracted content:", content);
|
|
279
285
|
return content || "Thinking";
|
|
280
286
|
}
|
|
287
|
+
console.log("No matches found, returning 'Thinking'");
|
|
281
288
|
return "Thinking";
|
|
282
289
|
};
|
|
283
|
-
const
|
|
290
|
+
const processResponseContent = (text, isStreaming = false) => {
|
|
284
291
|
if (!text) return "";
|
|
285
|
-
let
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
292
|
+
let processedText = text;
|
|
293
|
+
processedText = processedText.replace(
|
|
294
|
+
/<reasoning>([\s\S]*?)<\/reasoning>/gi,
|
|
295
|
+
(match, content) => {
|
|
296
|
+
const trimmedContent = content.trim();
|
|
297
|
+
if (!trimmedContent) return "";
|
|
298
|
+
return `
|
|
299
|
+
|
|
300
|
+
<div class="reasoning-section">
|
|
301
|
+
<div class="reasoning-header">\u{1F914} Reasoning</div>
|
|
302
|
+
<div class="reasoning-content">${trimmedContent}</div>
|
|
303
|
+
</div>
|
|
304
|
+
|
|
305
|
+
`;
|
|
306
|
+
}
|
|
307
|
+
);
|
|
308
|
+
processedText = processedText.replace(
|
|
309
|
+
/<searching>([\s\S]*?)<\/searching>/gi,
|
|
310
|
+
(match, content) => {
|
|
311
|
+
const trimmedContent = content.trim();
|
|
312
|
+
if (!trimmedContent) return "";
|
|
313
|
+
return `
|
|
314
|
+
|
|
315
|
+
<div class="searching-section">
|
|
316
|
+
<div class="searching-header">\u{1F50D} Searching</div>
|
|
317
|
+
<div class="searching-content">${trimmedContent}</div>
|
|
318
|
+
</div>
|
|
319
|
+
|
|
320
|
+
`;
|
|
321
|
+
}
|
|
322
|
+
);
|
|
323
|
+
return processedText;
|
|
289
324
|
};
|
|
290
325
|
const getBrowserInfo = () => {
|
|
291
326
|
try {
|
|
@@ -437,6 +472,16 @@ var ChatPanel = ({
|
|
|
437
472
|
};
|
|
438
473
|
})
|
|
439
474
|
});
|
|
475
|
+
useEffect2(() => {
|
|
476
|
+
console.log("Streaming state changed:", {
|
|
477
|
+
isLoading,
|
|
478
|
+
idle,
|
|
479
|
+
responseLength: (response == null ? void 0 : response.length) || 0,
|
|
480
|
+
lastCallId,
|
|
481
|
+
hasResponse: !!response,
|
|
482
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
483
|
+
});
|
|
484
|
+
}, [isLoading, idle, response, lastCallId]);
|
|
440
485
|
useEffect2(() => {
|
|
441
486
|
setShowEmailPanel(customerEmailCaptureMode !== "HIDE");
|
|
442
487
|
if (customerEmailCaptureMode === "REQUIRED") {
|
|
@@ -859,6 +904,14 @@ var ChatPanel = ({
|
|
|
859
904
|
});
|
|
860
905
|
useEffect2(() => {
|
|
861
906
|
if (response && response.length > 0) {
|
|
907
|
+
console.log("Response updated:", {
|
|
908
|
+
length: response.length,
|
|
909
|
+
isLoading,
|
|
910
|
+
idle,
|
|
911
|
+
hasReasoningTags: response.includes("<reasoning>"),
|
|
912
|
+
hasSearchingTags: response.includes("<searching>"),
|
|
913
|
+
preview: response.substring(0, 200) + "..."
|
|
914
|
+
});
|
|
862
915
|
setIsLoading(false);
|
|
863
916
|
let newResponse = response;
|
|
864
917
|
const toolRequests = [];
|
|
@@ -930,6 +983,12 @@ var ChatPanel = ({
|
|
|
930
983
|
} else {
|
|
931
984
|
setPendingToolRequests([]);
|
|
932
985
|
}
|
|
986
|
+
console.log("Storing raw response to history:", {
|
|
987
|
+
originalLength: newResponse.length,
|
|
988
|
+
hasReasoningTags: newResponse.includes("<reasoning>"),
|
|
989
|
+
hasSearchingTags: newResponse.includes("<searching>"),
|
|
990
|
+
preview: newResponse.substring(0, 200) + "..."
|
|
991
|
+
});
|
|
933
992
|
setHistory((prevHistory) => {
|
|
934
993
|
const existingEntry = prevHistory[lastKey != null ? lastKey : ""] || {
|
|
935
994
|
content: "",
|
|
@@ -938,7 +997,8 @@ var ChatPanel = ({
|
|
|
938
997
|
return __spreadProps(__spreadValues({}, prevHistory), {
|
|
939
998
|
[lastKey != null ? lastKey : ""]: __spreadProps(__spreadValues({}, existingEntry), {
|
|
940
999
|
// This preserves toolCalls and toolResponses
|
|
941
|
-
content:
|
|
1000
|
+
content: newResponse,
|
|
1001
|
+
// Store raw response without processing
|
|
942
1002
|
callId: lastCallId
|
|
943
1003
|
})
|
|
944
1004
|
});
|
|
@@ -1156,7 +1216,7 @@ var ChatPanel = ({
|
|
|
1156
1216
|
setHistory((prevHistory) => {
|
|
1157
1217
|
return __spreadProps(__spreadValues({}, prevHistory), {
|
|
1158
1218
|
[lastKey != null ? lastKey : ""]: {
|
|
1159
|
-
content:
|
|
1219
|
+
content: processResponseContent(response) + "\n\n(response cancelled)",
|
|
1160
1220
|
callId: lastCallId
|
|
1161
1221
|
}
|
|
1162
1222
|
});
|
|
@@ -1184,7 +1244,7 @@ var ChatPanel = ({
|
|
|
1184
1244
|
messagesAndHistory.push({ role: "user", content: promptToSend });
|
|
1185
1245
|
messagesAndHistory.push({
|
|
1186
1246
|
role: "assistant",
|
|
1187
|
-
content:
|
|
1247
|
+
content: processResponseContent(response2.content)
|
|
1188
1248
|
});
|
|
1189
1249
|
});
|
|
1190
1250
|
let nextPromptToSend = suggestion != null ? suggestion : nextPrompt;
|
|
@@ -1551,7 +1611,19 @@ var ChatPanel = ({
|
|
|
1551
1611
|
var _a2, _b;
|
|
1552
1612
|
const isLastEntry = index === Object.keys(history).length - 1;
|
|
1553
1613
|
const hasToolData = !!((((_a2 = historyEntry == null ? void 0 : historyEntry.toolCalls) == null ? void 0 : _a2.length) || 0) > 0 || (((_b = historyEntry == null ? void 0 : historyEntry.toolResponses) == null ? void 0 : _b.length) || 0) > 0);
|
|
1554
|
-
return /* @__PURE__ */ React3.createElement("div", { className: "history-entry", key: index }, hideInitialPrompt && index === 0 ? null : /* @__PURE__ */ React3.createElement("div", { className: "prompt" }, formatPromptForDisplay(prompt)), /* @__PURE__ */ React3.createElement("div", { className: "response" }, index === Object.keys(history).length - 1 && isLoading
|
|
1614
|
+
return /* @__PURE__ */ React3.createElement("div", { className: "history-entry", key: index }, hideInitialPrompt && index === 0 ? null : /* @__PURE__ */ React3.createElement("div", { className: "prompt" }, formatPromptForDisplay(prompt)), /* @__PURE__ */ React3.createElement("div", { className: "response" }, index === Object.keys(history).length - 1 && isLoading ? /* @__PURE__ */ React3.createElement("div", { className: "streaming-response" }, response && response.length > 0 ? /* @__PURE__ */ React3.createElement(
|
|
1615
|
+
ReactMarkdown,
|
|
1616
|
+
{
|
|
1617
|
+
className: markdownClass,
|
|
1618
|
+
remarkPlugins: [remarkGfm],
|
|
1619
|
+
rehypePlugins: [rehypeRaw],
|
|
1620
|
+
components: {
|
|
1621
|
+
/*a: CustomLink,*/
|
|
1622
|
+
code: CodeBlock
|
|
1623
|
+
}
|
|
1624
|
+
},
|
|
1625
|
+
processResponseContent(response, true)
|
|
1626
|
+
) : /* @__PURE__ */ React3.createElement("div", { className: "loading-text" }, extractLastThinkingTag(response || ""), "\xA0", /* @__PURE__ */ React3.createElement("div", { className: "dot" }), /* @__PURE__ */ React3.createElement("div", { className: "dot" }), /* @__PURE__ */ React3.createElement("div", { className: "dot" }))) : /* @__PURE__ */ React3.createElement(
|
|
1555
1627
|
ReactMarkdown,
|
|
1556
1628
|
{
|
|
1557
1629
|
className: markdownClass,
|
|
@@ -1562,7 +1634,7 @@ var ChatPanel = ({
|
|
|
1562
1634
|
code: CodeBlock
|
|
1563
1635
|
}
|
|
1564
1636
|
},
|
|
1565
|
-
historyEntry.content
|
|
1637
|
+
processResponseContent(historyEntry.content)
|
|
1566
1638
|
), isLastEntry && pendingToolRequests.length > 0 && /* @__PURE__ */ React3.createElement("div", { className: "approve-tools-panel" }, getUniqueToolNames(pendingToolRequests).map(
|
|
1567
1639
|
(toolName) => {
|
|
1568
1640
|
const tool = toolList.find(
|
|
@@ -1599,7 +1671,7 @@ var ChatPanel = ({
|
|
|
1599
1671
|
{
|
|
1600
1672
|
className: "copy-button",
|
|
1601
1673
|
onClick: () => {
|
|
1602
|
-
copyToClipboard(historyEntry.content);
|
|
1674
|
+
copyToClipboard(processResponseContent(historyEntry.content));
|
|
1603
1675
|
},
|
|
1604
1676
|
disabled: isDisabledDueToNoEmail()
|
|
1605
1677
|
},
|
package/package.json
CHANGED
package/src/ChatPanel.css
CHANGED
|
@@ -490,6 +490,7 @@
|
|
|
490
490
|
display: flex;
|
|
491
491
|
align-items: center;
|
|
492
492
|
justify-content: center;
|
|
493
|
+
margin-top: 4px;
|
|
493
494
|
font-size: 10px;
|
|
494
495
|
color: #666;
|
|
495
496
|
opacity: 0.7;
|
|
@@ -885,4 +886,72 @@
|
|
|
885
886
|
/* Dark theme support */
|
|
886
887
|
.dark-theme .tool-status {
|
|
887
888
|
color: #999;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/* Reasoning and Searching Sections */
|
|
892
|
+
.reasoning-section, .searching-section {
|
|
893
|
+
margin: 1rem 0;
|
|
894
|
+
padding: 0.75rem;
|
|
895
|
+
border-radius: var(--border-radius);
|
|
896
|
+
border-left: 4px solid;
|
|
897
|
+
background-color: var(--reasoning-background-color, #f8f9fa);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
.reasoning-section {
|
|
901
|
+
border-left-color: var(--reasoning-border-color, #007bff);
|
|
902
|
+
background-color: var(--reasoning-background-color, #f0f8ff);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
.searching-section {
|
|
906
|
+
border-left-color: var(--searching-border-color, #28a745);
|
|
907
|
+
background-color: var(--searching-background-color, #f0fff0);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
.reasoning-header, .searching-header {
|
|
911
|
+
font-weight: 600;
|
|
912
|
+
font-size: 0.9rem;
|
|
913
|
+
margin-bottom: 0.5rem;
|
|
914
|
+
color: var(--prompt-text-color);
|
|
915
|
+
opacity: 0.8;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
.reasoning-content, .searching-content {
|
|
919
|
+
font-size: 0.85rem;
|
|
920
|
+
line-height: 1.4;
|
|
921
|
+
color: var(--prompt-text-color);
|
|
922
|
+
opacity: 0.9;
|
|
923
|
+
font-style: italic;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/* Dark theme support for reasoning/searching */
|
|
927
|
+
.dark-theme .reasoning-section {
|
|
928
|
+
background-color: var(--reasoning-background-color-dark, #1a1a2e);
|
|
929
|
+
border-left-color: var(--reasoning-border-color-dark, #4a9eff);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
.dark-theme .searching-section {
|
|
933
|
+
background-color: var(--searching-background-color-dark, #1a2e1a);
|
|
934
|
+
border-left-color: var(--searching-border-color-dark, #4ade80);
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
.dark-theme .reasoning-header,
|
|
938
|
+
.dark-theme .searching-header,
|
|
939
|
+
.dark-theme .reasoning-content,
|
|
940
|
+
.dark-theme .searching-content {
|
|
941
|
+
color: var(--response-text-color);
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
/* Streaming response styling */
|
|
945
|
+
.streaming-response {
|
|
946
|
+
/* Add a subtle animation to indicate streaming */
|
|
947
|
+
animation: fadeIn 0.3s ease-in-out;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
@keyframes fadeIn {
|
|
951
|
+
from {
|
|
952
|
+
opacity: 0;
|
|
953
|
+
}
|
|
954
|
+
to {
|
|
955
|
+
opacity: 1;
|
|
956
|
+
}
|
|
888
957
|
}
|
package/src/ChatPanel.tsx
CHANGED
|
@@ -232,17 +232,20 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
232
232
|
const responseAreaRef = useRef(null);
|
|
233
233
|
// Extract the last reasoning or searching tag from the response
|
|
234
234
|
const extractLastThinkingTag = (text: string): string => {
|
|
235
|
+
console.log("extractLastThinkingTag called with:", text?.length ? `${text.substring(0, 100)}...` : "empty");
|
|
236
|
+
|
|
235
237
|
if (!text) return "Thinking";
|
|
236
238
|
|
|
237
|
-
// Find all reasoning and searching tags using exec method
|
|
238
|
-
const reasoningRegex = /<reasoning>(
|
|
239
|
-
const searchingRegex = /<searching>(
|
|
239
|
+
// Find all reasoning and searching tags using exec method (with global and multiline flags)
|
|
240
|
+
const reasoningRegex = /<reasoning>([\s\S]*?)<\/reasoning>/gi;
|
|
241
|
+
const searchingRegex = /<searching>([\s\S]*?)<\/searching>/gi;
|
|
240
242
|
|
|
241
243
|
const allMatches: Array<{ content: string; index: number; type: string }> = [];
|
|
242
244
|
|
|
243
245
|
// Find all reasoning matches
|
|
244
246
|
let reasoningMatch;
|
|
245
247
|
while ((reasoningMatch = reasoningRegex.exec(text)) !== null) {
|
|
248
|
+
console.log("Found reasoning match:", reasoningMatch[1]?.substring(0, 50) + "...");
|
|
246
249
|
allMatches.push({
|
|
247
250
|
content: reasoningMatch[1]?.trim() || "",
|
|
248
251
|
index: reasoningMatch.index,
|
|
@@ -253,6 +256,7 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
253
256
|
// Find all searching matches
|
|
254
257
|
let searchingMatch;
|
|
255
258
|
while ((searchingMatch = searchingRegex.exec(text)) !== null) {
|
|
259
|
+
console.log("Found searching match:", searchingMatch[1]?.substring(0, 50) + "...");
|
|
256
260
|
allMatches.push({
|
|
257
261
|
content: searchingMatch[1]?.trim() || "",
|
|
258
262
|
index: searchingMatch.index,
|
|
@@ -260,11 +264,15 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
260
264
|
});
|
|
261
265
|
}
|
|
262
266
|
|
|
267
|
+
console.log("Total matches found:", allMatches.length);
|
|
268
|
+
|
|
263
269
|
// Sort by position and get the last one
|
|
264
270
|
if (allMatches.length > 0) {
|
|
265
271
|
const lastMatch = allMatches.sort((a, b) => b.index - a.index)[0];
|
|
266
272
|
let content = lastMatch?.content || "Thinking";
|
|
267
273
|
|
|
274
|
+
console.log("Last match content:", content?.substring(0, 100));
|
|
275
|
+
|
|
268
276
|
// Clean up the content - remove markdown formatting and limit length
|
|
269
277
|
content = content.replace(/\*\*(.*?)\*\*/g, '$1'); // Remove bold
|
|
270
278
|
content = content.replace(/\*(.*?)\*/g, '$1'); // Remove italics
|
|
@@ -277,26 +285,49 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
277
285
|
content = content.substring(0, 77) + '...';
|
|
278
286
|
}
|
|
279
287
|
|
|
288
|
+
console.log("Final extracted content:", content);
|
|
280
289
|
return content || "Thinking";
|
|
281
290
|
}
|
|
282
291
|
|
|
292
|
+
console.log("No matches found, returning 'Thinking'");
|
|
283
293
|
return "Thinking";
|
|
284
294
|
};
|
|
285
295
|
|
|
286
|
-
//
|
|
287
|
-
const
|
|
296
|
+
// Process response content to show reasoning/searching in a styled format
|
|
297
|
+
const processResponseContent = (text: string, isStreaming: boolean = false): string => {
|
|
288
298
|
if (!text) return "";
|
|
289
299
|
|
|
290
|
-
|
|
291
|
-
let cleanText = text.replace(/<reasoning>[\s\S]*?<\/reasoning>/gi, '');
|
|
300
|
+
let processedText = text;
|
|
292
301
|
|
|
293
|
-
//
|
|
294
|
-
|
|
302
|
+
// Replace reasoning tags with styled content
|
|
303
|
+
processedText = processedText.replace(
|
|
304
|
+
/<reasoning>([\s\S]*?)<\/reasoning>/gi,
|
|
305
|
+
(match, content) => {
|
|
306
|
+
const trimmedContent = content.trim();
|
|
307
|
+
if (!trimmedContent) return '';
|
|
308
|
+
|
|
309
|
+
return `\n\n<div class="reasoning-section">
|
|
310
|
+
<div class="reasoning-header">🤔 Reasoning</div>
|
|
311
|
+
<div class="reasoning-content">${trimmedContent}</div>
|
|
312
|
+
</div>\n\n`;
|
|
313
|
+
}
|
|
314
|
+
);
|
|
295
315
|
|
|
296
|
-
//
|
|
297
|
-
|
|
316
|
+
// Replace searching tags with styled content
|
|
317
|
+
processedText = processedText.replace(
|
|
318
|
+
/<searching>([\s\S]*?)<\/searching>/gi,
|
|
319
|
+
(match, content) => {
|
|
320
|
+
const trimmedContent = content.trim();
|
|
321
|
+
if (!trimmedContent) return '';
|
|
322
|
+
|
|
323
|
+
return `\n\n<div class="searching-section">
|
|
324
|
+
<div class="searching-header">🔍 Searching</div>
|
|
325
|
+
<div class="searching-content">${trimmedContent}</div>
|
|
326
|
+
</div>\n\n`;
|
|
327
|
+
}
|
|
328
|
+
);
|
|
298
329
|
|
|
299
|
-
return
|
|
330
|
+
return processedText;
|
|
300
331
|
};
|
|
301
332
|
|
|
302
333
|
const getBrowserInfo = () => {
|
|
@@ -477,6 +508,18 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
477
508
|
}) as [],
|
|
478
509
|
});
|
|
479
510
|
|
|
511
|
+
// Add logging for streaming states
|
|
512
|
+
useEffect(() => {
|
|
513
|
+
console.log("Streaming state changed:", {
|
|
514
|
+
isLoading,
|
|
515
|
+
idle,
|
|
516
|
+
responseLength: response?.length || 0,
|
|
517
|
+
lastCallId,
|
|
518
|
+
hasResponse: !!response,
|
|
519
|
+
timestamp: new Date().toISOString()
|
|
520
|
+
});
|
|
521
|
+
}, [isLoading, idle, response, lastCallId]);
|
|
522
|
+
|
|
480
523
|
useEffect(() => {
|
|
481
524
|
setShowEmailPanel(customerEmailCaptureMode !== "HIDE");
|
|
482
525
|
|
|
@@ -998,6 +1041,15 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
998
1041
|
|
|
999
1042
|
useEffect(() => {
|
|
1000
1043
|
if (response && response.length > 0) {
|
|
1044
|
+
console.log("Response updated:", {
|
|
1045
|
+
length: response.length,
|
|
1046
|
+
isLoading,
|
|
1047
|
+
idle,
|
|
1048
|
+
hasReasoningTags: response.includes('<reasoning>'),
|
|
1049
|
+
hasSearchingTags: response.includes('<searching>'),
|
|
1050
|
+
preview: response.substring(0, 200) + "..."
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1001
1053
|
setIsLoading(false);
|
|
1002
1054
|
|
|
1003
1055
|
let newResponse = response;
|
|
@@ -1088,6 +1140,15 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
1088
1140
|
setPendingToolRequests([]);
|
|
1089
1141
|
}
|
|
1090
1142
|
|
|
1143
|
+
// Store the raw response without processing reasoning/searching tags
|
|
1144
|
+
// Tags will be processed only during streaming display
|
|
1145
|
+
console.log("Storing raw response to history:", {
|
|
1146
|
+
originalLength: newResponse.length,
|
|
1147
|
+
hasReasoningTags: newResponse.includes('<reasoning>'),
|
|
1148
|
+
hasSearchingTags: newResponse.includes('<searching>'),
|
|
1149
|
+
preview: newResponse.substring(0, 200) + "..."
|
|
1150
|
+
});
|
|
1151
|
+
|
|
1091
1152
|
setHistory((prevHistory) => {
|
|
1092
1153
|
// Get any existing tool data from the previous state
|
|
1093
1154
|
const existingEntry = prevHistory[lastKey ?? ""] || {
|
|
@@ -1099,7 +1160,7 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
1099
1160
|
...prevHistory,
|
|
1100
1161
|
[lastKey ?? ""]: {
|
|
1101
1162
|
...existingEntry, // This preserves toolCalls and toolResponses
|
|
1102
|
-
content:
|
|
1163
|
+
content: newResponse, // Store raw response without processing
|
|
1103
1164
|
callId: lastCallId,
|
|
1104
1165
|
},
|
|
1105
1166
|
};
|
|
@@ -1374,7 +1435,7 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
1374
1435
|
return {
|
|
1375
1436
|
...prevHistory,
|
|
1376
1437
|
[lastKey ?? ""]: {
|
|
1377
|
-
content:
|
|
1438
|
+
content: processResponseContent(response) + "\n\n(response cancelled)",
|
|
1378
1439
|
callId: lastCallId,
|
|
1379
1440
|
},
|
|
1380
1441
|
};
|
|
@@ -1410,7 +1471,7 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
1410
1471
|
messagesAndHistory.push({ role: "user", content: promptToSend });
|
|
1411
1472
|
messagesAndHistory.push({
|
|
1412
1473
|
role: "assistant",
|
|
1413
|
-
content:
|
|
1474
|
+
content: processResponseContent(response.content),
|
|
1414
1475
|
});
|
|
1415
1476
|
});
|
|
1416
1477
|
|
|
@@ -1885,22 +1946,37 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
1885
1946
|
)}
|
|
1886
1947
|
|
|
1887
1948
|
<div className="response">
|
|
1888
|
-
{
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1949
|
+
{/* Show streaming response with reasoning/searching tags */}
|
|
1950
|
+
{index === Object.keys(history).length - 1 && isLoading ? (
|
|
1951
|
+
<div className="streaming-response">
|
|
1952
|
+
{response && response.length > 0 ? (
|
|
1953
|
+
<ReactMarkdown
|
|
1954
|
+
className={markdownClass}
|
|
1955
|
+
remarkPlugins={[remarkGfm]}
|
|
1956
|
+
rehypePlugins={[rehypeRaw]}
|
|
1957
|
+
components={{ /*a: CustomLink,*/ code: CodeBlock }}
|
|
1958
|
+
>
|
|
1959
|
+
{processResponseContent(response, true)}
|
|
1960
|
+
</ReactMarkdown>
|
|
1961
|
+
) : (
|
|
1962
|
+
<div className="loading-text">
|
|
1963
|
+
{extractLastThinkingTag(response || "")}
|
|
1964
|
+
<div className="dot"></div>
|
|
1965
|
+
<div className="dot"></div>
|
|
1966
|
+
<div className="dot"></div>
|
|
1967
|
+
</div>
|
|
1968
|
+
)}
|
|
1894
1969
|
</div>
|
|
1895
|
-
) :
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1970
|
+
) : (
|
|
1971
|
+
<ReactMarkdown
|
|
1972
|
+
className={markdownClass}
|
|
1973
|
+
remarkPlugins={[remarkGfm]}
|
|
1974
|
+
rehypePlugins={[rehypeRaw]}
|
|
1975
|
+
components={{ /*a: CustomLink,*/ code: CodeBlock }}
|
|
1976
|
+
>
|
|
1977
|
+
{processResponseContent(historyEntry.content)}
|
|
1978
|
+
</ReactMarkdown>
|
|
1979
|
+
)}
|
|
1904
1980
|
|
|
1905
1981
|
{isLastEntry && pendingToolRequests.length > 0 && (
|
|
1906
1982
|
<div className="approve-tools-panel">
|
|
@@ -1963,7 +2039,7 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
1963
2039
|
<button
|
|
1964
2040
|
className="copy-button"
|
|
1965
2041
|
onClick={() => {
|
|
1966
|
-
copyToClipboard(historyEntry.content);
|
|
2042
|
+
copyToClipboard(processResponseContent(historyEntry.content));
|
|
1967
2043
|
}}
|
|
1968
2044
|
disabled={isDisabledDueToNoEmail()}
|
|
1969
2045
|
>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Test to verify that our fix prevents duplication of reasoning blocks
|
|
2
|
+
|
|
3
|
+
const testResponse = `Hello! <reasoning>Let me think about this step by step.
|
|
4
|
+
I need to analyze the problem first.</reasoning>Based on my analysis, here's the answer.`;
|
|
5
|
+
|
|
6
|
+
console.log("Testing duplication fix...\n");
|
|
7
|
+
|
|
8
|
+
// Simulate processing function from ChatPanel
|
|
9
|
+
function processResponseContent(text, isStreaming = false) {
|
|
10
|
+
if (!text) return "";
|
|
11
|
+
|
|
12
|
+
let processedText = text;
|
|
13
|
+
|
|
14
|
+
// Replace reasoning tags with styled content
|
|
15
|
+
processedText = processedText.replace(
|
|
16
|
+
/<reasoning>([\s\S]*?)<\/reasoning>/gi,
|
|
17
|
+
(match, content) => {
|
|
18
|
+
const trimmedContent = content.trim();
|
|
19
|
+
if (!trimmedContent) return '';
|
|
20
|
+
|
|
21
|
+
return `\n\n<div class="reasoning-section">
|
|
22
|
+
<div class="reasoning-header">🤔 Reasoning</div>
|
|
23
|
+
<div class="reasoning-content">${trimmedContent}</div>
|
|
24
|
+
</div>\n\n`;
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return processedText;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.log("1. Original response (what would be stored in history):");
|
|
32
|
+
console.log(testResponse);
|
|
33
|
+
console.log("\n" + "=".repeat(80) + "\n");
|
|
34
|
+
|
|
35
|
+
console.log("2. Processed response (what would be displayed during streaming):");
|
|
36
|
+
const processedOnce = processResponseContent(testResponse);
|
|
37
|
+
console.log(processedOnce);
|
|
38
|
+
console.log("\n" + "=".repeat(80) + "\n");
|
|
39
|
+
|
|
40
|
+
console.log("3. OLD BUGGY BEHAVIOR - Processing the same content twice:");
|
|
41
|
+
const processedTwice = processResponseContent(processedOnce);
|
|
42
|
+
console.log(processedTwice);
|
|
43
|
+
console.log("\n" + "=".repeat(80) + "\n");
|
|
44
|
+
|
|
45
|
+
console.log("4. NEW FIXED BEHAVIOR - Processing raw content from history:");
|
|
46
|
+
const processedFromHistory = processResponseContent(testResponse);
|
|
47
|
+
console.log(processedFromHistory);
|
|
48
|
+
console.log("\n" + "=".repeat(80) + "\n");
|
|
49
|
+
|
|
50
|
+
console.log("5. Verification:");
|
|
51
|
+
console.log("Processing twice creates duplication:", processedTwice.includes('reasoning-section') && processedTwice.split('reasoning-section').length > 2);
|
|
52
|
+
console.log("Processing from raw history works correctly:", processedFromHistory === processedOnce);
|
|
File without changes
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Test file to verify tag extraction functions
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
// Mock test data
|
|
6
|
+
const testTexts = [
|
|
7
|
+
"This is a simple response without any tags.",
|
|
8
|
+
"<reasoning>I need to think about this problem step by step.</reasoning>Here's my answer.",
|
|
9
|
+
"Some text <searching>Looking for information about cats</searching> more text",
|
|
10
|
+
"<reasoning>First, I'll analyze the problem.</reasoning>Then I'll search. <searching>Finding relevant data</searching>Final answer here.",
|
|
11
|
+
"Multiple <reasoning>First reasoning</reasoning> and <reasoning>Second reasoning</reasoning> tags.",
|
|
12
|
+
"Incomplete <reasoning>Missing closing tag...",
|
|
13
|
+
"<reasoning>\nMultiline reasoning\nwith several lines\nof content\n</reasoning>Response text here.",
|
|
14
|
+
"Mixed <reasoning>Some thinking</reasoning> and <searching>Some searching</searching> with final answer."
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
// Copy the extraction function from the React component
|
|
18
|
+
function extractLastThinkingTag(text) {
|
|
19
|
+
console.log("extractLastThinkingTag called with:", text?.length ? `${text.substring(0, 100)}...` : "empty");
|
|
20
|
+
|
|
21
|
+
if (!text) return "Thinking";
|
|
22
|
+
|
|
23
|
+
// Find all reasoning and searching tags using exec method (with global and multiline flags)
|
|
24
|
+
const reasoningRegex = /<reasoning>([\s\S]*?)<\/reasoning>/gi;
|
|
25
|
+
const searchingRegex = /<searching>([\s\S]*?)<\/searching>/gi;
|
|
26
|
+
|
|
27
|
+
const allMatches = [];
|
|
28
|
+
|
|
29
|
+
// Find all reasoning matches
|
|
30
|
+
let reasoningMatch;
|
|
31
|
+
while ((reasoningMatch = reasoningRegex.exec(text)) !== null) {
|
|
32
|
+
console.log("Found reasoning match:", reasoningMatch[1]?.substring(0, 50) + "...");
|
|
33
|
+
allMatches.push({
|
|
34
|
+
content: reasoningMatch[1]?.trim() || "",
|
|
35
|
+
index: reasoningMatch.index,
|
|
36
|
+
type: 'reasoning'
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Find all searching matches
|
|
41
|
+
let searchingMatch;
|
|
42
|
+
while ((searchingMatch = searchingRegex.exec(text)) !== null) {
|
|
43
|
+
console.log("Found searching match:", searchingMatch[1]?.substring(0, 50) + "...");
|
|
44
|
+
allMatches.push({
|
|
45
|
+
content: searchingMatch[1]?.trim() || "",
|
|
46
|
+
index: searchingMatch.index,
|
|
47
|
+
type: 'searching'
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log("Total matches found:", allMatches.length);
|
|
52
|
+
|
|
53
|
+
// Sort by position and get the last one
|
|
54
|
+
if (allMatches.length > 0) {
|
|
55
|
+
const lastMatch = allMatches.sort((a, b) => b.index - a.index)[0];
|
|
56
|
+
let content = lastMatch?.content || "Thinking";
|
|
57
|
+
|
|
58
|
+
console.log("Last match content:", content?.substring(0, 100));
|
|
59
|
+
|
|
60
|
+
// Clean up the content - remove markdown formatting and limit length
|
|
61
|
+
content = content.replace(/\*\*(.*?)\*\*/g, '$1'); // Remove bold
|
|
62
|
+
content = content.replace(/\*(.*?)\*/g, '$1'); // Remove italics
|
|
63
|
+
content = content.replace(/\n+/g, ' '); // Replace newlines with spaces
|
|
64
|
+
content = content.replace(/\s+/g, ' '); // Normalize whitespace
|
|
65
|
+
content = content.trim();
|
|
66
|
+
|
|
67
|
+
// Limit length to keep UI clean
|
|
68
|
+
if (content.length > 80) {
|
|
69
|
+
content = content.substring(0, 77) + '...';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log("Final extracted content:", content);
|
|
73
|
+
return content || "Thinking";
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log("No matches found, returning 'Thinking'");
|
|
77
|
+
return "Thinking";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Copy the processing function from the React component
|
|
81
|
+
function processResponseContent(text, isStreaming = false) {
|
|
82
|
+
if (!text) return "";
|
|
83
|
+
|
|
84
|
+
let processedText = text;
|
|
85
|
+
|
|
86
|
+
// Replace reasoning tags with styled content
|
|
87
|
+
processedText = processedText.replace(
|
|
88
|
+
/<reasoning>([\s\S]*?)<\/reasoning>/gi,
|
|
89
|
+
(match, content) => {
|
|
90
|
+
const trimmedContent = content.trim();
|
|
91
|
+
if (!trimmedContent) return '';
|
|
92
|
+
|
|
93
|
+
return `\n\n<div class="reasoning-section">
|
|
94
|
+
<div class="reasoning-header">🤔 Reasoning</div>
|
|
95
|
+
<div class="reasoning-content">${trimmedContent}</div>
|
|
96
|
+
</div>\n\n`;
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// Replace searching tags with styled content
|
|
101
|
+
processedText = processedText.replace(
|
|
102
|
+
/<searching>([\s\S]*?)<\/searching>/gi,
|
|
103
|
+
(match, content) => {
|
|
104
|
+
const trimmedContent = content.trim();
|
|
105
|
+
if (!trimmedContent) return '';
|
|
106
|
+
|
|
107
|
+
return `\n\n<div class="searching-section">
|
|
108
|
+
<div class="searching-header">🔍 Searching</div>
|
|
109
|
+
<div class="searching-content">${trimmedContent}</div>
|
|
110
|
+
</div>\n\n`;
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
return processedText;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
console.log("Testing tag extraction and processing functions...\n");
|
|
118
|
+
|
|
119
|
+
testTexts.forEach((text, index) => {
|
|
120
|
+
console.log(`\n=== Test ${index + 1} ===`);
|
|
121
|
+
console.log("Input:", text);
|
|
122
|
+
console.log("Extracted tag:", extractLastThinkingTag(text));
|
|
123
|
+
console.log("Processed content:", processResponseContent(text));
|
|
124
|
+
console.log("---");
|
|
125
|
+
});
|
|
File without changes
|
|
File without changes
|