hdsp-jupyter-extension 2.0.23__py3-none-any.whl → 2.0.25__py3-none-any.whl
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.
- agent_server/context_providers/__init__.py +22 -0
- agent_server/context_providers/actions.py +45 -0
- agent_server/context_providers/base.py +231 -0
- agent_server/context_providers/file.py +316 -0
- agent_server/context_providers/processor.py +150 -0
- agent_server/main.py +2 -1
- agent_server/routers/chat.py +61 -10
- agent_server/routers/context.py +168 -0
- agent_server/routers/langchain_agent.py +609 -182
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/build_log.json +1 -1
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/package.json +2 -2
- hdsp_jupyter_extension-2.0.23.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.96745acc14125453fba8.js → hdsp_jupyter_extension-2.0.25.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.b5e4416b4e07ec087aad.js +245 -121
- hdsp_jupyter_extension-2.0.25.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.b5e4416b4e07ec087aad.js.map +1 -0
- jupyter_ext/labextension/static/lib_index_js.2d5ea542350862f7c531.js → hdsp_jupyter_extension-2.0.25.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.67505497667f9c0a763d.js +583 -39
- hdsp_jupyter_extension-2.0.25.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.67505497667f9c0a763d.js.map +1 -0
- hdsp_jupyter_extension-2.0.23.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.f0127d8744730f2092c1.js → hdsp_jupyter_extension-2.0.25.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.ffc2b4bc8e6cb300e1e1.js +3 -3
- jupyter_ext/labextension/static/remoteEntry.f0127d8744730f2092c1.js.map → hdsp_jupyter_extension-2.0.25.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.ffc2b4bc8e6cb300e1e1.js.map +1 -1
- {hdsp_jupyter_extension-2.0.23.dist-info → hdsp_jupyter_extension-2.0.25.dist-info}/METADATA +1 -1
- {hdsp_jupyter_extension-2.0.23.dist-info → hdsp_jupyter_extension-2.0.25.dist-info}/RECORD +50 -44
- jupyter_ext/_version.py +1 -1
- jupyter_ext/handlers.py +29 -0
- jupyter_ext/labextension/build_log.json +1 -1
- jupyter_ext/labextension/package.json +2 -2
- jupyter_ext/labextension/static/{frontend_styles_index_js.96745acc14125453fba8.js → frontend_styles_index_js.b5e4416b4e07ec087aad.js} +245 -121
- jupyter_ext/labextension/static/frontend_styles_index_js.b5e4416b4e07ec087aad.js.map +1 -0
- hdsp_jupyter_extension-2.0.23.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.2d5ea542350862f7c531.js → jupyter_ext/labextension/static/lib_index_js.67505497667f9c0a763d.js +583 -39
- jupyter_ext/labextension/static/lib_index_js.67505497667f9c0a763d.js.map +1 -0
- jupyter_ext/labextension/static/{remoteEntry.f0127d8744730f2092c1.js → remoteEntry.ffc2b4bc8e6cb300e1e1.js} +3 -3
- hdsp_jupyter_extension-2.0.23.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.f0127d8744730f2092c1.js.map → jupyter_ext/labextension/static/remoteEntry.ffc2b4bc8e6cb300e1e1.js.map +1 -1
- hdsp_jupyter_extension-2.0.23.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.96745acc14125453fba8.js.map +0 -1
- hdsp_jupyter_extension-2.0.23.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.2d5ea542350862f7c531.js.map +0 -1
- jupyter_ext/labextension/static/frontend_styles_index_js.96745acc14125453fba8.js.map +0 -1
- jupyter_ext/labextension/static/lib_index_js.2d5ea542350862f7c531.js.map +0 -1
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/install.json +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b80.c095373419d05e6f141a.js +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b80.c095373419d05e6f141a.js.map +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b81.61e75fb98ecff46cf836.js +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b81.61e75fb98ecff46cf836.js.map +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/style.js +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_babel_runtime_helpers_esm_extends_js-node_modules_emotion_serialize_dist-051195.e2553aab0c3963b83dd7.js +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_babel_runtime_helpers_esm_extends_js-node_modules_emotion_serialize_dist-051195.e2553aab0c3963b83dd7.js.map +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js.24edcc52a1c014a8a5f0.js +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js.24edcc52a1c014a8a5f0.js.map +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.19ecf6babe00caff6b8a.js +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.19ecf6babe00caff6b8a.js.map +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js.map +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js.map +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.1f5038488cdfd8b3a85d.js +0 -0
- {hdsp_jupyter_extension-2.0.23.data → hdsp_jupyter_extension-2.0.25.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.1f5038488cdfd8b3a85d.js.map +0 -0
- {hdsp_jupyter_extension-2.0.23.dist-info → hdsp_jupyter_extension-2.0.25.dist-info}/WHEEL +0 -0
- {hdsp_jupyter_extension-2.0.23.dist-info → hdsp_jupyter_extension-2.0.25.dist-info}/licenses/LICENSE +0 -0
|
@@ -22,10 +22,11 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
22
22
|
/* harmony import */ var _utils_markdownRenderer__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../utils/markdownRenderer */ "./lib/utils/markdownRenderer.js");
|
|
23
23
|
/* harmony import */ var _FileSelectionDialog__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./FileSelectionDialog */ "./lib/components/FileSelectionDialog.js");
|
|
24
24
|
/* harmony import */ var _StreamingMessage__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./StreamingMessage */ "./lib/components/StreamingMessage.js");
|
|
25
|
-
/* harmony import */ var
|
|
26
|
-
/* harmony import */ var
|
|
27
|
-
/* harmony import */ var
|
|
28
|
-
/* harmony import */ var
|
|
25
|
+
/* harmony import */ var _ContextAutocomplete__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./ContextAutocomplete */ "./lib/components/ContextAutocomplete.js");
|
|
26
|
+
/* harmony import */ var _utils_icons__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../utils/icons */ "./lib/utils/icons.js");
|
|
27
|
+
/* harmony import */ var _mui_icons_material_ExpandLess__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @mui/icons-material/ExpandLess */ "./node_modules/@mui/icons-material/esm/ExpandLess.js");
|
|
28
|
+
/* harmony import */ var _mui_icons_material_ExpandMore__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @mui/icons-material/ExpandMore */ "./node_modules/@mui/icons-material/esm/ExpandMore.js");
|
|
29
|
+
/* harmony import */ var _logoSvg__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../logoSvg */ "./lib/logoSvg.js");
|
|
29
30
|
/**
|
|
30
31
|
* Agent Panel - Main sidebar panel for Jupyter Agent
|
|
31
32
|
* Cursor AI Style: Unified Chat + Agent Interface
|
|
@@ -41,12 +42,13 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
|
|
45
|
+
|
|
44
46
|
// 로고 이미지 (SVG) - TypeScript 모듈에서 인라인 문자열로 import
|
|
45
47
|
|
|
46
48
|
// 탭바 아이콘 생성
|
|
47
49
|
const hdspTabIcon = new _jupyterlab_ui_components__WEBPACK_IMPORTED_MODULE_1__.LabIcon({
|
|
48
50
|
name: 'hdsp-agent:tab-icon',
|
|
49
|
-
svgstr:
|
|
51
|
+
svgstr: _logoSvg__WEBPACK_IMPORTED_MODULE_12__.tabbarLogoSvg
|
|
50
52
|
});
|
|
51
53
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
52
54
|
// Python 파일 에러 감지 및 처리 유틸리티
|
|
@@ -179,6 +181,11 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
179
181
|
// File selection state
|
|
180
182
|
const [fileSelectionMetadata, setFileSelectionMetadata] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
181
183
|
const [pendingAgentRequest, setPendingAgentRequest] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
184
|
+
// Context autocomplete state (@file)
|
|
185
|
+
const [showAutocomplete, setShowAutocomplete] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
186
|
+
const [hasAutocompleteOptions, setHasAutocompleteOptions] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
187
|
+
const [cursorPosition, setCursorPosition] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(0);
|
|
188
|
+
const textareaRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);
|
|
182
189
|
// Human-in-the-Loop state
|
|
183
190
|
const [debugStatus, setDebugStatusRaw] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
184
191
|
const [isDebugExpanded, setIsDebugExpanded] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
@@ -1013,26 +1020,66 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
1013
1020
|
showNotification('작업이 중단되었습니다.', 'info');
|
|
1014
1021
|
console.log('[AgentPanel] Task stopped successfully');
|
|
1015
1022
|
};
|
|
1023
|
+
// Auto-scroll state refs for smooth scrolling
|
|
1024
|
+
const scrollRafRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);
|
|
1025
|
+
const lastScrollTimeRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(0);
|
|
1026
|
+
const userScrolledUpRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(false);
|
|
1027
|
+
// Track user scroll to detect if they scrolled up
|
|
1028
|
+
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
1029
|
+
const container = messagesContainerRef.current;
|
|
1030
|
+
if (!container)
|
|
1031
|
+
return;
|
|
1032
|
+
const handleScroll = () => {
|
|
1033
|
+
const isNearBottom = container.scrollHeight - container.scrollTop - container.clientHeight < 100;
|
|
1034
|
+
userScrolledUpRef.current = !isNearBottom;
|
|
1035
|
+
};
|
|
1036
|
+
container.addEventListener('scroll', handleScroll, { passive: true });
|
|
1037
|
+
return () => container.removeEventListener('scroll', handleScroll);
|
|
1038
|
+
}, []);
|
|
1016
1039
|
// Auto-scroll to bottom when messages change or streaming (only if near bottom)
|
|
1017
1040
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
1018
1041
|
const container = messagesContainerRef.current;
|
|
1019
1042
|
if (!container)
|
|
1020
1043
|
return;
|
|
1044
|
+
// If user scrolled up, don't auto-scroll
|
|
1045
|
+
if (userScrolledUpRef.current && isStreaming) {
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1021
1048
|
// Check if user is near bottom (within 100px threshold)
|
|
1022
1049
|
const isNearBottom = container.scrollHeight - container.scrollTop - container.clientHeight < 100;
|
|
1023
|
-
if (isNearBottom) {
|
|
1050
|
+
if (isNearBottom || !isStreaming) {
|
|
1024
1051
|
if (isStreaming) {
|
|
1025
|
-
// 스트리밍
|
|
1026
|
-
|
|
1052
|
+
// 스트리밍 중: requestAnimationFrame으로 부드럽게 스크롤
|
|
1053
|
+
// 이전 RAF가 있으면 취소하고 새로 스케줄링
|
|
1054
|
+
if (scrollRafRef.current) {
|
|
1055
|
+
cancelAnimationFrame(scrollRafRef.current);
|
|
1056
|
+
}
|
|
1057
|
+
scrollRafRef.current = requestAnimationFrame(() => {
|
|
1058
|
+
const now = Date.now();
|
|
1059
|
+
// 최소 16ms 간격 유지 (60fps)
|
|
1060
|
+
if (now - lastScrollTimeRef.current >= 16) {
|
|
1061
|
+
container.scrollTop = container.scrollHeight;
|
|
1062
|
+
lastScrollTimeRef.current = now;
|
|
1063
|
+
}
|
|
1064
|
+
scrollRafRef.current = null;
|
|
1065
|
+
});
|
|
1027
1066
|
}
|
|
1028
|
-
else {
|
|
1067
|
+
else if (isNearBottom) {
|
|
1029
1068
|
// 일반 메시지 추가 시 부드러운 스크롤
|
|
1030
1069
|
container.scrollTo({
|
|
1031
1070
|
top: container.scrollHeight,
|
|
1032
1071
|
behavior: 'smooth'
|
|
1033
1072
|
});
|
|
1073
|
+
// 새 메시지 추가 시 userScrolledUp 리셋
|
|
1074
|
+
userScrolledUpRef.current = false;
|
|
1034
1075
|
}
|
|
1035
1076
|
}
|
|
1077
|
+
// Cleanup RAF on unmount
|
|
1078
|
+
return () => {
|
|
1079
|
+
if (scrollRafRef.current) {
|
|
1080
|
+
cancelAnimationFrame(scrollRafRef.current);
|
|
1081
|
+
}
|
|
1082
|
+
};
|
|
1036
1083
|
}, [messages, isStreaming]);
|
|
1037
1084
|
const handleNextItemSelection = async (nextText) => {
|
|
1038
1085
|
const trimmed = nextText.trim();
|
|
@@ -1124,6 +1171,8 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
1124
1171
|
// Agent V2 모드 또는 그 외: LangChain Deep Agent (sendAgentV2Stream)
|
|
1125
1172
|
if (inputMode === 'chat') {
|
|
1126
1173
|
// 단순 Chat 모드 - /chat/stream 사용
|
|
1174
|
+
// Create AbortController for chat streaming
|
|
1175
|
+
abortControllerRef.current = new AbortController();
|
|
1127
1176
|
await apiService.sendChatStream({
|
|
1128
1177
|
message: messageToSend,
|
|
1129
1178
|
conversationId: conversationId || undefined,
|
|
@@ -1141,7 +1190,9 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
1141
1190
|
if (metadata.conversationId && !conversationId) {
|
|
1142
1191
|
setConversationId(metadata.conversationId);
|
|
1143
1192
|
}
|
|
1144
|
-
}
|
|
1193
|
+
},
|
|
1194
|
+
// AbortSignal for stopping the stream
|
|
1195
|
+
abortControllerRef.current.signal);
|
|
1145
1196
|
}
|
|
1146
1197
|
else {
|
|
1147
1198
|
// Agent V2 모드 - /agent/langchain/stream 사용 (HITL, Todo, 도구 실행)
|
|
@@ -1284,20 +1335,34 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
1284
1335
|
}
|
|
1285
1336
|
}
|
|
1286
1337
|
catch (error) {
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1338
|
+
// Handle abort error gracefully (user clicked stop)
|
|
1339
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
1340
|
+
console.log('[AgentPanel] Chat stream stopped by user');
|
|
1341
|
+
setDebugStatus(null);
|
|
1342
|
+
// Keep the streamed content as-is, just add a stopped indicator
|
|
1343
|
+
if (streamedContent) {
|
|
1344
|
+
setMessages(prev => prev.map(msg => msg.id === assistantMessageId && isChatMessage(msg)
|
|
1345
|
+
? { ...msg, content: streamedContent + '\n\n*(응답 중단됨)*' }
|
|
1346
|
+
: msg));
|
|
1294
1347
|
}
|
|
1295
|
-
|
|
1348
|
+
}
|
|
1349
|
+
else {
|
|
1350
|
+
const message = error instanceof Error ? error.message : 'Failed to send message';
|
|
1351
|
+
setDebugStatus(`오류: ${message}`);
|
|
1352
|
+
// Update the assistant message with error
|
|
1353
|
+
setMessages(prev => prev.map(msg => msg.id === assistantMessageId && isChatMessage(msg)
|
|
1354
|
+
? {
|
|
1355
|
+
...msg,
|
|
1356
|
+
content: streamedContent + `\n\nError: ${message}`
|
|
1357
|
+
}
|
|
1358
|
+
: msg));
|
|
1359
|
+
}
|
|
1296
1360
|
}
|
|
1297
1361
|
finally {
|
|
1298
1362
|
setIsLoading(false);
|
|
1299
1363
|
setIsStreaming(false);
|
|
1300
1364
|
setStreamingMessageId(null);
|
|
1365
|
+
abortControllerRef.current = null;
|
|
1301
1366
|
// Keep completed todos visible after the run
|
|
1302
1367
|
}
|
|
1303
1368
|
};
|
|
@@ -3320,7 +3385,137 @@ SyntaxError: '(' was never closed
|
|
|
3320
3385
|
}
|
|
3321
3386
|
await resumeFromInterrupt(interruptData, decision);
|
|
3322
3387
|
};
|
|
3388
|
+
// Handle input change and track cursor position for autocomplete
|
|
3389
|
+
const handleInputChange = (e) => {
|
|
3390
|
+
const newValue = e.target.value;
|
|
3391
|
+
const newCursorPosition = e.target.selectionStart || 0;
|
|
3392
|
+
setInput(newValue);
|
|
3393
|
+
setCursorPosition(newCursorPosition);
|
|
3394
|
+
// Check if we should show autocomplete (when typing @ or @file:)
|
|
3395
|
+
const textBeforeCursor = newValue.slice(0, newCursorPosition);
|
|
3396
|
+
const lastAtIndex = textBeforeCursor.lastIndexOf('@');
|
|
3397
|
+
if (lastAtIndex >= 0) {
|
|
3398
|
+
// Check if there's a space between @ and cursor (means @ is complete)
|
|
3399
|
+
const textAfterAt = textBeforeCursor.slice(lastAtIndex);
|
|
3400
|
+
if (!/\s/.test(textAfterAt) || textAfterAt.includes(':')) {
|
|
3401
|
+
// Show autocomplete if typing a context command
|
|
3402
|
+
setShowAutocomplete(true);
|
|
3403
|
+
}
|
|
3404
|
+
else {
|
|
3405
|
+
setShowAutocomplete(false);
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
else {
|
|
3409
|
+
setShowAutocomplete(false);
|
|
3410
|
+
}
|
|
3411
|
+
};
|
|
3412
|
+
// Handle autocomplete selection
|
|
3413
|
+
// viaEnter: true = Enter key or click (final selection), false = Tab key (navigation)
|
|
3414
|
+
const handleAutocompleteSelect = async (option, viaEnter) => {
|
|
3415
|
+
// Check if this is an action command (like @reset)
|
|
3416
|
+
if (option.id === '@reset' && option.is_complete) {
|
|
3417
|
+
// Execute reset action
|
|
3418
|
+
await executeResetAction();
|
|
3419
|
+
setShowAutocomplete(false);
|
|
3420
|
+
setHasAutocompleteOptions(false);
|
|
3421
|
+
setInput('');
|
|
3422
|
+
return;
|
|
3423
|
+
}
|
|
3424
|
+
if (!textareaRef.current)
|
|
3425
|
+
return;
|
|
3426
|
+
const text = input;
|
|
3427
|
+
// Find the start of the current context command
|
|
3428
|
+
let start = cursorPosition;
|
|
3429
|
+
while (start > 0 && !/\s/.test(text[start - 1])) {
|
|
3430
|
+
start--;
|
|
3431
|
+
}
|
|
3432
|
+
// Build new text with the selected option
|
|
3433
|
+
const beforeCommand = text.slice(0, start);
|
|
3434
|
+
const afterCursor = text.slice(cursorPosition);
|
|
3435
|
+
// For Enter (final selection): add space after complete options
|
|
3436
|
+
// For Tab (navigation): don't add space, allow further navigation
|
|
3437
|
+
const addSpace = viaEnter && option.is_complete;
|
|
3438
|
+
const newText = beforeCommand + option.label + (addSpace ? ' ' : '') + afterCursor;
|
|
3439
|
+
const newCursorPosition = beforeCommand.length + option.label.length + (addSpace ? 1 : 0);
|
|
3440
|
+
setInput(newText);
|
|
3441
|
+
setCursorPosition(newCursorPosition);
|
|
3442
|
+
// Close autocomplete only on Enter (final selection)
|
|
3443
|
+
if (viaEnter) {
|
|
3444
|
+
setShowAutocomplete(false);
|
|
3445
|
+
setHasAutocompleteOptions(false);
|
|
3446
|
+
}
|
|
3447
|
+
// For Tab on directory, keep autocomplete open - it will refetch options
|
|
3448
|
+
// Focus and set cursor position
|
|
3449
|
+
setTimeout(() => {
|
|
3450
|
+
if (textareaRef.current) {
|
|
3451
|
+
textareaRef.current.focus();
|
|
3452
|
+
textareaRef.current.setSelectionRange(newCursorPosition, newCursorPosition);
|
|
3453
|
+
}
|
|
3454
|
+
}, 0);
|
|
3455
|
+
};
|
|
3456
|
+
// Execute @reset action
|
|
3457
|
+
const executeResetAction = async () => {
|
|
3458
|
+
try {
|
|
3459
|
+
// Reset both agent thread and conversation
|
|
3460
|
+
const threadId = agentThreadId || conversationId;
|
|
3461
|
+
if (threadId) {
|
|
3462
|
+
const result = await apiService.resetAgent(threadId);
|
|
3463
|
+
console.log('[AgentPanel] Reset result:', result);
|
|
3464
|
+
}
|
|
3465
|
+
// Clear local state
|
|
3466
|
+
setMessages([]);
|
|
3467
|
+
setConversationId('');
|
|
3468
|
+
setAgentThreadId(null);
|
|
3469
|
+
setIsAgentRunning(false);
|
|
3470
|
+
setIsLoading(false);
|
|
3471
|
+
setIsStreaming(false);
|
|
3472
|
+
setTodos([]);
|
|
3473
|
+
setInterruptData(null);
|
|
3474
|
+
setIsRejectionMode(false);
|
|
3475
|
+
setIsAskUserMode(false);
|
|
3476
|
+
// Add system message about reset
|
|
3477
|
+
const resetMessage = {
|
|
3478
|
+
id: `reset-${Date.now()}`,
|
|
3479
|
+
role: 'assistant',
|
|
3480
|
+
content: 'Agent가 reset되었습니다. 새로운 대화를 시작하세요.',
|
|
3481
|
+
timestamp: Date.now(),
|
|
3482
|
+
};
|
|
3483
|
+
setMessages([resetMessage]);
|
|
3484
|
+
console.log('[AgentPanel] Session reset complete');
|
|
3485
|
+
}
|
|
3486
|
+
catch (error) {
|
|
3487
|
+
console.error('[AgentPanel] Failed to reset session:', error);
|
|
3488
|
+
const errorMessage = {
|
|
3489
|
+
id: `error-${Date.now()}`,
|
|
3490
|
+
role: 'assistant',
|
|
3491
|
+
content: `Failed to reset session: ${error}`,
|
|
3492
|
+
timestamp: Date.now(),
|
|
3493
|
+
};
|
|
3494
|
+
setMessages(prev => [...prev, errorMessage]);
|
|
3495
|
+
}
|
|
3496
|
+
};
|
|
3323
3497
|
const handleKeyDown = (e) => {
|
|
3498
|
+
// If autocomplete is visible AND has options, let it handle Tab/Enter
|
|
3499
|
+
if (showAutocomplete && hasAutocompleteOptions) {
|
|
3500
|
+
// These keys are handled by ContextAutocomplete
|
|
3501
|
+
if (e.key === 'Tab' || e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
|
3502
|
+
return; // Let autocomplete handle it
|
|
3503
|
+
}
|
|
3504
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
3505
|
+
return; // Let autocomplete handle it
|
|
3506
|
+
}
|
|
3507
|
+
if (e.key === 'Escape') {
|
|
3508
|
+
setShowAutocomplete(false);
|
|
3509
|
+
setHasAutocompleteOptions(false);
|
|
3510
|
+
return;
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
// Escape: Stop chat streaming (only in chat mode when streaming)
|
|
3514
|
+
if (e.key === 'Escape' && inputMode === 'chat' && isStreaming) {
|
|
3515
|
+
e.preventDefault();
|
|
3516
|
+
stopCurrentTask();
|
|
3517
|
+
return;
|
|
3518
|
+
}
|
|
3324
3519
|
// Enter: 전송
|
|
3325
3520
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
3326
3521
|
e.preventDefault();
|
|
@@ -3387,7 +3582,7 @@ SyntaxError: '(' was never closed
|
|
|
3387
3582
|
if (!debugStatus || typeof debugStatus === 'string')
|
|
3388
3583
|
return '';
|
|
3389
3584
|
if (debugStatus.icon) {
|
|
3390
|
-
return (0,
|
|
3585
|
+
return (0,_utils_icons__WEBPACK_IMPORTED_MODULE_9__.getIconByName)(debugStatus.icon);
|
|
3391
3586
|
}
|
|
3392
3587
|
return '';
|
|
3393
3588
|
};
|
|
@@ -3415,7 +3610,7 @@ SyntaxError: '(' was never closed
|
|
|
3415
3610
|
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-panel" },
|
|
3416
3611
|
showSettings && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_SettingsPanel__WEBPACK_IMPORTED_MODULE_3__.SettingsPanel, { onClose: () => setShowSettings(false), onSave: handleSaveConfig, currentConfig: llmConfig || undefined })),
|
|
3417
3612
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-header" },
|
|
3418
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-header-logo", dangerouslySetInnerHTML: { __html:
|
|
3613
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-header-logo", dangerouslySetInnerHTML: { __html: _logoSvg__WEBPACK_IMPORTED_MODULE_12__.headerLogoSvg } }),
|
|
3419
3614
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-header-buttons" },
|
|
3420
3615
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "jp-agent-clear-button", onClick: clearChat, title: "\uB300\uD654 \uCD08\uAE30\uD654" },
|
|
3421
3616
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
@@ -3522,7 +3717,7 @@ SyntaxError: '(' was never closed
|
|
|
3522
3717
|
const decision = msg.metadata?.interrupt?.decision;
|
|
3523
3718
|
const autoApproved = msg.metadata?.interrupt?.autoApproved;
|
|
3524
3719
|
// 자동 승인일 때는 코드블럭 헤더에 배지가 표시되므로 actionHtml에는 표시하지 않음
|
|
3525
|
-
const resolvedIcon = autoApproved ? '' : (decision === 'reject' ?
|
|
3720
|
+
const resolvedIcon = autoApproved ? '' : (decision === 'reject' ? _utils_icons__WEBPACK_IMPORTED_MODULE_9__.Icons.rejectCircle : _utils_icons__WEBPACK_IMPORTED_MODULE_9__.Icons.doubleCheck);
|
|
3526
3721
|
const resolvedClass = autoApproved ? '' : (decision === 'reject' ? 'jp-agent-interrupt-actions--rejected' : 'jp-agent-interrupt-actions--resolved');
|
|
3527
3722
|
const actionHtml = resolved && !autoApproved
|
|
3528
3723
|
? `<div class="jp-agent-interrupt-actions ${resolvedClass}">${resolvedIcon}</div>`
|
|
@@ -3530,8 +3725,8 @@ SyntaxError: '(' was never closed
|
|
|
3530
3725
|
? '' // 자동 승인일 때는 actionHtml 비움 (코드블럭 헤더에 배지 표시)
|
|
3531
3726
|
: `
|
|
3532
3727
|
<div class="code-block-actions jp-agent-interrupt-actions">
|
|
3533
|
-
<button class="jp-agent-interrupt-approve-btn" data-action="approve" title="승인">${
|
|
3534
|
-
<button class="jp-agent-interrupt-reject-btn" data-action="reject" title="거부">${
|
|
3728
|
+
<button class="jp-agent-interrupt-approve-btn" data-action="approve" title="승인">${_utils_icons__WEBPACK_IMPORTED_MODULE_9__.Icons.approveCircle}</button>
|
|
3729
|
+
<button class="jp-agent-interrupt-reject-btn" data-action="reject" title="거부">${_utils_icons__WEBPACK_IMPORTED_MODULE_9__.Icons.rejectCircle}</button>
|
|
3535
3730
|
</div>
|
|
3536
3731
|
`;
|
|
3537
3732
|
// Get tool description from args (for jupyter_cell_tool)
|
|
@@ -3547,7 +3742,7 @@ SyntaxError: '(' was never closed
|
|
|
3547
3742
|
}
|
|
3548
3743
|
if ((isEditFile || isMultiEditFile) && editPath) {
|
|
3549
3744
|
const safePath = escapeHtml(editPath);
|
|
3550
|
-
const editIcon =
|
|
3745
|
+
const editIcon = _utils_icons__WEBPACK_IMPORTED_MODULE_9__.Icons.edit;
|
|
3551
3746
|
html = html.replace(/<span class="code-block-language">[^<]*<\/span>/, `<span class="code-block-language jp-agent-interrupt-path">${editIcon} ${safePath}</span>`);
|
|
3552
3747
|
}
|
|
3553
3748
|
// actionHtml이 비어있지 않을 때만 추가
|
|
@@ -3574,12 +3769,12 @@ SyntaxError: '(' was never closed
|
|
|
3574
3769
|
.replace(/\n/g, ' ') // Remove actual newlines
|
|
3575
3770
|
.replace(/\s+/g, ' ') // Collapse multiple spaces
|
|
3576
3771
|
.trim();
|
|
3577
|
-
result += `<div class="jp-agent-code-description">${
|
|
3772
|
+
result += `<div class="jp-agent-code-description">${_utils_icons__WEBPACK_IMPORTED_MODULE_9__.Icons.description} ${safeDescription}</div>`;
|
|
3578
3773
|
}
|
|
3579
3774
|
// 2. 승인 메시지 (자동 승인이 아닐 때만) - 코드 블록 바로 위
|
|
3580
3775
|
if (!msg.metadata?.interrupt?.autoApproved && msg.content) {
|
|
3581
3776
|
const safeContent = escapeHtml(msg.content);
|
|
3582
|
-
result += `<div class="jp-agent-interrupt-description">${
|
|
3777
|
+
result += `<div class="jp-agent-interrupt-description">${_utils_icons__WEBPACK_IMPORTED_MODULE_9__.Icons.approvalWarning} ${safeContent}</div>`;
|
|
3583
3778
|
}
|
|
3584
3779
|
// 3. 코드 블록
|
|
3585
3780
|
result += codeHtml;
|
|
@@ -3664,7 +3859,7 @@ SyntaxError: '(' was never closed
|
|
|
3664
3859
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-agent-todo-compact-current" }, "\uC791\uC5C5 \uB9C8\uBB34\uB9AC \uC911...")));
|
|
3665
3860
|
}
|
|
3666
3861
|
else {
|
|
3667
|
-
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-agent-todo-compact-current", dangerouslySetInnerHTML: { __html: `${
|
|
3862
|
+
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-agent-todo-compact-current", dangerouslySetInnerHTML: { __html: `${_utils_icons__WEBPACK_IMPORTED_MODULE_9__.Icons.check} 모든 작업 완료` } }));
|
|
3668
3863
|
}
|
|
3669
3864
|
})()),
|
|
3670
3865
|
(isStreaming || isLoading || isAgentRunning || todos.some(t => t.status === 'in_progress')) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "jp-agent-todo-stop-btn", onClick: (e) => {
|
|
@@ -3684,7 +3879,7 @@ SyntaxError: '(' was never closed
|
|
|
3684
3879
|
getDebugStatusIcon() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-agent-debug-icon", dangerouslySetInnerHTML: { __html: getDebugStatusIcon() } })),
|
|
3685
3880
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: `jp-agent-debug-text${isDebugStatusExpandable() ? ' jp-agent-debug-text--expandable' : ''}`, onClick: isDebugStatusExpandable() ? () => setIsDebugExpanded(!isDebugExpanded) : undefined, title: isDebugStatusExpandable() ? (isDebugExpanded ? '접기' : '펼치기') : undefined },
|
|
3686
3881
|
statusText,
|
|
3687
|
-
isDebugStatusExpandable() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-agent-debug-expand-icon" }, isDebugExpanded ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
3882
|
+
isDebugStatusExpandable() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-agent-debug-expand-icon" }, isDebugExpanded ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ExpandLess__WEBPACK_IMPORTED_MODULE_10__["default"], { sx: { fontSize: 14 } }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ExpandMore__WEBPACK_IMPORTED_MODULE_11__["default"], { sx: { fontSize: 14 } }))))))),
|
|
3688
3883
|
isTodoExpanded && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-todo-expanded" }, todos.map((todo, index) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { key: index, className: `jp-agent-todo-item jp-agent-todo-item--${todo.status}` },
|
|
3689
3884
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-todo-item-indicator" },
|
|
3690
3885
|
todo.status === 'completed' && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("svg", { viewBox: "0 0 16 16", fill: "currentColor", width: "12", height: "12" },
|
|
@@ -3697,15 +3892,22 @@ SyntaxError: '(' was never closed
|
|
|
3697
3892
|
getDebugStatusIcon() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-agent-debug-icon", dangerouslySetInnerHTML: { __html: getDebugStatusIcon() } })),
|
|
3698
3893
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: `jp-agent-debug-text${isDebugStatusExpandable() ? ' jp-agent-debug-text--expandable' : ''}`, onClick: isDebugStatusExpandable() ? () => setIsDebugExpanded(!isDebugExpanded) : undefined, title: isDebugStatusExpandable() ? (isDebugExpanded ? '접기' : '펼치기') : undefined },
|
|
3699
3894
|
statusText,
|
|
3700
|
-
isDebugStatusExpandable() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-agent-debug-expand-icon" }, isDebugExpanded ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
3895
|
+
isDebugStatusExpandable() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-agent-debug-expand-icon" }, isDebugExpanded ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ExpandLess__WEBPACK_IMPORTED_MODULE_10__["default"], { sx: { fontSize: 14 } }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ExpandMore__WEBPACK_IMPORTED_MODULE_11__["default"], { sx: { fontSize: 14 } }))))))),
|
|
3701
3896
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-input-container" },
|
|
3702
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-input-wrapper" },
|
|
3703
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(
|
|
3897
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-input-wrapper", style: { position: 'relative' } },
|
|
3898
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_ContextAutocomplete__WEBPACK_IMPORTED_MODULE_8__.ContextAutocomplete, { apiService: apiService, inputValue: input, cursorPosition: cursorPosition, baseDir: notebookTracker?.currentWidget?.context?.path ?
|
|
3899
|
+
notebookTracker.currentWidget.context.path.replace(/[^/]*$/, '') : undefined, onSelect: handleAutocompleteSelect, onClose: () => { setShowAutocomplete(false); setHasAutocompleteOptions(false); }, onOptionsChange: setHasAutocompleteOptions, visible: showAutocomplete, anchorEl: textareaRef.current }),
|
|
3900
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("textarea", { ref: textareaRef, className: `jp-agent-input ${inputMode !== 'chat' ? 'jp-agent-input--agent-mode' : ''} ${isRejectionMode ? 'jp-agent-input--rejection-mode' : ''}`, value: input, onChange: handleInputChange, onKeyDown: handleKeyDown, onSelect: (e) => setCursorPosition(e.target.selectionStart || 0), placeholder: isRejectionMode
|
|
3704
3901
|
? '다른 방향 제시'
|
|
3705
3902
|
: (inputMode === 'agent'
|
|
3706
|
-
? '노트북 작업을 입력하세요... (예:
|
|
3707
|
-
: '메시지를 입력하세요...'), rows: 3, disabled: isLoading || isAgentRunning }),
|
|
3708
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("
|
|
3903
|
+
? '노트북 작업을 입력하세요... (예: @file:path로 파일 참조)'
|
|
3904
|
+
: '메시지를 입력하세요... (@file:path로 파일 참조)'), rows: 3, disabled: isLoading || isAgentRunning }),
|
|
3905
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-button-container" },
|
|
3906
|
+
inputMode === 'chat' && isStreaming && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "jp-agent-stop-button", onClick: stopCurrentTask, title: "\uC751\uB2F5 \uC911\uB2E8 (Esc)" },
|
|
3907
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "14", height: "14" },
|
|
3908
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("rect", { x: "6", y: "6", width: "12", height: "12", rx: "1" })),
|
|
3909
|
+
"\uC911\uB2E8")),
|
|
3910
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "jp-agent-send-button", onClick: handleSendMessage, disabled: (!input.trim() && !isRejectionMode) || isLoading || isStreaming || isAgentRunning, title: isRejectionMode ? "거부 전송 (Enter)" : "전송 (Enter)" }, isAgentRunning ? '실행 중...' : (isRejectionMode ? '거부' : '전송')))),
|
|
3709
3911
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-mode-bar" },
|
|
3710
3912
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-mode-toggle-container" },
|
|
3711
3913
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: `jp-agent-mode-toggle ${inputMode !== 'chat' ? 'jp-agent-mode-toggle--active' : ''}`, onClick: toggleMode, title: `${inputMode === 'chat' ? 'Chat' : 'Agent'} 모드 (⇧Tab)` },
|
|
@@ -3909,6 +4111,216 @@ ${cell.output}
|
|
|
3909
4111
|
}
|
|
3910
4112
|
|
|
3911
4113
|
|
|
4114
|
+
/***/ },
|
|
4115
|
+
|
|
4116
|
+
/***/ "./lib/components/ContextAutocomplete.js"
|
|
4117
|
+
/*!***********************************************!*\
|
|
4118
|
+
!*** ./lib/components/ContextAutocomplete.js ***!
|
|
4119
|
+
\***********************************************/
|
|
4120
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
4121
|
+
|
|
4122
|
+
__webpack_require__.r(__webpack_exports__);
|
|
4123
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
4124
|
+
/* harmony export */ ContextAutocomplete: () => (/* binding */ ContextAutocomplete),
|
|
4125
|
+
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
|
|
4126
|
+
/* harmony export */ });
|
|
4127
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react");
|
|
4128
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
4129
|
+
/* harmony import */ var _mui_icons_material_InsertDriveFile__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @mui/icons-material/InsertDriveFile */ "./node_modules/@mui/icons-material/esm/InsertDriveFile.js");
|
|
4130
|
+
/* harmony import */ var _mui_icons_material_Folder__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @mui/icons-material/Folder */ "./node_modules/@mui/icons-material/esm/Folder.js");
|
|
4131
|
+
/* harmony import */ var _mui_icons_material_Description__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @mui/icons-material/Description */ "./node_modules/@mui/icons-material/esm/Description.js");
|
|
4132
|
+
/**
|
|
4133
|
+
* Context Autocomplete Component
|
|
4134
|
+
*
|
|
4135
|
+
* Provides autocomplete functionality for @file and other context commands.
|
|
4136
|
+
* Inspired by jupyter-ai's autocomplete implementation.
|
|
4137
|
+
*/
|
|
4138
|
+
|
|
4139
|
+
|
|
4140
|
+
|
|
4141
|
+
|
|
4142
|
+
/**
|
|
4143
|
+
* Extract the word at cursor position that might be a context command.
|
|
4144
|
+
* Returns the partial command (e.g., "@file:" or "@file:src/")
|
|
4145
|
+
*/
|
|
4146
|
+
function getPartialCommand(text, cursorPosition) {
|
|
4147
|
+
// Find the start of the current word
|
|
4148
|
+
let start = cursorPosition;
|
|
4149
|
+
while (start > 0 && !/\s/.test(text[start - 1])) {
|
|
4150
|
+
start--;
|
|
4151
|
+
}
|
|
4152
|
+
const word = text.slice(start, cursorPosition);
|
|
4153
|
+
// Check if it looks like a context command
|
|
4154
|
+
if (word.startsWith('@')) {
|
|
4155
|
+
return word;
|
|
4156
|
+
}
|
|
4157
|
+
return null;
|
|
4158
|
+
}
|
|
4159
|
+
/**
|
|
4160
|
+
* Get icon for autocomplete option
|
|
4161
|
+
*/
|
|
4162
|
+
function getOptionIcon(option) {
|
|
4163
|
+
const description = option.description.toLowerCase();
|
|
4164
|
+
if (description.includes('directory') || description.includes('folder')) {
|
|
4165
|
+
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_Folder__WEBPACK_IMPORTED_MODULE_2__["default"], { sx: { fontSize: 16, color: 'var(--jp-ui-font-color2)' } });
|
|
4166
|
+
}
|
|
4167
|
+
if (description.includes('python') || description.includes('.py')) {
|
|
4168
|
+
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_InsertDriveFile__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { fontSize: 16, color: '#3572A5' } });
|
|
4169
|
+
}
|
|
4170
|
+
if (description.includes('notebook') || description.includes('.ipynb')) {
|
|
4171
|
+
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_InsertDriveFile__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { fontSize: 16, color: '#F37626' } });
|
|
4172
|
+
}
|
|
4173
|
+
if (description.includes('javascript') || description.includes('typescript')) {
|
|
4174
|
+
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_InsertDriveFile__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { fontSize: 16, color: '#f1e05a' } });
|
|
4175
|
+
}
|
|
4176
|
+
if (description.includes('markdown')) {
|
|
4177
|
+
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_Description__WEBPACK_IMPORTED_MODULE_3__["default"], { sx: { fontSize: 16, color: 'var(--jp-ui-font-color2)' } });
|
|
4178
|
+
}
|
|
4179
|
+
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_InsertDriveFile__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { fontSize: 16, color: 'var(--jp-ui-font-color2)' } });
|
|
4180
|
+
}
|
|
4181
|
+
const ContextAutocomplete = ({ apiService, inputValue, cursorPosition, baseDir, onSelect, onClose, onOptionsChange, visible, anchorEl, }) => {
|
|
4182
|
+
const [options, setOptions] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
|
|
4183
|
+
const [selectedIndex, setSelectedIndex] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(0);
|
|
4184
|
+
const [loading, setLoading] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
4185
|
+
const [partialCommand, setPartialCommand] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
|
|
4186
|
+
const containerRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);
|
|
4187
|
+
// Fetch autocomplete options
|
|
4188
|
+
const fetchOptions = (0,react__WEBPACK_IMPORTED_MODULE_0__.useCallback)(async (partial) => {
|
|
4189
|
+
setLoading(true);
|
|
4190
|
+
try {
|
|
4191
|
+
const response = await apiService.getContextAutocomplete({
|
|
4192
|
+
partialCommand: partial,
|
|
4193
|
+
baseDir,
|
|
4194
|
+
});
|
|
4195
|
+
setOptions(response.options);
|
|
4196
|
+
setSelectedIndex(0);
|
|
4197
|
+
}
|
|
4198
|
+
catch (error) {
|
|
4199
|
+
console.error('[ContextAutocomplete] Failed to fetch options:', error);
|
|
4200
|
+
setOptions([]);
|
|
4201
|
+
}
|
|
4202
|
+
finally {
|
|
4203
|
+
setLoading(false);
|
|
4204
|
+
}
|
|
4205
|
+
}, [apiService, baseDir]);
|
|
4206
|
+
// Update options when input changes
|
|
4207
|
+
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
4208
|
+
const partial = getPartialCommand(inputValue, cursorPosition);
|
|
4209
|
+
setPartialCommand(partial);
|
|
4210
|
+
if (partial) {
|
|
4211
|
+
// Debounce the fetch
|
|
4212
|
+
const timer = setTimeout(() => {
|
|
4213
|
+
fetchOptions(partial);
|
|
4214
|
+
}, 150);
|
|
4215
|
+
return () => clearTimeout(timer);
|
|
4216
|
+
}
|
|
4217
|
+
else {
|
|
4218
|
+
setOptions([]);
|
|
4219
|
+
}
|
|
4220
|
+
}, [inputValue, cursorPosition, fetchOptions]);
|
|
4221
|
+
// Notify parent when options change
|
|
4222
|
+
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
4223
|
+
onOptionsChange?.(options.length > 0);
|
|
4224
|
+
}, [options, onOptionsChange]);
|
|
4225
|
+
// Handle keyboard navigation
|
|
4226
|
+
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
4227
|
+
if (!visible || options.length === 0)
|
|
4228
|
+
return;
|
|
4229
|
+
const handleKeyDown = (e) => {
|
|
4230
|
+
const selectedOption = options[selectedIndex];
|
|
4231
|
+
switch (e.key) {
|
|
4232
|
+
case 'ArrowDown':
|
|
4233
|
+
e.preventDefault();
|
|
4234
|
+
setSelectedIndex(prev => (prev + 1) % options.length);
|
|
4235
|
+
break;
|
|
4236
|
+
case 'ArrowUp':
|
|
4237
|
+
e.preventDefault();
|
|
4238
|
+
setSelectedIndex(prev => (prev - 1 + options.length) % options.length);
|
|
4239
|
+
break;
|
|
4240
|
+
case 'Tab':
|
|
4241
|
+
// Tab: Only navigate into directories (is_complete=false)
|
|
4242
|
+
// On files (is_complete=true), do nothing
|
|
4243
|
+
if (selectedOption && !selectedOption.is_complete) {
|
|
4244
|
+
e.preventDefault();
|
|
4245
|
+
onSelect(selectedOption, false); // viaEnter=false (Tab navigation)
|
|
4246
|
+
}
|
|
4247
|
+
else {
|
|
4248
|
+
// On complete file, just prevent default but don't select
|
|
4249
|
+
e.preventDefault();
|
|
4250
|
+
}
|
|
4251
|
+
break;
|
|
4252
|
+
case 'Enter':
|
|
4253
|
+
// Enter: Select any option (directory or file) and close autocomplete
|
|
4254
|
+
if (selectedOption) {
|
|
4255
|
+
e.preventDefault();
|
|
4256
|
+
e.stopPropagation(); // Prevent AgentPanel from sending message
|
|
4257
|
+
onSelect(selectedOption, true); // viaEnter=true (final selection)
|
|
4258
|
+
}
|
|
4259
|
+
break;
|
|
4260
|
+
case 'Escape':
|
|
4261
|
+
e.preventDefault();
|
|
4262
|
+
onClose();
|
|
4263
|
+
break;
|
|
4264
|
+
}
|
|
4265
|
+
};
|
|
4266
|
+
document.addEventListener('keydown', handleKeyDown, true);
|
|
4267
|
+
return () => document.removeEventListener('keydown', handleKeyDown, true);
|
|
4268
|
+
}, [visible, options, selectedIndex, onSelect, onClose]);
|
|
4269
|
+
// Scroll selected item into view
|
|
4270
|
+
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
4271
|
+
if (containerRef.current && options.length > 0) {
|
|
4272
|
+
const selectedItem = containerRef.current.querySelector('.jp-context-autocomplete-item--selected');
|
|
4273
|
+
if (selectedItem) {
|
|
4274
|
+
selectedItem.scrollIntoView({ block: 'nearest' });
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
}, [selectedIndex, options]);
|
|
4278
|
+
// Close on click outside
|
|
4279
|
+
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
4280
|
+
if (!visible || options.length === 0)
|
|
4281
|
+
return;
|
|
4282
|
+
const handleClickOutside = (e) => {
|
|
4283
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
4284
|
+
// Also check if click is on the anchor element (textarea)
|
|
4285
|
+
if (anchorEl && !anchorEl.contains(e.target)) {
|
|
4286
|
+
onClose();
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
};
|
|
4290
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
4291
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
4292
|
+
}, [visible, options, anchorEl, onClose]);
|
|
4293
|
+
// Don't render if not visible or no partial command
|
|
4294
|
+
if (!visible || !partialCommand || options.length === 0) {
|
|
4295
|
+
return null;
|
|
4296
|
+
}
|
|
4297
|
+
// Calculate position based on anchor element
|
|
4298
|
+
const style = {
|
|
4299
|
+
position: 'absolute',
|
|
4300
|
+
bottom: anchorEl ? anchorEl.offsetHeight + 4 : 'auto',
|
|
4301
|
+
left: 0,
|
|
4302
|
+
right: 0,
|
|
4303
|
+
zIndex: 1000,
|
|
4304
|
+
};
|
|
4305
|
+
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { ref: containerRef, className: "jp-context-autocomplete", style: style },
|
|
4306
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-context-autocomplete-header" },
|
|
4307
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-context-autocomplete-hint" }, partialCommand.includes(':') ? 'Select a file' : 'Context commands'),
|
|
4308
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-context-autocomplete-loading" }, loading && 'Loading...')),
|
|
4309
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-context-autocomplete-list" }, options.map((option, index) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { key: `${option.id}-${option.label}-${index}`, className: `jp-context-autocomplete-item ${index === selectedIndex ? 'jp-context-autocomplete-item--selected' : ''}`, onClick: () => onSelect(option, true), onMouseEnter: () => setSelectedIndex(index) },
|
|
4310
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-context-autocomplete-item-icon" }, getOptionIcon(option)),
|
|
4311
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-context-autocomplete-item-label" }, option.label),
|
|
4312
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { className: "jp-context-autocomplete-item-description" }, option.description))))),
|
|
4313
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-context-autocomplete-footer" },
|
|
4314
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("kbd", null, "Tab"),
|
|
4315
|
+
" navigate, ",
|
|
4316
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("kbd", null, "Enter"),
|
|
4317
|
+
" select, ",
|
|
4318
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("kbd", null, "Esc"),
|
|
4319
|
+
" close")));
|
|
4320
|
+
};
|
|
4321
|
+
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ContextAutocomplete);
|
|
4322
|
+
|
|
4323
|
+
|
|
3912
4324
|
/***/ },
|
|
3913
4325
|
|
|
3914
4326
|
/***/ "./lib/components/FileSelectionDialog.js"
|
|
@@ -9062,7 +9474,7 @@ class ApiService {
|
|
|
9062
9474
|
* 단순 Chat용 스트리밍 - /chat/stream 사용
|
|
9063
9475
|
* 원래 main 브랜치의 구현 복원 - LangChain 에이전트 없이 단순 Q&A
|
|
9064
9476
|
*/
|
|
9065
|
-
async sendChatStream(request, onChunk, onMetadata) {
|
|
9477
|
+
async sendChatStream(request, onChunk, onMetadata, abortSignal) {
|
|
9066
9478
|
const MAX_RETRIES = 10;
|
|
9067
9479
|
let currentConfig = request.llmConfig;
|
|
9068
9480
|
let lastError = null;
|
|
@@ -9071,11 +9483,16 @@ class ApiService {
|
|
|
9071
9483
|
? { ...request, llmConfig: (0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.buildSingleKeyConfig)(currentConfig) }
|
|
9072
9484
|
: request;
|
|
9073
9485
|
try {
|
|
9074
|
-
await this.sendChatStreamInternal(requestToSend, onChunk, onMetadata);
|
|
9486
|
+
await this.sendChatStreamInternal(requestToSend, onChunk, onMetadata, abortSignal);
|
|
9075
9487
|
(0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.resetKeyRotation)();
|
|
9076
9488
|
return;
|
|
9077
9489
|
}
|
|
9078
9490
|
catch (error) {
|
|
9491
|
+
// Check if it's an abort error
|
|
9492
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
9493
|
+
console.log('[ApiService] Chat stream aborted by user');
|
|
9494
|
+
throw error;
|
|
9495
|
+
}
|
|
9079
9496
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
9080
9497
|
lastError = error instanceof Error ? error : new Error(errorMsg);
|
|
9081
9498
|
if ((0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.isRateLimitError)(errorMsg) && request.llmConfig) {
|
|
@@ -9097,12 +9514,13 @@ class ApiService {
|
|
|
9097
9514
|
/**
|
|
9098
9515
|
* 단순 Chat 스트리밍 내부 구현 - /chat/stream 엔드포인트 사용
|
|
9099
9516
|
*/
|
|
9100
|
-
async sendChatStreamInternal(request, onChunk, onMetadata) {
|
|
9517
|
+
async sendChatStreamInternal(request, onChunk, onMetadata, abortSignal) {
|
|
9101
9518
|
const response = await fetch(`${this.baseUrl}/chat/stream`, {
|
|
9102
9519
|
method: 'POST',
|
|
9103
9520
|
headers: this.getHeaders(),
|
|
9104
9521
|
credentials: 'include',
|
|
9105
|
-
body: JSON.stringify(request)
|
|
9522
|
+
body: JSON.stringify(request),
|
|
9523
|
+
signal: abortSignal
|
|
9106
9524
|
});
|
|
9107
9525
|
if (!response.ok) {
|
|
9108
9526
|
const error = await response.text();
|
|
@@ -9624,6 +10042,23 @@ class ApiService {
|
|
|
9624
10042
|
}
|
|
9625
10043
|
return response.json();
|
|
9626
10044
|
}
|
|
10045
|
+
/**
|
|
10046
|
+
* Reset an agent thread (clear session and recreate agent)
|
|
10047
|
+
*/
|
|
10048
|
+
async resetAgent(threadId) {
|
|
10049
|
+
const response = await fetch(`${this.baseUrl}/agent/langchain/reset`, {
|
|
10050
|
+
method: 'POST',
|
|
10051
|
+
headers: this.getHeaders(),
|
|
10052
|
+
credentials: 'include',
|
|
10053
|
+
body: JSON.stringify({ thread_id: threadId })
|
|
10054
|
+
});
|
|
10055
|
+
if (!response.ok) {
|
|
10056
|
+
const error = await response.text();
|
|
10057
|
+
console.warn('[ApiService] Failed to reset agent:', error);
|
|
10058
|
+
return { status: 'error', message: error };
|
|
10059
|
+
}
|
|
10060
|
+
return response.json();
|
|
10061
|
+
}
|
|
9627
10062
|
async executeCommand(command, timeout, cwd, stdin, workspaceRoot) {
|
|
9628
10063
|
const response = await fetch(`${this.baseUrl}/execute-command`, {
|
|
9629
10064
|
method: 'POST',
|
|
@@ -10045,6 +10480,49 @@ class ApiService {
|
|
|
10045
10480
|
}
|
|
10046
10481
|
return response.json();
|
|
10047
10482
|
}
|
|
10483
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
10484
|
+
// Context Provider APIs (@file autocomplete)
|
|
10485
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
10486
|
+
/**
|
|
10487
|
+
* Get autocomplete options for context commands (@file, etc.)
|
|
10488
|
+
*/
|
|
10489
|
+
async getContextAutocomplete(options) {
|
|
10490
|
+
const params = new URLSearchParams();
|
|
10491
|
+
if (options?.partialCommand) {
|
|
10492
|
+
params.append('partialCommand', options.partialCommand);
|
|
10493
|
+
}
|
|
10494
|
+
if (options?.baseDir) {
|
|
10495
|
+
params.append('baseDir', options.baseDir);
|
|
10496
|
+
}
|
|
10497
|
+
const url = `${this.baseUrl}/context/autocomplete${params.toString() ? '?' + params.toString() : ''}`;
|
|
10498
|
+
console.log('[ApiService] getContextAutocomplete:', url);
|
|
10499
|
+
const response = await fetch(url, {
|
|
10500
|
+
method: 'GET',
|
|
10501
|
+
headers: this.getHeaders(),
|
|
10502
|
+
credentials: 'include'
|
|
10503
|
+
});
|
|
10504
|
+
if (!response.ok) {
|
|
10505
|
+
const error = await response.text();
|
|
10506
|
+
throw new Error(`Failed to get autocomplete options: ${error}`);
|
|
10507
|
+
}
|
|
10508
|
+
return response.json();
|
|
10509
|
+
}
|
|
10510
|
+
/**
|
|
10511
|
+
* List available context providers
|
|
10512
|
+
*/
|
|
10513
|
+
async listContextProviders() {
|
|
10514
|
+
const response = await fetch(`${this.baseUrl}/context/providers`, {
|
|
10515
|
+
method: 'GET',
|
|
10516
|
+
headers: this.getHeaders(),
|
|
10517
|
+
credentials: 'include'
|
|
10518
|
+
});
|
|
10519
|
+
if (!response.ok) {
|
|
10520
|
+
const error = await response.text();
|
|
10521
|
+
throw new Error(`Failed to list context providers: ${error}`);
|
|
10522
|
+
}
|
|
10523
|
+
const data = await response.json();
|
|
10524
|
+
return data.providers;
|
|
10525
|
+
}
|
|
10048
10526
|
}
|
|
10049
10527
|
|
|
10050
10528
|
|
|
@@ -11657,6 +12135,28 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
11657
12135
|
|
|
11658
12136
|
/***/ },
|
|
11659
12137
|
|
|
12138
|
+
/***/ "./node_modules/@mui/icons-material/esm/Description.js"
|
|
12139
|
+
/*!*************************************************************!*\
|
|
12140
|
+
!*** ./node_modules/@mui/icons-material/esm/Description.js ***!
|
|
12141
|
+
\*************************************************************/
|
|
12142
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
12143
|
+
|
|
12144
|
+
__webpack_require__.r(__webpack_exports__);
|
|
12145
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
12146
|
+
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
|
|
12147
|
+
/* harmony export */ });
|
|
12148
|
+
/* harmony import */ var _utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/createSvgIcon.js */ "./node_modules/@mui/material/utils/createSvgIcon.js");
|
|
12149
|
+
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-runtime */ "./node_modules/react/jsx-runtime.js");
|
|
12150
|
+
"use client";
|
|
12151
|
+
|
|
12152
|
+
|
|
12153
|
+
|
|
12154
|
+
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,_utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__["default"])(/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("path", {
|
|
12155
|
+
d: "M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8zm2 16H8v-2h8zm0-4H8v-2h8zm-3-5V3.5L18.5 9z"
|
|
12156
|
+
}), 'Description'));
|
|
12157
|
+
|
|
12158
|
+
/***/ },
|
|
12159
|
+
|
|
11660
12160
|
/***/ "./node_modules/@mui/icons-material/esm/Error.js"
|
|
11661
12161
|
/*!*******************************************************!*\
|
|
11662
12162
|
!*** ./node_modules/@mui/icons-material/esm/Error.js ***!
|
|
@@ -11723,6 +12223,28 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
11723
12223
|
|
|
11724
12224
|
/***/ },
|
|
11725
12225
|
|
|
12226
|
+
/***/ "./node_modules/@mui/icons-material/esm/Folder.js"
|
|
12227
|
+
/*!********************************************************!*\
|
|
12228
|
+
!*** ./node_modules/@mui/icons-material/esm/Folder.js ***!
|
|
12229
|
+
\********************************************************/
|
|
12230
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
12231
|
+
|
|
12232
|
+
__webpack_require__.r(__webpack_exports__);
|
|
12233
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
12234
|
+
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
|
|
12235
|
+
/* harmony export */ });
|
|
12236
|
+
/* harmony import */ var _utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/createSvgIcon.js */ "./node_modules/@mui/material/utils/createSvgIcon.js");
|
|
12237
|
+
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-runtime */ "./node_modules/react/jsx-runtime.js");
|
|
12238
|
+
"use client";
|
|
12239
|
+
|
|
12240
|
+
|
|
12241
|
+
|
|
12242
|
+
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,_utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__["default"])(/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("path", {
|
|
12243
|
+
d: "M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8z"
|
|
12244
|
+
}), 'Folder'));
|
|
12245
|
+
|
|
12246
|
+
/***/ },
|
|
12247
|
+
|
|
11726
12248
|
/***/ "./node_modules/@mui/icons-material/esm/GpsFixed.js"
|
|
11727
12249
|
/*!**********************************************************!*\
|
|
11728
12250
|
!*** ./node_modules/@mui/icons-material/esm/GpsFixed.js ***!
|
|
@@ -11767,6 +12289,28 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
11767
12289
|
|
|
11768
12290
|
/***/ },
|
|
11769
12291
|
|
|
12292
|
+
/***/ "./node_modules/@mui/icons-material/esm/InsertDriveFile.js"
|
|
12293
|
+
/*!*****************************************************************!*\
|
|
12294
|
+
!*** ./node_modules/@mui/icons-material/esm/InsertDriveFile.js ***!
|
|
12295
|
+
\*****************************************************************/
|
|
12296
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
12297
|
+
|
|
12298
|
+
__webpack_require__.r(__webpack_exports__);
|
|
12299
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
12300
|
+
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
|
|
12301
|
+
/* harmony export */ });
|
|
12302
|
+
/* harmony import */ var _utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/createSvgIcon.js */ "./node_modules/@mui/material/utils/createSvgIcon.js");
|
|
12303
|
+
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-runtime */ "./node_modules/react/jsx-runtime.js");
|
|
12304
|
+
"use client";
|
|
12305
|
+
|
|
12306
|
+
|
|
12307
|
+
|
|
12308
|
+
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,_utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__["default"])(/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("path", {
|
|
12309
|
+
d: "M6 2c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm7 7V3.5L18.5 9z"
|
|
12310
|
+
}), 'InsertDriveFile'));
|
|
12311
|
+
|
|
12312
|
+
/***/ },
|
|
12313
|
+
|
|
11770
12314
|
/***/ "./node_modules/@mui/icons-material/esm/Lightbulb.js"
|
|
11771
12315
|
/*!***********************************************************!*\
|
|
11772
12316
|
!*** ./node_modules/@mui/icons-material/esm/Lightbulb.js ***!
|
|
@@ -11878,4 +12422,4 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
11878
12422
|
/***/ }
|
|
11879
12423
|
|
|
11880
12424
|
}]);
|
|
11881
|
-
//# sourceMappingURL=lib_index_js.
|
|
12425
|
+
//# sourceMappingURL=lib_index_js.67505497667f9c0a763d.js.map
|