hdsp-jupyter-extension 2.0.28__py3-none-any.whl → 2.0.30__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/config/__init__.py +5 -0
- agent_server/config/server_config.py +213 -0
- agent_server/core/__init__.py +2 -2
- agent_server/core/llm_service.py +2 -3
- agent_server/main.py +4 -4
- agent_server/routers/agent.py +2 -2
- agent_server/routers/chat.py +31 -28
- agent_server/routers/config.py +8 -7
- agent_server/routers/langchain_agent.py +97 -79
- hdsp_agent_core/managers/config_manager.py +37 -87
- {hdsp_jupyter_extension-2.0.28.data → hdsp_jupyter_extension-2.0.30.data}/data/share/jupyter/labextensions/hdsp-agent/build_log.json +1 -1
- {hdsp_jupyter_extension-2.0.28.data → hdsp_jupyter_extension-2.0.30.data}/data/share/jupyter/labextensions/hdsp-agent/package.json +2 -2
- hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.55727265b00191e68d9a.js → hdsp_jupyter_extension-2.0.30.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.f2eca2f8fa682eb21f72.js +11 -12
- hdsp_jupyter_extension-2.0.30.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.f2eca2f8fa682eb21f72.js.map +1 -0
- jupyter_ext/labextension/static/lib_index_js.df05d90f366bfd5fa023.js → hdsp_jupyter_extension-2.0.30.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.cc0a7158a5e3de7f22f7.js +125 -949
- hdsp_jupyter_extension-2.0.30.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.cc0a7158a5e3de7f22f7.js.map +1 -0
- hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.08fce819ee32e9d25175.js → hdsp_jupyter_extension-2.0.30.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.f6cc904a0e9d0d4a9792.js +3 -3
- jupyter_ext/labextension/static/remoteEntry.08fce819ee32e9d25175.js.map → hdsp_jupyter_extension-2.0.30.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.f6cc904a0e9d0d4a9792.js.map +1 -1
- {hdsp_jupyter_extension-2.0.28.dist-info → hdsp_jupyter_extension-2.0.30.dist-info}/METADATA +1 -1
- {hdsp_jupyter_extension-2.0.28.dist-info → hdsp_jupyter_extension-2.0.30.dist-info}/RECORD +50 -48
- jupyter_ext/_version.py +1 -1
- jupyter_ext/labextension/build_log.json +1 -1
- jupyter_ext/labextension/package.json +2 -2
- jupyter_ext/labextension/static/{frontend_styles_index_js.55727265b00191e68d9a.js → frontend_styles_index_js.f2eca2f8fa682eb21f72.js} +11 -12
- jupyter_ext/labextension/static/frontend_styles_index_js.f2eca2f8fa682eb21f72.js.map +1 -0
- hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.df05d90f366bfd5fa023.js → jupyter_ext/labextension/static/lib_index_js.cc0a7158a5e3de7f22f7.js +125 -949
- jupyter_ext/labextension/static/lib_index_js.cc0a7158a5e3de7f22f7.js.map +1 -0
- jupyter_ext/labextension/static/{remoteEntry.08fce819ee32e9d25175.js → remoteEntry.f6cc904a0e9d0d4a9792.js} +3 -3
- hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.08fce819ee32e9d25175.js.map → jupyter_ext/labextension/static/remoteEntry.f6cc904a0e9d0d4a9792.js.map +1 -1
- hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.55727265b00191e68d9a.js.map +0 -1
- hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.df05d90f366bfd5fa023.js.map +0 -1
- jupyter_ext/labextension/static/frontend_styles_index_js.55727265b00191e68d9a.js.map +0 -1
- jupyter_ext/labextension/static/lib_index_js.df05d90f366bfd5fa023.js.map +0 -1
- {hdsp_jupyter_extension-2.0.28.data → hdsp_jupyter_extension-2.0.30.data}/data/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +0 -0
- {hdsp_jupyter_extension-2.0.28.data → hdsp_jupyter_extension-2.0.30.data}/data/share/jupyter/labextensions/hdsp-agent/install.json +0 -0
- {hdsp_jupyter_extension-2.0.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.data}/data/share/jupyter/labextensions/hdsp-agent/static/style.js +0 -0
- {hdsp_jupyter_extension-2.0.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js +0 -0
- {hdsp_jupyter_extension-2.0.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.data → hdsp_jupyter_extension-2.0.30.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.28.dist-info → hdsp_jupyter_extension-2.0.30.dist-info}/WHEEL +0 -0
- {hdsp_jupyter_extension-2.0.28.dist-info → hdsp_jupyter_extension-2.0.30.dist-info}/licenses/LICENSE +0 -0
|
@@ -30,10 +30,11 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
30
30
|
* - LLM Provider settings (API keys, models, endpoints)
|
|
31
31
|
* - Summarization LLM settings
|
|
32
32
|
* - Embedding configuration
|
|
33
|
-
* - RAG/Qdrant settings
|
|
34
33
|
* - User preferences (also editable by admin)
|
|
35
34
|
* - Agent prompts
|
|
36
35
|
* - Server settings
|
|
36
|
+
*
|
|
37
|
+
* Note: RAG/Qdrant URL is configured in Agent Server only (not exposed in UI)
|
|
37
38
|
*/
|
|
38
39
|
|
|
39
40
|
|
|
@@ -55,7 +56,6 @@ const AdminSettingsPanel = ({ onClose, onSave, apiService }) => {
|
|
|
55
56
|
llm: true,
|
|
56
57
|
summarization: false,
|
|
57
58
|
embedding: false,
|
|
58
|
-
rag: false,
|
|
59
59
|
user: true,
|
|
60
60
|
server: false,
|
|
61
61
|
prompts: false
|
|
@@ -91,10 +91,6 @@ const AdminSettingsPanel = ({ onClose, onSave, apiService }) => {
|
|
|
91
91
|
const [embeddingApiKey, setEmbeddingApiKey] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
92
92
|
const [embeddingEndpoint, setEmbeddingEndpoint] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
93
93
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
94
|
-
// RAG Settings
|
|
95
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
96
|
-
const [qdrantUrl, setQdrantUrl] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('http://localhost:6333');
|
|
97
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
98
94
|
// User Settings (also editable by admin)
|
|
99
95
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
100
96
|
const [workspaceRoot, setWorkspaceRoot] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
|
|
@@ -105,7 +101,7 @@ const AdminSettingsPanel = ({ onClose, onSave, apiService }) => {
|
|
|
105
101
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
106
102
|
const [agentServerUrl, setAgentServerUrl] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('http://localhost:8000');
|
|
107
103
|
const [agentServerTimeout, setAgentServerTimeout] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(120);
|
|
108
|
-
const [idleTimeout, setIdleTimeout] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(
|
|
104
|
+
const [idleTimeout, setIdleTimeout] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(3600); // Default: 1 hour
|
|
109
105
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
110
106
|
// Agent Prompts
|
|
111
107
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -171,14 +167,10 @@ const AdminSettingsPanel = ({ onClose, onSave, apiService }) => {
|
|
|
171
167
|
setEmbeddingApiKey(adminConfig.embedding.apiKey || '');
|
|
172
168
|
setEmbeddingEndpoint(adminConfig.embedding.endpoint || '');
|
|
173
169
|
}
|
|
174
|
-
// RAG
|
|
175
|
-
if (adminConfig.rag) {
|
|
176
|
-
setQdrantUrl(adminConfig.rag.qdrantUrl || 'http://localhost:6333');
|
|
177
|
-
}
|
|
178
170
|
// Server
|
|
179
171
|
setAgentServerUrl(adminConfig.agentServerUrl || 'http://localhost:8000');
|
|
180
172
|
setAgentServerTimeout(adminConfig.agentServerTimeout || 120);
|
|
181
|
-
setIdleTimeout(adminConfig.idleTimeout ||
|
|
173
|
+
setIdleTimeout(adminConfig.idleTimeout || 3600); // Default: 1 hour
|
|
182
174
|
// Prompts
|
|
183
175
|
if (adminConfig.prompts) {
|
|
184
176
|
setAgentPrompts(adminConfig.prompts);
|
|
@@ -236,10 +228,6 @@ const AdminSettingsPanel = ({ onClose, onSave, apiService }) => {
|
|
|
236
228
|
apiKey: embeddingApiKey || undefined,
|
|
237
229
|
...(embeddingProvider === 'vllm' ? { endpoint: embeddingEndpoint } : {})
|
|
238
230
|
},
|
|
239
|
-
rag: {
|
|
240
|
-
qdrantUrl,
|
|
241
|
-
collectionName: '' // Will be set by agent
|
|
242
|
-
},
|
|
243
231
|
agentServerUrl,
|
|
244
232
|
agentServerTimeout,
|
|
245
233
|
prompts: agentPrompts,
|
|
@@ -252,29 +240,13 @@ const AdminSettingsPanel = ({ onClose, onSave, apiService }) => {
|
|
|
252
240
|
temperature,
|
|
253
241
|
autoApprove
|
|
254
242
|
});
|
|
255
|
-
//
|
|
256
|
-
const
|
|
257
|
-
provider,
|
|
258
|
-
gemini: {
|
|
259
|
-
apiKey: geminiApiKeys[0] || '',
|
|
260
|
-
apiKeys: geminiApiKeys.filter(k => k && k.trim()),
|
|
261
|
-
model: geminiModel
|
|
262
|
-
},
|
|
263
|
-
openai: {
|
|
264
|
-
apiKey: openaiApiKey,
|
|
265
|
-
model: openaiModel
|
|
266
|
-
},
|
|
267
|
-
vllm: {
|
|
268
|
-
endpoint: vllmEndpoint,
|
|
269
|
-
apiKey: vllmApiKey,
|
|
270
|
-
model: vllmModel
|
|
271
|
-
},
|
|
243
|
+
// Save only user preferences to localStorage
|
|
244
|
+
const userPrefs = {
|
|
272
245
|
workspaceRoot: workspaceRoot.trim(),
|
|
273
|
-
autoApprove
|
|
274
|
-
agentPrompts
|
|
246
|
+
autoApprove
|
|
275
247
|
};
|
|
276
|
-
(0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_10__.saveLLMConfig)(
|
|
277
|
-
console.log('[AdminSettingsPanel]
|
|
248
|
+
(0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_10__.saveLLMConfig)(userPrefs);
|
|
249
|
+
console.log('[AdminSettingsPanel] User preferences saved to localStorage');
|
|
278
250
|
onSave(adminConfig);
|
|
279
251
|
onClose();
|
|
280
252
|
}
|
|
@@ -478,12 +450,6 @@ const AdminSettingsPanel = ({ onClose, onSave, apiService }) => {
|
|
|
478
450
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-admin-row" },
|
|
479
451
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-admin-label" }, "\uBAA8\uB378"),
|
|
480
452
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", className: "jp-admin-input", value: embeddingModel, onChange: (e) => setEmbeddingModel(e.target.value), placeholder: "text-embedding-3-small" }))))),
|
|
481
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-admin-section" },
|
|
482
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(SectionHeader, { title: "RAG / Qdrant", sectionKey: "rag", subtitle: "\uBCA1\uD130 \uB370\uC774\uD130\uBCA0\uC774\uC2A4" }),
|
|
483
|
-
expandedSections.rag && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-admin-section-content" },
|
|
484
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-admin-row" },
|
|
485
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-admin-label" }, "Qdrant URL"),
|
|
486
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", className: "jp-admin-input", value: qdrantUrl, onChange: (e) => setQdrantUrl(e.target.value), placeholder: "http://localhost:6333" }))))),
|
|
487
453
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-admin-section" },
|
|
488
454
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(SectionHeader, { title: "\uC11C\uBC84 \uC124\uC815", sectionKey: "server", subtitle: "Agent \uC11C\uBC84, \uD0C0\uC784\uC544\uC6C3" }),
|
|
489
455
|
expandedSections.server && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-admin-section-content" },
|
|
@@ -1297,22 +1263,11 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
1297
1263
|
return;
|
|
1298
1264
|
}
|
|
1299
1265
|
setLlmConfig(config);
|
|
1300
|
-
// Log loaded
|
|
1301
|
-
console.log('=== HDSP Agent
|
|
1302
|
-
console.log('
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
console.log('Gemini API Key:', config.gemini?.apiKey ? '✓ Configured' : '✗ Not configured');
|
|
1306
|
-
}
|
|
1307
|
-
else if (config.provider === 'vllm') {
|
|
1308
|
-
console.log('vLLM Model:', config.vllm?.model || 'default');
|
|
1309
|
-
console.log('vLLM Endpoint:', config.vllm?.endpoint || 'http://localhost:8000/v1');
|
|
1310
|
-
console.log('vLLM API Key:', config.vllm?.apiKey ? '✓ Configured' : '✗ Not configured');
|
|
1311
|
-
}
|
|
1312
|
-
else if (config.provider === 'openai') {
|
|
1313
|
-
console.log('OpenAI Model:', config.openai?.model || 'gpt-4');
|
|
1314
|
-
console.log('OpenAI API Key:', config.openai?.apiKey ? '✓ Configured' : '✗ Not configured');
|
|
1315
|
-
}
|
|
1266
|
+
// Log loaded user preferences (LLM settings now come from server AdminConfig)
|
|
1267
|
+
console.log('=== HDSP Agent User Preferences (localStorage) ===');
|
|
1268
|
+
console.log('Workspace Root:', config.workspaceRoot || '(default)');
|
|
1269
|
+
console.log('Auto Approve:', config.autoApprove ? '✓ Enabled' : '✗ Disabled');
|
|
1270
|
+
console.log('Note: LLM settings are managed by Agent Server AdminConfig');
|
|
1316
1271
|
console.log('====================================================');
|
|
1317
1272
|
};
|
|
1318
1273
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -1504,14 +1459,14 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
1504
1459
|
setMessages(prev => [...prev, errorMessage]);
|
|
1505
1460
|
};
|
|
1506
1461
|
const handleSaveConfig = (config) => {
|
|
1507
|
-
console.log('[AgentPanel] Saving
|
|
1508
|
-
console.log('
|
|
1509
|
-
console.log('
|
|
1462
|
+
console.log('[AgentPanel] Saving user preferences to localStorage');
|
|
1463
|
+
console.log('Workspace Root:', config.workspaceRoot || '(default)');
|
|
1464
|
+
console.log('Auto Approve:', config.autoApprove ? '✓ Enabled' : '✗ Disabled');
|
|
1510
1465
|
// Save to localStorage using ApiKeyManager
|
|
1511
1466
|
(0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_6__.saveLLMConfig)(config);
|
|
1512
1467
|
// Update state
|
|
1513
1468
|
setLlmConfig(config);
|
|
1514
|
-
console.log('[AgentPanel]
|
|
1469
|
+
console.log('[AgentPanel] User preferences saved successfully');
|
|
1515
1470
|
};
|
|
1516
1471
|
// File selection handlers (simplified - old agent mode removed)
|
|
1517
1472
|
const handleFileSelect = async (index) => {
|
|
@@ -1726,22 +1681,8 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
1726
1681
|
currentConfig = (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_6__.getLLMConfig)() || (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_6__.getDefaultLLMConfig)();
|
|
1727
1682
|
setLlmConfig(currentConfig);
|
|
1728
1683
|
}
|
|
1729
|
-
//
|
|
1730
|
-
const hasApiKey = (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_6__.hasValidApiKey)(currentConfig);
|
|
1684
|
+
// Get user preferences (API keys are now managed by Agent Server)
|
|
1731
1685
|
const autoApproveEnabled = getAutoApproveEnabled(currentConfig);
|
|
1732
|
-
if (!hasApiKey) {
|
|
1733
|
-
// Show error message and open settings
|
|
1734
|
-
const providerName = currentConfig?.provider || 'LLM';
|
|
1735
|
-
const errorMessage = {
|
|
1736
|
-
id: makeMessageId(),
|
|
1737
|
-
role: 'assistant',
|
|
1738
|
-
content: `API Key가 설정되지 않았습니다.\n\n${providerName === 'gemini' ? 'Gemini' : providerName === 'openai' ? 'OpenAI' : 'vLLM'} API Key를 먼저 설정해주세요.\n\n설정 버튼을 클릭하여 API Key를 입력하세요.`,
|
|
1739
|
-
timestamp: Date.now()
|
|
1740
|
-
};
|
|
1741
|
-
setMessages(prev => [...prev, errorMessage]);
|
|
1742
|
-
setShowSettings(true);
|
|
1743
|
-
return;
|
|
1744
|
-
}
|
|
1745
1686
|
const userMessage = {
|
|
1746
1687
|
id: makeMessageId(),
|
|
1747
1688
|
role: 'user',
|
|
@@ -3863,7 +3804,7 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
3863
3804
|
setTimeout(() => {
|
|
3864
3805
|
const textarea = document.querySelector('.jp-agent-input');
|
|
3865
3806
|
if (textarea) {
|
|
3866
|
-
textarea.placeholder = '
|
|
3807
|
+
textarea.placeholder = '메세지를 입력하세요.';
|
|
3867
3808
|
}
|
|
3868
3809
|
}, 100);
|
|
3869
3810
|
// Resume with user response passed as feedback
|
|
@@ -4201,7 +4142,13 @@ SyntaxError: '(' was never closed
|
|
|
4201
4142
|
};
|
|
4202
4143
|
// Execute /help action - Display help guide (no LLM call)
|
|
4203
4144
|
const executeHelpAction = () => {
|
|
4204
|
-
|
|
4145
|
+
// Create logo with 60px height for help content (use base64 data URL)
|
|
4146
|
+
const svgBase64 = btoa(unescape(encodeURIComponent(_logoSvg__WEBPACK_IMPORTED_MODULE_14__.headerLogoSvg)));
|
|
4147
|
+
const helpContent = `<div style="text-align: center; margin-bottom: 16px;"><img src="data:image/svg+xml;base64,${svgBase64}" style="max-width: 50%; height: auto;" alt="HALO Logo" /></div>
|
|
4148
|
+
|
|
4149
|
+
## HALO 사용 가이드
|
|
4150
|
+
|
|
4151
|
+
**HALO**는 **H**DSP **A**ssistant with **L**LM **O**perator의 약자로, LLM 기반의 지능형 데이터 분석 어시스턴트입니다. JupyterLab 환경에서 AI와 대화하며 데이터 분석, 코드 작성, 문제 해결을 도와받을 수 있습니다.
|
|
4205
4152
|
|
|
4206
4153
|
### 사용 가능한 명령어
|
|
4207
4154
|
|
|
@@ -4713,7 +4660,7 @@ Jupyter 노트북의 각 코드 셀 옆에 있는 아이콘 버튼을 활용하
|
|
|
4713
4660
|
? '다른 방향 제시'
|
|
4714
4661
|
: (inputMode === 'agent'
|
|
4715
4662
|
? '노트북 작업을 입력하세요... (예: @file:path로 파일 참조)'
|
|
4716
|
-
: '
|
|
4663
|
+
: '메세지를 입력하세요.'), disabled: isLoading || isAgentRunning }),
|
|
4717
4664
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-button-container" }, inputMode === 'chat' && isStreaming ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "jp-agent-stop-button", onClick: stopCurrentTask, title: "\uC751\uB2F5 \uC911\uB2E8 (Esc)" },
|
|
4718
4665
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("svg", { viewBox: "0 0 24 24", fill: "currentColor", width: "14", height: "14" },
|
|
4719
4666
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("rect", { x: "6", y: "6", width: "12", height: "12", rx: "1" })),
|
|
@@ -5405,450 +5352,65 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
5405
5352
|
/* harmony export */ });
|
|
5406
5353
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react");
|
|
5407
5354
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
5408
|
-
/* harmony import */ var
|
|
5409
|
-
/* harmony import */ var _mui_icons_material_Error__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @mui/icons-material/Error */ "./node_modules/@mui/icons-material/esm/Error.js");
|
|
5410
|
-
/* harmony import */ var _mui_icons_material_HourglassEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @mui/icons-material/HourglassEmpty */ "./node_modules/@mui/icons-material/esm/HourglassEmpty.js");
|
|
5411
|
-
/* harmony import */ var _mui_icons_material_Code__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @mui/icons-material/Code */ "./node_modules/@mui/icons-material/esm/Code.js");
|
|
5412
|
-
/* harmony import */ var _mui_icons_material_Search__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @mui/icons-material/Search */ "./node_modules/@mui/icons-material/esm/Search.js");
|
|
5413
|
-
/* harmony import */ var _mui_icons_material_Analytics__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @mui/icons-material/Analytics */ "./node_modules/@mui/icons-material/esm/Analytics.js");
|
|
5414
|
-
/* harmony import */ var _mui_icons_material_GpsFixed__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @mui/icons-material/GpsFixed */ "./node_modules/@mui/icons-material/esm/GpsFixed.js");
|
|
5415
|
-
/* harmony import */ var _mui_icons_material_ExpandMore__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @mui/icons-material/ExpandMore */ "./node_modules/@mui/icons-material/esm/ExpandMore.js");
|
|
5416
|
-
/* harmony import */ var _mui_icons_material_ChevronRight__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @mui/icons-material/ChevronRight */ "./node_modules/@mui/icons-material/esm/ChevronRight.js");
|
|
5417
|
-
/* harmony import */ var _services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../services/ApiKeyManager */ "./lib/services/ApiKeyManager.js");
|
|
5355
|
+
/* harmony import */ var _services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../services/ApiKeyManager */ "./lib/services/ApiKeyManager.js");
|
|
5418
5356
|
/**
|
|
5419
5357
|
* Settings Panel Component
|
|
5420
|
-
*
|
|
5358
|
+
* User preference settings panel
|
|
5421
5359
|
*
|
|
5422
|
-
*
|
|
5423
|
-
*
|
|
5360
|
+
* NOTE: LLM settings (provider, API keys, models, prompts) are now managed
|
|
5361
|
+
* by the Agent Server's AdminConfig. This panel only handles user preferences:
|
|
5362
|
+
* - workspaceRoot: User's workspace directory
|
|
5363
|
+
* - autoApprove: Skip human approval for code execution
|
|
5424
5364
|
*/
|
|
5425
5365
|
|
|
5426
5366
|
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
5367
|
const SettingsPanel = ({ onClose, onSave, currentConfig }) => {
|
|
5437
5368
|
// Initialize from localStorage or props
|
|
5438
|
-
const initConfig = currentConfig || (0,
|
|
5439
|
-
|
|
5440
|
-
const [isTesting, setIsTesting] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
|
|
5441
|
-
const [testResults, setTestResults] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({});
|
|
5442
|
-
// Track active key index (first valid key by default)
|
|
5443
|
-
const [activeKeyIndex, setActiveKeyIndex] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(0);
|
|
5444
|
-
// Gemini settings - support multiple keys (max 10)
|
|
5445
|
-
const [geminiApiKeys, setGeminiApiKeys] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.gemini?.apiKeys?.length
|
|
5446
|
-
? initConfig.gemini.apiKeys
|
|
5447
|
-
: initConfig.gemini?.apiKey
|
|
5448
|
-
? [initConfig.gemini.apiKey]
|
|
5449
|
-
: ['']);
|
|
5450
|
-
// Legacy single key for backward compatibility
|
|
5451
|
-
const geminiApiKey = geminiApiKeys[0] || '';
|
|
5452
|
-
// Validate gemini model - only allow valid options
|
|
5453
|
-
const validateGeminiModel = (model) => {
|
|
5454
|
-
const validModels = ['gemini-2.5-pro', 'gemini-2.5-flash'];
|
|
5455
|
-
if (model && validModels.includes(model)) {
|
|
5456
|
-
return model;
|
|
5457
|
-
}
|
|
5458
|
-
return 'gemini-2.5-flash';
|
|
5459
|
-
};
|
|
5460
|
-
const [geminiModel, setGeminiModel] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(validateGeminiModel(initConfig.gemini?.model));
|
|
5461
|
-
// vLLM settings
|
|
5462
|
-
const [vllmEndpoint, setVllmEndpoint] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.vllm?.endpoint || 'http://localhost:8000/v1');
|
|
5463
|
-
const [vllmApiKey, setVllmApiKey] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.vllm?.apiKey || '');
|
|
5464
|
-
const [vllmModel, setVllmModel] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.vllm?.model || 'meta-llama/Llama-2-7b-chat-hf');
|
|
5465
|
-
const [vllmUseResponsesApi, setVllmUseResponsesApi] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(Boolean(initConfig.vllm?.useResponsesApi));
|
|
5466
|
-
const [vllmTemperature, setVllmTemperature] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.vllm?.temperature ?? 0.0);
|
|
5467
|
-
// OpenAI settings
|
|
5468
|
-
const [openaiApiKey, setOpenaiApiKey] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.openai?.apiKey || '');
|
|
5469
|
-
const [openaiModel, setOpenaiModel] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.openai?.model || 'gpt-4');
|
|
5470
|
-
const [systemPrompt, setSystemPrompt] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.systemPrompt || '');
|
|
5369
|
+
const initConfig = currentConfig || (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_1__.getLLMConfig)() || (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_1__.getDefaultLLMConfig)();
|
|
5370
|
+
// User preferences (the only settings stored in localStorage)
|
|
5471
5371
|
const [workspaceRoot, setWorkspaceRoot] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.workspaceRoot || '');
|
|
5472
5372
|
const [autoApprove, setAutoApprove] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(Boolean(initConfig.autoApprove));
|
|
5473
|
-
const [idleTimeoutMinutes, setIdleTimeoutMinutes] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.idleTimeoutMinutes ?? 60);
|
|
5474
|
-
// Multi-Agent settings
|
|
5475
|
-
const [agentPrompts, setAgentPrompts] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.agentPrompts || {});
|
|
5476
|
-
const [expandedAgents, setExpandedAgents] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({});
|
|
5477
|
-
// Summarization LLM settings
|
|
5478
|
-
const [summarizationEnabled, setSummarizationEnabled] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(Boolean(initConfig.summarization?.enabled));
|
|
5479
|
-
const [summarizationProvider, setSummarizationProvider] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.summarization?.provider || 'gemini');
|
|
5480
|
-
const [summarizationModel, setSummarizationModel] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(initConfig.summarization?.model || '');
|
|
5481
|
-
// Default prompts fetched from API
|
|
5482
|
-
const [defaultPrompts, setDefaultPrompts] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)((0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_10__.getCachedPrompts)());
|
|
5483
|
-
const [isLoadingPrompts, setIsLoadingPrompts] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(!(0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_10__.getCachedPrompts)());
|
|
5484
|
-
// Fetch default prompts from API on mount
|
|
5485
|
-
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
5486
|
-
if (!defaultPrompts) {
|
|
5487
|
-
setIsLoadingPrompts(true);
|
|
5488
|
-
(0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_10__.fetchDefaultPrompts)().then(prompts => {
|
|
5489
|
-
setDefaultPrompts(prompts);
|
|
5490
|
-
setIsLoadingPrompts(false);
|
|
5491
|
-
});
|
|
5492
|
-
}
|
|
5493
|
-
}, []);
|
|
5494
5373
|
// Update state when currentConfig changes
|
|
5495
5374
|
(0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
|
|
5496
5375
|
if (currentConfig) {
|
|
5497
|
-
setProvider(currentConfig.provider || 'gemini');
|
|
5498
|
-
// Handle multiple keys
|
|
5499
|
-
if (currentConfig.gemini?.apiKeys?.length) {
|
|
5500
|
-
setGeminiApiKeys(currentConfig.gemini.apiKeys);
|
|
5501
|
-
}
|
|
5502
|
-
else if (currentConfig.gemini?.apiKey) {
|
|
5503
|
-
setGeminiApiKeys([currentConfig.gemini.apiKey]);
|
|
5504
|
-
}
|
|
5505
|
-
else {
|
|
5506
|
-
setGeminiApiKeys(['']);
|
|
5507
|
-
}
|
|
5508
|
-
setGeminiModel(validateGeminiModel(currentConfig.gemini?.model));
|
|
5509
|
-
setVllmEndpoint(currentConfig.vllm?.endpoint || 'http://localhost:8000/v1');
|
|
5510
|
-
setVllmApiKey(currentConfig.vllm?.apiKey || '');
|
|
5511
|
-
setVllmModel(currentConfig.vllm?.model || 'meta-llama/Llama-2-7b-chat-hf');
|
|
5512
|
-
setVllmUseResponsesApi(Boolean(currentConfig.vllm?.useResponsesApi));
|
|
5513
|
-
setVllmTemperature(currentConfig.vllm?.temperature ?? 0.0);
|
|
5514
|
-
setOpenaiApiKey(currentConfig.openai?.apiKey || '');
|
|
5515
|
-
setOpenaiModel(currentConfig.openai?.model || 'gpt-4');
|
|
5516
|
-
setSystemPrompt(currentConfig.systemPrompt || (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_10__.getDefaultLLMConfig)().systemPrompt || '');
|
|
5517
5376
|
setWorkspaceRoot(currentConfig.workspaceRoot || '');
|
|
5518
5377
|
setAutoApprove(Boolean(currentConfig.autoApprove));
|
|
5519
|
-
setIdleTimeoutMinutes(currentConfig.idleTimeoutMinutes ?? 60);
|
|
5520
|
-
// Use currentConfig prompts, or cached defaults, or empty object
|
|
5521
|
-
const cachedDefaults = (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_10__.getCachedPrompts)();
|
|
5522
|
-
setAgentPrompts(currentConfig.agentPrompts || (cachedDefaults ? {
|
|
5523
|
-
planner: cachedDefaults.planner,
|
|
5524
|
-
python_developer: cachedDefaults.python_developer,
|
|
5525
|
-
researcher: cachedDefaults.researcher,
|
|
5526
|
-
athena_query: cachedDefaults.athena_query,
|
|
5527
|
-
} : {}));
|
|
5528
|
-
// Summarization settings
|
|
5529
|
-
setSummarizationEnabled(Boolean(currentConfig.summarization?.enabled));
|
|
5530
|
-
setSummarizationProvider(currentConfig.summarization?.provider || 'gemini');
|
|
5531
|
-
setSummarizationModel(currentConfig.summarization?.model || '');
|
|
5532
5378
|
}
|
|
5533
5379
|
}, [currentConfig]);
|
|
5534
|
-
//
|
|
5380
|
+
// Build config from state
|
|
5535
5381
|
const buildLLMConfig = () => ({
|
|
5536
|
-
provider,
|
|
5537
|
-
gemini: {
|
|
5538
|
-
apiKey: geminiApiKeys[0] || '',
|
|
5539
|
-
apiKeys: geminiApiKeys.filter(k => k && k.trim()),
|
|
5540
|
-
model: geminiModel
|
|
5541
|
-
},
|
|
5542
|
-
vllm: {
|
|
5543
|
-
endpoint: vllmEndpoint,
|
|
5544
|
-
apiKey: vllmApiKey,
|
|
5545
|
-
model: vllmModel,
|
|
5546
|
-
useResponsesApi: vllmUseResponsesApi,
|
|
5547
|
-
temperature: vllmTemperature
|
|
5548
|
-
},
|
|
5549
|
-
openai: {
|
|
5550
|
-
apiKey: openaiApiKey,
|
|
5551
|
-
model: openaiModel
|
|
5552
|
-
},
|
|
5553
5382
|
workspaceRoot: workspaceRoot.trim() ? workspaceRoot.trim() : undefined,
|
|
5554
|
-
|
|
5555
|
-
agentPrompts,
|
|
5556
|
-
summarization: summarizationEnabled ? {
|
|
5557
|
-
enabled: true,
|
|
5558
|
-
provider: summarizationProvider,
|
|
5559
|
-
model: summarizationModel.trim() || undefined,
|
|
5560
|
-
} : undefined,
|
|
5561
|
-
autoApprove,
|
|
5562
|
-
idleTimeoutMinutes
|
|
5383
|
+
autoApprove
|
|
5563
5384
|
});
|
|
5564
|
-
// Handlers for multiple API keys
|
|
5565
|
-
const handleAddKey = () => {
|
|
5566
|
-
if (geminiApiKeys.length < 10) {
|
|
5567
|
-
setGeminiApiKeys([...geminiApiKeys, '']);
|
|
5568
|
-
}
|
|
5569
|
-
};
|
|
5570
|
-
const handleRemoveKey = (index) => {
|
|
5571
|
-
if (geminiApiKeys.length > 1) {
|
|
5572
|
-
const newKeys = geminiApiKeys.filter((_, i) => i !== index);
|
|
5573
|
-
setGeminiApiKeys(newKeys);
|
|
5574
|
-
}
|
|
5575
|
-
};
|
|
5576
|
-
const handleKeyChange = (index, value) => {
|
|
5577
|
-
const newKeys = [...geminiApiKeys];
|
|
5578
|
-
newKeys[index] = value;
|
|
5579
|
-
setGeminiApiKeys(newKeys);
|
|
5580
|
-
};
|
|
5581
|
-
const validKeyCount = geminiApiKeys.filter(k => k && k.trim()).length;
|
|
5582
|
-
const handleTest = async () => {
|
|
5583
|
-
setIsTesting(true);
|
|
5584
|
-
setTestResults({});
|
|
5585
|
-
if (provider === 'gemini') {
|
|
5586
|
-
// Test each Gemini key individually
|
|
5587
|
-
const validKeys = geminiApiKeys.map((k, i) => ({ key: k, index: i }))
|
|
5588
|
-
.filter(({ key }) => key && key.trim());
|
|
5589
|
-
for (const { key, index } of validKeys) {
|
|
5590
|
-
setTestResults(prev => ({ ...prev, [index]: 'testing' }));
|
|
5591
|
-
const testConfig = {
|
|
5592
|
-
provider: 'gemini',
|
|
5593
|
-
gemini: { apiKey: key, apiKeys: [key], model: geminiModel }
|
|
5594
|
-
};
|
|
5595
|
-
try {
|
|
5596
|
-
const result = await (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_10__.testApiKey)(testConfig);
|
|
5597
|
-
setTestResults(prev => ({ ...prev, [index]: result.success ? 'success' : 'error' }));
|
|
5598
|
-
}
|
|
5599
|
-
catch {
|
|
5600
|
-
setTestResults(prev => ({ ...prev, [index]: 'error' }));
|
|
5601
|
-
}
|
|
5602
|
-
}
|
|
5603
|
-
}
|
|
5604
|
-
else {
|
|
5605
|
-
// For other providers, just test the single config
|
|
5606
|
-
try {
|
|
5607
|
-
const config = buildLLMConfig();
|
|
5608
|
-
const result = await (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_10__.testApiKey)(config);
|
|
5609
|
-
setTestResults({ 0: result.success ? 'success' : 'error' });
|
|
5610
|
-
}
|
|
5611
|
-
catch {
|
|
5612
|
-
setTestResults({ 0: 'error' });
|
|
5613
|
-
}
|
|
5614
|
-
}
|
|
5615
|
-
setIsTesting(false);
|
|
5616
|
-
};
|
|
5617
|
-
// Handle clicking a key row to set it as active
|
|
5618
|
-
const handleSetActiveKey = (index) => {
|
|
5619
|
-
if (geminiApiKeys[index] && geminiApiKeys[index].trim()) {
|
|
5620
|
-
setActiveKeyIndex(index);
|
|
5621
|
-
}
|
|
5622
|
-
};
|
|
5623
5385
|
const handleSave = () => {
|
|
5624
5386
|
const config = buildLLMConfig();
|
|
5625
5387
|
// Save to localStorage
|
|
5626
|
-
(0,
|
|
5388
|
+
(0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_1__.saveLLMConfig)(config);
|
|
5627
5389
|
// Notify parent component
|
|
5628
5390
|
onSave(config);
|
|
5629
5391
|
onClose();
|
|
5630
5392
|
};
|
|
5631
|
-
// Get test status icon for a key
|
|
5632
|
-
const getTestStatusIcon = (index) => {
|
|
5633
|
-
const status = testResults[index];
|
|
5634
|
-
if (status === 'testing')
|
|
5635
|
-
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_HourglassEmpty__WEBPACK_IMPORTED_MODULE_3__["default"], { sx: { fontSize: 16, color: 'info.main' } });
|
|
5636
|
-
if (status === 'success')
|
|
5637
|
-
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_CheckCircle__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { fontSize: 16, color: 'success.main' } });
|
|
5638
|
-
if (status === 'error')
|
|
5639
|
-
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_Error__WEBPACK_IMPORTED_MODULE_2__["default"], { sx: { fontSize: 16, color: 'error.main' } });
|
|
5640
|
-
return null;
|
|
5641
|
-
};
|
|
5642
5393
|
return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-overlay" },
|
|
5643
5394
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-dialog" },
|
|
5644
5395
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-header" },
|
|
5645
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h2", null, "
|
|
5396
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h2", null, "\uC0AC\uC6A9\uC790 \uC124\uC815"),
|
|
5646
5397
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "jp-agent-settings-close", onClick: onClose, title: "\uB2EB\uAE30" }, "\u00D7")),
|
|
5647
5398
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-content" },
|
|
5648
5399
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-notice" },
|
|
5649
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "
|
|
5650
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5651
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" }, "\uD504\uB85C\uBC14\uC774\uB354"),
|
|
5652
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("select", { className: "jp-agent-settings-select", value: provider, onChange: (e) => setProvider(e.target.value) },
|
|
5653
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { value: "gemini" }, "Google Gemini"),
|
|
5654
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { value: "vllm" }, "vLLM"),
|
|
5655
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { value: "openai" }, "OpenAI"))),
|
|
5400
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "LLM \uC124\uC815 (\uD504\uB85C\uBC14\uC774\uB354, API \uD0A4, \uBAA8\uB378, \uD504\uB86C\uD504\uD2B8)\uC740 \uAD00\uB9AC\uC790 \uC124\uC815\uC5D0\uC11C \uAD00\uB9AC\uB429\uB2C8\uB2E4.")),
|
|
5656
5401
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5657
5402
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label", htmlFor: "jp-agent-workspace-root" },
|
|
5658
5403
|
"\uC6CC\uD06C\uC2A4\uD398\uC774\uC2A4 \uB8E8\uD2B8",
|
|
5659
5404
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { style: { fontWeight: 'normal', marginLeft: '8px', color: '#666' } }, "\uBE44\uC6B0\uBA74 \uD604\uC7AC \uB178\uD2B8\uBD81 \uD3F4\uB354 \uAE30\uC900, \uC808\uB300/\uC0C1\uB300 \uACBD\uB85C \uAC00\uB2A5")),
|
|
5660
5405
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { id: "jp-agent-workspace-root", type: "text", className: "jp-agent-settings-input", value: workspaceRoot, onChange: (e) => setWorkspaceRoot(e.target.value), placeholder: "\uC608: /Users/you/project", "data-testid": "workspace-root-input" })),
|
|
5661
|
-
provider === 'gemini' && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-provider" },
|
|
5662
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h3", null, "Gemini \uC124\uC815"),
|
|
5663
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5664
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" },
|
|
5665
|
-
"API \uD0A4 (",
|
|
5666
|
-
validKeyCount,
|
|
5667
|
-
"/10)",
|
|
5668
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { style: { fontWeight: 'normal', marginLeft: '8px', color: '#666' } }, "Rate limit \uC2DC \uC790\uB3D9 \uB85C\uD14C\uC774\uC158")),
|
|
5669
|
-
geminiApiKeys.map((key, index) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { key: index, className: "jp-agent-settings-key-row", style: {
|
|
5670
|
-
display: 'flex',
|
|
5671
|
-
gap: '8px',
|
|
5672
|
-
marginBottom: '8px',
|
|
5673
|
-
alignItems: 'center',
|
|
5674
|
-
padding: '4px',
|
|
5675
|
-
borderRadius: '4px',
|
|
5676
|
-
background: activeKeyIndex === index && key && key.trim() ? 'rgba(66, 133, 244, 0.1)' : 'transparent',
|
|
5677
|
-
border: activeKeyIndex === index && key && key.trim() ? '1px solid rgba(66, 133, 244, 0.3)' : '1px solid transparent'
|
|
5678
|
-
} },
|
|
5679
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "radio", name: "activeKey", checked: activeKeyIndex === index && key && key.trim() !== '', onChange: () => handleSetActiveKey(index), disabled: !key || !key.trim(), title: "\uD65C\uC131 \uD0A4\uB85C \uC124\uC815", style: { cursor: key && key.trim() ? 'pointer' : 'default' } }),
|
|
5680
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { style: {
|
|
5681
|
-
minWidth: '20px',
|
|
5682
|
-
color: '#666',
|
|
5683
|
-
fontSize: '12px'
|
|
5684
|
-
} },
|
|
5685
|
-
index + 1,
|
|
5686
|
-
"."),
|
|
5687
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "password", className: "jp-agent-settings-input", style: { flex: 1 }, value: key, onChange: (e) => handleKeyChange(index, e.target.value), placeholder: "AIza..." }),
|
|
5688
|
-
getTestStatusIcon(index) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { style: { fontSize: '14px', minWidth: '20px' } }, getTestStatusIcon(index))),
|
|
5689
|
-
geminiApiKeys.length > 1 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { type: "button", className: "jp-agent-settings-button-icon", onClick: () => handleRemoveKey(index), title: "\uD0A4 \uC0AD\uC81C", style: {
|
|
5690
|
-
padding: '4px 8px',
|
|
5691
|
-
background: '#ff4444',
|
|
5692
|
-
color: 'white',
|
|
5693
|
-
border: 'none',
|
|
5694
|
-
borderRadius: '4px',
|
|
5695
|
-
cursor: 'pointer'
|
|
5696
|
-
} }, "\u00D7"))))),
|
|
5697
|
-
geminiApiKeys.length < 10 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { type: "button", className: "jp-agent-settings-button jp-agent-settings-button-secondary", onClick: handleAddKey, style: { marginTop: '8px' } }, "+ \uD0A4 \uCD94\uAC00"))),
|
|
5698
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5699
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" }, "\uBAA8\uB378"),
|
|
5700
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("select", { className: "jp-agent-settings-select", value: geminiModel, onChange: (e) => setGeminiModel(e.target.value) },
|
|
5701
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { value: "gemini-2.5-flash" }, "Gemini 2.5 Flash"),
|
|
5702
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { value: "gemini-2.5-pro" }, "Gemini 2.5 Pro"))))),
|
|
5703
|
-
provider === 'vllm' && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-provider" },
|
|
5704
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h3", null, "vLLM / OpenAI Compatible \uC124\uC815"),
|
|
5705
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5706
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" }, "API Base URL (\uC804\uCCB4 \uACBD\uB85C \uC785\uB825)"),
|
|
5707
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", className: "jp-agent-settings-input", value: vllmEndpoint, onChange: (e) => setVllmEndpoint(e.target.value), placeholder: "https://openrouter.ai/api/v1" })),
|
|
5708
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5709
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" }, "API \uD0A4 (\uC120\uD0DD\uC0AC\uD56D)"),
|
|
5710
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "password", className: "jp-agent-settings-input", value: vllmApiKey, onChange: (e) => setVllmApiKey(e.target.value), placeholder: "API \uD0A4\uAC00 \uD544\uC694\uD55C \uACBD\uC6B0 \uC785\uB825" })),
|
|
5711
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5712
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" }, "\uBAA8\uB378 \uC774\uB984"),
|
|
5713
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", className: "jp-agent-settings-input", value: vllmModel, onChange: (e) => setVllmModel(e.target.value), placeholder: "meta-llama/Llama-2-7b-chat-hf" })),
|
|
5714
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5715
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" }, "Temperature"),
|
|
5716
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "number", className: "jp-agent-settings-input", value: vllmTemperature, onChange: (e) => setVllmTemperature(Math.max(0, Math.min(2, parseFloat(e.target.value) || 0))), min: 0, max: 2, step: 0.1, style: { width: '100px' } }),
|
|
5717
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { style: { color: '#666', marginLeft: '8px' } }, "0.0 = \uACB0\uC815\uC801, 1.0+ = \uCC3D\uC758\uC801")),
|
|
5718
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5719
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-checkbox" },
|
|
5720
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "checkbox", checked: vllmUseResponsesApi, onChange: (e) => setVllmUseResponsesApi(e.target.checked) }),
|
|
5721
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "Use Responses API (/v1/responses)")),
|
|
5722
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { style: { color: '#666', display: 'block', marginTop: '4px' } }, "OpenAI Responses API\uB97C \uC9C0\uC6D0\uD558\uB294 \uC5D4\uB4DC\uD3EC\uC778\uD2B8\uC5D0\uC11C \uC0AC\uC6A9")))),
|
|
5723
|
-
provider === 'openai' && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-provider" },
|
|
5724
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("h3", null, "OpenAI \uC124\uC815"),
|
|
5725
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5726
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" }, "API \uD0A4"),
|
|
5727
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "password", className: "jp-agent-settings-input", value: openaiApiKey, onChange: (e) => setOpenaiApiKey(e.target.value), placeholder: "sk-..." })),
|
|
5728
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5729
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" }, "\uBAA8\uB378"),
|
|
5730
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("select", { className: "jp-agent-settings-select", value: openaiModel, onChange: (e) => setOpenaiModel(e.target.value) },
|
|
5731
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { value: "gpt-4" }, "GPT-4"),
|
|
5732
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { value: "gpt-4-turbo" }, "GPT-4 Turbo"),
|
|
5733
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { value: "gpt-3.5-turbo" }, "GPT-3.5 Turbo"))))),
|
|
5734
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-summarization" },
|
|
5735
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-summarization-header" },
|
|
5736
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label", style: { marginBottom: 0 } }, "\uC694\uC57D\uC6A9 LLM \uC124\uC815"),
|
|
5737
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", null, "\uB300\uD654 \uC555\uCD95 (/compact) \uBC0F Agent \uC694\uC57D\uC5D0 \uC0AC\uC6A9")),
|
|
5738
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-checkbox" },
|
|
5739
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "checkbox", checked: summarizationEnabled, onChange: (e) => setSummarizationEnabled(e.target.checked) }),
|
|
5740
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\uBCC4\uB3C4 LLM\uC73C\uB85C \uC694\uC57D \uC218\uD589 (\uBBF8\uC124\uC815 \uC2DC \uAE30\uBCF8 LLM \uC0AC\uC6A9)")),
|
|
5741
|
-
summarizationEnabled && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-summarization-content" },
|
|
5742
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5743
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" }, "\uD504\uB85C\uBC14\uC774\uB354"),
|
|
5744
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("select", { className: "jp-agent-settings-select", value: summarizationProvider, onChange: (e) => setSummarizationProvider(e.target.value) },
|
|
5745
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { value: "gemini" }, "Gemini (gemini-2.5-flash)"),
|
|
5746
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { value: "openai" }, "OpenAI (gpt-4o-mini)"),
|
|
5747
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("option", { value: "vllm" }, "vLLM / OpenRouter")),
|
|
5748
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { className: "jp-agent-settings-summarization-hint" }, "\uAE30\uBCF8 \uC124\uC815\uC758 API \uD0A4\uB97C \uC0AC\uC6A9\uD569\uB2C8\uB2E4")),
|
|
5749
|
-
summarizationProvider === 'vllm' && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5750
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" }, "\uBAA8\uB378\uBA85 (\uC120\uD0DD)"),
|
|
5751
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "text", className: "jp-agent-settings-input", value: summarizationModel, onChange: (e) => setSummarizationModel(e.target.value), placeholder: "\uC608: mistralai/mistral-7b-instruct" }),
|
|
5752
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { className: "jp-agent-settings-summarization-hint" }, "\uBE44\uC6CC\uB450\uBA74 \uAE30\uBCF8 vLLM \uBAA8\uB378 \uC0AC\uC6A9"))),
|
|
5753
|
-
summarizationProvider !== 'vllm' && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-summarization-default-model" },
|
|
5754
|
-
"\uAE30\uBCF8 \uBAA8\uB378: ",
|
|
5755
|
-
summarizationProvider === 'gemini' ? 'gemini-2.5-flash' : 'gpt-4o-mini'))))),
|
|
5756
5406
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5757
5407
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" }, "\uC790\uB3D9 \uC2E4\uD589 \uC2B9\uC778"),
|
|
5758
5408
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-checkbox" },
|
|
5759
5409
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "checkbox", checked: autoApprove, onChange: (e) => setAutoApprove(e.target.checked), "data-testid": "auto-approve-checkbox" }),
|
|
5760
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\uC2B9\uC778 \uC5C6\uC774 \uBC14\uB85C \uC2E4\uD589 (\uCF54\uB4DC/\uD30C\uC77C/\uC178 \uD3EC\uD568)"))
|
|
5761
|
-
|
|
5762
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label", htmlFor: "jp-agent-idle-timeout" },
|
|
5763
|
-
"Idle Timeout (\uBD84)",
|
|
5764
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { style: { fontWeight: 'normal', marginLeft: '8px', color: '#666' } }, "\uBE44\uD65C\uB3D9 \uC2DC \uC790\uB3D9 \uC885\uB8CC (0 = \uBE44\uD65C\uC131\uD654)")),
|
|
5765
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { id: "jp-agent-idle-timeout", type: "number", className: "jp-agent-settings-input", value: idleTimeoutMinutes, onChange: (e) => setIdleTimeoutMinutes(Math.max(0, parseInt(e.target.value) || 0)), min: 0, max: 1440, placeholder: "60", style: { width: '120px' }, "data-testid": "idle-timeout-input" })),
|
|
5766
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-group" },
|
|
5767
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", { className: "jp-agent-settings-label" },
|
|
5768
|
-
"\uC5D0\uC774\uC804\uD2B8\uBCC4 System Prompt",
|
|
5769
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { style: { fontWeight: 'normal', marginLeft: '8px', color: '#666' } }, "\uAC01 \uC5D0\uC774\uC804\uD2B8\uC758 \uC5ED\uD560\uACFC \uB3D9\uC791\uC744 \uC815\uC758\uD569\uB2C8\uB2E4.")),
|
|
5770
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-agent-section", style: { marginTop: '12px', border: '1px solid #ddd', borderRadius: '4px' } },
|
|
5771
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-agent-header", style: {
|
|
5772
|
-
padding: '8px 12px',
|
|
5773
|
-
background: '#f5f5f5',
|
|
5774
|
-
cursor: 'pointer',
|
|
5775
|
-
display: 'flex',
|
|
5776
|
-
justifyContent: 'space-between',
|
|
5777
|
-
alignItems: 'center'
|
|
5778
|
-
}, onClick: () => setExpandedAgents(prev => ({ ...prev, planner: !prev.planner })) },
|
|
5779
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { style: { fontWeight: 'bold', display: 'flex', alignItems: 'center', gap: '6px' } },
|
|
5780
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_GpsFixed__WEBPACK_IMPORTED_MODULE_7__["default"], { sx: { fontSize: 18 } }),
|
|
5781
|
-
" Planner (Supervisor)"),
|
|
5782
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, expandedAgents.planner ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ExpandMore__WEBPACK_IMPORTED_MODULE_8__["default"], { sx: { fontSize: 18 } }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ChevronRight__WEBPACK_IMPORTED_MODULE_9__["default"], { sx: { fontSize: 18 } }))),
|
|
5783
|
-
expandedAgents.planner && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { style: { padding: '12px' } },
|
|
5784
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { style: { color: '#666', display: 'block', marginBottom: '8px' } }, "\uC791\uC5C5 \uACC4\uD68D \uBC0F \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8 \uC704\uC784\uC744 \uB2F4\uB2F9\uD569\uB2C8\uB2E4."),
|
|
5785
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("textarea", { className: "jp-agent-settings-input jp-agent-settings-textarea", value: agentPrompts.planner || '', onChange: (e) => setAgentPrompts(prev => ({ ...prev, planner: e.target.value })), rows: 6 }),
|
|
5786
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { type: "button", className: "jp-agent-settings-button jp-agent-settings-button-secondary jp-agent-settings-button-compact", style: { marginTop: '8px' }, onClick: () => defaultPrompts && setAgentPrompts(prev => ({ ...prev, planner: defaultPrompts.planner })), disabled: isLoadingPrompts }, isLoadingPrompts ? '로딩중...' : '기본값으로 되돌리기')))),
|
|
5787
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-agent-section", style: { marginTop: '8px', border: '1px solid #ddd', borderRadius: '4px' } },
|
|
5788
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-agent-header", style: {
|
|
5789
|
-
padding: '8px 12px',
|
|
5790
|
-
background: '#f5f5f5',
|
|
5791
|
-
cursor: 'pointer',
|
|
5792
|
-
display: 'flex',
|
|
5793
|
-
justifyContent: 'space-between',
|
|
5794
|
-
alignItems: 'center'
|
|
5795
|
-
}, onClick: () => setExpandedAgents(prev => ({ ...prev, python_developer: !prev.python_developer })) },
|
|
5796
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { style: { fontWeight: 'bold', display: 'flex', alignItems: 'center', gap: '6px' } },
|
|
5797
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_Code__WEBPACK_IMPORTED_MODULE_4__["default"], { sx: { fontSize: 18 } }),
|
|
5798
|
-
" Python Developer"),
|
|
5799
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, expandedAgents.python_developer ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ExpandMore__WEBPACK_IMPORTED_MODULE_8__["default"], { sx: { fontSize: 18 } }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ChevronRight__WEBPACK_IMPORTED_MODULE_9__["default"], { sx: { fontSize: 18 } }))),
|
|
5800
|
-
expandedAgents.python_developer && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { style: { padding: '12px' } },
|
|
5801
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { style: { color: '#666', display: 'block', marginBottom: '8px' } }, "Python \uCF54\uB4DC \uC2E4\uD589, \uB370\uC774\uD130 \uBD84\uC11D, \uC2DC\uAC01\uD654, ML \uBAA8\uB378\uB9C1\uC744 \uB2F4\uB2F9\uD569\uB2C8\uB2E4."),
|
|
5802
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("textarea", { className: "jp-agent-settings-input jp-agent-settings-textarea", value: agentPrompts.python_developer || '', onChange: (e) => setAgentPrompts(prev => ({ ...prev, python_developer: e.target.value })), rows: 6 }),
|
|
5803
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { type: "button", className: "jp-agent-settings-button jp-agent-settings-button-secondary jp-agent-settings-button-compact", style: { marginTop: '8px' }, onClick: () => defaultPrompts && setAgentPrompts(prev => ({ ...prev, python_developer: defaultPrompts.python_developer })), disabled: isLoadingPrompts }, isLoadingPrompts ? '로딩중...' : '기본값으로 되돌리기')))),
|
|
5804
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-agent-section", style: { marginTop: '8px', border: '1px solid #ddd', borderRadius: '4px' } },
|
|
5805
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-agent-header", style: {
|
|
5806
|
-
padding: '8px 12px',
|
|
5807
|
-
background: '#f5f5f5',
|
|
5808
|
-
cursor: 'pointer',
|
|
5809
|
-
display: 'flex',
|
|
5810
|
-
justifyContent: 'space-between',
|
|
5811
|
-
alignItems: 'center'
|
|
5812
|
-
}, onClick: () => setExpandedAgents(prev => ({ ...prev, researcher: !prev.researcher })) },
|
|
5813
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { style: { fontWeight: 'bold', display: 'flex', alignItems: 'center', gap: '6px' } },
|
|
5814
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_Search__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { fontSize: 18 } }),
|
|
5815
|
-
" Researcher"),
|
|
5816
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, expandedAgents.researcher ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ExpandMore__WEBPACK_IMPORTED_MODULE_8__["default"], { sx: { fontSize: 18 } }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ChevronRight__WEBPACK_IMPORTED_MODULE_9__["default"], { sx: { fontSize: 18 } }))),
|
|
5817
|
-
expandedAgents.researcher && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { style: { padding: '12px' } },
|
|
5818
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { style: { color: '#666', display: 'block', marginBottom: '8px' } }, "\uD30C\uC77C \uAC80\uC0C9, \uCF54\uB4DC \uBD84\uC11D, Qdrant RAG \uAC80\uC0C9\uC744 \uB2F4\uB2F9\uD569\uB2C8\uB2E4 (READ-ONLY)."),
|
|
5819
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("textarea", { className: "jp-agent-settings-input jp-agent-settings-textarea", value: agentPrompts.researcher || '', onChange: (e) => setAgentPrompts(prev => ({ ...prev, researcher: e.target.value })), rows: 6 }),
|
|
5820
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { type: "button", className: "jp-agent-settings-button jp-agent-settings-button-secondary jp-agent-settings-button-compact", style: { marginTop: '8px' }, onClick: () => defaultPrompts && setAgentPrompts(prev => ({ ...prev, researcher: defaultPrompts.researcher })), disabled: isLoadingPrompts }, isLoadingPrompts ? '로딩중...' : '기본값으로 되돌리기')))),
|
|
5821
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-agent-section", style: { marginTop: '8px', border: '1px solid #ddd', borderRadius: '4px' } },
|
|
5822
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-agent-header", style: {
|
|
5823
|
-
padding: '8px 12px',
|
|
5824
|
-
background: '#f5f5f5',
|
|
5825
|
-
cursor: 'pointer',
|
|
5826
|
-
display: 'flex',
|
|
5827
|
-
justifyContent: 'space-between',
|
|
5828
|
-
alignItems: 'center'
|
|
5829
|
-
}, onClick: () => setExpandedAgents(prev => ({ ...prev, athena_query: !prev.athena_query })) },
|
|
5830
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", { style: { fontWeight: 'bold', display: 'flex', alignItems: 'center', gap: '6px' } },
|
|
5831
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_Analytics__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { fontSize: 18 } }),
|
|
5832
|
-
" Athena Query"),
|
|
5833
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, expandedAgents.athena_query ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ExpandMore__WEBPACK_IMPORTED_MODULE_8__["default"], { sx: { fontSize: 18 } }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material_ChevronRight__WEBPACK_IMPORTED_MODULE_9__["default"], { sx: { fontSize: 18 } }))),
|
|
5834
|
-
expandedAgents.athena_query && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { style: { padding: '12px' } },
|
|
5835
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { style: { color: '#666', display: 'block', marginBottom: '8px' } }, "Qdrant RAG\uB97C \uD65C\uC6A9\uD55C Athena SQL \uCFFC\uB9AC \uC0DD\uC131\uC744 \uB2F4\uB2F9\uD569\uB2C8\uB2E4 (Python Developer\uC5D0\uC11C \uD638\uCD9C)."),
|
|
5836
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("textarea", { className: "jp-agent-settings-input jp-agent-settings-textarea", value: agentPrompts.athena_query || '', onChange: (e) => setAgentPrompts(prev => ({ ...prev, athena_query: e.target.value })), rows: 6 }),
|
|
5837
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { type: "button", className: "jp-agent-settings-button jp-agent-settings-button-secondary jp-agent-settings-button-compact", style: { marginTop: '8px' }, onClick: () => defaultPrompts && setAgentPrompts(prev => ({ ...prev, athena_query: defaultPrompts.athena_query })), disabled: isLoadingPrompts }, isLoadingPrompts ? '로딩중...' : '기본값으로 되돌리기')))),
|
|
5838
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { style: { marginTop: '12px' } },
|
|
5839
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { type: "button", className: "jp-agent-settings-button jp-agent-settings-button-secondary", onClick: () => {
|
|
5840
|
-
if (defaultPrompts) {
|
|
5841
|
-
setAgentPrompts({
|
|
5842
|
-
planner: defaultPrompts.planner,
|
|
5843
|
-
python_developer: defaultPrompts.python_developer,
|
|
5844
|
-
researcher: defaultPrompts.researcher,
|
|
5845
|
-
athena_query: defaultPrompts.athena_query,
|
|
5846
|
-
});
|
|
5847
|
-
}
|
|
5848
|
-
}, disabled: isLoadingPrompts }, isLoadingPrompts ? '로딩중...' : '모든 프롬프트 기본값으로 되돌리기')))),
|
|
5410
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\uC2B9\uC778 \uC5C6\uC774 \uBC14\uB85C \uC2E4\uD589 (\uCF54\uB4DC/\uD30C\uC77C/\uC178 \uD3EC\uD568)")),
|
|
5411
|
+
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("small", { style: { color: '#666', display: 'block', marginTop: '4px', marginLeft: '24px' } }, "\uD65C\uC131\uD654 \uC2DC Human-in-the-Loop \uC2B9\uC778 \uB2E8\uACC4\uB97C \uAC74\uB108\uB701\uB2C8\uB2E4"))),
|
|
5849
5412
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-settings-footer" },
|
|
5850
5413
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "jp-agent-settings-button jp-agent-settings-button-secondary", onClick: onClose }, "\uCDE8\uC18C"),
|
|
5851
|
-
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "jp-agent-settings-button jp-agent-settings-button-test", onClick: handleTest, disabled: isTesting }, isTesting ? '테스트 중...' : 'API 테스트'),
|
|
5852
5414
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("button", { className: "jp-agent-settings-button jp-agent-settings-button-primary", onClick: handleSave }, "\uC800\uC7A5")))));
|
|
5853
5415
|
};
|
|
5854
5416
|
|
|
@@ -7919,7 +7481,6 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
7919
7481
|
* Plugin namespace
|
|
7920
7482
|
*/
|
|
7921
7483
|
const PLUGIN_ID = '@hdsp-agent/idle-monitor';
|
|
7922
|
-
const CONFIG_STORAGE_KEY = 'hdsp-agent-llm-config';
|
|
7923
7484
|
/**
|
|
7924
7485
|
* Default idle timeout (in minutes)
|
|
7925
7486
|
*/
|
|
@@ -7946,81 +7507,61 @@ class IdleMonitorService {
|
|
|
7946
7507
|
*/
|
|
7947
7508
|
this.mouseMoveThrottleTime = 0;
|
|
7948
7509
|
this.lastActivityTime = Date.now();
|
|
7949
|
-
//
|
|
7950
|
-
this.idleTimeoutMinutes =
|
|
7951
|
-
this.isDisabled =
|
|
7510
|
+
// Start with default (60 minutes), then fetch from server
|
|
7511
|
+
this.idleTimeoutMinutes = DEFAULT_IDLE_TIMEOUT_MINUTES;
|
|
7512
|
+
this.isDisabled = false;
|
|
7952
7513
|
this.idleTimeoutMs = this.idleTimeoutMinutes * 60 * 1000;
|
|
7953
|
-
// Warning period: 25% of timeout or minimum 30 seconds
|
|
7954
7514
|
const warningPeriod = Math.max(MIN_WARNING_PERIOD_MS, this.idleTimeoutMs * 0.25);
|
|
7955
7515
|
this.warningStartMs = this.idleTimeoutMs - warningPeriod;
|
|
7956
7516
|
this.setupActivityListeners();
|
|
7957
|
-
this.setupStorageListener();
|
|
7958
7517
|
this.createCountdownElement();
|
|
7518
|
+
// Fetch actual timeout from Agent Server
|
|
7519
|
+
this.fetchIdleTimeoutFromServer();
|
|
7959
7520
|
if (!this.isDisabled) {
|
|
7960
7521
|
this.startIdleCheck();
|
|
7961
7522
|
}
|
|
7962
7523
|
console.log('[IdleMonitor] Service initialized. Idle timeout:', this.idleTimeoutMinutes, 'minutes, warning at:', Math.round(this.warningStartMs / 1000), 'sec', this.isDisabled ? '(DISABLED)' : '');
|
|
7963
7524
|
}
|
|
7964
7525
|
/**
|
|
7965
|
-
*
|
|
7526
|
+
* Fetch idle timeout setting from Agent Server
|
|
7966
7527
|
*/
|
|
7967
|
-
|
|
7528
|
+
async fetchIdleTimeoutFromServer() {
|
|
7968
7529
|
try {
|
|
7969
|
-
const
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
}
|
|
7530
|
+
const serverRoot = _jupyterlab_coreutils__WEBPACK_IMPORTED_MODULE_2__.PageConfig.getBaseUrl();
|
|
7531
|
+
const response = await fetch(`${serverRoot}hdsp-agent/config/admin`);
|
|
7532
|
+
if (!response.ok) {
|
|
7533
|
+
console.warn('[IdleMonitor] Failed to fetch config from server:', response.status);
|
|
7534
|
+
return;
|
|
7975
7535
|
}
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
*/
|
|
7985
|
-
setupStorageListener() {
|
|
7986
|
-
window.addEventListener('storage', (e) => {
|
|
7987
|
-
if (e.key === CONFIG_STORAGE_KEY) {
|
|
7988
|
-
const newTimeout = this.loadTimeoutFromConfig();
|
|
7989
|
-
if (newTimeout !== this.idleTimeoutMinutes) {
|
|
7990
|
-
this.updateTimeout(newTimeout);
|
|
7536
|
+
const config = await response.json();
|
|
7537
|
+
const serverTimeoutSeconds = config.idleTimeout;
|
|
7538
|
+
if (typeof serverTimeoutSeconds === 'number' && serverTimeoutSeconds > 0) {
|
|
7539
|
+
// Server sends seconds, convert to minutes
|
|
7540
|
+
const newTimeoutMinutes = Math.ceil(serverTimeoutSeconds / 60);
|
|
7541
|
+
if (newTimeoutMinutes !== this.idleTimeoutMinutes) {
|
|
7542
|
+
this.updateIdleTimeout(newTimeoutMinutes);
|
|
7543
|
+
console.log('[IdleMonitor] Updated timeout from server:', newTimeoutMinutes, 'minutes');
|
|
7991
7544
|
}
|
|
7992
7545
|
}
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
this.updateTimeout(newTimeout);
|
|
7546
|
+
else if (serverTimeoutSeconds === 0) {
|
|
7547
|
+
// 0 means disabled
|
|
7548
|
+
this.isDisabled = true;
|
|
7549
|
+
this.stopIdleCheck();
|
|
7550
|
+
console.log('[IdleMonitor] Idle timeout disabled by server config');
|
|
7999
7551
|
}
|
|
8000
|
-
}
|
|
7552
|
+
}
|
|
7553
|
+
catch (error) {
|
|
7554
|
+
console.warn('[IdleMonitor] Error fetching config from server:', error);
|
|
7555
|
+
}
|
|
8001
7556
|
}
|
|
8002
7557
|
/**
|
|
8003
|
-
* Update timeout dynamically
|
|
7558
|
+
* Update idle timeout dynamically
|
|
8004
7559
|
*/
|
|
8005
|
-
|
|
8006
|
-
const wasDisabled = this.isDisabled;
|
|
7560
|
+
updateIdleTimeout(minutes) {
|
|
8007
7561
|
this.idleTimeoutMinutes = minutes;
|
|
8008
|
-
this.isDisabled = minutes === 0;
|
|
8009
7562
|
this.idleTimeoutMs = minutes * 60 * 1000;
|
|
8010
|
-
// Warning period: 25% of timeout or minimum 30 seconds
|
|
8011
7563
|
const warningPeriod = Math.max(MIN_WARNING_PERIOD_MS, this.idleTimeoutMs * 0.25);
|
|
8012
7564
|
this.warningStartMs = this.idleTimeoutMs - warningPeriod;
|
|
8013
|
-
console.log('[IdleMonitor] Timeout updated to:', minutes, 'minutes', this.isDisabled ? '(DISABLED)' : '');
|
|
8014
|
-
// Stop idle check if disabled
|
|
8015
|
-
if (this.isDisabled) {
|
|
8016
|
-
this.stopIdleCheck();
|
|
8017
|
-
this.hideCountdown();
|
|
8018
|
-
}
|
|
8019
|
-
else if (wasDisabled) {
|
|
8020
|
-
// Re-enable if was disabled
|
|
8021
|
-
this.resetIdleTimer();
|
|
8022
|
-
this.startIdleCheck();
|
|
8023
|
-
}
|
|
8024
7565
|
}
|
|
8025
7566
|
/**
|
|
8026
7567
|
* Stop idle check interval
|
|
@@ -9829,26 +9370,15 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
9829
9370
|
/* harmony export */ DEFAULT_PLANNER_PROMPT: () => (/* binding */ DEFAULT_PLANNER_PROMPT),
|
|
9830
9371
|
/* harmony export */ DEFAULT_PYTHON_DEVELOPER_PROMPT: () => (/* binding */ DEFAULT_PYTHON_DEVELOPER_PROMPT),
|
|
9831
9372
|
/* harmony export */ DEFAULT_RESEARCHER_PROMPT: () => (/* binding */ DEFAULT_RESEARCHER_PROMPT),
|
|
9832
|
-
/* harmony export */ buildSingleKeyConfig: () => (/* binding */ buildSingleKeyConfig),
|
|
9833
9373
|
/* harmony export */ clearCachedPrompts: () => (/* binding */ clearCachedPrompts),
|
|
9834
9374
|
/* harmony export */ clearLLMConfig: () => (/* binding */ clearLLMConfig),
|
|
9835
9375
|
/* harmony export */ fetchDefaultPrompts: () => (/* binding */ fetchDefaultPrompts),
|
|
9836
|
-
/* harmony export */ getAvailableKeyCount: () => (/* binding */ getAvailableKeyCount),
|
|
9837
9376
|
/* harmony export */ getCachedPrompts: () => (/* binding */ getCachedPrompts),
|
|
9838
|
-
/* harmony export */ getCurrentKeyIndex: () => (/* binding */ getCurrentKeyIndex),
|
|
9839
9377
|
/* harmony export */ getDefaultLLMConfig: () => (/* binding */ getDefaultLLMConfig),
|
|
9840
9378
|
/* harmony export */ getLLMConfig: () => (/* binding */ getLLMConfig),
|
|
9841
|
-
/* harmony export */ getRandomApiKey: () => (/* binding */ getRandomApiKey),
|
|
9842
|
-
/* harmony export */ getValidApiKeysCount: () => (/* binding */ getValidApiKeysCount),
|
|
9843
|
-
/* harmony export */ getValidGeminiKeys: () => (/* binding */ getValidGeminiKeys),
|
|
9844
|
-
/* harmony export */ handleRateLimitError: () => (/* binding */ handleRateLimitError),
|
|
9845
|
-
/* harmony export */ hasAvailableKeys: () => (/* binding */ hasAvailableKeys),
|
|
9846
9379
|
/* harmony export */ hasValidApiKey: () => (/* binding */ hasValidApiKey),
|
|
9847
9380
|
/* harmony export */ initializePrompts: () => (/* binding */ initializePrompts),
|
|
9848
|
-
/* harmony export */ isRateLimitError: () => (/* binding */ isRateLimitError),
|
|
9849
9381
|
/* harmony export */ maskApiKey: () => (/* binding */ maskApiKey),
|
|
9850
|
-
/* harmony export */ resetKeyRotation: () => (/* binding */ resetKeyRotation),
|
|
9851
|
-
/* harmony export */ rotateToNextKey: () => (/* binding */ rotateToNextKey),
|
|
9852
9382
|
/* harmony export */ saveLLMConfig: () => (/* binding */ saveLLMConfig),
|
|
9853
9383
|
/* harmony export */ testApiKey: () => (/* binding */ testApiKey)
|
|
9854
9384
|
/* harmony export */ });
|
|
@@ -9943,14 +9473,8 @@ async function initializePrompts() {
|
|
|
9943
9473
|
};
|
|
9944
9474
|
}
|
|
9945
9475
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
9946
|
-
//
|
|
9476
|
+
// LocalStorage Functions
|
|
9947
9477
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
9948
|
-
/** Current key index for rotation (per-session, not persisted) */
|
|
9949
|
-
let currentKeyIndex = 0;
|
|
9950
|
-
/** Set of rate-limited key indices (reset after successful request) */
|
|
9951
|
-
const rateLimitedKeys = new Set();
|
|
9952
|
-
/** Maximum retry attempts with different keys */
|
|
9953
|
-
const MAX_KEY_ROTATION_ATTEMPTS = 10;
|
|
9954
9478
|
/**
|
|
9955
9479
|
* Get the current LLM configuration from localStorage
|
|
9956
9480
|
*/
|
|
@@ -9989,92 +9513,22 @@ function clearLLMConfig() {
|
|
|
9989
9513
|
console.log('[ApiKeyManager] Config cleared from localStorage');
|
|
9990
9514
|
}
|
|
9991
9515
|
/**
|
|
9992
|
-
* Check if API key is configured
|
|
9516
|
+
* Check if API key is configured - DEPRECATED
|
|
9517
|
+
* All LLM settings now come from Agent Server
|
|
9993
9518
|
*/
|
|
9994
|
-
function hasValidApiKey(
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
switch (config.provider) {
|
|
9998
|
-
case 'gemini':
|
|
9999
|
-
// Check both single key and multiple keys
|
|
10000
|
-
const hasMainKey = !!(config.gemini?.apiKey && config.gemini.apiKey.trim());
|
|
10001
|
-
const hasArrayKeys = !!(config.gemini?.apiKeys && config.gemini.apiKeys.some(k => k && k.trim()));
|
|
10002
|
-
return hasMainKey || hasArrayKeys;
|
|
10003
|
-
case 'openai':
|
|
10004
|
-
return !!(config.openai?.apiKey && config.openai.apiKey.trim());
|
|
10005
|
-
case 'vllm':
|
|
10006
|
-
// vLLM may not require API key
|
|
10007
|
-
return true;
|
|
10008
|
-
default:
|
|
10009
|
-
return false;
|
|
10010
|
-
}
|
|
9519
|
+
function hasValidApiKey(_config) {
|
|
9520
|
+
// Always return true - API keys are managed by Agent Server
|
|
9521
|
+
return true;
|
|
10011
9522
|
}
|
|
10012
9523
|
/**
|
|
10013
|
-
* Get default LLM configuration
|
|
10014
|
-
* Uses cached prompts from API if available, otherwise uses placeholders
|
|
9524
|
+
* Get default LLM configuration (simplified - user preferences only)
|
|
10015
9525
|
*/
|
|
10016
9526
|
function getDefaultLLMConfig() {
|
|
10017
|
-
const prompts = getCachedPrompts();
|
|
10018
9527
|
return {
|
|
10019
|
-
|
|
10020
|
-
gemini: {
|
|
10021
|
-
apiKey: '',
|
|
10022
|
-
apiKeys: [],
|
|
10023
|
-
model: 'gemini-2.5-flash'
|
|
10024
|
-
},
|
|
10025
|
-
openai: {
|
|
10026
|
-
apiKey: '',
|
|
10027
|
-
model: 'gpt-4'
|
|
10028
|
-
},
|
|
10029
|
-
vllm: {
|
|
10030
|
-
endpoint: 'http://localhost:8000/v1',
|
|
10031
|
-
model: 'default'
|
|
10032
|
-
},
|
|
10033
|
-
agentPrompts: prompts ? {
|
|
10034
|
-
planner: prompts.planner,
|
|
10035
|
-
python_developer: prompts.python_developer,
|
|
10036
|
-
researcher: prompts.researcher,
|
|
10037
|
-
athena_query: prompts.athena_query,
|
|
10038
|
-
} : { ...DEFAULT_AGENT_PROMPTS },
|
|
9528
|
+
workspaceRoot: '',
|
|
10039
9529
|
autoApprove: false
|
|
10040
9530
|
};
|
|
10041
9531
|
}
|
|
10042
|
-
/**
|
|
10043
|
-
* Get a random API key from the list (for load balancing)
|
|
10044
|
-
*/
|
|
10045
|
-
function getRandomApiKey(config) {
|
|
10046
|
-
if (config.provider === 'gemini' && config.gemini) {
|
|
10047
|
-
const keys = config.gemini.apiKeys.filter(k => k && k.trim());
|
|
10048
|
-
if (keys.length === 0) {
|
|
10049
|
-
return config.gemini.apiKey || null;
|
|
10050
|
-
}
|
|
10051
|
-
// Random selection for load balancing
|
|
10052
|
-
const randomIndex = Math.floor(Math.random() * keys.length);
|
|
10053
|
-
return keys[randomIndex];
|
|
10054
|
-
}
|
|
10055
|
-
if (config.provider === 'openai' && config.openai) {
|
|
10056
|
-
return config.openai.apiKey || null;
|
|
10057
|
-
}
|
|
10058
|
-
if (config.provider === 'vllm' && config.vllm) {
|
|
10059
|
-
return config.vllm.apiKey || null;
|
|
10060
|
-
}
|
|
10061
|
-
return null;
|
|
10062
|
-
}
|
|
10063
|
-
/**
|
|
10064
|
-
* Get all valid API keys count
|
|
10065
|
-
*/
|
|
10066
|
-
function getValidApiKeysCount(config) {
|
|
10067
|
-
if (config.provider === 'gemini' && config.gemini) {
|
|
10068
|
-
return config.gemini.apiKeys.filter(k => k && k.trim()).length;
|
|
10069
|
-
}
|
|
10070
|
-
if (config.provider === 'openai' && config.openai) {
|
|
10071
|
-
return config.openai.apiKey && config.openai.apiKey.trim() ? 1 : 0;
|
|
10072
|
-
}
|
|
10073
|
-
if (config.provider === 'vllm') {
|
|
10074
|
-
return 1; // vLLM doesn't require API key
|
|
10075
|
-
}
|
|
10076
|
-
return 0;
|
|
10077
|
-
}
|
|
10078
9532
|
/**
|
|
10079
9533
|
* Mask API key for display (show first 4 and last 4 characters)
|
|
10080
9534
|
*/
|
|
@@ -10084,159 +9538,14 @@ function maskApiKey(key) {
|
|
|
10084
9538
|
return `${key.slice(0, 4)}...${key.slice(-4)}`;
|
|
10085
9539
|
}
|
|
10086
9540
|
/**
|
|
10087
|
-
* Test API key
|
|
10088
|
-
|
|
10089
|
-
async function testApiKey(config) {
|
|
10090
|
-
try {
|
|
10091
|
-
// Simple validation - just check if key exists
|
|
10092
|
-
if (!hasValidApiKey(config)) {
|
|
10093
|
-
return { success: false, message: 'API key not configured' };
|
|
10094
|
-
}
|
|
10095
|
-
// For more thorough testing, you could make a minimal API call here
|
|
10096
|
-
// But for now, just validate format
|
|
10097
|
-
const key = config[config.provider];
|
|
10098
|
-
if (config.provider === 'gemini' && key?.apiKey) {
|
|
10099
|
-
if (!key.apiKey.startsWith('AIza')) {
|
|
10100
|
-
return { success: false, message: 'Invalid Gemini API key format (should start with AIza)' };
|
|
10101
|
-
}
|
|
10102
|
-
}
|
|
10103
|
-
if (config.provider === 'openai' && key?.apiKey) {
|
|
10104
|
-
if (!key.apiKey.startsWith('sk-')) {
|
|
10105
|
-
return { success: false, message: 'Invalid OpenAI API key format (should start with sk-)' };
|
|
10106
|
-
}
|
|
10107
|
-
}
|
|
10108
|
-
return { success: true, message: 'API key format is valid' };
|
|
10109
|
-
}
|
|
10110
|
-
catch (e) {
|
|
10111
|
-
return { success: false, message: `Error: ${e}` };
|
|
10112
|
-
}
|
|
10113
|
-
}
|
|
10114
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
10115
|
-
// Key Rotation Functions (Financial Security Compliance)
|
|
10116
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
10117
|
-
/**
|
|
10118
|
-
* Get all valid Gemini API keys from config
|
|
10119
|
-
*/
|
|
10120
|
-
function getValidGeminiKeys(config) {
|
|
10121
|
-
if (config.provider !== 'gemini' || !config.gemini) {
|
|
10122
|
-
return [];
|
|
10123
|
-
}
|
|
10124
|
-
const keys = config.gemini.apiKeys?.filter(k => k && k.trim()) || [];
|
|
10125
|
-
// Fallback to single apiKey if no array
|
|
10126
|
-
if (keys.length === 0 && config.gemini.apiKey && config.gemini.apiKey.trim()) {
|
|
10127
|
-
return [config.gemini.apiKey];
|
|
10128
|
-
}
|
|
10129
|
-
return keys;
|
|
10130
|
-
}
|
|
10131
|
-
/**
|
|
10132
|
-
* Get current key index for rotation tracking
|
|
10133
|
-
*/
|
|
10134
|
-
function getCurrentKeyIndex() {
|
|
10135
|
-
return currentKeyIndex;
|
|
10136
|
-
}
|
|
10137
|
-
/**
|
|
10138
|
-
* Reset key rotation state (call after successful request)
|
|
10139
|
-
*/
|
|
10140
|
-
function resetKeyRotation() {
|
|
10141
|
-
rateLimitedKeys.clear();
|
|
10142
|
-
console.log('[ApiKeyManager] Key rotation state reset');
|
|
10143
|
-
}
|
|
10144
|
-
/**
|
|
10145
|
-
* Mark current key as rate-limited and rotate to next available key
|
|
10146
|
-
* @returns true if rotation successful, false if all keys exhausted
|
|
10147
|
-
*/
|
|
10148
|
-
function rotateToNextKey(config) {
|
|
10149
|
-
const keys = getValidGeminiKeys(config);
|
|
10150
|
-
if (keys.length <= 1) {
|
|
10151
|
-
console.log('[ApiKeyManager] Cannot rotate - only one key available');
|
|
10152
|
-
return false;
|
|
10153
|
-
}
|
|
10154
|
-
// Mark current key as rate-limited
|
|
10155
|
-
rateLimitedKeys.add(currentKeyIndex);
|
|
10156
|
-
console.log(`[ApiKeyManager] Key ${currentKeyIndex + 1} marked as rate-limited`);
|
|
10157
|
-
// Find next available key
|
|
10158
|
-
for (let i = 0; i < keys.length; i++) {
|
|
10159
|
-
const nextIndex = (currentKeyIndex + 1 + i) % keys.length;
|
|
10160
|
-
if (!rateLimitedKeys.has(nextIndex)) {
|
|
10161
|
-
currentKeyIndex = nextIndex;
|
|
10162
|
-
console.log(`[ApiKeyManager] Rotated to key ${currentKeyIndex + 1}/${keys.length}`);
|
|
10163
|
-
return true;
|
|
10164
|
-
}
|
|
10165
|
-
}
|
|
10166
|
-
// All keys rate-limited
|
|
10167
|
-
console.log('[ApiKeyManager] All keys rate-limited');
|
|
10168
|
-
return false;
|
|
10169
|
-
}
|
|
10170
|
-
/**
|
|
10171
|
-
* Check if there are available keys (not all rate-limited)
|
|
10172
|
-
*/
|
|
10173
|
-
function hasAvailableKeys(config) {
|
|
10174
|
-
const keys = getValidGeminiKeys(config);
|
|
10175
|
-
return keys.length > rateLimitedKeys.size;
|
|
10176
|
-
}
|
|
10177
|
-
/**
|
|
10178
|
-
* Get count of remaining available keys
|
|
10179
|
-
*/
|
|
10180
|
-
function getAvailableKeyCount(config) {
|
|
10181
|
-
const keys = getValidGeminiKeys(config);
|
|
10182
|
-
return Math.max(0, keys.length - rateLimitedKeys.size);
|
|
10183
|
-
}
|
|
10184
|
-
/**
|
|
10185
|
-
* Build config with SINGLE current API key for server request.
|
|
10186
|
-
* Server receives only one key - rotation is handled by frontend.
|
|
10187
|
-
*/
|
|
10188
|
-
function buildSingleKeyConfig(config) {
|
|
10189
|
-
if (config.provider !== 'gemini' || !config.gemini) {
|
|
10190
|
-
// Non-Gemini providers - return as-is (no rotation)
|
|
10191
|
-
return config;
|
|
10192
|
-
}
|
|
10193
|
-
const keys = getValidGeminiKeys(config);
|
|
10194
|
-
if (keys.length === 0) {
|
|
10195
|
-
return config;
|
|
10196
|
-
}
|
|
10197
|
-
// Ensure currentKeyIndex is within bounds
|
|
10198
|
-
if (currentKeyIndex >= keys.length) {
|
|
10199
|
-
currentKeyIndex = 0;
|
|
10200
|
-
}
|
|
10201
|
-
const currentKey = keys[currentKeyIndex];
|
|
10202
|
-
console.log(`[ApiKeyManager] Using key ${currentKeyIndex + 1}/${keys.length}`);
|
|
10203
|
-
// Return config with single apiKey (server only uses apiKey field)
|
|
10204
|
-
return {
|
|
10205
|
-
...config,
|
|
10206
|
-
gemini: {
|
|
10207
|
-
...config.gemini,
|
|
10208
|
-
apiKey: currentKey,
|
|
10209
|
-
// Don't send apiKeys array to server (security)
|
|
10210
|
-
apiKeys: [],
|
|
10211
|
-
},
|
|
10212
|
-
};
|
|
10213
|
-
}
|
|
10214
|
-
/**
|
|
10215
|
-
* Handle rate limit error with automatic key rotation
|
|
10216
|
-
* @returns New config with rotated key, or null if all keys exhausted
|
|
10217
|
-
*/
|
|
10218
|
-
function handleRateLimitError(config) {
|
|
10219
|
-
if (config.provider !== 'gemini') {
|
|
10220
|
-
// Non-Gemini providers don't support rotation
|
|
10221
|
-
return null;
|
|
10222
|
-
}
|
|
10223
|
-
const rotated = rotateToNextKey(config);
|
|
10224
|
-
if (!rotated) {
|
|
10225
|
-
console.log('[ApiKeyManager] Rate limit: All keys exhausted');
|
|
10226
|
-
return null;
|
|
10227
|
-
}
|
|
10228
|
-
return buildSingleKeyConfig(config);
|
|
10229
|
-
}
|
|
10230
|
-
/**
|
|
10231
|
-
* Check if error is a rate limit error (429)
|
|
9541
|
+
* Test API key - DEPRECATED
|
|
9542
|
+
* All LLM settings now come from Agent Server
|
|
10232
9543
|
*/
|
|
10233
|
-
function
|
|
10234
|
-
|
|
10235
|
-
return
|
|
10236
|
-
errorMsg.includes('429') ||
|
|
10237
|
-
errorMsg.toLowerCase().includes('quota exceeded') ||
|
|
10238
|
-
errorMsg.toLowerCase().includes('rate limit');
|
|
9544
|
+
async function testApiKey(_config) {
|
|
9545
|
+
// API key testing should be done via Agent Server
|
|
9546
|
+
return { success: true, message: 'API keys are managed by Agent Server' };
|
|
10239
9547
|
}
|
|
9548
|
+
// Key rotation functions removed - API keys are now managed by Agent Server
|
|
10240
9549
|
|
|
10241
9550
|
|
|
10242
9551
|
/***/ },
|
|
@@ -10251,13 +9560,11 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
10251
9560
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
10252
9561
|
/* harmony export */ ApiService: () => (/* binding */ ApiService)
|
|
10253
9562
|
/* harmony export */ });
|
|
10254
|
-
/* harmony import */ var
|
|
10255
|
-
/* harmony import */ var
|
|
10256
|
-
/* harmony import */ var _jupyterlab_coreutils__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_jupyterlab_coreutils__WEBPACK_IMPORTED_MODULE_1__);
|
|
9563
|
+
/* harmony import */ var _jupyterlab_coreutils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @jupyterlab/coreutils */ "webpack/sharing/consume/default/@jupyterlab/coreutils");
|
|
9564
|
+
/* harmony import */ var _jupyterlab_coreutils__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_jupyterlab_coreutils__WEBPACK_IMPORTED_MODULE_0__);
|
|
10257
9565
|
/**
|
|
10258
9566
|
* API Service Layer for REST communication with backend
|
|
10259
9567
|
*/
|
|
10260
|
-
|
|
10261
9568
|
// ✅ 핵심 변경 1: ServerConnection 대신 PageConfig 임포트
|
|
10262
9569
|
|
|
10263
9570
|
class ApiService {
|
|
@@ -10271,10 +9578,10 @@ class ApiService {
|
|
|
10271
9578
|
else {
|
|
10272
9579
|
// ✅ 핵심 변경 2: ServerConnection 대신 PageConfig로 URL 가져오기
|
|
10273
9580
|
// PageConfig.getBaseUrl()은 '/user/아이디/프로젝트/' 형태의 주소를 정확히 가져옵니다.
|
|
10274
|
-
const serverRoot =
|
|
9581
|
+
const serverRoot = _jupyterlab_coreutils__WEBPACK_IMPORTED_MODULE_0__.PageConfig.getBaseUrl();
|
|
10275
9582
|
// 3. 경로 합치기
|
|
10276
9583
|
// 결과: /user/453467/pl2wadmprj/hdsp-agent
|
|
10277
|
-
this.baseUrl =
|
|
9584
|
+
this.baseUrl = _jupyterlab_coreutils__WEBPACK_IMPORTED_MODULE_0__.URLExt.join(serverRoot, 'hdsp-agent');
|
|
10278
9585
|
}
|
|
10279
9586
|
console.log('[ApiService] Base URL initialized:', this.baseUrl); // 디버깅용 로그
|
|
10280
9587
|
}
|
|
@@ -10334,88 +9641,41 @@ class ApiService {
|
|
|
10334
9641
|
}
|
|
10335
9642
|
}
|
|
10336
9643
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
10337
|
-
//
|
|
9644
|
+
// API Request Helper
|
|
10338
9645
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
10339
9646
|
/**
|
|
10340
|
-
*
|
|
9647
|
+
* Simple fetch wrapper for POST requests
|
|
10341
9648
|
*
|
|
10342
|
-
* NOTE
|
|
10343
|
-
*
|
|
10344
|
-
* - Server receives ONLY ONE key per request
|
|
10345
|
-
* - On 429 rate limit, frontend rotates key and retries with next key
|
|
9649
|
+
* NOTE: API keys are now managed by Agent Server's AdminConfig.
|
|
9650
|
+
* Client only sends workspaceRoot and autoApprove preferences.
|
|
10346
9651
|
*/
|
|
10347
9652
|
async fetchWithKeyRotation(url, request, options) {
|
|
10348
|
-
|
|
10349
|
-
|
|
10350
|
-
|
|
10351
|
-
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
|
|
10355
|
-
|
|
9653
|
+
try {
|
|
9654
|
+
const response = await fetch(url, {
|
|
9655
|
+
method: 'POST',
|
|
9656
|
+
headers: this.getHeaders(),
|
|
9657
|
+
credentials: 'include',
|
|
9658
|
+
body: JSON.stringify(request)
|
|
9659
|
+
});
|
|
9660
|
+
if (response.ok) {
|
|
9661
|
+
return response.json();
|
|
9662
|
+
}
|
|
9663
|
+
// Handle error response
|
|
9664
|
+
const errorText = await response.text();
|
|
9665
|
+
let errorMessage = options?.defaultErrorMessage || 'API 요청 실패';
|
|
10356
9666
|
try {
|
|
10357
|
-
const
|
|
10358
|
-
|
|
10359
|
-
headers: this.getHeaders(),
|
|
10360
|
-
credentials: 'include',
|
|
10361
|
-
body: JSON.stringify(requestToSend)
|
|
10362
|
-
});
|
|
10363
|
-
if (response.ok) {
|
|
10364
|
-
// Success - reset key rotation state
|
|
10365
|
-
(0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.resetKeyRotation)();
|
|
10366
|
-
return response.json();
|
|
10367
|
-
}
|
|
10368
|
-
// Handle error response
|
|
10369
|
-
const errorText = await response.text();
|
|
10370
|
-
// Check if rate limit error
|
|
10371
|
-
if ((0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.isRateLimitError)(errorText) && originalConfig) {
|
|
10372
|
-
console.log(`[ApiService] Rate limit on attempt ${attempt + 1}, rotating key...`);
|
|
10373
|
-
// Try to rotate to next key
|
|
10374
|
-
const rotatedConfig = (0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.handleRateLimitError)(originalConfig);
|
|
10375
|
-
if (rotatedConfig) {
|
|
10376
|
-
// Notify UI about key rotation
|
|
10377
|
-
const keys = (0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.getValidGeminiKeys)(originalConfig);
|
|
10378
|
-
if (options?.onKeyRotation) {
|
|
10379
|
-
options.onKeyRotation((0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.getCurrentKeyIndex)(), keys.length);
|
|
10380
|
-
}
|
|
10381
|
-
continue; // Try next key
|
|
10382
|
-
}
|
|
10383
|
-
else {
|
|
10384
|
-
// All keys exhausted
|
|
10385
|
-
throw new Error('모든 API 키가 Rate Limit 상태입니다. 잠시 후 다시 시도해주세요.');
|
|
10386
|
-
}
|
|
10387
|
-
}
|
|
10388
|
-
// Not a rate limit error - parse and throw
|
|
10389
|
-
let errorMessage = options?.defaultErrorMessage || 'API 요청 실패';
|
|
10390
|
-
try {
|
|
10391
|
-
const errorJson = JSON.parse(errorText);
|
|
10392
|
-
errorMessage = errorJson.detail || errorJson.error || errorJson.message || errorMessage;
|
|
10393
|
-
}
|
|
10394
|
-
catch (e) {
|
|
10395
|
-
errorMessage = errorText || errorMessage;
|
|
10396
|
-
}
|
|
10397
|
-
throw new Error(errorMessage);
|
|
9667
|
+
const errorJson = JSON.parse(errorText);
|
|
9668
|
+
errorMessage = errorJson.detail || errorJson.error || errorJson.message || errorMessage;
|
|
10398
9669
|
}
|
|
10399
|
-
catch (
|
|
10400
|
-
|
|
10401
|
-
lastError = error instanceof Error ? error : new Error(errorMsg);
|
|
10402
|
-
// If it's a rate limit error from the catch block, check rotation
|
|
10403
|
-
if ((0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.isRateLimitError)(errorMsg) && originalConfig) {
|
|
10404
|
-
const rotatedConfig = (0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.handleRateLimitError)(originalConfig);
|
|
10405
|
-
if (rotatedConfig) {
|
|
10406
|
-
const keys = (0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.getValidGeminiKeys)(originalConfig);
|
|
10407
|
-
if (options?.onKeyRotation) {
|
|
10408
|
-
options.onKeyRotation((0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.getCurrentKeyIndex)(), keys.length);
|
|
10409
|
-
}
|
|
10410
|
-
continue;
|
|
10411
|
-
}
|
|
10412
|
-
throw new Error('모든 API 키가 Rate Limit 상태입니다. 잠시 후 다시 시도해주세요.');
|
|
10413
|
-
}
|
|
10414
|
-
// Not a rate limit error, throw immediately
|
|
10415
|
-
throw error;
|
|
9670
|
+
catch (e) {
|
|
9671
|
+
errorMessage = errorText || errorMessage;
|
|
10416
9672
|
}
|
|
9673
|
+
throw new Error(errorMessage);
|
|
9674
|
+
}
|
|
9675
|
+
catch (error) {
|
|
9676
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
9677
|
+
throw error instanceof Error ? error : new Error(errorMsg);
|
|
10417
9678
|
}
|
|
10418
|
-
throw lastError || new Error('Maximum retry attempts exceeded');
|
|
10419
9679
|
}
|
|
10420
9680
|
/**
|
|
10421
9681
|
* Execute cell action (explain, fix, custom)
|
|
@@ -10444,43 +9704,11 @@ class ApiService {
|
|
|
10444
9704
|
/**
|
|
10445
9705
|
* 단순 Chat용 스트리밍 - /chat/stream 사용
|
|
10446
9706
|
* 원래 main 브랜치의 구현 복원 - LangChain 에이전트 없이 단순 Q&A
|
|
9707
|
+
*
|
|
9708
|
+
* NOTE: API keys are now managed by Agent Server's AdminConfig.
|
|
10447
9709
|
*/
|
|
10448
9710
|
async sendChatStream(request, onChunk, onMetadata, abortSignal, onDebug) {
|
|
10449
|
-
|
|
10450
|
-
let currentConfig = request.llmConfig;
|
|
10451
|
-
let lastError = null;
|
|
10452
|
-
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
10453
|
-
const requestToSend = currentConfig
|
|
10454
|
-
? { ...request, llmConfig: (0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.buildSingleKeyConfig)(currentConfig) }
|
|
10455
|
-
: request;
|
|
10456
|
-
try {
|
|
10457
|
-
await this.sendChatStreamInternal(requestToSend, onChunk, onMetadata, abortSignal, onDebug);
|
|
10458
|
-
(0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.resetKeyRotation)();
|
|
10459
|
-
return;
|
|
10460
|
-
}
|
|
10461
|
-
catch (error) {
|
|
10462
|
-
// Check if it's an abort error
|
|
10463
|
-
if (error instanceof Error && error.name === 'AbortError') {
|
|
10464
|
-
console.log('[ApiService] Chat stream aborted by user');
|
|
10465
|
-
throw error;
|
|
10466
|
-
}
|
|
10467
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10468
|
-
lastError = error instanceof Error ? error : new Error(errorMsg);
|
|
10469
|
-
if ((0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.isRateLimitError)(errorMsg) && request.llmConfig) {
|
|
10470
|
-
console.log(`[ApiService] Chat rate limit on attempt ${attempt + 1}, trying next key...`);
|
|
10471
|
-
const rotatedConfig = (0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.handleRateLimitError)(request.llmConfig);
|
|
10472
|
-
if (rotatedConfig) {
|
|
10473
|
-
currentConfig = request.llmConfig;
|
|
10474
|
-
continue;
|
|
10475
|
-
}
|
|
10476
|
-
else {
|
|
10477
|
-
throw new Error('모든 API 키가 Rate Limit 상태입니다. 잠시 후 다시 시도해주세요.');
|
|
10478
|
-
}
|
|
10479
|
-
}
|
|
10480
|
-
throw error;
|
|
10481
|
-
}
|
|
10482
|
-
}
|
|
10483
|
-
throw lastError || new Error('Maximum retry attempts exceeded');
|
|
9711
|
+
await this.sendChatStreamInternal(request, onChunk, onMetadata, abortSignal, onDebug);
|
|
10484
9712
|
}
|
|
10485
9713
|
/**
|
|
10486
9714
|
* 단순 Chat 스트리밍 내부 구현 - /chat/stream 엔드포인트 사용
|
|
@@ -10550,65 +9778,13 @@ class ApiService {
|
|
|
10550
9778
|
/**
|
|
10551
9779
|
* Agent V2용 스트리밍 - /agent/langchain/stream 사용
|
|
10552
9780
|
* LangChain Deep Agent (HITL, Todo, 도구 실행 등)
|
|
9781
|
+
*
|
|
9782
|
+
* NOTE: API keys are now managed by Agent Server's AdminConfig.
|
|
10553
9783
|
*/
|
|
10554
9784
|
async sendAgentV2Stream(request, onChunk, onMetadata, onDebug, onInterrupt, onTodos, onDebugClear, onToolCall, onComplete, // Callback to capture thread_id for context persistence
|
|
10555
9785
|
threadId // Optional thread_id to continue existing conversation
|
|
10556
9786
|
) {
|
|
10557
|
-
|
|
10558
|
-
const MAX_RETRIES = 10;
|
|
10559
|
-
let currentConfig = request.llmConfig;
|
|
10560
|
-
let lastError = null;
|
|
10561
|
-
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
10562
|
-
// Build request with single key for this attempt
|
|
10563
|
-
const requestToSend = currentConfig
|
|
10564
|
-
? { ...request, llmConfig: (0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.buildSingleKeyConfig)(currentConfig) }
|
|
10565
|
-
: request;
|
|
10566
|
-
try {
|
|
10567
|
-
await this.sendAgentV2StreamInternal(requestToSend, onChunk, onMetadata, onDebug, onInterrupt, onTodos, onDebugClear, onToolCall, onComplete, threadId);
|
|
10568
|
-
// Success - reset key rotation state
|
|
10569
|
-
(0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.resetKeyRotation)();
|
|
10570
|
-
return;
|
|
10571
|
-
}
|
|
10572
|
-
catch (error) {
|
|
10573
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10574
|
-
lastError = error instanceof Error ? error : new Error(errorMsg);
|
|
10575
|
-
// Check if rate limit error and we have config to rotate
|
|
10576
|
-
if ((0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.isRateLimitError)(errorMsg) && request.llmConfig) {
|
|
10577
|
-
console.log(`[ApiService] Rate limit on attempt ${attempt + 1}, trying next key...`);
|
|
10578
|
-
// Try to rotate to next key using ORIGINAL config (with all keys)
|
|
10579
|
-
const rotatedConfig = (0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.handleRateLimitError)(request.llmConfig);
|
|
10580
|
-
if (rotatedConfig) {
|
|
10581
|
-
// Update currentConfig with the rotated key for next attempt
|
|
10582
|
-
// Note: rotatedConfig already has single key, but we need full config for next rotation
|
|
10583
|
-
currentConfig = request.llmConfig;
|
|
10584
|
-
continue; // Try next key
|
|
10585
|
-
}
|
|
10586
|
-
else {
|
|
10587
|
-
// All keys exhausted
|
|
10588
|
-
throw new Error('모든 API 키가 Rate Limit 상태입니다. 잠시 후 다시 시도해주세요.');
|
|
10589
|
-
}
|
|
10590
|
-
}
|
|
10591
|
-
// Not a rate limit error, throw immediately
|
|
10592
|
-
throw error;
|
|
10593
|
-
}
|
|
10594
|
-
}
|
|
10595
|
-
// Should not reach here, but just in case
|
|
10596
|
-
throw lastError || new Error('Maximum retry attempts exceeded');
|
|
10597
|
-
}
|
|
10598
|
-
/**
|
|
10599
|
-
* Build request with single API key for server
|
|
10600
|
-
* (Key rotation is managed by frontend for financial security compliance)
|
|
10601
|
-
*/
|
|
10602
|
-
buildRequestWithSingleKey(request) {
|
|
10603
|
-
if (!request.llmConfig) {
|
|
10604
|
-
return request;
|
|
10605
|
-
}
|
|
10606
|
-
// Build config with single key (server only uses apiKey field)
|
|
10607
|
-
const singleKeyConfig = (0,_ApiKeyManager__WEBPACK_IMPORTED_MODULE_0__.buildSingleKeyConfig)(request.llmConfig);
|
|
10608
|
-
return {
|
|
10609
|
-
...request,
|
|
10610
|
-
llmConfig: singleKeyConfig
|
|
10611
|
-
};
|
|
9787
|
+
await this.sendAgentV2StreamInternal(request, onChunk, onMetadata, onDebug, onInterrupt, onTodos, onDebugClear, onToolCall, onComplete, threadId);
|
|
10612
9788
|
}
|
|
10613
9789
|
/**
|
|
10614
9790
|
* 기존 sendMessageStream 유지 (하위 호환성)
|
|
@@ -13519,4 +12695,4 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
13519
12695
|
/***/ }
|
|
13520
12696
|
|
|
13521
12697
|
}]);
|
|
13522
|
-
//# sourceMappingURL=lib_index_js.
|
|
12698
|
+
//# sourceMappingURL=lib_index_js.cc0a7158a5e3de7f22f7.js.map
|