@hef2024/llmasaservice-ui 0.19.1 → 0.20.1
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/AICHATPANEL-PORT-INVENTORY.md +831 -0
- package/DEBUG-ERROR-HANDLING.md +131 -0
- package/FIX-APPLIED.md +235 -0
- package/IMPLEMENTATION-COMPLETE.md +247 -0
- package/README.md +1 -0
- package/dist/index.css +635 -1
- package/dist/index.d.mts +37 -1
- package/dist/index.d.ts +37 -1
- package/dist/index.js +1241 -454
- package/dist/index.mjs +1083 -296
- package/docs/CHANGELOG-ERROR-HANDLING.md +248 -0
- package/docs/CONVERSATION-HISTORY.md +1 -0
- package/docs/ERROR-HANDLING-413.md +254 -0
- package/docs/ERROR-HANDLING-SUMMARY.md +132 -0
- package/package.json +2 -2
- package/src/AIAgentPanel.tsx +97 -1
- package/src/AIChatPanel.css +656 -1
- package/src/AIChatPanel.tsx +914 -69
- package/src/AgentPanel.tsx +3 -1
- package/src/ChatPanel.css +111 -0
- package/src/ChatPanel.tsx +169 -33
- package/src/components/ui/Button.tsx +1 -0
- package/src/components/ui/Dialog.tsx +1 -0
- package/src/components/ui/Input.tsx +1 -0
- package/src/components/ui/Select.tsx +1 -0
- package/src/components/ui/ToolInfoModal.tsx +66 -0
- package/src/components/ui/Tooltip.tsx +1 -0
- package/src/components/ui/index.ts +1 -0
- package/src/hooks/useAgentRegistry.ts +1 -0
package/src/AgentPanel.tsx
CHANGED
|
@@ -159,7 +159,9 @@ const AgentPanel: React.FC<AgentPanelProps & ExtraProps> = ({
|
|
|
159
159
|
useEffect(() => {
|
|
160
160
|
const fetchAgentData = async () => {
|
|
161
161
|
try {
|
|
162
|
-
const fetchUrl =
|
|
162
|
+
const fetchUrl = url.endsWith("dev")
|
|
163
|
+
? `https://8ftw8droff.execute-api.us-east-1.amazonaws.com/dev/agents/${agent}`
|
|
164
|
+
: `https://api.llmasaservice.io/agents/${agent}`;
|
|
163
165
|
|
|
164
166
|
const response = await fetch(fetchUrl, {
|
|
165
167
|
method: "GET",
|
package/src/ChatPanel.css
CHANGED
|
@@ -1090,4 +1090,115 @@ button[data-pending="true"]::after {
|
|
|
1090
1090
|
|
|
1091
1091
|
.searching-section {
|
|
1092
1092
|
border-left: 3px solid #7b68ee;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/* ============================================================================
|
|
1096
|
+
Error Banner
|
|
1097
|
+
============================================================================ */
|
|
1098
|
+
|
|
1099
|
+
.error-banner {
|
|
1100
|
+
display: flex;
|
|
1101
|
+
align-items: flex-start;
|
|
1102
|
+
gap: 12px;
|
|
1103
|
+
padding: 12px 16px;
|
|
1104
|
+
margin: 12px 16px;
|
|
1105
|
+
background: #fef2f2;
|
|
1106
|
+
border: 1px solid #fecaca;
|
|
1107
|
+
border-radius: 8px;
|
|
1108
|
+
animation: slideDown 0.2s ease-out;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
.dark-theme .error-banner {
|
|
1112
|
+
background: #7f1d1d;
|
|
1113
|
+
border-color: #991b1b;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
.error-banner__icon {
|
|
1117
|
+
flex-shrink: 0;
|
|
1118
|
+
color: #dc2626;
|
|
1119
|
+
margin-top: 2px;
|
|
1120
|
+
width: 20px;
|
|
1121
|
+
height: 20px;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
.error-banner__icon svg {
|
|
1125
|
+
width: 100%;
|
|
1126
|
+
height: 100%;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
.dark-theme .error-banner__icon {
|
|
1130
|
+
color: #fca5a5;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
.error-banner__content {
|
|
1134
|
+
flex: 1;
|
|
1135
|
+
display: flex;
|
|
1136
|
+
flex-direction: column;
|
|
1137
|
+
gap: 4px;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
.error-banner__message {
|
|
1141
|
+
color: #991b1b;
|
|
1142
|
+
font-size: 14px;
|
|
1143
|
+
font-weight: 500;
|
|
1144
|
+
line-height: 1.4;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
.dark-theme .error-banner__message {
|
|
1148
|
+
color: #fecaca;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
.error-banner__hint {
|
|
1152
|
+
color: #b91c1c;
|
|
1153
|
+
font-size: 13px;
|
|
1154
|
+
line-height: 1.4;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
.dark-theme .error-banner__hint {
|
|
1158
|
+
color: #fca5a5;
|
|
1159
|
+
opacity: 0.8;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
.error-banner__close {
|
|
1163
|
+
flex-shrink: 0;
|
|
1164
|
+
background: none;
|
|
1165
|
+
border: none;
|
|
1166
|
+
padding: 4px;
|
|
1167
|
+
cursor: pointer;
|
|
1168
|
+
color: #991b1b;
|
|
1169
|
+
border-radius: 4px;
|
|
1170
|
+
transition: background-color 0.15s;
|
|
1171
|
+
width: 24px;
|
|
1172
|
+
height: 24px;
|
|
1173
|
+
display: flex;
|
|
1174
|
+
align-items: center;
|
|
1175
|
+
justify-content: center;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
.error-banner__close svg {
|
|
1179
|
+
width: 16px;
|
|
1180
|
+
height: 16px;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
.dark-theme .error-banner__close {
|
|
1184
|
+
color: #fca5a5;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
.error-banner__close:hover {
|
|
1188
|
+
background: rgba(220, 38, 38, 0.1);
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
.dark-theme .error-banner__close:hover {
|
|
1192
|
+
background: rgba(252, 165, 165, 0.1);
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
@keyframes slideDown {
|
|
1196
|
+
from {
|
|
1197
|
+
opacity: 0;
|
|
1198
|
+
transform: translateY(-8px);
|
|
1199
|
+
}
|
|
1200
|
+
to {
|
|
1201
|
+
opacity: 1;
|
|
1202
|
+
transform: translateY(0);
|
|
1203
|
+
}
|
|
1093
1204
|
}
|
package/src/ChatPanel.tsx
CHANGED
|
@@ -222,6 +222,9 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
222
222
|
>([]);
|
|
223
223
|
const [currentThinkingIndex, setCurrentThinkingIndex] = useState(0);
|
|
224
224
|
|
|
225
|
+
// State for error handling
|
|
226
|
+
const [error, setError] = useState<{ message: string; code?: string } | null>(null);
|
|
227
|
+
|
|
225
228
|
// State for tracking user-resized textarea height
|
|
226
229
|
const [userResizedHeight, setUserResizedHeight] = useState<number | null>(null);
|
|
227
230
|
|
|
@@ -680,7 +683,7 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
680
683
|
fetchAndSetTools();
|
|
681
684
|
}, [mcpServers, publicAPIUrl]);
|
|
682
685
|
|
|
683
|
-
const
|
|
686
|
+
const llmResult = useLLM({
|
|
684
687
|
project_id: project_id,
|
|
685
688
|
customer: currentCustomer,
|
|
686
689
|
url: url,
|
|
@@ -694,6 +697,57 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
694
697
|
};
|
|
695
698
|
}) as [],
|
|
696
699
|
});
|
|
700
|
+
|
|
701
|
+
const { send, response, idle, stop, lastCallId, setResponse, error: llmError } = llmResult;
|
|
702
|
+
|
|
703
|
+
// Error handler function - reusable for both error state and callbacks
|
|
704
|
+
const handleError = useCallback((errorMessage: string, historyKey?: string) => {
|
|
705
|
+
console.log('[ChatPanel] Error detected:', errorMessage);
|
|
706
|
+
|
|
707
|
+
// Detect 413 Content Too Large error
|
|
708
|
+
if (errorMessage.includes('413') || errorMessage.toLowerCase().includes('content too large')) {
|
|
709
|
+
setError({
|
|
710
|
+
message: 'The context is too large to process. Please start a new conversation or reduce the amount of context.',
|
|
711
|
+
code: '413',
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
// Detect other network errors
|
|
715
|
+
else if (errorMessage.toLowerCase().includes('network error') || errorMessage.toLowerCase().includes('fetch')) {
|
|
716
|
+
setError({
|
|
717
|
+
message: 'Network error. Please check your connection and try again.',
|
|
718
|
+
code: 'NETWORK_ERROR',
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
// Generic error
|
|
722
|
+
else {
|
|
723
|
+
setError({
|
|
724
|
+
message: errorMessage,
|
|
725
|
+
code: 'UNKNOWN_ERROR',
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Reset loading state
|
|
730
|
+
setIsLoading(false);
|
|
731
|
+
|
|
732
|
+
// Update history to show error
|
|
733
|
+
const keyToUse = historyKey || lastKey;
|
|
734
|
+
if (keyToUse) {
|
|
735
|
+
setHistory((prev) => ({
|
|
736
|
+
...prev,
|
|
737
|
+
[keyToUse]: {
|
|
738
|
+
content: `Error: ${errorMessage}`,
|
|
739
|
+
callId: lastCallId || '',
|
|
740
|
+
},
|
|
741
|
+
}));
|
|
742
|
+
}
|
|
743
|
+
}, [lastKey, lastCallId]);
|
|
744
|
+
|
|
745
|
+
// Monitor for errors from useLLM hook (for errors not caught by callback)
|
|
746
|
+
useEffect(() => {
|
|
747
|
+
if (llmError && llmError.trim()) {
|
|
748
|
+
handleError(llmError);
|
|
749
|
+
}
|
|
750
|
+
}, [llmError, handleError]);
|
|
697
751
|
|
|
698
752
|
// Centralized action processing function to eliminate duplication
|
|
699
753
|
const processActionsOnContent = useCallback((
|
|
@@ -1459,7 +1513,9 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
1459
1513
|
true,
|
|
1460
1514
|
service,
|
|
1461
1515
|
currentConversation,
|
|
1462
|
-
lastController
|
|
1516
|
+
lastController,
|
|
1517
|
+
undefined, // onComplete
|
|
1518
|
+
(errorMsg: string) => handleError(errorMsg) // onError
|
|
1463
1519
|
);
|
|
1464
1520
|
} catch (error) {
|
|
1465
1521
|
console.error("Error in processing all tools:", error);
|
|
@@ -1941,7 +1997,9 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
1941
1997
|
true,
|
|
1942
1998
|
service,
|
|
1943
1999
|
convId,
|
|
1944
|
-
controller
|
|
2000
|
+
controller,
|
|
2001
|
+
undefined, // onComplete
|
|
2002
|
+
(errorMsg: string) => handleError(errorMsg) // onError
|
|
1945
2003
|
);
|
|
1946
2004
|
|
|
1947
2005
|
// Store the context in component state
|
|
@@ -2153,6 +2211,9 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
2153
2211
|
// Clear thinking blocks for new response
|
|
2154
2212
|
setThinkingBlocks([]);
|
|
2155
2213
|
setCurrentThinkingIndex(0);
|
|
2214
|
+
|
|
2215
|
+
// Clear any previous errors
|
|
2216
|
+
setError(null);
|
|
2156
2217
|
|
|
2157
2218
|
// IMPORTANT: Clear the response BEFORE setting new lastKey
|
|
2158
2219
|
// This prevents the old response from being written to the new history entry
|
|
@@ -2302,7 +2363,9 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
2302
2363
|
true,
|
|
2303
2364
|
service,
|
|
2304
2365
|
convId,
|
|
2305
|
-
controller
|
|
2366
|
+
controller,
|
|
2367
|
+
undefined, // onComplete
|
|
2368
|
+
(errorMsg: string) => handleError(errorMsg) // onError
|
|
2306
2369
|
);
|
|
2307
2370
|
|
|
2308
2371
|
setLastPrompt(nextPromptToSend);
|
|
@@ -2404,15 +2467,23 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
2404
2467
|
};
|
|
2405
2468
|
|
|
2406
2469
|
const convertMarkdownToHTML = (markdown: string): string => {
|
|
2407
|
-
const
|
|
2470
|
+
const markdownContent = (
|
|
2408
2471
|
<ReactMarkdown
|
|
2409
|
-
className={markdownClass}
|
|
2410
2472
|
remarkPlugins={[remarkGfm]}
|
|
2411
2473
|
rehypePlugins={[rehypeRaw]}
|
|
2412
2474
|
>
|
|
2413
2475
|
{markdown}
|
|
2414
2476
|
</ReactMarkdown>
|
|
2415
2477
|
);
|
|
2478
|
+
const html = ReactDOMServer.renderToStaticMarkup(
|
|
2479
|
+
markdownClass ? (
|
|
2480
|
+
<div className={markdownClass}>
|
|
2481
|
+
{markdownContent}
|
|
2482
|
+
</div>
|
|
2483
|
+
) : (
|
|
2484
|
+
markdownContent
|
|
2485
|
+
)
|
|
2486
|
+
);
|
|
2416
2487
|
return html;
|
|
2417
2488
|
};
|
|
2418
2489
|
|
|
@@ -2697,17 +2768,59 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
2697
2768
|
className={"llm-panel" + (theme === "light" ? "" : " dark-theme")}
|
|
2698
2769
|
>
|
|
2699
2770
|
{title && title !== "" ? <div className="title">{title}</div> : null}
|
|
2771
|
+
|
|
2772
|
+
{/* Error Banner */}
|
|
2773
|
+
{error && (
|
|
2774
|
+
<div className="error-banner">
|
|
2775
|
+
<div className="error-banner__icon">
|
|
2776
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
2777
|
+
<circle cx="12" cy="12" r="10" />
|
|
2778
|
+
<line x1="12" x2="12" y1="8" y2="12" />
|
|
2779
|
+
<line x1="12" x2="12.01" y1="16" y2="16" />
|
|
2780
|
+
</svg>
|
|
2781
|
+
</div>
|
|
2782
|
+
<div className="error-banner__content">
|
|
2783
|
+
<div className="error-banner__message">{error.message}</div>
|
|
2784
|
+
{error.code === '413' && (
|
|
2785
|
+
<div className="error-banner__hint">
|
|
2786
|
+
Try starting a new conversation or reducing the amount of information being sent.
|
|
2787
|
+
</div>
|
|
2788
|
+
)}
|
|
2789
|
+
</div>
|
|
2790
|
+
<button
|
|
2791
|
+
className="error-banner__close"
|
|
2792
|
+
onClick={() => setError(null)}
|
|
2793
|
+
aria-label="Dismiss error"
|
|
2794
|
+
>
|
|
2795
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
2796
|
+
<line x1="18" x2="6" y1="6" y2="18" />
|
|
2797
|
+
<line x1="6" x2="18" y1="6" y2="18" />
|
|
2798
|
+
</svg>
|
|
2799
|
+
</button>
|
|
2800
|
+
</div>
|
|
2801
|
+
)}
|
|
2802
|
+
|
|
2700
2803
|
<div className="responseArea" ref={responseAreaRef}>
|
|
2701
2804
|
{initialMessage && initialMessage !== "" ? (
|
|
2702
2805
|
<div className="history-entry">
|
|
2703
2806
|
<div className="response">
|
|
2704
|
-
|
|
2705
|
-
className={markdownClass}
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2807
|
+
{markdownClass ? (
|
|
2808
|
+
<div className={markdownClass}>
|
|
2809
|
+
<ReactMarkdown
|
|
2810
|
+
remarkPlugins={[remarkGfm]}
|
|
2811
|
+
rehypePlugins={[rehypeRaw]}
|
|
2812
|
+
>
|
|
2813
|
+
{initialMessage}
|
|
2814
|
+
</ReactMarkdown>
|
|
2815
|
+
</div>
|
|
2816
|
+
) : (
|
|
2817
|
+
<ReactMarkdown
|
|
2818
|
+
remarkPlugins={[remarkGfm]}
|
|
2819
|
+
rehypePlugins={[rehypeRaw]}
|
|
2820
|
+
>
|
|
2821
|
+
{initialMessage}
|
|
2822
|
+
</ReactMarkdown>
|
|
2823
|
+
)}
|
|
2711
2824
|
</div>
|
|
2712
2825
|
</div>
|
|
2713
2826
|
) : null}
|
|
@@ -2782,9 +2895,8 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
2782
2895
|
// Get the processed content that includes action buttons from history
|
|
2783
2896
|
// During streaming, use the most recent history entry if it exists
|
|
2784
2897
|
if (lastKey && history[lastKey] && history[lastKey].content) {
|
|
2785
|
-
|
|
2898
|
+
const content = (
|
|
2786
2899
|
<ReactMarkdown
|
|
2787
|
-
className={markdownClass}
|
|
2788
2900
|
remarkPlugins={[remarkGfm]}
|
|
2789
2901
|
rehypePlugins={[rehypeRaw]}
|
|
2790
2902
|
components={{ /*a: CustomLink,*/ code: CodeBlock }}
|
|
@@ -2792,22 +2904,34 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
2792
2904
|
{history[lastKey].content}
|
|
2793
2905
|
</ReactMarkdown>
|
|
2794
2906
|
);
|
|
2907
|
+
return markdownClass ? (
|
|
2908
|
+
<div className={markdownClass}>{content}</div>
|
|
2909
|
+
) : (
|
|
2910
|
+
content
|
|
2911
|
+
);
|
|
2795
2912
|
}
|
|
2796
2913
|
|
|
2797
2914
|
// Fallback to cleaned text if no processed history exists yet
|
|
2798
2915
|
const { cleanedText } = processThinkingTags(
|
|
2799
2916
|
response || ""
|
|
2800
2917
|
);
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2918
|
+
if (cleanedText && cleanedText.length > 0) {
|
|
2919
|
+
const content = (
|
|
2920
|
+
<ReactMarkdown
|
|
2921
|
+
remarkPlugins={[remarkGfm]}
|
|
2922
|
+
rehypePlugins={[rehypeRaw]}
|
|
2923
|
+
components={{ /*a: CustomLink,*/ code: CodeBlock }}
|
|
2924
|
+
>
|
|
2925
|
+
{cleanedText}
|
|
2926
|
+
</ReactMarkdown>
|
|
2927
|
+
);
|
|
2928
|
+
return markdownClass ? (
|
|
2929
|
+
<div className={markdownClass}>{content}</div>
|
|
2930
|
+
) : (
|
|
2931
|
+
content
|
|
2932
|
+
);
|
|
2933
|
+
}
|
|
2934
|
+
return null;
|
|
2811
2935
|
})()}
|
|
2812
2936
|
</div>
|
|
2813
2937
|
) : (
|
|
@@ -2818,14 +2942,25 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
2818
2942
|
renderThinkingBlocks()}
|
|
2819
2943
|
|
|
2820
2944
|
{/* Show the main content (cleaned of thinking tags) */}
|
|
2821
|
-
|
|
2822
|
-
className={markdownClass}
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2945
|
+
{markdownClass ? (
|
|
2946
|
+
<div className={markdownClass}>
|
|
2947
|
+
<ReactMarkdown
|
|
2948
|
+
remarkPlugins={[remarkGfm]}
|
|
2949
|
+
rehypePlugins={[rehypeRaw]}
|
|
2950
|
+
components={{ /*a: CustomLink,*/ code: CodeBlock }}
|
|
2951
|
+
>
|
|
2952
|
+
{processThinkingTags(historyEntry.content).cleanedText}
|
|
2953
|
+
</ReactMarkdown>
|
|
2954
|
+
</div>
|
|
2955
|
+
) : (
|
|
2956
|
+
<ReactMarkdown
|
|
2957
|
+
remarkPlugins={[remarkGfm]}
|
|
2958
|
+
rehypePlugins={[rehypeRaw]}
|
|
2959
|
+
components={{ /*a: CustomLink,*/ code: CodeBlock }}
|
|
2960
|
+
>
|
|
2961
|
+
{processThinkingTags(historyEntry.content).cleanedText}
|
|
2962
|
+
</ReactMarkdown>
|
|
2963
|
+
)}
|
|
2829
2964
|
</div>
|
|
2830
2965
|
)}
|
|
2831
2966
|
|
|
@@ -3158,6 +3293,7 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
3158
3293
|
setIsToolInfoModalOpen(false);
|
|
3159
3294
|
setToolInfoData(null);
|
|
3160
3295
|
setJustReset(true);
|
|
3296
|
+
setError(null); // Clear any errors
|
|
3161
3297
|
|
|
3162
3298
|
// Create a new AbortController for future requests
|
|
3163
3299
|
setLastController(new AbortController());
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface ToolInfoModalProps {
|
|
4
|
+
isOpen: boolean;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
data: { calls: any[]; responses: any[] } | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const ToolInfoModal: React.FC<ToolInfoModalProps> = ({
|
|
10
|
+
isOpen,
|
|
11
|
+
onClose,
|
|
12
|
+
data,
|
|
13
|
+
}) => {
|
|
14
|
+
if (!isOpen || !data) return null;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div className="ai-chat-modal-overlay" onClick={onClose}>
|
|
18
|
+
<div
|
|
19
|
+
className="ai-chat-modal-content ai-chat-tool-info-modal"
|
|
20
|
+
onClick={(e) => e.stopPropagation()}
|
|
21
|
+
>
|
|
22
|
+
<div className="ai-chat-modal-header">
|
|
23
|
+
<h3>Tool Information</h3>
|
|
24
|
+
<button
|
|
25
|
+
className="ai-chat-modal-close"
|
|
26
|
+
onClick={onClose}
|
|
27
|
+
aria-label="Close"
|
|
28
|
+
>
|
|
29
|
+
×
|
|
30
|
+
</button>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div className="ai-chat-modal-body ai-chat-tool-info-container">
|
|
34
|
+
<div className="ai-chat-tool-info-section">
|
|
35
|
+
<h4>Tool Calls</h4>
|
|
36
|
+
<textarea
|
|
37
|
+
className="ai-chat-tool-info-json"
|
|
38
|
+
readOnly
|
|
39
|
+
value={JSON.stringify(data.calls, null, 2)}
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
<div className="ai-chat-tool-info-section">
|
|
43
|
+
<h4>Tool Responses</h4>
|
|
44
|
+
<textarea
|
|
45
|
+
className="ai-chat-tool-info-json"
|
|
46
|
+
readOnly
|
|
47
|
+
value={JSON.stringify(data.responses, null, 2)}
|
|
48
|
+
/>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div className="ai-chat-modal-footer">
|
|
53
|
+
<button
|
|
54
|
+
className="ai-chat-modal-button ai-chat-modal-button--primary"
|
|
55
|
+
onClick={onClose}
|
|
56
|
+
>
|
|
57
|
+
Close
|
|
58
|
+
</button>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default ToolInfoModal;
|
|
66
|
+
|