hdsp-jupyter-extension 2.0.8__py3-none-any.whl → 2.0.11__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/core/notebook_generator.py +4 -4
- agent_server/core/rag_manager.py +12 -3
- agent_server/core/retriever.py +2 -1
- agent_server/core/vllm_embedding_service.py +8 -5
- agent_server/langchain/ARCHITECTURE.md +7 -51
- agent_server/langchain/agent.py +31 -20
- agent_server/langchain/custom_middleware.py +234 -31
- agent_server/langchain/hitl_config.py +5 -8
- agent_server/langchain/logging_utils.py +7 -7
- agent_server/langchain/prompts.py +106 -120
- agent_server/langchain/tools/__init__.py +1 -10
- agent_server/langchain/tools/file_tools.py +9 -61
- agent_server/langchain/tools/jupyter_tools.py +0 -1
- agent_server/langchain/tools/lsp_tools.py +8 -8
- agent_server/langchain/tools/resource_tools.py +12 -12
- agent_server/langchain/tools/search_tools.py +3 -158
- agent_server/prompts/file_action_prompts.py +8 -8
- agent_server/routers/langchain_agent.py +200 -125
- hdsp_agent_core/__init__.py +46 -47
- hdsp_agent_core/factory.py +6 -10
- hdsp_agent_core/interfaces.py +4 -2
- hdsp_agent_core/knowledge/__init__.py +5 -5
- hdsp_agent_core/knowledge/chunking.py +87 -61
- hdsp_agent_core/knowledge/loader.py +103 -101
- hdsp_agent_core/llm/service.py +192 -107
- hdsp_agent_core/managers/config_manager.py +16 -22
- hdsp_agent_core/managers/session_manager.py +5 -4
- hdsp_agent_core/models/__init__.py +12 -12
- hdsp_agent_core/models/agent.py +15 -8
- hdsp_agent_core/models/common.py +1 -2
- hdsp_agent_core/models/rag.py +48 -111
- hdsp_agent_core/prompts/__init__.py +12 -12
- hdsp_agent_core/prompts/cell_action_prompts.py +9 -7
- hdsp_agent_core/services/agent_service.py +10 -8
- hdsp_agent_core/services/chat_service.py +10 -6
- hdsp_agent_core/services/rag_service.py +3 -6
- hdsp_agent_core/tests/conftest.py +4 -1
- hdsp_agent_core/tests/test_factory.py +2 -2
- hdsp_agent_core/tests/test_services.py +12 -19
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/build_log.json +1 -1
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/package.json +2 -2
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.8740a527757068814573.js → hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2d9fb488c82498c45c2d.js +93 -4
- hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2d9fb488c82498c45c2d.js.map +1 -0
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.e4ff4b5779b5e049f84c.js → hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.58c1e128ba0b76f41f04.js +153 -130
- hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.58c1e128ba0b76f41f04.js.map +1 -0
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.020cdb0b864cfaa4e41e.js → hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.9da31d1134a53b0c4af5.js +6 -6
- hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.9da31d1134a53b0c4af5.js.map +1 -0
- {hdsp_jupyter_extension-2.0.8.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/METADATA +1 -3
- hdsp_jupyter_extension-2.0.11.dist-info/RECORD +144 -0
- jupyter_ext/__init__.py +21 -11
- jupyter_ext/_version.py +1 -1
- jupyter_ext/handlers.py +69 -50
- jupyter_ext/labextension/build_log.json +1 -1
- jupyter_ext/labextension/package.json +2 -2
- jupyter_ext/labextension/static/{frontend_styles_index_js.8740a527757068814573.js → frontend_styles_index_js.2d9fb488c82498c45c2d.js} +93 -4
- jupyter_ext/labextension/static/frontend_styles_index_js.2d9fb488c82498c45c2d.js.map +1 -0
- jupyter_ext/labextension/static/{lib_index_js.e4ff4b5779b5e049f84c.js → lib_index_js.58c1e128ba0b76f41f04.js} +153 -130
- jupyter_ext/labextension/static/lib_index_js.58c1e128ba0b76f41f04.js.map +1 -0
- jupyter_ext/labextension/static/{remoteEntry.020cdb0b864cfaa4e41e.js → remoteEntry.9da31d1134a53b0c4af5.js} +6 -6
- jupyter_ext/labextension/static/remoteEntry.9da31d1134a53b0c4af5.js.map +1 -0
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.8740a527757068814573.js.map +0 -1
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.e4ff4b5779b5e049f84c.js.map +0 -1
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.020cdb0b864cfaa4e41e.js.map +0 -1
- hdsp_jupyter_extension-2.0.8.dist-info/RECORD +0 -144
- jupyter_ext/labextension/static/frontend_styles_index_js.8740a527757068814573.js.map +0 -1
- jupyter_ext/labextension/static/lib_index_js.e4ff4b5779b5e049f84c.js.map +0 -1
- jupyter_ext/labextension/static/remoteEntry.020cdb0b864cfaa4e41e.js.map +0 -1
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/install.json +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/style.js +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.data → hdsp_jupyter_extension-2.0.11.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.8.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/WHEEL +0 -0
- {hdsp_jupyter_extension-2.0.8.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/licenses/LICENSE +0 -0
|
@@ -1157,10 +1157,8 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
1157
1157
|
console.log('[AgentPanel] Captured agentThreadId from interrupt:', interrupt.threadId);
|
|
1158
1158
|
}
|
|
1159
1159
|
// Auto-approve search/file/resource tools - execute immediately without user interaction
|
|
1160
|
-
if (interrupt.action === '
|
|
1161
|
-
|| interrupt.action === 'search_notebook_cells_tool'
|
|
1160
|
+
if (interrupt.action === 'search_notebook_cells_tool'
|
|
1162
1161
|
|| interrupt.action === 'check_resource_tool'
|
|
1163
|
-
|| interrupt.action === 'list_files_tool'
|
|
1164
1162
|
|| interrupt.action === 'read_file_tool') {
|
|
1165
1163
|
void handleAutoToolInterrupt(interrupt);
|
|
1166
1164
|
return;
|
|
@@ -2212,8 +2210,12 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
2212
2210
|
if (!pathCheck.valid) {
|
|
2213
2211
|
return { success: false, error: pathCheck.error };
|
|
2214
2212
|
}
|
|
2215
|
-
|
|
2216
|
-
const
|
|
2213
|
+
// Support both old (maxLines) and new (offset/limit) parameters
|
|
2214
|
+
const offset = typeof params.offset === 'number' ? Math.max(0, params.offset) : 0;
|
|
2215
|
+
const limit = typeof params.limit === 'number'
|
|
2216
|
+
? params.limit
|
|
2217
|
+
: (typeof params.maxLines === 'number' ? params.maxLines : 500);
|
|
2218
|
+
const safeLimit = Math.max(0, limit);
|
|
2217
2219
|
const contentsResult = await fetchContentsModel(params.path, { content: true, format: 'text' });
|
|
2218
2220
|
if (!contentsResult.success) {
|
|
2219
2221
|
return { success: false, error: contentsResult.error };
|
|
@@ -2233,13 +2235,18 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
2233
2235
|
content = JSON.stringify(content, null, 2);
|
|
2234
2236
|
}
|
|
2235
2237
|
const lines = content.split('\n');
|
|
2236
|
-
const
|
|
2238
|
+
const totalLines = lines.length;
|
|
2239
|
+
// Apply offset and limit
|
|
2240
|
+
const sliced = lines.slice(offset, offset + safeLimit);
|
|
2237
2241
|
return {
|
|
2238
2242
|
success: true,
|
|
2239
2243
|
output: sliced.join('\n'),
|
|
2240
2244
|
metadata: {
|
|
2241
2245
|
lineCount: sliced.length,
|
|
2242
|
-
|
|
2246
|
+
totalLines,
|
|
2247
|
+
offset,
|
|
2248
|
+
limit: safeLimit,
|
|
2249
|
+
truncated: totalLines > offset + safeLimit
|
|
2243
2250
|
}
|
|
2244
2251
|
};
|
|
2245
2252
|
};
|
|
@@ -2249,18 +2256,7 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
2249
2256
|
console.log('[AgentPanel] Auto-approving tool:', action, args);
|
|
2250
2257
|
try {
|
|
2251
2258
|
let executionResult;
|
|
2252
|
-
if (action === '
|
|
2253
|
-
setDebugStatus(`🔍 검색 실행 중: ${args?.pattern || ''}`);
|
|
2254
|
-
executionResult = await apiService.searchWorkspace({
|
|
2255
|
-
pattern: args?.pattern || '',
|
|
2256
|
-
file_types: args?.file_types || ['*.py', '*.ipynb'],
|
|
2257
|
-
path: args?.path || '.',
|
|
2258
|
-
max_results: args?.max_results || 50,
|
|
2259
|
-
case_sensitive: args?.case_sensitive || false
|
|
2260
|
-
});
|
|
2261
|
-
console.log('[AgentPanel] search_workspace result:', executionResult);
|
|
2262
|
-
}
|
|
2263
|
-
else if (action === 'search_notebook_cells_tool') {
|
|
2259
|
+
if (action === 'search_notebook_cells_tool') {
|
|
2264
2260
|
setDebugStatus(`🔍 노트북 검색 실행 중: ${args?.pattern || ''}`);
|
|
2265
2261
|
executionResult = await apiService.searchNotebookCells({
|
|
2266
2262
|
pattern: args?.pattern || '',
|
|
@@ -2282,22 +2278,13 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
2282
2278
|
});
|
|
2283
2279
|
console.log('[AgentPanel] check_resource result:', executionResult);
|
|
2284
2280
|
}
|
|
2285
|
-
else if (action === 'list_files_tool') {
|
|
2286
|
-
setDebugStatus('📂 파일 목록 조회 중...');
|
|
2287
|
-
const listParams = {
|
|
2288
|
-
path: typeof args?.path === 'string' ? args.path : '.',
|
|
2289
|
-
recursive: args?.recursive ?? false,
|
|
2290
|
-
pattern: args?.pattern ?? undefined
|
|
2291
|
-
};
|
|
2292
|
-
executionResult = await executeListFilesTool(listParams);
|
|
2293
|
-
console.log('[AgentPanel] list_files result:', executionResult);
|
|
2294
|
-
}
|
|
2295
2281
|
else if (action === 'read_file_tool') {
|
|
2296
2282
|
setDebugStatus('📄 파일 읽는 중...');
|
|
2297
2283
|
const readParams = {
|
|
2298
2284
|
path: typeof args?.path === 'string' ? args.path : '',
|
|
2299
2285
|
encoding: typeof args?.encoding === 'string' ? args.encoding : undefined,
|
|
2300
|
-
|
|
2286
|
+
offset: typeof args?.offset === 'number' ? args.offset : 0,
|
|
2287
|
+
limit: typeof args?.limit === 'number' ? args.limit : (args?.max_lines ?? args?.maxLines ?? 500)
|
|
2301
2288
|
};
|
|
2302
2289
|
executionResult = await executeReadFileTool(readParams);
|
|
2303
2290
|
console.log('[AgentPanel] read_file result:', executionResult);
|
|
@@ -2341,10 +2328,8 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
2341
2328
|
approvalPendingRef.current = true;
|
|
2342
2329
|
const autoApproveEnabled = getAutoApproveEnabled(llmConfig || (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_4__.getLLMConfig)() || (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_4__.getDefaultLLMConfig)());
|
|
2343
2330
|
// Handle next interrupt (could be another search or code execution)
|
|
2344
|
-
if (nextInterrupt.action === '
|
|
2345
|
-
|| nextInterrupt.action === 'search_notebook_cells_tool'
|
|
2331
|
+
if (nextInterrupt.action === 'search_notebook_cells_tool'
|
|
2346
2332
|
|| nextInterrupt.action === 'check_resource_tool'
|
|
2347
|
-
|| nextInterrupt.action === 'list_files_tool'
|
|
2348
2333
|
|| nextInterrupt.action === 'read_file_tool') {
|
|
2349
2334
|
void handleAutoToolInterrupt(nextInterrupt);
|
|
2350
2335
|
return;
|
|
@@ -2673,7 +2658,7 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
2673
2658
|
};
|
|
2674
2659
|
}
|
|
2675
2660
|
else {
|
|
2676
|
-
// LSP not available - suggest using
|
|
2661
|
+
// LSP not available - suggest using execute_command_tool with grep
|
|
2677
2662
|
console.log('[AgentPanel] LSP not available for references, suggesting grep fallback');
|
|
2678
2663
|
resumeDecision = 'approve';
|
|
2679
2664
|
resumeArgs = {
|
|
@@ -2839,10 +2824,8 @@ const ChatPanel = (0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)(({ apiServic
|
|
|
2839
2824
|
approvalPendingRef.current = true;
|
|
2840
2825
|
const autoApproveEnabled = getAutoApproveEnabled(llmConfig || (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_4__.getLLMConfig)() || (0,_services_ApiKeyManager__WEBPACK_IMPORTED_MODULE_4__.getDefaultLLMConfig)());
|
|
2841
2826
|
// Auto-approve search/file/resource tools
|
|
2842
|
-
if (nextInterrupt.action === '
|
|
2843
|
-
|| nextInterrupt.action === 'search_notebook_cells_tool'
|
|
2827
|
+
if (nextInterrupt.action === 'search_notebook_cells_tool'
|
|
2844
2828
|
|| nextInterrupt.action === 'check_resource_tool'
|
|
2845
|
-
|| nextInterrupt.action === 'list_files_tool'
|
|
2846
2829
|
|| nextInterrupt.action === 'read_file_tool') {
|
|
2847
2830
|
void handleAutoToolInterrupt(nextInterrupt);
|
|
2848
2831
|
return;
|
|
@@ -3278,9 +3261,10 @@ SyntaxError: '(' was never closed
|
|
|
3278
3261
|
const interruptAction = msg.metadata?.interrupt?.action;
|
|
3279
3262
|
const isWriteFile = interruptAction === 'write_file_tool';
|
|
3280
3263
|
const isEditFile = interruptAction === 'edit_file_tool';
|
|
3264
|
+
const isMultiEditFile = interruptAction === 'multiedit_file_tool';
|
|
3281
3265
|
const writePath = (isWriteFile
|
|
3282
3266
|
&& typeof msg.metadata?.interrupt?.args?.path === 'string') ? msg.metadata?.interrupt?.args?.path : '';
|
|
3283
|
-
const editPath = (isEditFile
|
|
3267
|
+
const editPath = ((isEditFile || isMultiEditFile)
|
|
3284
3268
|
&& typeof msg.metadata?.interrupt?.args?.path === 'string') ? msg.metadata?.interrupt?.args?.path : '';
|
|
3285
3269
|
const autoApproved = msg.metadata?.interrupt?.autoApproved;
|
|
3286
3270
|
const headerRole = msg.role === 'user'
|
|
@@ -3300,10 +3284,26 @@ SyntaxError: '(' was never closed
|
|
|
3300
3284
|
react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { className: "jp-agent-interrupt-action-args" }, (() => {
|
|
3301
3285
|
const command = msg.metadata?.interrupt?.args?.command;
|
|
3302
3286
|
const code = msg.metadata?.interrupt?.args?.code || msg.metadata?.interrupt?.args?.content || '';
|
|
3303
|
-
// Handle edit_file_tool with diff preview
|
|
3287
|
+
// Handle edit_file_tool and multiedit_file_tool with diff preview
|
|
3304
3288
|
let snippet;
|
|
3305
3289
|
let language;
|
|
3306
|
-
if (
|
|
3290
|
+
if (isMultiEditFile) {
|
|
3291
|
+
// Handle multiedit_file_tool - show all edits
|
|
3292
|
+
const edits = msg.metadata?.interrupt?.args?.edits || [];
|
|
3293
|
+
const editsPreview = edits.slice(0, 5).map((edit, idx) => {
|
|
3294
|
+
const oldStr = edit.old_string || '';
|
|
3295
|
+
const newStr = edit.new_string || '';
|
|
3296
|
+
const oldPreview = oldStr.length > 100 ? oldStr.slice(0, 100) + '...' : oldStr;
|
|
3297
|
+
const newPreview = newStr.length > 100 ? newStr.slice(0, 100) + '...' : newStr;
|
|
3298
|
+
return `# Edit ${idx + 1}${edit.replace_all ? ' (replace_all)' : ''}\n` +
|
|
3299
|
+
oldPreview.split('\n').map((line) => `-${line}`).join('\n') + '\n' +
|
|
3300
|
+
newPreview.split('\n').map((line) => `+${line}`).join('\n');
|
|
3301
|
+
}).join('\n\n');
|
|
3302
|
+
const moreEdits = edits.length > 5 ? `\n\n... and ${edits.length - 5} more edits` : '';
|
|
3303
|
+
snippet = `--- ${editPath} (${edits.length} edits)\n+++ ${editPath} (after)\n\n${editsPreview}${moreEdits}`;
|
|
3304
|
+
language = 'diff';
|
|
3305
|
+
}
|
|
3306
|
+
else if (isEditFile) {
|
|
3307
3307
|
const oldStr = msg.metadata?.interrupt?.args?.old_string || '';
|
|
3308
3308
|
const newStr = msg.metadata?.interrupt?.args?.new_string || '';
|
|
3309
3309
|
const replaceAll = msg.metadata?.interrupt?.args?.replace_all;
|
|
@@ -3342,9 +3342,10 @@ SyntaxError: '(' was never closed
|
|
|
3342
3342
|
const safePath = escapeHtml(writePath);
|
|
3343
3343
|
html = html.replace(/<span class="code-block-language">[^<]*<\/span>/, `<span class="code-block-language jp-agent-interrupt-path">${safePath}</span>`);
|
|
3344
3344
|
}
|
|
3345
|
-
if (isEditFile && editPath) {
|
|
3345
|
+
if ((isEditFile || isMultiEditFile) && editPath) {
|
|
3346
3346
|
const safePath = escapeHtml(editPath);
|
|
3347
|
-
|
|
3347
|
+
const editIcon = isMultiEditFile ? '📝' : '✏️';
|
|
3348
|
+
html = html.replace(/<span class="code-block-language">[^<]*<\/span>/, `<span class="code-block-language jp-agent-interrupt-path">${editIcon} ${safePath}</span>`);
|
|
3348
3349
|
}
|
|
3349
3350
|
// actionHtml이 비어있지 않을 때만 추가
|
|
3350
3351
|
return actionHtml ? html.replace('</div>', `${actionHtml}</div>`) : html;
|
|
@@ -5699,10 +5700,10 @@ class IdleMonitorService {
|
|
|
5699
5700
|
console.log('[IdleMonitor] Idle timeout reached. Triggering shutdown...');
|
|
5700
5701
|
// Hide countdown
|
|
5701
5702
|
this.hideCountdown();
|
|
5702
|
-
//
|
|
5703
|
+
// Call shutdown API FIRST (non-blocking) - shutdown starts immediately
|
|
5704
|
+
this.callShutdownApi().catch(e => console.error('[IdleMonitor] Shutdown API error:', e));
|
|
5705
|
+
// Show notification popup (for user info only - shutdown already initiated)
|
|
5703
5706
|
alert(`${this.idleTimeoutMinutes}분 동안 활동이 없어 세션이 종료됩니다.`);
|
|
5704
|
-
// Call shutdown API
|
|
5705
|
-
await this.callShutdownApi();
|
|
5706
5707
|
}
|
|
5707
5708
|
/**
|
|
5708
5709
|
* Call HDSP shutdown API via Jupyter server endpoint
|
|
@@ -6059,7 +6060,7 @@ class LSPBridgeService {
|
|
|
6059
6060
|
};
|
|
6060
6061
|
}
|
|
6061
6062
|
// TODO: jupyterlab-lsp 연결 시 구현
|
|
6062
|
-
// 현재는 빈 결과 반환 (Agent가
|
|
6063
|
+
// 현재는 빈 결과 반환 (Agent가 execute_command_tool with grep 사용하도록)
|
|
6063
6064
|
return {
|
|
6064
6065
|
success: false,
|
|
6065
6066
|
locations: []
|
|
@@ -9051,72 +9052,63 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
9051
9052
|
* - Key rotation on rate limit (429) is handled by frontend
|
|
9052
9053
|
*/
|
|
9053
9054
|
const STORAGE_KEY = 'hdsp-agent-llm-config';
|
|
9054
|
-
const DEFAULT_LANGCHAIN_SYSTEM_PROMPT = `You are an expert Python data scientist and Jupyter notebook assistant.
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9060
|
-
|
|
9061
|
-
|
|
9062
|
-
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
|
|
9066
|
-
|
|
9067
|
-
1.
|
|
9068
|
-
2.
|
|
9069
|
-
3.
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
}
|
|
9078
|
-
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
9084
|
-
|
|
9085
|
-
|
|
9086
|
-
|
|
9087
|
-
|
|
9088
|
-
|
|
9089
|
-
|
|
9090
|
-
|
|
9091
|
-
|
|
9092
|
-
|
|
9093
|
-
|
|
9094
|
-
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9098
|
-
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
-
|
|
9109
|
-
-
|
|
9110
|
-
-
|
|
9111
|
-
- Any research or investigation task
|
|
9112
|
-
|
|
9113
|
-
**When full read is OK:**
|
|
9114
|
-
- Small files (<500 lines)
|
|
9115
|
-
- Files you need to edit immediately after reading
|
|
9116
|
-
- After confirming file size with first scan
|
|
9117
|
-
|
|
9118
|
-
## 🔧 Code Development
|
|
9119
|
-
For code generation/refactoring, use LSP tools (diagnostics_tool, references_tool) to check errors and find symbol usages. Use multiedit_file_tool for multiple changes in one file.
|
|
9055
|
+
const DEFAULT_LANGCHAIN_SYSTEM_PROMPT = `You are an expert Python data scientist and Jupyter notebook assistant. Respond in Korean only.
|
|
9056
|
+
|
|
9057
|
+
# Core Rules
|
|
9058
|
+
1. Be concise (≤4 lines unless detail requested)
|
|
9059
|
+
2. ALWAYS call a tool in every response - never respond with text only
|
|
9060
|
+
3. ALWAYS include a brief Korean explanation before tool calls
|
|
9061
|
+
|
|
9062
|
+
# Task Workflow
|
|
9063
|
+
|
|
9064
|
+
## Simple Tasks (1-2 steps)
|
|
9065
|
+
Execute directly without todos.
|
|
9066
|
+
|
|
9067
|
+
## Complex Tasks (3+ steps)
|
|
9068
|
+
1. Create todos with write_todos (all items in Korean)
|
|
9069
|
+
2. ALWAYS include "작업 요약 및 다음단계 제시" as the LAST item
|
|
9070
|
+
3. After each tool result: check todos → call next tool → repeat
|
|
9071
|
+
4. **Final todo ("작업 요약 및 다음단계 제시")**:
|
|
9072
|
+
- FIRST: Output summary JSON in your content (REQUIRED!)
|
|
9073
|
+
- THEN: Call write_todos to mark all as completed
|
|
9074
|
+
- Both must be in the SAME response
|
|
9075
|
+
|
|
9076
|
+
### Summary JSON Format (MUST output before marking complete)
|
|
9077
|
+
\`\`\`json
|
|
9078
|
+
{"summary": "실행된 작업 요약", "next_items": [{"subject": "제목", "description": "설명"}]}
|
|
9079
|
+
\`\`\`
|
|
9080
|
+
Suggest 3-5 next items. **You CANNOT mark "작업 요약" as completed without outputting this JSON first.**
|
|
9081
|
+
|
|
9082
|
+
# Mandatory Checks
|
|
9083
|
+
|
|
9084
|
+
## Resource Check (BEFORE data operations)
|
|
9085
|
+
Call \`check_resource_tool\` FIRST when:
|
|
9086
|
+
- Loading files (.csv, .parquet, .json, .xlsx, .pickle, .h5, .feather)
|
|
9087
|
+
- Using pandas/polars/dask for dataframes
|
|
9088
|
+
- Training ML models
|
|
9089
|
+
|
|
9090
|
+
# Tool Usage
|
|
9091
|
+
|
|
9092
|
+
## File Search (execute_command_tool)
|
|
9093
|
+
\`\`\`bash
|
|
9094
|
+
find . -iname '*filename*.csv' 2>/dev/null # Find by name
|
|
9095
|
+
grep -rn 'pattern' --include='*.py' . # Search contents
|
|
9096
|
+
\`\`\`
|
|
9097
|
+
|
|
9098
|
+
## File Reading (read_file_tool)
|
|
9099
|
+
- Large files: \`read_file_tool(path, limit=100)\` first
|
|
9100
|
+
- Use \`offset\` for pagination
|
|
9101
|
+
- Small files (<500 lines): Read without limit
|
|
9102
|
+
|
|
9103
|
+
## Code Output
|
|
9104
|
+
- For plots/charts: Use English labels only
|
|
9105
|
+
- Use LSP tools for error checking and symbol lookup
|
|
9106
|
+
- Use multiedit_file_tool for multiple changes
|
|
9107
|
+
|
|
9108
|
+
# Forbidden
|
|
9109
|
+
- Empty responses (no tool call AND no content)
|
|
9110
|
+
- Tool calls without Korean explanation
|
|
9111
|
+
- Stopping with pending/in_progress todos
|
|
9120
9112
|
`;
|
|
9121
9113
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
9122
9114
|
// Key Rotation State (in-memory, not persisted)
|
|
@@ -12183,7 +12175,7 @@ class ToolExecutor {
|
|
|
12183
12175
|
return { text, truncated: lines.length > maxLines };
|
|
12184
12176
|
}
|
|
12185
12177
|
/**
|
|
12186
|
-
* read_file 도구: 파일 읽기
|
|
12178
|
+
* read_file 도구: 파일 읽기 (offset/limit 지원)
|
|
12187
12179
|
*/
|
|
12188
12180
|
async executeReadFile(params) {
|
|
12189
12181
|
console.log('[ToolExecutor] executeReadFile:', params);
|
|
@@ -12193,15 +12185,29 @@ class ToolExecutor {
|
|
|
12193
12185
|
return { success: false, error: pathCheck.error };
|
|
12194
12186
|
}
|
|
12195
12187
|
const encoding = params.encoding || 'utf-8';
|
|
12196
|
-
|
|
12197
|
-
|
|
12188
|
+
// Support both old (maxLines) and new (offset/limit) parameters
|
|
12189
|
+
const offset = typeof params.offset === 'number' ? Math.max(0, params.offset) : 0;
|
|
12190
|
+
const limit = typeof params.limit === 'number'
|
|
12191
|
+
? params.limit
|
|
12192
|
+
: (typeof params.maxLines === 'number' ? params.maxLines : 500);
|
|
12193
|
+
// Python 코드로 파일 읽기 (커널에서 실행) - offset/limit 적용
|
|
12198
12194
|
const pythonCode = `
|
|
12199
12195
|
import json
|
|
12200
12196
|
try:
|
|
12201
12197
|
with open(${JSON.stringify(params.path)}, 'r', encoding=${JSON.stringify(encoding)}) as f:
|
|
12202
|
-
|
|
12203
|
-
|
|
12204
|
-
|
|
12198
|
+
all_lines = f.readlines()
|
|
12199
|
+
total_lines = len(all_lines)
|
|
12200
|
+
sliced_lines = all_lines[${offset}:${offset + limit}]
|
|
12201
|
+
content = ''.join(sliced_lines)
|
|
12202
|
+
result = {
|
|
12203
|
+
'success': True,
|
|
12204
|
+
'content': content,
|
|
12205
|
+
'lineCount': len(sliced_lines),
|
|
12206
|
+
'totalLines': total_lines,
|
|
12207
|
+
'offset': ${offset},
|
|
12208
|
+
'limit': ${limit},
|
|
12209
|
+
'truncated': total_lines > ${offset + limit}
|
|
12210
|
+
}
|
|
12205
12211
|
except FileNotFoundError:
|
|
12206
12212
|
result = {'success': False, 'error': f'File not found: ${params.path}'}
|
|
12207
12213
|
except PermissionError:
|
|
@@ -15068,19 +15074,19 @@ function extractNextItemsBlock(text) {
|
|
|
15068
15074
|
if (lang && lang !== 'json' && !content.includes('"next_items"')) {
|
|
15069
15075
|
continue;
|
|
15070
15076
|
}
|
|
15071
|
-
const
|
|
15072
|
-
if (
|
|
15077
|
+
const parsed = parseNextItemsPayload(content);
|
|
15078
|
+
if (parsed) {
|
|
15073
15079
|
const placeholder = `__NEXT_ITEMS_${Math.random().toString(36).slice(2, 11)}__`;
|
|
15074
15080
|
const updated = text.slice(0, match.index) + placeholder + text.slice(match.index + match[0].length);
|
|
15075
|
-
return { items, placeholder, text: updated };
|
|
15081
|
+
return { items: parsed.items, summary: parsed.summary, placeholder, text: updated };
|
|
15076
15082
|
}
|
|
15077
15083
|
}
|
|
15078
15084
|
const range = findNextItemsJsonRange(text);
|
|
15079
15085
|
if (!range)
|
|
15080
15086
|
return null;
|
|
15081
15087
|
const candidate = text.slice(range.start, range.end + 1);
|
|
15082
|
-
const
|
|
15083
|
-
if (!
|
|
15088
|
+
const parsed = parseNextItemsPayload(candidate);
|
|
15089
|
+
if (!parsed)
|
|
15084
15090
|
return null;
|
|
15085
15091
|
let replacementStart = range.start;
|
|
15086
15092
|
const lineStart = text.lastIndexOf('\n', range.start - 1) + 1;
|
|
@@ -15091,7 +15097,7 @@ function extractNextItemsBlock(text) {
|
|
|
15091
15097
|
}
|
|
15092
15098
|
const placeholder = `__NEXT_ITEMS_${Math.random().toString(36).slice(2, 11)}__`;
|
|
15093
15099
|
const updated = text.slice(0, replacementStart) + placeholder + text.slice(range.end + 1);
|
|
15094
|
-
return { items, placeholder, text: updated };
|
|
15100
|
+
return { items: parsed.items, summary: parsed.summary, placeholder, text: updated };
|
|
15095
15101
|
}
|
|
15096
15102
|
function findNextItemsJsonRange(text) {
|
|
15097
15103
|
const key = '"next_items"';
|
|
@@ -15169,17 +15175,25 @@ function parseNextItemsPayload(payload) {
|
|
|
15169
15175
|
return { subject, description };
|
|
15170
15176
|
})
|
|
15171
15177
|
.filter((item) => Boolean(item));
|
|
15172
|
-
|
|
15178
|
+
// Extract summary field if present
|
|
15179
|
+
const summaryRaw = parsed.summary;
|
|
15180
|
+
const summary = typeof summaryRaw === 'string' && summaryRaw.trim() ? summaryRaw.trim() : null;
|
|
15181
|
+
return items.length > 0 ? { items, summary } : null;
|
|
15173
15182
|
}
|
|
15174
15183
|
catch {
|
|
15175
15184
|
return null;
|
|
15176
15185
|
}
|
|
15177
15186
|
}
|
|
15178
|
-
function renderNextItemsList(items) {
|
|
15179
|
-
// Simple arrow icon
|
|
15187
|
+
function renderNextItemsList(items, summary) {
|
|
15188
|
+
// Simple arrow icon for next items
|
|
15180
15189
|
const arrowSvg = `
|
|
15181
15190
|
<svg class="jp-next-items-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
15182
15191
|
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"/>
|
|
15192
|
+
</svg>`;
|
|
15193
|
+
// Checkmark icon for summary
|
|
15194
|
+
const checkSvg = `
|
|
15195
|
+
<svg class="jp-summary-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
15196
|
+
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
|
15183
15197
|
</svg>`;
|
|
15184
15198
|
const listItems = items.map((item) => {
|
|
15185
15199
|
const subject = escapeHtml(item.subject);
|
|
@@ -15195,7 +15209,16 @@ function renderNextItemsList(items) {
|
|
|
15195
15209
|
${arrowSvg}
|
|
15196
15210
|
</li>`;
|
|
15197
15211
|
}).join('');
|
|
15198
|
-
|
|
15212
|
+
// Render summary as separate block above next items
|
|
15213
|
+
const summaryHtml = summary ? `
|
|
15214
|
+
<div class="jp-summary-block">
|
|
15215
|
+
<div class="jp-summary-header">작업 요약</div>
|
|
15216
|
+
<div class="jp-summary-body">
|
|
15217
|
+
${checkSvg}
|
|
15218
|
+
<div class="jp-summary-content">${escapeHtml(summary)}</div>
|
|
15219
|
+
</div>
|
|
15220
|
+
</div>` : '';
|
|
15221
|
+
return `${summaryHtml}
|
|
15199
15222
|
<div class="jp-next-items" data-next-items="true">
|
|
15200
15223
|
<div class="jp-next-items-header">다음 단계 제안</div>
|
|
15201
15224
|
<ul class="jp-next-items-list" role="list">
|
|
@@ -15821,7 +15844,7 @@ function formatMarkdownToHtml(text) {
|
|
|
15821
15844
|
});
|
|
15822
15845
|
// Step 8.5: Restore next items list placeholders
|
|
15823
15846
|
if (nextItemsBlock) {
|
|
15824
|
-
html = html.split(nextItemsBlock.placeholder).join(renderNextItemsList(nextItemsBlock.items));
|
|
15847
|
+
html = html.split(nextItemsBlock.placeholder).join(renderNextItemsList(nextItemsBlock.items, nextItemsBlock.summary));
|
|
15825
15848
|
}
|
|
15826
15849
|
return html;
|
|
15827
15850
|
}
|
|
@@ -15984,4 +16007,4 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
15984
16007
|
/***/ }
|
|
15985
16008
|
|
|
15986
16009
|
}]);
|
|
15987
|
-
//# sourceMappingURL=lib_index_js.
|
|
16010
|
+
//# sourceMappingURL=lib_index_js.58c1e128ba0b76f41f04.js.map
|