reactbridge-sdk 0.2.16 → 0.2.18
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/components/ReactBridgeChatbox.d.ts.map +1 -1
- package/dist/components/ReactBridgeSearch.d.ts.map +1 -1
- package/dist/hooks/useReactBridge.d.ts.map +1 -1
- package/dist/index.esm.js +95 -5
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +95 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -525,6 +525,7 @@ function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechSta
|
|
|
525
525
|
let currentResponse = response;
|
|
526
526
|
let toolCallCount = 0;
|
|
527
527
|
const maxToolCalls = 50; // Prevent infinite loops
|
|
528
|
+
let previousResultResponse = null;
|
|
528
529
|
while (currentToolCall && toolCallCount < maxToolCalls) {
|
|
529
530
|
toolCallCount++;
|
|
530
531
|
// Execute the current tool
|
|
@@ -532,6 +533,14 @@ function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechSta
|
|
|
532
533
|
// Step 3: Send tool result back to orchestrator
|
|
533
534
|
if (lastRequestRef.current && currentResponse.sessionId) {
|
|
534
535
|
const resultResponse = yield api.sendToolResult(currentResponse.sessionId, toolResult, lastRequestRef.current);
|
|
536
|
+
// Check if result is identical to previous one (prevent infinite loops on duplicate responses)
|
|
537
|
+
const currentResultString = JSON.stringify(resultResponse);
|
|
538
|
+
if (previousResultResponse === currentResultString) {
|
|
539
|
+
console.warn("Identical tool response detected. Exiting loop to prevent infinite loop.");
|
|
540
|
+
currentToolCall = null;
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
previousResultResponse = currentResultString;
|
|
535
544
|
// Add assistant message with tool result context
|
|
536
545
|
const finalMessage = {
|
|
537
546
|
id: `assistant-final-${Date.now()}-${toolCallCount}`,
|
|
@@ -881,6 +890,42 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
881
890
|
document.addEventListener("mousedown", handleClickOutside);
|
|
882
891
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
883
892
|
}, [isUploadMenuOpen, isOpen, renderMode]);
|
|
893
|
+
// Add scrollbar styling for textareas
|
|
894
|
+
React.useEffect(() => {
|
|
895
|
+
const styleId = "react-bridge-textarea-styles";
|
|
896
|
+
// Check if styles are already injected
|
|
897
|
+
if (!document.getElementById(styleId)) {
|
|
898
|
+
const style = document.createElement("style");
|
|
899
|
+
style.id = styleId;
|
|
900
|
+
style.textContent = `
|
|
901
|
+
.react-bridge-textarea {
|
|
902
|
+
scrollbar-width: thin;
|
|
903
|
+
scrollbar-color: rgba(0, 0, 0, 0.3) transparent;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
.react-bridge-textarea::-webkit-scrollbar {
|
|
907
|
+
width: 6px;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
.react-bridge-textarea::-webkit-scrollbar-track {
|
|
911
|
+
background: transparent;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
.react-bridge-textarea::-webkit-scrollbar-thumb {
|
|
915
|
+
background: rgba(0, 0, 0, 0.3);
|
|
916
|
+
border-radius: 3px;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.react-bridge-textarea::-webkit-scrollbar-thumb:hover {
|
|
920
|
+
background: rgba(0, 0, 0, 0.5);
|
|
921
|
+
}
|
|
922
|
+
`;
|
|
923
|
+
document.head.appendChild(style);
|
|
924
|
+
}
|
|
925
|
+
return () => {
|
|
926
|
+
// Optional: cleanup if needed
|
|
927
|
+
};
|
|
928
|
+
}, []);
|
|
884
929
|
const handleSubmit = (e) => __awaiter(this, void 0, void 0, function* () {
|
|
885
930
|
e.preventDefault();
|
|
886
931
|
if ((!inputValue.trim() && !selectedFile) || isLoading)
|
|
@@ -1006,7 +1051,7 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
1006
1051
|
gap: theme.spacing.sm,
|
|
1007
1052
|
alignItems: "flex-end",
|
|
1008
1053
|
} },
|
|
1009
|
-
React.createElement("textarea", { ref: textareaRef, value: inputValue, onChange: handleTextareaChange, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: isLoading, style: {
|
|
1054
|
+
React.createElement("textarea", { ref: textareaRef, value: inputValue, onChange: handleTextareaChange, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: isLoading, className: "react-bridge-textarea", style: {
|
|
1010
1055
|
flex: 1,
|
|
1011
1056
|
padding: theme.spacing.sm,
|
|
1012
1057
|
fontSize: theme.fontSizes.md,
|
|
@@ -1020,6 +1065,7 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
1020
1065
|
minHeight: "40px",
|
|
1021
1066
|
maxHeight: "120px",
|
|
1022
1067
|
height: `${textareaHeight}px`,
|
|
1068
|
+
scrollbarWidth: "thin",
|
|
1023
1069
|
} }),
|
|
1024
1070
|
React.createElement("button", { type: "button", onClick: () => setIsUploadMenuOpen(!isUploadMenuOpen), disabled: isLoading, title: "Attach file", style: {
|
|
1025
1071
|
padding: theme.spacing.sm,
|
|
@@ -1212,7 +1258,7 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
1212
1258
|
gap: theme.spacing.sm,
|
|
1213
1259
|
alignItems: "flex-end",
|
|
1214
1260
|
} },
|
|
1215
|
-
React.createElement("textarea", { ref: textareaRef, value: inputValue, onChange: handleTextareaChange, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: isLoading, style: {
|
|
1261
|
+
React.createElement("textarea", { ref: textareaRef, value: inputValue, onChange: handleTextareaChange, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: isLoading, className: "react-bridge-textarea", style: {
|
|
1216
1262
|
flex: 1,
|
|
1217
1263
|
padding: theme.spacing.sm,
|
|
1218
1264
|
fontSize: theme.fontSizes.md,
|
|
@@ -1226,6 +1272,7 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
|
|
|
1226
1272
|
minHeight: "40px",
|
|
1227
1273
|
maxHeight: "120px",
|
|
1228
1274
|
height: `${textareaHeight}px`,
|
|
1275
|
+
scrollbarWidth: "thin",
|
|
1229
1276
|
} }),
|
|
1230
1277
|
React.createElement("button", { type: "button", onClick: () => setIsUploadMenuOpen(!isUploadMenuOpen), disabled: isLoading, title: "Attach file", style: {
|
|
1231
1278
|
padding: theme.spacing.sm,
|
|
@@ -1359,6 +1406,34 @@ const MIC_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/200
|
|
|
1359
1406
|
// Plus Icon SVG
|
|
1360
1407
|
const PLUS_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
|
|
1361
1408
|
React.createElement("path", { d: "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" })));
|
|
1409
|
+
// Expandable Message Component for Search Results
|
|
1410
|
+
const SearchResultItem = ({ content, theme, isExpanded, onToggleExpand, }) => {
|
|
1411
|
+
const characterLimit = 300;
|
|
1412
|
+
const isLongMessage = content.length > characterLimit;
|
|
1413
|
+
const displayText = isExpanded ? content : content.substring(0, characterLimit);
|
|
1414
|
+
return (React.createElement("div", { style: {
|
|
1415
|
+
display: "flex",
|
|
1416
|
+
flexDirection: "column",
|
|
1417
|
+
gap: "8px",
|
|
1418
|
+
} },
|
|
1419
|
+
React.createElement("div", { style: {
|
|
1420
|
+
whiteSpace: "pre-wrap",
|
|
1421
|
+
wordWrap: "break-word",
|
|
1422
|
+
overflowWrap: "break-word",
|
|
1423
|
+
color: theme.colors.text,
|
|
1424
|
+
} }, displayText),
|
|
1425
|
+
isLongMessage && (React.createElement("button", { onClick: onToggleExpand, style: {
|
|
1426
|
+
background: "none",
|
|
1427
|
+
border: "none",
|
|
1428
|
+
color: theme.colors.primary,
|
|
1429
|
+
cursor: "pointer",
|
|
1430
|
+
textDecoration: "underline",
|
|
1431
|
+
padding: "0",
|
|
1432
|
+
textAlign: "left",
|
|
1433
|
+
fontSize: theme.fontSizes.sm,
|
|
1434
|
+
fontWeight: "bold",
|
|
1435
|
+
} }, isExpanded ? "Show less" : "Show more..."))));
|
|
1436
|
+
};
|
|
1362
1437
|
function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = "Search...", width = "100%", maxResults = 5, theme: themeOverride, onError, onSpeechStart, onSpeechEnd, onTranscript, onAgentResponse, }) {
|
|
1363
1438
|
const { theme: contextTheme } = useReactBridgeContext();
|
|
1364
1439
|
const theme = Object.assign(Object.assign({}, contextTheme), themeOverride);
|
|
@@ -1376,6 +1451,7 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = "Se
|
|
|
1376
1451
|
const [isUploadMenuOpen, setIsUploadMenuOpen] = React.useState(false);
|
|
1377
1452
|
const [selectedFile, setSelectedFile] = React.useState(null);
|
|
1378
1453
|
const [filePreview, setFilePreview] = React.useState(null);
|
|
1454
|
+
const [expandedMessages, setExpandedMessages] = React.useState(new Set());
|
|
1379
1455
|
const containerRef = React.useRef(null);
|
|
1380
1456
|
const fileInputRef = React.useRef(null);
|
|
1381
1457
|
// Close dropdown and upload menu when clicking outside
|
|
@@ -1458,6 +1534,19 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = "Se
|
|
|
1458
1534
|
fileInputRef.current.value = "";
|
|
1459
1535
|
}
|
|
1460
1536
|
};
|
|
1537
|
+
// Toggle message expansion
|
|
1538
|
+
const toggleMessageExpansion = React.useCallback((messageId) => {
|
|
1539
|
+
setExpandedMessages((prev) => {
|
|
1540
|
+
const newSet = new Set(prev);
|
|
1541
|
+
if (newSet.has(messageId)) {
|
|
1542
|
+
newSet.delete(messageId);
|
|
1543
|
+
}
|
|
1544
|
+
else {
|
|
1545
|
+
newSet.add(messageId);
|
|
1546
|
+
}
|
|
1547
|
+
return newSet;
|
|
1548
|
+
});
|
|
1549
|
+
}, []);
|
|
1461
1550
|
const handleSubmit = (e) => __awaiter(this, void 0, void 0, function* () {
|
|
1462
1551
|
e.preventDefault();
|
|
1463
1552
|
if ((!inputValue.trim() && !selectedFile) || isLoading)
|
|
@@ -1484,7 +1573,8 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = "Se
|
|
|
1484
1573
|
// Get only assistant messages (not system messages)
|
|
1485
1574
|
const displayMessages = messages
|
|
1486
1575
|
.filter((msg) => msg.role === "assistant")
|
|
1487
|
-
.slice(-maxResults)
|
|
1576
|
+
.slice(-maxResults)
|
|
1577
|
+
.reverse();
|
|
1488
1578
|
return (React.createElement("div", { ref: containerRef, style: {
|
|
1489
1579
|
position: "relative",
|
|
1490
1580
|
width,
|
|
@@ -1656,12 +1746,12 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = "Se
|
|
|
1656
1746
|
borderBottom: `1px solid ${theme.colors.border}`,
|
|
1657
1747
|
fontSize: theme.fontSizes.sm,
|
|
1658
1748
|
color: theme.colors.text,
|
|
1659
|
-
cursor: "pointer",
|
|
1660
1749
|
}, onMouseEnter: (e) => {
|
|
1661
1750
|
e.currentTarget.style.backgroundColor = theme.colors.surface;
|
|
1662
1751
|
}, onMouseLeave: (e) => {
|
|
1663
1752
|
e.currentTarget.style.backgroundColor = theme.colors.background;
|
|
1664
|
-
} },
|
|
1753
|
+
} },
|
|
1754
|
+
React.createElement(SearchResultItem, { content: message.content, theme: theme, isExpanded: expandedMessages.has(message.id), onToggleExpand: () => toggleMessageExpansion(message.id) }))))))));
|
|
1665
1755
|
}
|
|
1666
1756
|
|
|
1667
1757
|
const darkTheme = {
|