hdsp-jupyter-extension 2.0.0__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/__init__.py +8 -0
- agent_server/core/__init__.py +92 -0
- agent_server/core/api_key_manager.py +427 -0
- agent_server/core/code_validator.py +1238 -0
- agent_server/core/context_condenser.py +308 -0
- agent_server/core/embedding_service.py +254 -0
- agent_server/core/error_classifier.py +577 -0
- agent_server/core/llm_client.py +95 -0
- agent_server/core/llm_service.py +649 -0
- agent_server/core/notebook_generator.py +274 -0
- agent_server/core/prompt_builder.py +35 -0
- agent_server/core/rag_manager.py +742 -0
- agent_server/core/reflection_engine.py +489 -0
- agent_server/core/retriever.py +248 -0
- agent_server/core/state_verifier.py +452 -0
- agent_server/core/summary_generator.py +484 -0
- agent_server/core/task_manager.py +198 -0
- agent_server/knowledge/__init__.py +9 -0
- agent_server/knowledge/watchdog_service.py +352 -0
- agent_server/main.py +160 -0
- agent_server/prompts/__init__.py +60 -0
- agent_server/prompts/file_action_prompts.py +113 -0
- agent_server/routers/__init__.py +9 -0
- agent_server/routers/agent.py +591 -0
- agent_server/routers/chat.py +188 -0
- agent_server/routers/config.py +100 -0
- agent_server/routers/file_resolver.py +293 -0
- agent_server/routers/health.py +42 -0
- agent_server/routers/rag.py +163 -0
- agent_server/schemas/__init__.py +60 -0
- hdsp_agent_core/__init__.py +158 -0
- hdsp_agent_core/factory.py +252 -0
- hdsp_agent_core/interfaces.py +203 -0
- hdsp_agent_core/knowledge/__init__.py +31 -0
- hdsp_agent_core/knowledge/chunking.py +356 -0
- hdsp_agent_core/knowledge/libraries/dask.md +188 -0
- hdsp_agent_core/knowledge/libraries/matplotlib.md +164 -0
- hdsp_agent_core/knowledge/libraries/polars.md +68 -0
- hdsp_agent_core/knowledge/loader.py +337 -0
- hdsp_agent_core/llm/__init__.py +13 -0
- hdsp_agent_core/llm/service.py +556 -0
- hdsp_agent_core/managers/__init__.py +22 -0
- hdsp_agent_core/managers/config_manager.py +133 -0
- hdsp_agent_core/managers/session_manager.py +251 -0
- hdsp_agent_core/models/__init__.py +115 -0
- hdsp_agent_core/models/agent.py +316 -0
- hdsp_agent_core/models/chat.py +41 -0
- hdsp_agent_core/models/common.py +95 -0
- hdsp_agent_core/models/rag.py +368 -0
- hdsp_agent_core/prompts/__init__.py +63 -0
- hdsp_agent_core/prompts/auto_agent_prompts.py +1260 -0
- hdsp_agent_core/prompts/cell_action_prompts.py +98 -0
- hdsp_agent_core/services/__init__.py +18 -0
- hdsp_agent_core/services/agent_service.py +438 -0
- hdsp_agent_core/services/chat_service.py +205 -0
- hdsp_agent_core/services/rag_service.py +262 -0
- hdsp_agent_core/tests/__init__.py +1 -0
- hdsp_agent_core/tests/conftest.py +102 -0
- hdsp_agent_core/tests/test_factory.py +251 -0
- hdsp_agent_core/tests/test_services.py +326 -0
- hdsp_jupyter_extension-2.0.0.data/data/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +7 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/build_log.json +738 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/install.json +5 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/package.json +134 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2607ff74c74acfa83158.js +4369 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2607ff74c74acfa83158.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.622c1a5918b3aafb2315.js +12496 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.622c1a5918b3aafb2315.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.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 +94 -0
- hdsp_jupyter_extension-2.0.0.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 +1 -0
- hdsp_jupyter_extension-2.0.0.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 +94 -0
- hdsp_jupyter_extension-2.0.0.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 +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.dae97cde171e13b8c834.js +623 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.dae97cde171e13b8c834.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/style.js +4 -0
- hdsp_jupyter_extension-2.0.0.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 +507 -0
- hdsp_jupyter_extension-2.0.0.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 +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js-node_modules-782ee5.d9ed8645ef1d311657d8.js +2071 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js-node_modules-782ee5.d9ed8645ef1d311657d8.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.36b49c71871f98d4f549.js +1059 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.36b49c71871f98d4f549.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js +376 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js +60336 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js +7132 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.dist-info/METADATA +152 -0
- hdsp_jupyter_extension-2.0.0.dist-info/RECORD +121 -0
- hdsp_jupyter_extension-2.0.0.dist-info/WHEEL +4 -0
- hdsp_jupyter_extension-2.0.0.dist-info/licenses/LICENSE +21 -0
- jupyter_ext/__init__.py +233 -0
- jupyter_ext/_version.py +4 -0
- jupyter_ext/config.py +111 -0
- jupyter_ext/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +7 -0
- jupyter_ext/handlers.py +632 -0
- jupyter_ext/labextension/build_log.json +738 -0
- jupyter_ext/labextension/package.json +134 -0
- jupyter_ext/labextension/static/frontend_styles_index_js.2607ff74c74acfa83158.js +4369 -0
- jupyter_ext/labextension/static/frontend_styles_index_js.2607ff74c74acfa83158.js.map +1 -0
- jupyter_ext/labextension/static/lib_index_js.622c1a5918b3aafb2315.js +12496 -0
- jupyter_ext/labextension/static/lib_index_js.622c1a5918b3aafb2315.js.map +1 -0
- jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b80.c095373419d05e6f141a.js +94 -0
- jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b80.c095373419d05e6f141a.js.map +1 -0
- jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b81.61e75fb98ecff46cf836.js +94 -0
- jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b81.61e75fb98ecff46cf836.js.map +1 -0
- jupyter_ext/labextension/static/remoteEntry.dae97cde171e13b8c834.js +623 -0
- jupyter_ext/labextension/static/remoteEntry.dae97cde171e13b8c834.js.map +1 -0
- jupyter_ext/labextension/static/style.js +4 -0
- jupyter_ext/labextension/static/vendors-node_modules_babel_runtime_helpers_esm_extends_js-node_modules_emotion_serialize_dist-051195.e2553aab0c3963b83dd7.js +507 -0
- jupyter_ext/labextension/static/vendors-node_modules_babel_runtime_helpers_esm_extends_js-node_modules_emotion_serialize_dist-051195.e2553aab0c3963b83dd7.js.map +1 -0
- jupyter_ext/labextension/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js-node_modules-782ee5.d9ed8645ef1d311657d8.js +2071 -0
- jupyter_ext/labextension/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js-node_modules-782ee5.d9ed8645ef1d311657d8.js.map +1 -0
- jupyter_ext/labextension/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.36b49c71871f98d4f549.js +1059 -0
- jupyter_ext/labextension/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.36b49c71871f98d4f549.js.map +1 -0
- jupyter_ext/labextension/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js +376 -0
- jupyter_ext/labextension/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js.map +1 -0
- jupyter_ext/labextension/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js +60336 -0
- jupyter_ext/labextension/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js.map +1 -0
- jupyter_ext/labextension/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js +7132 -0
- jupyter_ext/labextension/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lib_index_js.622c1a5918b3aafb2315.js","mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACyG;AACxC;AACjB;AAC6D;AAC3C;AACD;AACA;AACL;AAC5D;AAC0D;AAC1D;AACA,wBAAwB,8DAAO;AAC/B;AACA,YAAY,mDAAa;AACzB,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB,iDAAU,IAAI,6CAA6C;AAC7E;AACA,oCAAoC,+CAAQ;AAC5C,8BAA8B,+CAAQ;AACtC,sCAAsC,+CAAQ;AAC9C,0CAA0C,+CAAQ;AAClD,wDAAwD,+CAAQ;AAChE,gDAAgD,+CAAQ;AACxD,4CAA4C,+CAAQ;AACpD,sCAAsC,+CAAQ;AAC9C;AACA,gDAAgD,+CAAQ;AACxD,8DAA8D,+CAAQ;AACtE,gDAAgD,+CAAQ;AACxD;AACA,sCAAsC,+CAAQ;AAC9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,oDAAoD,+CAAQ;AAC5D;AACA,oDAAoD,+CAAQ;AAC5D;AACA,oDAAoD,+CAAQ;AAC5D,4EAA4E,+CAAQ;AACpF;AACA,8DAA8D,+CAAQ;AACtE,0DAA0D,+CAAQ;AAClE;AACA,IAAI,gDAAS;AACb;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,2BAA2B,6CAAM;AACjC,gCAAgC,6CAAM;AACtC,6BAA6B,6CAAM;AACnC,6BAA6B,6CAAM;AACnC,gCAAgC,6CAAM;AACtC,4BAA4B,6CAAM;AAClC;AACA,IAAI,0DAAmB;AACvB;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,IAAI,gDAAS;AACb;AACA,KAAK;AACL;AACA;AACA;AACA,IAAI,gDAAS;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,iCAAiC,kDAAW;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,GAAG,wEAAyB;AACrD,iCAAiC,0EAAiB;AAClD;AACA,wCAAwC,WAAW;AACnD;AACA;AACA;AACA;AACA,sBAAsB,6CAA6C;AACnE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,qEAAY,MAAM,4EAAmB;AACvF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,mCAAmC;AAC9E;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAA8B,yDAAyD;AACvF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,uBAAuB,qEAAY;AACnC;AACA;AACA,kCAAkC,4EAAmB;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,qBAAqB,QAAQ,gLAA+B;AAChF;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,qBAAqB,QAAQ,gLAA+B;AAChF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,yCAAyC;AACrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,eAAe;AACvD;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,QAAQ,GAAG,WAAW,UAAU,WAAW;AACvF;AACA;AACA;AACA,wCAAwC,2BAA2B;AACnE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,wCAAwC;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,8BAA8B;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,SAAS;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yCAAyC,SAAS;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,QAAQ;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,uEAAc;AACzD;AACA,QAAQ,sEAAa;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,sBAAsB;AAClE,qBAAqB;AACrB;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,mCAAmC,iBAAiB,UAAU,kBAAkB;AAChF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,sBAAsB;AAClE,qBAAqB;AACrB;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,gDAAS;AACb,iDAAiD,oBAAoB;AACrE,KAAK;AACL;AACA,IAAI,gDAAS;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8CAA8C,mBAAmB;AACjE;AACA;AACA;AACA;AACA;AACA;AACA,gEAAgE,QAAQ;AACxE;AACA,+DAA+D,SAAS;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,+CAA+C,mBAAmB;AAClE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8FAA8F,QAAQ;AACtG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA,mGAAmG,kBAAkB;AACrH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,QAAQ;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,SAAS;AACT;AACA;AACA;AACA,6DAA6D,kCAAkC;AAC/F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,WAAW,GAAG,wCAAwC;AACtF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,oBAAoB;AACtE;AACA,mEAAmE,GAAG;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,qBAAqB,UAAU,mBAAmB;AACzF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,UAAU;AAC9B;AACA,yCAAyC,gBAAgB,iCAAiC,qBAAqB,kBAAkB,wBAAwB;AACzJ,gBAAgB,oBAAoB,EAAE;AACtC;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,wCAAwC;AACxC,wCAAwC,gBAAgB,iBAAiB,iBAAiB;AAC1F;AACA;AACA,+BAA+B,gBAAgB,gBAAgB;AAC/D;AACA;AACA;AACA,mEAAmE;AACnE,YAAY;AACZ;AACA,mCAAmC,WAAW,0BAA0B;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,aAAa;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,qEAAY,MAAM,4EAAmB;AACjE;AACA;AACA;AACA,0BAA0B,uEAAc;AACxC;AACA;AACA;AACA;AACA;AACA;AACA,oDAAoD,sFAAsF;AAC1I;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,wBAAwB;AACxB;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA,6DAA6D,kEAAkE;AAC/H;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,6DAA6D;AAC7E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,0DAAmB,UAAU,yCAAyC;AACtF,YAAY,0DAAmB,UAAU,wCAAwC;AACjF,gBAAgB,0DAAmB,UAAU,uCAAuC;AACpF,oBAAoB,0DAAmB,UAAU,uEAAuE;AACxH,wBAAwB,0DAAmB,WAAW,+EAA+E;AACrI,wBAAwB,0DAAmB,WAAW,sGAAsG;AAC5J;AACA,gBAAgB,0DAAmB,WAAW,yCAAyC;AACvF,YAAY,0DAAmB,UAAU,mEAAmE,aAAa,GAAG;AAC5H,4BAA4B,0DAAmB,UAAU,yCAAyC;AAClG,iDAAiD,0DAAmB,UAAU,2FAA2F;AACzK,oBAAoB,0DAAmB,WAAW,sIAAsI;AACxL,8CAA8C,0DAAmB,UAAU,yFAAyF;AACpK,oBAAoB,0DAAmB,WAAW,4LAA4L;AAC9O,gBAAgB,0DAAmB,WAAW,6CAA6C;AAC3F;AACA;AACA;AACA;AACA,qBAAqB,0DAAmB,UAAU,sCAAsC;AACxF,gBAAgB,0DAAmB,UAAU,6CAA6C;AAC1F,oBAAoB,0DAAmB;AACvC,oBAAoB,0DAAmB,WAAW,+CAA+C;AACjG;AACA;AACA;AACA,gBAAgB,0DAAmB,UAAU,8CAA8C;AAC3F,oBAAoB,0DAAmB,UAAU,wDAAwD,UAAU,gBAAgB,MAAM;AACzI,gBAAgB,0DAAmB,UAAU,uCAAuC;AACpF;AACA,4BAA4B,0DAAmB,UAAU,qFAAqF,WAAW;AACzJ;AACA;AACA,oDAAoD,sCAAsC;AAC1F;AACA,2BAA2B;AAC3B,wBAAwB,0DAAmB,UAAU,gDAAgD;AACrG,2DAA2D,0DAAmB,UAAU,4CAA4C;AACpI,gCAAgC,0DAAmB,WAAW,sIAAsI;AACpM,wDAAwD,0DAAmB,UAAU,4CAA4C;AACjI,gCAAgC,0DAAmB,WAAW,4LAA4L;AAC1P,wDAAwD,0DAAmB,UAAU,8CAA8C;AACnI,wDAAwD,0DAAmB;AAC3E,wBAAwB,0DAAmB,UAAU,8CAA8C;AACnG,4BAA4B,0DAAmB,WAAW,2CAA2C,uEAAuE,GAAG;AAC/K,4BAA4B,0DAAmB,UAAU,4CAA4C;AACrG;AACA,iDAAiD,0DAAmB,WAAW,kDAAkD;AACjI,iBAAiB;AACjB,uBAAuB,0DAAmB,UAAU,mEAAmE,qCAAqC,GAAG;AAC/J,uCAAuC,0DAAmB,UAAU,iGAAiG,QAAQ,6EAAoB,wBAAwB;AACzN,iCAAiC,0DAAmB,QAAQ,8CAA8C;AAC1G,gBAAgB,0DAAmB,UAAU,8CAA8C;AAC3F,oBAAoB,0DAAmB;AACvC;AACA;AACA,oBAAoB,0DAAmB;AACvC;AACA;AACA,6CAA6C,0DAAmB;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,0DAAmB,UAAU,6BAA6B;AACtE,yBAAyB,0DAAmB,CAAC,yDAAa,IAAI,wGAAwG;AACtK,QAAQ,0DAAmB,UAAU,8BAA8B;AACnE,YAAY,0DAAmB,UAAU,8DAA8D,QAAQ,mDAAa,IAAI;AAChI,YAAY,0DAAmB,UAAU,sCAAsC;AAC/E,gBAAgB,0DAAmB,aAAa,kGAAkG;AAClJ,oBAAoB,0DAAmB,UAAU,0JAA0J;AAC3M,wBAAwB,0DAAmB,eAAe,wBAAwB;AAClF,wBAAwB,0DAAmB,WAAW,qFAAqF;AAC3I,wBAAwB,0DAAmB,WAAW,wCAAwC;AAC9F,wBAAwB,0DAAmB,WAAW,wCAAwC;AAC9F,gBAAgB,0DAAmB,aAAa,yGAAyG;AACzJ,oBAAoB,0DAAmB,UAAU,0JAA0J;AAC3M,wBAAwB,0DAAmB,WAAW,sCAAsC;AAC5F,wBAAwB,0DAAmB,WAAW,qCAAqC;AAC3F,wBAAwB,0DAAmB,WAAW,wCAAwC;AAC9F,wBAAwB,0DAAmB,WAAW,sCAAsC;AAC5F,wBAAwB,0DAAmB,WAAW,wCAAwC;AAC9F,wBAAwB,0DAAmB,WAAW,uCAAuC;AAC7F,wBAAwB,0DAAmB,WAAW,sCAAsC;AAC5F,wBAAwB,0DAAmB,WAAW,qCAAqC;AAC3F,wBAAwB,0DAAmB,WAAW,wCAAwC;AAC9F,QAAQ,0DAAmB,UAAU,gCAAgC;AACrE,qCAAqC,0DAAmB,UAAU,mCAAmC;AACrG,gBAAgB,0DAAmB;AACnC,gBAAgB,0DAAmB,QAAQ,kCAAkC;AAC7E;AACA;AACA;AACA;AACA,4BAA4B,0DAAmB,UAAU,6DAA6D,SAAS,GAAG;AAClI,wBAAwB,0DAAmB,UAAU,sCAAsC;AAC3F,4BAA4B,0DAAmB,WAAW,oCAAoC;AAC9F,4BAA4B,0DAAmB,WAAW,oCAAoC;AAC9F,wBAAwB,0DAAmB,UAAU,sCAAsC,kDAAkD,GAAG;AAChJ;AACA,wBAAwB,0DAAmB,UAAU,6CAA6C,kBAAkB,6BAA6B,QAAQ,6EAAoB,iBAAiB;AAC9L;AACA,wBAAwB,0DAAmB,UAAU,SAAS,0BAA0B;AACxF;AACA;AACA;AACA,4BAA4B,0DAAmB,UAAU,6EAA6E;AACtI;AACA,aAAa;AACb,6DAA6D,0DAAmB,UAAU,0DAA0D;AACpJ,gBAAgB,0DAAmB,UAAU,sCAAsC;AACnF,oBAAoB,0DAAmB,WAAW,oCAAoC;AACtF,gBAAgB,0DAAmB,UAAU,wDAAwD;AACrG,oBAAoB,0DAAmB,WAAW,mCAAmC;AACrF,oBAAoB,0DAAmB,WAAW,mCAAmC;AACrF,oBAAoB,0DAAmB,WAAW,mCAAmC;AACrF,iEAAiE,0DAAmB,UAAU,kDAAkD;AAChJ,gBAAgB,0DAAmB,UAAU,4CAA4C;AACzF,oBAAoB,0DAAmB,UAAU,uEAAuE;AACxH,wBAAwB,0DAAmB,WAAW,qPAAqP;AAC3S,oBAAoB,0DAAmB;AACvC,gBAAgB,0DAAmB,UAAU,6CAA6C;AAC1F;AACA;AACA,gBAAgB,0DAAmB,UAAU,6CAA6C;AAC1F,oBAAoB,0DAAmB,aAAa;AACpD;AACA,+DAA+D,iBAAiB;AAChF;AACA;AACA;AACA;AACA;AACA,2BAA2B;AAC3B,oBAAoB,0DAAmB,aAAa,wGAAwG;AAC5J,4CAA4C,0DAAmB,UAAU,kCAAkC;AAC3G,gBAAgB,0DAAmB,UAAU,yCAAyC;AACtF,oBAAoB,0DAAmB,UAAU,uEAAuE;AACxH,wBAAwB,0DAAmB,WAAW,0IAA0I;AAChM,wBAAwB,0DAAmB,WAAW,iIAAiI;AACvL,oBAAoB,0DAAmB;AACvC;AACA;AACA;AACA,gBAAgB,0DAAmB,UAAU,uCAAuC,wCAAwC,0DAAmB,UAAU,iDAAiD;AAC1M,oBAAoB,0DAAmB,UAAU,qCAAqC;AACtF,wBAAwB,0DAAmB,UAAU,uEAAuE;AAC5H,4BAA4B,0DAAmB,WAAW,8MAA8M;AACxQ,wBAAwB,0DAAmB,WAAW,qCAAqC;AAC3F,oBAAoB,0DAAmB,aAAa,kFAAkF,UAAU,YAAY;AAC5J,gBAAgB,0DAAmB,aAAa,mIAAmI;AACnL,YAAY,0DAAmB,UAAU,qBAAqB;AAC9D,QAAQ,0DAAmB,UAAU,uCAAuC;AAC5E,YAAY,0DAAmB,UAAU,qCAAqC;AAC9E,gBAAgB,0DAAmB,eAAe,6BAA6B,0DAA0D;AACzI;AACA,2FAA2F;AAC3F,gBAAgB,0DAAmB,aAAa,qKAAqK;AACrN,YAAY,0DAAmB,UAAU,gCAAgC;AACzE,gBAAgB,0DAAmB,UAAU,6CAA6C;AAC1F,oBAAoB,0DAAmB,aAAa,mCAAmC,4DAA4D,kCAAkC,0CAA0C,YAAY;AAC3O,wBAAwB,0DAAmB,UAAU,wGAAwG;AAC7J;AACA,wBAAwB,0DAAmB,WAAW,siBAAsiB;AAC5lB;AACA,wBAAwB,0DAAmB,WAAW,kNAAkN;AACxQ,wBAAwB,0DAAmB,WAAW,kCAAkC;AACxF,wBAAwB,0DAAmB,UAAU,2GAA2G;AAChK,4BAA4B,0DAAmB,WAAW,yHAAyH;AACnL,yCAAyC,0DAAmB,UAAU,qCAAqC;AAC3G,wBAAwB,0DAAmB,aAAa,mCAAmC,6DAA6D,oBAAoB,sBAAsB,+BAA+B;AACjO,4BAA4B,0DAAmB,UAAU,uEAAuE;AAChI,gCAAgC,0DAAmB,WAAW,kNAAkN;AAChR,4BAA4B,0DAAmB;AAC/C,4BAA4B,0DAAmB,WAAW,qCAAqC;AAC/F,wBAAwB,0DAAmB,aAAa,mCAAmC,8DAA8D,oBAAoB,uBAAuB,+BAA+B;AACnO,4BAA4B,0DAAmB,UAAU,uEAAuE;AAChI,gCAAgC,0DAAmB,WAAW,0HAA0H;AACxL,4BAA4B,0DAAmB;AAC/C,4BAA4B,0DAAmB,WAAW,qCAAqC;AAC/F,gBAAgB,0DAAmB,UAAU,kCAAkC;AAC/E,oBAAoB,0DAAmB,WAAW,iCAAiC;AACnF,kCAAkC,0DAAmB,CAAC,qEAAmB,IAAI,uLAAuL;AACpQ,CAAC;AACD;AACA;AACA;AACA;AACO,+BAA+B,kEAAW;AACjD;AACA;AACA,4BAA4B,sDAAe;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,0DAAmB,cAAc,iIAAiI;AAClL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,+CAA+C,WAAW;AAC1D;AACA;;AAEA;AACA,YAAY,WAAW;AACvB,cAAc,gBAAgB;AAC9B,kBAAkB,iBAAiB;AACnC,kBAAkB,aAAa;;AAE/B;;AAEA;AACA;AACA,kCAAkC,WAAW,OAAO,QAAQ;AAC5D;AACA,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,WAAW,MAAM,gCAAgC;AACzF,iBAAiB;AACjB;AACA;AACA,SAAS;AACT;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA,SAAS;AACT;AACA;;;;;;;;;;;;;;;;;AC58DA;AACA;AACA;AACA;AACA;AAC0B;AACnB,+BAA+B,gDAAgD;AACtF,YAAY,0DAAmB,UAAU,oCAAoC;AAC7E,QAAQ,0DAAmB,UAAU,wDAAwD;AAC7F,QAAQ,0DAAmB,UAAU,qCAAqC;AAC1E,YAAY,0DAAmB;AAC/B,YAAY,0DAAmB,QAAQ,qCAAqC;AAC5E,YAAY,0DAAmB,UAAU,qCAAqC,gCAAgC,0DAAmB,aAAa,6EAA6E;AAC3N,gBAAgB,0DAAmB,WAAW,iCAAiC;AAC/E,gBAAgB,0DAAmB,WAAW,+BAA+B;AAC7E,YAAY,0DAAmB,UAAU,qCAAqC;AAC9E,gBAAgB,0DAAmB,aAAa,uDAAuD;AACvG,QAAQ,0DAAmB;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;AC3IA;AACA;AACA;AACA;AACwC;AACoF;AAC9D;AAC9D;AACA;AACA;AACA;AACA;AACA;AACO,kCAAkC,2BAA2B;AACpE,gCAAgC,+CAAQ;AACxC,4CAA4C,+CAAQ;AACpD,oCAAoC,+CAAQ;AAC5C,8CAA8C,+CAAQ;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,0DAAmB,CAAC,iDAAM,IAAI;AAC1C;AACA;AACA;AACA;AACA,WAAW;AACX,QAAQ,0DAAmB,CAAC,sDAAW;AACvC,YAAY,0DAAmB,CAAC,8CAAG,IAAI,+CAA+C;AACtF,gBAAgB,0DAAmB,CAAC,uEAAe,IAAI,kBAAkB;AACzE,gBAAgB,0DAAmB,CAAC,qDAAU,IAAI,eAAe;AACjE,QAAQ,0DAAmB,CAAC,wDAAa;AACzC,YAAY,0DAAmB,CAAC,8CAAG,IAAI,yDAAyD;AAChG,gBAAgB,0DAAmB,CAAC,qDAAU,IAAI,2CAA2C;AAC7F,gBAAgB,0DAAmB,CAAC,oDAAS,IAAI;AACjD;AACA;AACA;AACA,uBAAuB;AACvB,gBAAgB,0DAAmB,CAAC,8CAAG;AACvC,oBAAoB,0DAAmB,CAAC,qDAAU,IAAI,sEAAsE;AAC5H,oBAAoB,0DAAmB,CAAC,8CAAG,IAAI,2CAA2C,2CAA2C,0DAAmB,CAAC,+CAAI,IAAI;AACjK;AACA;AACA;AACA;AACA,2BAA2B;AAC3B,gBAAgB,0DAAmB,CAAC,8CAAG,IAAI;AAC3C;AACA;AACA;AACA,uBAAuB;AACvB,oBAAoB,0DAAmB,CAAC,qDAAU,IAAI,6CAA6C;AACnG;AACA,wBAAwB,0DAAmB;AAC3C,wBAAwB,0DAAmB;AAC3C;AACA,wBAAwB,0DAAmB;AAC3C;AACA,wBAAwB,0DAAmB;AAC3C;AACA,wBAAwB,0DAAmB;AAC3C;AACA,QAAQ,0DAAmB,CAAC,wDAAa,IAAI,MAAM,6BAA6B;AAChF,YAAY,0DAAmB,CAAC,iDAAM,IAAI,0CAA0C;AACpF,YAAY,0DAAmB,CAAC,iDAAM,IAAI,oGAAoG,0DAAmB,CAAC,uEAAe,SAAS;AAC1L;;;;;;;;;;;;;;;;;;AChFA;AACA;AACA;AACA;AACA;AACA;AACA;AACmD;AACsD;AAClG,yBAAyB,gCAAgC;AAChE;AACA,wCAAwC,qEAAY,MAAM,4EAAmB;AAC7E,oCAAoC,+CAAQ;AAC5C,sCAAsC,+CAAQ;AAC9C,0CAA0C,+CAAQ,GAAG;AACrD;AACA,gDAAgD,+CAAQ;AACxD;AACA,8CAA8C,+CAAQ;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0CAA0C,+CAAQ;AAClD;AACA,4CAA4C,+CAAQ;AACpD,wCAAwC,+CAAQ;AAChD,sCAAsC,+CAAQ;AAC9C;AACA,4CAA4C,+CAAQ;AACpD,0CAA0C,+CAAQ;AAClD;AACA,IAAI,gDAAS;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA,6DAA6D,kBAAkB;AAC/E,2BAA2B,KAAK;AAChC,yBAAyB,aAAa;AACtC,0CAA0C,6BAA6B;AACvE;AACA;AACA,8BAA8B;AAC9B;AACA;AACA,yCAAyC,mEAAU;AACnD,8CAA8C,wDAAwD;AACtG;AACA;AACA,8CAA8C,2BAA2B;AACzE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC,mEAAU;AAC/C,iCAAiC,yCAAyC;AAC1E;AACA;AACA,iCAAiC,YAAY;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,sEAAa;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,0DAAmB,UAAU,wCAAwC;AACjF,QAAQ,0DAAmB,UAAU,uCAAuC;AAC5E,YAAY,0DAAmB,UAAU,uCAAuC;AAChF,gBAAgB,0DAAmB;AACnC,gBAAgB,0DAAmB,aAAa,+EAA+E;AAC/H,YAAY,0DAAmB,UAAU,wCAAwC;AACjF,gBAAgB,0DAAmB,UAAU,uCAAuC;AACpF,oBAAoB,0DAAmB;AACvC,gBAAgB,0DAAmB,UAAU,sCAAsC;AACnF,oBAAoB,0DAAmB,YAAY,sCAAsC;AACzF,oBAAoB,0DAAmB,aAAa,sGAAsG;AAC1J,wBAAwB,0DAAmB,aAAa,iBAAiB;AACzE,wBAAwB,0DAAmB,aAAa,eAAe;AACvE,wBAAwB,0DAAmB,aAAa,iBAAiB;AACzE,0CAA0C,0DAAmB,UAAU,yCAAyC;AAChH,oBAAoB,0DAAmB;AACvC,oBAAoB,0DAAmB,UAAU,sCAAsC;AACvF,wBAAwB,0DAAmB,YAAY,sCAAsC;AAC7F;AACA;AACA;AACA,4BAA4B,0DAAmB,YAAY,SAAS,0DAA0D;AAC9H,2DAA2D,0DAAmB,UAAU;AACxF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B;AAC/B,4BAA4B,0DAAmB,YAAY,qOAAqO,qDAAqD;AACrV,4BAA4B,0DAAmB,WAAW;AAC1D;AACA;AACA;AACA,mCAAmC;AACnC;AACA;AACA,4BAA4B,0DAAmB,YAAY,iEAAiE,SAAS,+FAA+F;AACpO,yDAAyD,0DAAmB,WAAW,SAAS,sCAAsC;AACtI,yDAAyD,0DAAmB,aAAa;AACzF;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC;AACnC,sDAAsD,0DAAmB,aAAa,0HAA0H,oBAAoB;AACpO,oBAAoB,0DAAmB,UAAU,sCAAsC;AACvF,wBAAwB,0DAAmB,YAAY,sCAAsC;AAC7F,wBAAwB,0DAAmB,aAAa,4GAA4G;AACpK,4BAA4B,0DAAmB,aAAa,2BAA2B;AACvF,4BAA4B,0DAAmB,aAAa,yBAAyB;AACrF,wCAAwC,0DAAmB,UAAU,yCAAyC;AAC9G,oBAAoB,0DAAmB;AACvC,oBAAoB,0DAAmB,UAAU,sCAAsC;AACvF,wBAAwB,0DAAmB,YAAY,sCAAsC;AAC7F,wBAAwB,0DAAmB,YAAY,iKAAiK;AACxN,oBAAoB,0DAAmB,UAAU,sCAAsC;AACvF,wBAAwB,0DAAmB,YAAY,sCAAsC;AAC7F,wBAAwB,0DAAmB,YAAY,yMAAyM;AAChQ,oBAAoB,0DAAmB,UAAU,sCAAsC;AACvF,wBAAwB,0DAAmB,YAAY,sCAAsC;AAC7F,wBAAwB,0DAAmB,YAAY,mKAAmK;AAC1N,0CAA0C,0DAAmB,UAAU,yCAAyC;AAChH,oBAAoB,0DAAmB;AACvC,oBAAoB,0DAAmB,UAAU,sCAAsC;AACvF,wBAAwB,0DAAmB,YAAY,sCAAsC;AAC7F,wBAAwB,0DAAmB,YAAY,sJAAsJ;AAC7M,oBAAoB,0DAAmB,UAAU,sCAAsC;AACvF,wBAAwB,0DAAmB,YAAY,sCAAsC;AAC7F,wBAAwB,0DAAmB,aAAa,4GAA4G;AACpK,4BAA4B,0DAAmB,aAAa,gBAAgB;AAC5E,4BAA4B,0DAAmB,aAAa,sBAAsB;AAClF,4BAA4B,0DAAmB,aAAa,wBAAwB;AACpF,YAAY,0DAAmB,UAAU,uCAAuC;AAChF,gBAAgB,0DAAmB,aAAa,4FAA4F;AAC5I,gBAAgB,0DAAmB,aAAa,+GAA+G;AAC/J,gBAAgB,0DAAmB,aAAa,6FAA6F;AAC7I;;;;;;;;;;;;;;;;;;;;;;;;;ACjPA;AACA;AACA;AACA;AACwC;AAC+E;AACrE;AACU;AACA;AACE;AACZ;AACE;AAC7C,8BAA8B,+CAA+C;AACpF,oCAAoC,+CAAQ;AAC5C,0CAA0C,+CAAQ;AAClD,YAAY,yDAAyD;AACrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC,0DAAmB,CAAC,uEAAe,IAAI,mBAAmB;AAC/F,kCAAkC,0DAAmB,CAAC,iEAAS,IAAI,mBAAmB;AACtF,qCAAqC,0DAAmB,CAAC,kEAAU,IAAI,mBAAmB;AAC1F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,0DAAmB,CAAC,+CAAI,IAAI;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,QAAQ,0DAAmB,CAAC,sDAAW,IAAI,MAAM,8BAA8B,sBAAsB;AACrG,YAAY,0DAAmB,CAAC,8CAAG,IAAI,+EAA+E;AACtH,gBAAgB,0DAAmB,CAAC,8CAAG,IAAI,+CAA+C;AAC1F,oBAAoB,0DAAmB,CAAC,qDAAU,IAAI,0CAA0C;AAChG,oBAAoB,0DAAmB,CAAC,+CAAI,IAAI,sHAAsH;AACtK,gBAAgB,0DAAmB,CAAC,8CAAG,IAAI,iBAAiB;AAC5D,oBAAoB,0DAAmB,CAAC,qDAAU,IAAI,4DAA4D,iBAAiB,0DAAmB,CAAC,sEAAc,IAAI,mBAAmB,MAAM,0DAAmB,CAAC,sEAAc,IAAI,mBAAmB;AAC3P,oBAAoB,0DAAmB,CAAC,qDAAU,IAAI,iCAAiC;AACvF,wBAAwB,0DAAmB,CAAC,iEAAS,IAAI,mBAAmB;AAC5E,wBAAwB,0DAAmB,CAAC,8CAAG,IAAI,OAAO;AAC1D,gBAAgB,0DAAmB,CAAC,yDAAc,IAAI,+CAA+C,8BAA8B;AACnI,gBAAgB,0DAAmB,CAAC,8CAAG,IAAI,2DAA2D;AACtG,oBAAoB,0DAAmB,CAAC,qDAAU,IAAI,6CAA6C;AACnG,oBAAoB,0DAAmB,CAAC,qDAAU,IAAI,6CAA6C;AACnG;AACA;AACA,2BAA2B,0DAAmB,CAAC,8CAAG,IAAI,OAAO;AAC7D,gBAAgB,0DAAmB,CAAC,qDAAU,IAAI,yCAAyC;AAC3F;AACA;AACA,kCAAkC,0DAAmB,CAAC,8CAAG,IAAI,OAAO;AACpE,gBAAgB,0DAAmB,CAAC,qDAAU,IAAI,uCAAuC;AACzF;AACA;AACA,YAAY,0DAAmB,CAAC,mDAAQ,IAAI,iBAAiB;AAC7D,gBAAgB,0DAAmB,CAAC,8CAAG,IAAI;AAC3C;AACA;AACA;AACA;AACA,uBAAuB;AACvB,oBAAoB,0DAAmB,CAAC,qDAAU,IAAI,wEAAwE;AAC9H,oBAAoB,0DAAmB,CAAC,qDAAU,IAAI,wBAAwB,2BAA2B;AACzG,qCAAqC,0DAAmB,CAAC,uDAAc;AACvE,wBAAwB,0DAAmB,CAAC,qDAAU,IAAI,+EAA+E;AACzI,wBAAwB,0DAAmB,CAAC,qDAAU,IAAI,0BAA0B,mDAAmD;AACvI,YAAY,0DAAmB,CAAC,8CAAG,IAAI,qDAAqD;AAC5F,8BAA8B,0DAAmB,CAAC,iDAAM,IAAI,uDAAuD;AACnH,+CAA+C,0DAAmB,CAAC,iDAAM,IAAI,8DAA8D;AAC3I,2BAA2B,0DAAmB,CAAC,iDAAM,IAAI,kDAAkD;AAC3G;;;;;;;;;;;;;;;;;;;ACpGA;AACA;AACA;AACA;AACyD;AACS;AACU;AACF;AAC1E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,kEAAa;AACjB,IAAI,2EAAiB;AACrB,IAAI,qFAAsB;AAC1B,IAAI,mFAAqB;AACzB;AACA,iEAAe,OAAO,EAAC;;;;;;;;;;;;;;;;ACrBvB;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;ACjBA;AACA;AACA;AACA;AACA;AACwD;AAClB;AACtC;AACA;AACA;AACO;AACP;AACA;AACA,eAAe,kEAAgB;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,aAAa;AACb,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,KAAK;AACL;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,6BAA6B;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,YAAY;AAChC;AACA;AACA;AACA;AACA,yBAAyB,8CAAU;AACnC,KAAK;AACL;AACA;AACA,yBAAyB,8CAAU;AACnC,KAAK;AACL;AACA;AACA,yBAAyB,8CAAU;AACnC,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB,8CAAU;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,8CAAU;AAC3B,6BAA6B,UAAU;AACvC;AACA;AACA,iBAAiB,8CAAU;AAC3B,6BAA6B,UAAU;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,oBAAoB;AACxC;AACA,0BAA0B;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,oBAAoB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,WAAW,GAAG,wCAAwC;AAC/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,8CAAU;AACvB;AACA,+BAA+B,UAAU;AACzC;AACA;;AAEA;AACA,EAAE;AACF;AACA;AACA,aAAa,8CAAU;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,UAAU;AAC7C;;AAEA;AACA;AACA,EAAE;AACF;;AAEA;AACA;AACA,EAAE;AACF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,mCAAmC,UAAU;AAC7C;;AAEA;AACA;AACA,EAAE;AACF;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sDAAsD,UAAU;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAsC;AACtC,uCAAuC,gBAAgB,iBAAiB,iBAAiB;AACzF,YAAY;AACZ;AACA,6BAA6B,gBAAgB,iBAAiB,iBAAiB;AAC/E,YAAY;AACZ;AACA;AACA,iCAAiC,WAAW,0BAA0B;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,SAAS;AACT;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC;AACpC,oCAAoC,gBAAgB,iBAAiB,iBAAiB;AACtF;AACA;AACA,2BAA2B,gBAAgB,gBAAgB;AAC3D,oBAAoB,cAAc;AAClC;AACA;AACA,oCAAoC;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,WAAW,0BAA0B;AACpE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC,UAAU,QAAQ,WAAW;AAC9D;AACA,2BAA2B,WAAW,qBAAqB,YAAY;AACvE;AACA,gDAAgD,WAAW;AAC3D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gDAAgD,8CAAU;AAC1D;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChyBA;AACA;AACA;AACA;AACiD;AACiC;AACxB;AACN;AACX;AACf;AACiC;AACH;AACsB;AACR;AAChB;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,8DAAO;AAC5B;AACA,YAAY,wDAAW;AACvB,CAAC;AACD;AACA;AACA;AACA;AACA,gCAAgC,6DAAW;AAC3C;AACA;AACA;AACA;AACA,+BAA+B,+DAAW;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uEAAuE,QAAQ;AAC/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,8DAAY,uBAAuB,qCAAqC;AAC5F;AACA,qBAAqB;AACrB;AACA;AACA,oBAAoB,8DAAY,qBAAqB,aAAa;AAClE;AACA,qBAAqB;AACrB;AACA,aAAa;AACb;AACA,gBAAgB,8DAAY,uBAAuB,iBAAiB;AACpE,aAAa;AACb;AACA;AACA,aAAa;AACb;AACA,YAAY,8DAAY,0BAA0B,iBAAiB;AACnE;AACA;AACA;AACA;AACA,YAAY,8DAAY,oBAAoB,cAAc;AAC1D;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,8DAAY,sBAAsB,iBAAiB;AAC/D;AACA;AACA;AACA,YAAY,8DAAY,iBAAiB,cAAc,KAAK,iBAAiB;AAC7E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,8DAAY,wBAAwB,SAAS;AACzD;AACA,aAAa;AACb;AACA;AACA;AACA,YAAY,8DAAY,qBAAqB,cAAc;AAC3D;AACA,aAAa;AACb;AACA;AACA;AACA,sBAAsB,0DAAW;AACjC;AACA,gBAAgB,0DAAmB,CAAC,wDAAa,IAAI,cAAc;AACnE,YAAY,0DAAmB,UAAU,SAAS,wDAAwD,0CAA0C,0DAAmB,UAAU;AACjL;AACA,mBAAmB;AACnB,gBAAgB,0DAAmB,CAAC,8EAAkB,IAAI;AAC1D,wEAAwE;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC,6DAAW;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB,0DAAW;AACjC,gBAAgB,0DAAmB,CAAC,wDAAa,IAAI,cAAc;AACnE,YAAY,0DAAmB,CAAC,sFAAsB,IAAI,kEAAkE;AAC5H;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,eAAe,oEAAgB;AAC/B,eAAe,2DAAS,EAAE,iEAAe;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,mDAAM;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;AC/NA;AACA;AACA;AACA;AACA;AACwD;AACD;AACvD;AACA;AACA;AACO;AACP;AACA;AACA,eAAe,kEAAgB;AAC/B,eAAe,iEAAe;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0GAA0G,MAAM;AAChH;AACA;AACA;AACA;AACA;AACA;AACA,0GAA0G,MAAM;AAChH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B;AAC5B;AACA;AACA;AACA;AACA,4BAA4B;AAC5B;AACA;AACA;AACA;AACA;AACA,sGAAsG,MAAM;AAC5G,4BAA4B;AAC5B;AACA,6GAA6G,MAAM;AACnH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,SAAS;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAsC;AACtC,uCAAuC,iCAAiC,iBAAiB,iBAAiB;AAC1G;AACA;AACA,6BAA6B,iCAAiC,iBAAiB,iBAAiB;AAChG;AACA;AACA;AACA,iCAAiC,WAAW,0BAA0B;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,6BAA6B;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAiE,YAAY;AAC7E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,qDAAqD,cAAc;AACnE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,WAAW,GAAG,wCAAwC;AAC/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,oBAAoB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;AC7kBA;AACA;AACA;AACA;AAC0D;AACY;AACd;AACF;AACM;AACR;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA,eAAe,oEAAe,EAAE,iEAAe,EAAE,kEAAgB,EAAE,gEAAe;AAClF;AACA;AACA;AACA;AACA,mCAAmC,4DAAU;AAC7C;AACA,mCAAmC,oEAAgB;AACnD;AACA;AACA,oCAAoC,+DAAa;AACjD;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA,iDAAiD,WAAW;AAC5D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAC0C;AACI;AACS;AACP;AACE;AACM;AACiC;AAClF;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,mDAAU;AACtD,gCAAgC,uDAAY;AAC5C,iCAAiC,+DAAa;AAC9C;AACA;AACA,SAAS;AACT;AACA,iCAAiC,yDAAa;AAC9C;AACA,kCAAkC,2DAAc;AAChD;AACA,qCAAqC,iEAAiB;AACtD,wBAAwB,GAAG,wEAAyB;AACpD;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,6CAA6C;AACtE;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,4BAA4B,gBAAgB;AAC5C,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0EAA0E,sFAAsF;AAChK;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qDAAqD,oBAAoB;AACzE;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,iBAAiB,MAAM,iBAAiB;AACnF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,UAAU;AACvD;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,cAAc;AAC1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gDAAgD,qDAAqD;AACrG;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,iBAAiB,eAAe,iBAAiB;AAC9F,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,iBAAiB,MAAM,iBAAiB;AACnF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0EAA0E,gBAAgB;AAC1F;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,6BAA6B;AAC7D;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA,0DAA0D,8BAA8B;AACxF;AACA;AACA;AACA,kHAAkH;AAClH,iCAAiC;AACjC,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA,kEAAkE,sEAAsE;AACxI,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yDAAyD,8BAA8B,MAAM,mEAAmE,GAAG;AACnK;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sDAAsD,8BAA8B;AACpF;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA,gCAAgC,iCAAiC;AACjE,6EAA6E,gCAAgC;AAC7G;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD,OAAO;AAC1D,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA,cAAc,oEAAoE;AAClF,cAAc,0DAA0D;AACxE,cAAc,2DAA2D;AACzE,cAAc,qDAAqD;AACnE;AACA,cAAc,8FAA8F;AAC5G;AACA,cAAc,mFAAmF;AACjG,cAAc,4CAA4C;AAC1D,cAAc,6CAA6C;AAC3D,cAAc,wCAAwC;AACtD,cAAc,wCAAwC;AACtD,cAAc,6CAA6C;AAC3D;AACA,cAAc,gGAAgG;AAC9G,cAAc,8FAA8F;AAC5G,cAAc,yFAAyF;AACvG,cAAc,qEAAqE;AACnF;AACA,cAAc,qDAAqD;AACnE,cAAc,kEAAkE;AAChF;AACA;AACA,qBAAqB,kBAAkB;AACvC;AACA;AACA,yBAAyB;AACzB;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAiD,yCAAyC;AAC1F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAoD,iBAAiB,IAAI,4CAA4C;AACrH,uDAAuD,mCAAmC;AAC1F;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAwD,QAAQ,KAAK,4BAA4B,IAAI,4BAA4B,IAAI,8BAA8B;AACnK;AACA,oEAAoE,WAAW,EAAE,mBAAmB,aAAa,OAAO;AACxH;AACA,wEAAwE,mBAAmB;AAC3F,iCAAiC;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD,mBAAmB;AACtE,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA,oDAAoD,mBAAmB;AACvE;AACA;AACA;AACA,oIAAoI;AACpI;AACA;AACA;AACA;AACA,mDAAmD,yBAAyB;AAC5E,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0CAA0C,KAAK;AAC/C,8CAA8C,OAAO;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,eAAe;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,gDAAgD;AAChE;AACA;AACA,6DAA6D,4BAA4B,IAAI,0BAA0B;AACvH,6BAA6B,6BAA6B,eAAe,+BAA+B;AACxG;AACA;AACA,yDAAyD,mBAAmB,UAAU,sCAAsC;AAC5H;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC,eAAe;AACpD;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,kBAAkB;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,kBAAkB;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC;AACrC,mCAAmC;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,oBAAoB;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC;AACjC;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,UAAU;AACvD,aAAa;AACb;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA,aAAa;AACb,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB;AACxB;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,qEAAsB;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mEAAmE,2BAA2B,UAAU,MAAM;AAC9G;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,wBAAwB,SAAS,2BAA2B;AACrF,gCAAgC,2BAA2B;AAC3D;AACA;AACA,iDAAiD;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA,gBAAgB,8BAA8B;AAC9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,iDAAiD;AAC7E,4BAA4B,qCAAqC;AACjE;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kEAAkE,WAAW;AAC7E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sEAAsE,WAAW;AACjF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAe,iBAAiB,EAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7xDjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,cAAc,gBAAgB,KAAK,cAAc;AACjD;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA,iBAAiB;AACjB;AACA;AACA,iBAAiB,mCAAmC,EAAE;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,qBAAqB;AAC5D;AACA,oBAAoB,iBAAiB;AACrC;AACA;AACA;AACA,0DAA0D,oBAAoB,GAAG,YAAY;AAC7F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,oBAAoB,GAAG,YAAY;AAChF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;ACvSA;AACA;AACA;AACyJ;AACzJ;AAC2D;AACpD;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,6DAAU;AACzC;AACA;AACA,2BAA2B,yDAAM;AACjC;AACA,yEAAyE;AACzE;AACA;AACA;AACA;AACA;AACA,yBAAyB,EAAE,gBAAgB;AAC3C,qCAAqC,EAAE,KAAK;AAC5C;AACA,wCAAwC;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAA8B,uBAAuB;AACrD;AACA;AACA,oBAAoB,uBAAuB,oEAAoB;AAC/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA,oBAAoB,gEAAgB;AACpC;AACA;AACA;AACA;AACA;AACA,oBAAoB,gEAAgB;AACpC,sEAAsE,YAAY;AAClF;AACA,0CAA0C,oEAAoB;AAC9D;AACA;AACA,qCAAqC,kEAAkB;AACvD;AACA,kDAAkD,kEAAkB;AACpE;AACA,kCAAkC;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,gEAAgB;AACpC,0CAA0C,oEAAoB;AAC9D;AACA,qCAAqC,kEAAkB;AACvD;AACA,kDAAkD,kEAAkB;AACpE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,aAAa,0BAA0B,gCAAgC;AACnH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,aAAa,2BAA2B,kCAAkC;AACtH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAA8B,uBAAuB;AACrD;AACA;AACA,oBAAoB,uBAAuB,oEAAoB;AAC/D;AACA;AACA;AACA;AACA,gBAAgB,gEAAgB;AAChC;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,gEAAgB;AACpC,sEAAsE,YAAY;AAClF;AACA,0CAA0C,oEAAoB;AAC9D;AACA;AACA;AACA;AACA,kCAAkC;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,oEAAoB;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa;AACrD;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,uDAAuD,MAAM;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,cAAc;AACtC;AACA;AACA,kDAAkD,cAAc;AAChE;AACA;AACA,4CAA4C;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa;AACrD;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,+DAA+D,yCAAyC;AACxG;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,aAAa,8BAA8B,gDAAgD;AACvI;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,aAAa,gCAAgC,gDAAgD;AACzI;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,aAAa,gCAAgC,iDAAiD;AAC1I;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,aAAa,kCAAkC,iCAAiC;AAC5H;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,aAAa,iCAAiC,qDAAqD;AAC/I;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,aAAa,sCAAsC,iCAAiC;AAChI;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa;AACrD;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,wDAAwD,MAAM;AAC9D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,cAAc;AACtC;AACA;AACA,kDAAkD,cAAc;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,aAAa,0BAA0B,gDAAgD;AACnI;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa;AACrD;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,uDAAuD,MAAM;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa;AACrD;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,sDAAsD,MAAM;AAC5D;AACA;AACA;AACA;;;;;;;;;;;;;;;;;ACxeA;AACA;AACA;AACA;AACA;AACA;AACA;AACiE;AACjE;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,wEAAyB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA,sBAAsB,WAAW,GAAG,WAAW;AAC/C;AACA;AACA;AACA,4BAA4B,SAAS;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+EAA+E,WAAW;AAC1F;AACA;AACA,uEAAuE,WAAW;AAClF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B;AAC/B;AACA,4BAA4B,6BAA6B;AACzD,sEAAsE;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8CAA8C,YAAY;AAC1D;AACA;AACA,gEAAgE,WAAW;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC;AACxC;AACA;AACA;AACA;AACA,6EAA6E,UAAU;AACvF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sFAAsF,cAAc;AACpG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0EAA0E,qBAAqB;AAC/F,4BAA4B,sBAAsB;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0DAA0D,WAAW;AACrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB,gBAAgB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,4BAA4B;AACxE,6CAA6C,sBAAsB;AACnE,wCAAwC,gCAAgC;AACxE,wCAAwC,gCAAgC;AACxE,0CAA0C,yDAAyD;AACnG,2CAA2C,0DAA0D;AACrG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAe,iBAAiB,EAAC;;;;;;;;;;;;;;;;;AC7UjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAC8D;AAC9D;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA,eAAe,qEAAsB;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA,0DAA0D,gBAAgB,IAAI,QAAQ;AACtF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,QAAQ;AAC1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8DAA8D,eAAe,OAAO,WAAW;AAC/F,2BAA2B,YAAY,IAAI,6BAA6B;AACxE;AACA;AACA;AACA,4DAA4D,eAAe,OAAO,YAAY;AAC9F,iDAAiD,iBAAiB;AAClE;AACA;AACA;AACA;AACA;AACA,wDAAwD,eAAe,OAAO,WAAW;AACzF;AACA;AACA;AACA;AACA;AACA,oBAAoB,yCAAyC;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,gBAAgB,IAAI,eAAe;AAClD,uBAAuB,aAAa,cAAc,eAAe;AACjE,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oEAAoE,sCAAsC;AAC1G,+BAA+B,mCAAmC;AAClE;AACA;AACA;AACA,oBAAoB,iCAAiC;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB,gBAAgB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,sBAAsB;AAC7D,kDAAkD,gCAAgC;AAClF,8CAA8C,mCAAmC;AACjF;AACA,8CAA8C,4BAA4B;AAC1E,wCAAwC,0BAA0B;AAClE,4CAA4C,8BAA8B;AAC1E,4CAA4C,6BAA6B;AACzE,8CAA8C,+CAA+C;AAC7F;AACA;AACA;AACA,iEAAe,cAAc,EAAC;;;;;;;;;;;;;;;;AC7T9B;AACA;AACA;AACA;AAC6D;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,kDAAkD;AAC9F;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,oBAAoB,4BAA4B;AAChD;AACA;AACA;AACA;AACA;AACA,oBAAoB,0BAA0B;AAC9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,4EAA4E;AAC/G,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,oEAAqB;AAC/C;AACA;AACA,+BAA+B,oEAAqB;AACpD;AACA;AACA,+BAA+B,oEAAqB;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,SAAS;AACpD;AACA;AACA,uCAAuC,SAAS;AAChD,iBAAiB;AACjB;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa;AACrD,iCAAiC,cAAc;AAC/C;AACA,+CAA+C,cAAc,mBAAmB,aAAa;AAC7F,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;AC/SA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,EAAE,gBAAgB;AAC3C,qCAAqC,EAAE,KAAK;AAC5C;AACA,wCAAwC;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa;AACrD;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,gCAAgC,gDAAgD;AAChF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa,QAAQ,OAAO;AACpE;AACA;AACA;AACA,gCAAgC,sCAAsC;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+CAA+C,aAAa,QAAQ,OAAO;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,aAAa,QAAQ,OAAO;AACpE;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,gCAAgC,kCAAkC;AAClE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;ACxIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACuD;AAC6C;AAC7F;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0CAA0C,WAAW,GAAG,wCAAwC;AAChG;AACA,qCAAqC,gBAAgB;AACrD,qCAAqC,gBAAgB;AACrD;AACA;AACA,wBAAwB,uDAAY;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC,gBAAgB;AACrD,qCAAqC,gBAAgB;AACrD,qCAAqC,gBAAgB;AACrD,qCAAqC,gBAAgB;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,mEAAwB;AACvD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,4BAA4B,mEAAwB;AACpD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,+BAA+B,mEAAwB;AACvD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA,qCAAqC,gBAAgB;AACrD;AACA;AACA;AACA;AACA,4BAA4B,mEAAwB;AACpD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,6BAA6B,mEAAwB;AACrD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,6BAA6B,mEAAwB;AACrD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,kCAAkC,mEAAwB;AAC1D;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,+BAA+B,mEAAwB;AACvD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA;AACA;AACA;AACA,kCAAkC,mEAAwB;AAC1D;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,4BAA4B,mEAAwB;AACpD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,8BAA8B,mEAAwB;AACtD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,iCAAiC,mEAAwB;AACzD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,kCAAkC,mEAAwB;AAC1D;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,gCAAgC,mEAAwB;AACxD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,8BAA8B,mEAAwB;AACtD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA;AACA;AACA;AACA,iCAAiC,mEAAwB;AACzD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,4BAA4B,mEAAwB;AACpD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA,gCAAgC,mEAAwB;AACxD;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,WAAW,KAAK,UAAU;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,WAAW,SAAS,eAAe;AAChF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA,qBAAqB;AACrB;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA,eAAe,qEAA0B;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,4BAA4B,kBAAkB,yBAAyB;AACvF,iCAAiC,SAAS;AAC1C;AACA,kBAAkB,2FAA2F;AAC7G;AACA,cAAc,+CAA+C,YAAY;AACzE;AACA,cAAc,kDAAkD,YAAY;AAC5E;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA,4CAA4C;AAC5C;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,aAAa;AACb,gBAAgB;;AAEhB;AACA;AACA;AACA;;AAEA;AACA;AACA,cAAc;AACd;AACA,cAAc,mDAAmD,KAAK;AACtE;AACA,cAAc,iDAAiD,KAAK;AACpE;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,aAAa,WAAW,YAAY;AAC/E;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kEAAkE,SAAS,GAAG,SAAS;AACvF;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB,8CAA8C,KAAK;AACrE;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8DAA8D,aAAa;AAC3E;AACA;AACA,mCAAmC,MAAM,EAAE,YAAY,EAAE,SAAS;AAClE,oCAAoC;AACpC;AACA;AACA,yBAAyB;AACzB;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB,8BAA8B;AAC9B,kBAAkB;;AAElB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;;AAEjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA,6BAA6B,2BAA2B,QAAQ;AAChE;AACA;AACA;AACA;AACA;AACA,sCAAsC,oBAAoB;AAC1D,oCAAoC;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC,QAAQ,iBAAiB,eAAe,gBAAgB,yBAAyB,MAAM,IAAI,WAAW,cAAc,oBAAoB,eAAe;AAC5L;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,gBAAgB;AAChB,kBAAkB;;AAElB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET,cAAc;AACd;AACA,cAAc,mDAAmD,KAAK;AACtE;AACA,cAAc,iDAAiD,KAAK;AACpE;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAiE,uBAAuB,EAAE,OAAO,EAAE,qBAAqB,QAAQ,QAAQ;AACxI;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,WAAW,GAAG,wCAAwC;AAC7F;AACA;AACA;AACA;AACA,qDAAqD,eAAe;AACpE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4DAA4D,2DAA2D;AACvH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB,oBAAoB;;AAEpB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,sDAAsD,YAAY;AAChF;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4FAA4F,kBAAkB;AAC9G;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB,oBAAoB;AACpB,oBAAoB;;AAEpB;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;;AAEA;AACA;;AAEA,cAAc;AACd;AACA,cAAc,qDAAqD,EAAE;AACrE;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mEAAmE,OAAO,GAAG,OAAO,IAAI,UAAU;AAClG;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,iBAAiB;AAChD;AACA;AACA,gCAAgC,QAAQ;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA,cAAc;AACd;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0DAA0D,eAAe,IAAI,cAAc;AAC3F;AACA;AACA;AACA;AACA;AACA,gGAAgG,kBAAkB;AAClH;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,aAAa;AACb,YAAY;;AAEZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,MAAM,oCAAoC,KAAK;AACtF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD,KAAK;;AAExD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA,cAAc;AACd;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,QAAQ,GAAG,YAAY,KAAK,+BAA+B;AAC9F;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6DAA6D,YAAY,MAAM,cAAc,EAAE,0CAA0C;AACzI;AACA;AACA,6BAA6B;AAC7B;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,YAAY;AAC5B;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA,8CAA8C,UAAU,mBAAmB,cAAc;AACzF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,UAAU,gBAAgB,UAAU,EAAE,mBAAmB,WAAW,WAAW;AAClH;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,iCAAiC;AACjD;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA,8CAA8C,UAAU,mBAAmB,cAAc;AACzF;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,WAAW;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,wBAAwB;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC,iBAAiB,IAAI,kBAAkB;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,cAAc;AACd,eAAe;;AAEf;AACA;AACA,0DAA0D,KAAK;;AAE/D;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA,SAAS;AACT;AACA,iCAAiC;;AAEjC;AACA;AACA;;AAEA,cAAc;AACd;AACA,cAAc;AACd;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qDAAqD,aAAa,OAAO,kBAAkB;AAC3F;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,gBAAgB;;AAEhB;AACA;AACA,sBAAsB;AACtB;AACA,yEAAyE,KAAK;AAC9E;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA,cAAc;AACd;AACA,cAAc,+DAA+D,sBAAsB;AACnG;AACA,cAAc,iDAAiD,KAAK;AACpE;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0CAA0C,OAAO,IAAI,YAAY;AACjE;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,kBAAkB;;AAElB;AACA,mDAAmD,KAAK;;AAExD;AACA;AACA;AACA,sBAAsB;AACtB;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA,sDAAsD,KAAK;AAC3D;AACA;AACA,kBAAkB;;AAElB;AACA,cAAc;AACd;AACA,cAAc,iDAAiD,KAAK;AACpE;AACA,cAAc;AACd;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,QAAQ,IAAI,YAAY;AACnE;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,qDAAqD;AACrE;AACA;AACA;AACA;AACA,sCAAsC,WAAW,GAAG,wCAAwC;AAC5F;AACA;AACA;AACA;AACA,uCAAuC,WAAW,YAAY,kCAAkC,QAAQ,aAAa,oBAAoB,EAAE;AAC3I;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAsC,WAAW,UAAU,yCAAyC;AACpG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yDAAyD,gBAAgB;AACzE;AACA;AACA,qDAAqD,MAAM;AAC3D;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,gBAAgB;AAC5D;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA,+CAA+C,6BAA6B;AAC5E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+CAA+C,OAAO;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA,6CAA6C,OAAO;AACpD;AACA;AACA;AACA;AACA;AACA,yBAAyB,iDAAiD,UAAU;AACpF;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA;AACA,cAAc;AACd;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,iBAAiB,KAAK,+BAA+B;AAC5F;AACA;AACA;AACA;AACA;AACA,uEAAuE,WAAW;AAClF;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB,aAAa;AACb,gBAAgB;AAChB,gBAAgB;AAChB,iBAAiB;;AAEjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC,mBAAmB,YAAY,mBAAmB,aAAa,mBAAmB,aAAa,oBAAoB;AACxJ;AACA;AACA;AACA,mCAAmC,QAAQ,MAAM,cAAc;AAC/D;AACA;AACA;AACA;AACA;AACA,gDAAgD,QAAQ,MAAM,cAAc,IAAI,cAAc;AAC9F;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA,gBAAgB,wDAAwD;AACxE;AACA;AACA,qBAAqB,0BAA0B,WAAW;AAC1D;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,kBAAkB;AAClB,iBAAiB;AACjB,iBAAiB;AACjB,mBAAmB;AACnB,iBAAiB;;AAEjB;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,6CAA6C,SAAS;AACtD;AACA;;AAEA;AACA,0CAA0C,SAAS;;AAEnD;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,sBAAsB,oBAAoB;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,SAAS,gBAAgB,KAAK;AAChF;;AAEA;AACA,cAAc,8CAA8C,KAAK;AACjE;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,eAAe,OAAO,eAAe;AAChF;AACA;AACA,sDAAsD,eAAe;AACrE;AACA;AACA,oDAAoD,eAAe;AACnE;AACA;AACA;AACA,mCAAmC,MAAM,GAAG,gBAAgB,aAAa,YAAY;AACrF;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,KAAK;AAC5C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,KAAK;AAChD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,KAAK;AAChD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+CAA+C,KAAK;AACpD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;AACF,MAAM,EAAE,oBAAoB,EAAE;AAC9B,0BAA0B,EAAE,oBAAoB,EAAE;AAClD,cAAc,EAAE;AAChB;AACA,cAAc,EAAE;;AAEhB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB;AACxB,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,qBAAqB;AAC7C,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,qBAAqB;AAC7C,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB;AACxB,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,WAAW;AACxD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,WAAW;AACxD;AACA;AACA;AACA;AACA;AACA,iCAAiC,iEAAe;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,oBAAoB;AAChD;AACA;AACA,qDAAqD,GAAG;AACxD;AACA;AACA;AACA,yDAAyD,GAAG;AAC5D;AACA;AACA,yDAAyD,GAAG;AAC5D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,wBAAwB;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,kBAAkB,IAAI,mBAAmB;AACzE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,QAAQ;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA;AACA;AACA,iEAAe,YAAY,EAAC;;;;;;;;;;;;;;;;;;;;;AC78E5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAiD,gBAAgB;AACjE;AACA;AACA,uDAAuD,iBAAiB,GAAG,qBAAqB;AAChG;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6DAA6D,KAAK;AAClE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mEAAmE,SAAS;AAC5E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,KAAK;AAC7C;AACA;AACA;AACA;AACA;AACA,uBAAuB,KAAK,GAAG,WAAW,GAAG,wCAAwC;AACrF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wEAAwE,KAAK;AAC7E;AACA;AACA,qEAAqE,KAAK,YAAY,sBAAsB;AAC5G;AACA;AACA,qDAAqD,yCAAyC;AAC9F;AACA;AACA,yDAAyD,KAAK;AAC9D;AACA;AACA;AACA,0DAA0D,KAAK;AAC/D;AACA;AACA;AACA,mEAAmE,KAAK;AACxE;AACA;AACA,mEAAmE,KAAK;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B,2BAA2B,EAAE,iBAAiB;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,IAAI,IAAI,SAAS;AAC3C,aAAa;AACb;AACA;AACA,0CAA0C,aAAa;AACvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,gBAAgB;AAC7D,8CAA8C,sBAAsB;AACpE;AACA;AACA,iCAAiC,MAAM,GAAG,cAAc,IAAI,eAAe,cAAc,sBAAsB;AAC/G;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,iEAAe,YAAY,EAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClZ5B;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;;;;;;;;;;;;;;;;;ACrDA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA,CAAC,gCAAgC;AAC1B;AACP;AACA;AACA;AACA;AACA;AACA,CAAC,gCAAgC;AACjC;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA,CAAC,gCAAgC;;;;;;;;;;;;;;;;ACxBjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA,oCAAoC,iCAAiC,IAAI,sBAAsB;AAC/F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,kBAAkB;AAC1C;AACA,sEAAsE,MAAM,IAAI,EAAE;AAClF;AACA,wFAAwF,MAAM,IAAI,EAAE;AACpG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAoD;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB;AACxB;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oEAAoE,EAAE;AACtE;AACA;AACA;AACA,6DAA6D,EAAE;AAC/D;AACA;AACA;AACA;AACA,iEAAe,aAAa,EAAC;;;;;;;;;;;;;;;;;;;;;AC9Q7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,gBAAgB;AACpC;AACA,4BAA4B;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA,oBAAoB,kBAAkB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA,kCAAkC,mBAAmB;AACrD,gCAAgC;AAChC,gCAAgC;AAChC,kCAAkC,kBAAkB;AACpD,iCAAiC;AACjC,mCAAmC,kBAAkB;AACrD,kCAAkC;AAClC,iCAAiC;AACjC;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,mBAAmB;AAC7C;AACA;AACA,kCAAkC,eAAe,IAAI,kBAAkB;AACvE,SAAS;AACT;AACA,KAAK;AACL;AACA,6CAA6C,EAAE;AAC/C,0BAA0B,mBAAmB;AAC7C;AACA;AACA,kCAAkC,cAAc,IAAI,kBAAkB;AACtE,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA,0BAA0B,mBAAmB;AAC7C;AACA;AACA,kCAAkC,cAAc,IAAI,kBAAkB;AACtE,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA,0BAA0B,mBAAmB;AAC7C;AACA;AACA,kCAAkC,cAAc,IAAI,MAAM;AAC1D,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,QAAQ;AAC/C;AACA,8BAA8B,mBAAmB;AACjD;AACA;AACA,sCAAsC,eAAe,IAAI,MAAM;AAC/D,aAAa;AACb;AACA,SAAS;AACT,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,QAAQ;AAC/C;AACA,8BAA8B,mBAAmB;AACjD;AACA;AACA,sCAAsC,eAAe,IAAI,MAAM;AAC/D,aAAa;AACb;AACA,SAAS;AACT,KAAK;AACL;AACA;AACA;AACA;AACA,8BAA8B,mBAAmB;AACjD;AACA;AACA,sCAAsC,gBAAgB,IAAI,SAAS;AACnE,aAAa;AACb;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA,oEAAoE,gBAAgB;AACpF;AACA,sCAAsC,sBAAsB,eAAe;AAC3E;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qDAAqD,mBAAmB,IAAI,gCAAgC;AAC5G;AACA;AACA,iDAAiD,mBAAmB,IAAI,KAAK;AAC7E;AACA;AACA;AACA;AACA,mEAAmE,mBAAmB,IAAI,gBAAgB;AAC1G;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,mBAAmB,IAAI,uDAAuD;AAChI;AACA;AACA;AACA;AACA;AACA,kDAAkD,mBAAmB,IAAI,kCAAkC;AAC3G;AACA;AACA;AACA;AACA;AACA;AACA,8CAA8C,mBAAmB,IAAI,6BAA6B;AAClG;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,8CAA8C,OAAO,IAAI,kCAAkC;AAC3F,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,kDAAkD,OAAO,IAAI,kCAAkC;AAC/F,aAAa;AACb;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;AACL;AACA;;;;;;;;;;;;;;;;;ACjmBA;;AAEqD;AACL;AAChD,iEAAe,mEAAa,cAAc,sDAAI;AAC9C;AACA,CAAC,iBAAiB,E;;;;;;;;;;;;;;;;ACNlB;;AAEqD;AACL;AAChD,iEAAe,mEAAa,cAAc,sDAAI;AAC9C;AACA,CAAC,YAAY,E;;;;;;;;;;;;;;;;ACNb;;AAEqD;AACL;AAChD,iEAAe,mEAAa,cAAc,sDAAI;AAC9C;AACA,CAAC,iBAAiB,E;;;;;;;;;;;;;;;;ACNlB;;AAEqD;AACL;AAChD,iEAAe,mEAAa,cAAc,sDAAI;AAC9C;AACA,CAAC,WAAW,E;;;;;;;;;;;;;;;;ACNZ;;AAEqD;AACL;AAChD,iEAAe,mEAAa,cAAc,sDAAI;AAC9C;AACA,CAAC,WAAW,E;;;;;;;;;;;;;;;;ACNZ;;AAEqD;AACL;AAChD,iEAAe,mEAAa,cAAc,sDAAI;AAC9C;AACA,CAAC,gBAAgB,E;;;;;;;;;;;;;;;;ACNjB;;AAEqD;AACL;AAChD,iEAAe,mEAAa,cAAc,sDAAI;AAC9C;AACA,CAAC,gBAAgB,E","sources":["webpack://hdsp-agent/./lib/components/AgentPanel.js","webpack://hdsp-agent/./lib/components/FileSelectionDialog.js","webpack://hdsp-agent/./lib/components/PromptGenerationDialog.js","webpack://hdsp-agent/./lib/components/SettingsPanel.js","webpack://hdsp-agent/./lib/components/TaskProgressWidget.js","webpack://hdsp-agent/./lib/index.js","webpack://hdsp-agent/./lib/logoSvg.js","webpack://hdsp-agent/./lib/plugins/cell-buttons-plugin.js","webpack://hdsp-agent/./lib/plugins/prompt-generation-plugin.js","webpack://hdsp-agent/./lib/plugins/save-interceptor-plugin.js","webpack://hdsp-agent/./lib/plugins/sidebar-plugin.js","webpack://hdsp-agent/./lib/services/AgentOrchestrator.js","webpack://hdsp-agent/./lib/services/ApiKeyManager.js","webpack://hdsp-agent/./lib/services/ApiService.js","webpack://hdsp-agent/./lib/services/CheckpointManager.js","webpack://hdsp-agent/./lib/services/ContextManager.js","webpack://hdsp-agent/./lib/services/StateVerifier.js","webpack://hdsp-agent/./lib/services/TaskService.js","webpack://hdsp-agent/./lib/services/ToolExecutor.js","webpack://hdsp-agent/./lib/services/ToolRegistry.js","webpack://hdsp-agent/./lib/types/auto-agent.js","webpack://hdsp-agent/./lib/types/index.js","webpack://hdsp-agent/./lib/utils/SafetyChecker.js","webpack://hdsp-agent/./lib/utils/markdownRenderer.js","webpack://hdsp-agent/./node_modules/@mui/icons-material/esm/AutoFixHigh.js","webpack://hdsp-agent/./node_modules/@mui/icons-material/esm/Cancel.js","webpack://hdsp-agent/./node_modules/@mui/icons-material/esm/CheckCircle.js","webpack://hdsp-agent/./node_modules/@mui/icons-material/esm/Close.js","webpack://hdsp-agent/./node_modules/@mui/icons-material/esm/Error.js","webpack://hdsp-agent/./node_modules/@mui/icons-material/esm/ExpandLess.js","webpack://hdsp-agent/./node_modules/@mui/icons-material/esm/ExpandMore.js"],"sourcesContent":["/**\n * Agent Panel - Main sidebar panel for Jupyter Agent\n * Cursor AI Style: Unified Chat + Agent Interface\n */\nimport React, { useState, useEffect, useRef, useImperativeHandle, forwardRef, useCallback } from 'react';\nimport { ReactWidget, LabIcon } from '@jupyterlab/ui-components';\nimport { SettingsPanel } from './SettingsPanel';\nimport { getLLMConfig, saveLLMConfig, hasValidApiKey, getDefaultLLMConfig } from '../services/ApiKeyManager';\nimport { AgentOrchestrator } from '../services/AgentOrchestrator';\nimport { DEFAULT_AUTO_AGENT_CONFIG, } from '../types/auto-agent';\nimport { formatMarkdownToHtml } from '../utils/markdownRenderer';\nimport { FileSelectionDialog } from './FileSelectionDialog';\n// ๋ก๊ณ ์ด๋ฏธ์ง (SVG) - TypeScript ๋ชจ๋์์ ์ธ๋ผ์ธ ๋ฌธ์์ด๋ก import\nimport { headerLogoSvg, tabbarLogoSvg } from '../logoSvg';\n// ํญ๋ฐ ์์ด์ฝ ์์ฑ\nconst hdspTabIcon = new LabIcon({\n name: 'hdsp-agent:tab-icon',\n svgstr: tabbarLogoSvg\n});\n// Agent ๋ช
๋ น์ด ๊ฐ์ง ํจ์\nconst isAgentCommand = (input) => {\n const trimmed = input.trim().toLowerCase();\n return trimmed.startsWith('/run ') ||\n trimmed.startsWith('@agent ') ||\n trimmed.startsWith('/agent ') ||\n trimmed.startsWith('/execute ');\n};\n// Agent ๋ช
๋ น์ด์์ ์ค์ ์์ฒญ ์ถ์ถ\nconst extractAgentRequest = (input) => {\n const trimmed = input.trim();\n if (trimmed.toLowerCase().startsWith('/run ')) {\n return trimmed.slice(5).trim();\n }\n if (trimmed.toLowerCase().startsWith('@agent ')) {\n return trimmed.slice(7).trim();\n }\n if (trimmed.toLowerCase().startsWith('/agent ')) {\n return trimmed.slice(7).trim();\n }\n if (trimmed.toLowerCase().startsWith('/execute ')) {\n return trimmed.slice(9).trim();\n }\n return trimmed;\n};\n// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n// Python ํ์ผ ์๋ฌ ๊ฐ์ง ๋ฐ ์ฒ๋ฆฌ ์ ํธ๋ฆฌํฐ\n// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n// Python ์๋ฌ ํจํด ๊ฐ์ง\nconst detectPythonError = (text) => {\n const errorPatterns = [\n /Traceback \\(most recent call last\\)/i,\n /SyntaxError:/i,\n /NameError:/i,\n /TypeError:/i,\n /ImportError:/i,\n /ModuleNotFoundError:/i,\n /AttributeError:/i,\n /ValueError:/i,\n /KeyError:/i,\n /IndexError:/i,\n /FileNotFoundError:/i,\n /File\\s+\"[^\"]+\\.py\"/i,\n ];\n return errorPatterns.some(pattern => pattern.test(text));\n};\n// ์๋ฌ ๋ฉ์์ง์์ Python ํ์ผ ๊ฒฝ๋ก ์ถ์ถ\nconst extractFilePathsFromError = (text) => {\n const paths = [];\n // ํจํด 1: python xxx.py ๋ช
๋ น์ด\n const cmdMatch = text.match(/python\\s+(\\S+\\.py)/gi);\n if (cmdMatch) {\n cmdMatch.forEach(match => {\n const pathMatch = match.match(/python\\s+(\\S+\\.py)/i);\n if (pathMatch)\n paths.push(pathMatch[1]);\n });\n }\n // ํจํด 2: File \"xxx.py\" ํ์ (ํธ๋ ์ด์ค๋ฐฑ)\n const fileMatches = text.matchAll(/File\\s+\"([^\"]+\\.py)\"/gi);\n for (const match of fileMatches) {\n if (!paths.includes(match[1])) {\n paths.push(match[1]);\n }\n }\n return paths;\n};\n// ๋ฉ์ธ ํ์ผ ๊ฒฝ๋ก ์ถ์ถ (๋ช
๋ น์ด์์ ์คํํ ํ์ผ)\nconst extractMainFilePath = (text) => {\n // python xxx.py ๋ช
๋ น์ด์์ ์ถ์ถ\n const cmdMatch = text.match(/python\\s+(\\S+\\.py)/i);\n if (cmdMatch) {\n return cmdMatch[1];\n }\n return null;\n};\n// ์๋ฌ๊ฐ ๋ฐ์ํ ์ค์ ํ์ผ ์ถ์ถ (ํธ๋ ์ด์ค๋ฐฑ์ ๋ง์ง๋ง ํ์ผ)\nconst extractErrorFilePath = (text) => {\n // File \"xxx.py\" ํจํด๋ค ์ค ๋ง์ง๋ง ๊ฒ (์ค์ ์๋ฌ ๋ฐ์ ์์น)\n const fileMatches = [...text.matchAll(/File\\s+\"([^\"]+\\.py)\"/gi)];\n if (fileMatches.length > 0) {\n return fileMatches[fileMatches.length - 1][1];\n }\n return null;\n};\n// Python ํ์ผ์์ ๋ก์ปฌ import ์ถ์ถ\nconst extractLocalImports = (content) => {\n const imports = [];\n // from xxx import yyy (๋ก์ปฌ ๋ชจ๋)\n const fromImports = content.matchAll(/^from\\s+(\\w+)\\s+import/gm);\n for (const match of fromImports) {\n const moduleName = match[1];\n // ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋ ๊ฒ๋ง (๊ฐ๋จํ ํด๋ฆฌ์คํฑ)\n if (!isStdLibModule(moduleName)) {\n imports.push(moduleName);\n }\n }\n // import xxx (๋ก์ปฌ ๋ชจ๋)\n const directImports = content.matchAll(/^import\\s+(\\w+)/gm);\n for (const match of directImports) {\n const moduleName = match[1];\n if (!isStdLibModule(moduleName)) {\n imports.push(moduleName);\n }\n }\n return [...new Set(imports)];\n};\n// ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ชจ๋ ์ฒดํฌ (๊ฐ๋จํ ๋ชฉ๋ก)\nconst isStdLibModule = (name) => {\n const stdLibModules = [\n 'os', 'sys', 'json', 're', 'math', 'datetime', 'time', 'random',\n 'collections', 'itertools', 'functools', 'typing', 'pathlib',\n 'subprocess', 'threading', 'multiprocessing', 'asyncio', 'socket',\n 'http', 'urllib', 'email', 'html', 'xml', 'logging', 'unittest',\n 'io', 'pickle', 'copy', 'pprint', 'traceback', 'warnings',\n 'contextlib', 'abc', 'dataclasses', 'enum', 'types',\n // ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ (์ผ๋ฐ์ ์ผ๋ก ์ค์น๋จ)\n 'numpy', 'pandas', 'matplotlib', 'seaborn', 'sklearn', 'scipy',\n 'torch', 'tensorflow', 'keras', 'requests', 'flask', 'django',\n ];\n return stdLibModules.includes(name.toLowerCase());\n};\nconst ChatPanel = forwardRef(({ apiService, notebookTracker, consoleTracker }, ref) => {\n // ํตํฉ ๋ฉ์์ง ๋ชฉ๋ก (Chat + Agent ์คํ)\n const [messages, setMessages] = useState([]);\n const [input, setInput] = useState('');\n const [isLoading, setIsLoading] = useState(false);\n const [isStreaming, setIsStreaming] = useState(false);\n const [streamingMessageId, setStreamingMessageId] = useState(null);\n const [conversationId, setConversationId] = useState('');\n const [showSettings, setShowSettings] = useState(false);\n const [llmConfig, setLlmConfig] = useState(null);\n // Agent ์คํ ์ํ\n const [isAgentRunning, setIsAgentRunning] = useState(false);\n const [currentAgentMessageId, setCurrentAgentMessageId] = useState(null);\n const [executionSpeed, setExecutionSpeed] = useState('normal');\n // ์
๋ ฅ ๋ชจ๋ (Cursor AI ์คํ์ผ) - ๋ก์ปฌ ์คํ ๋ฆฌ์ง์์ ๋ณต์\n const [inputMode, setInputMode] = useState(() => {\n try {\n const saved = localStorage.getItem('hdsp-agent-input-mode');\n return (saved === 'agent' || saved === 'chat') ? saved : 'chat';\n }\n catch {\n return 'chat';\n }\n });\n const [showModeDropdown, setShowModeDropdown] = useState(false);\n // ํ์ผ ์์ ๊ด๋ จ ์ํ\n const [pendingFileFixes, setPendingFileFixes] = useState([]);\n // Console ์๋ฌ ์๋ ๊ฐ์ง ์ํ\n const [lastConsoleError, setLastConsoleError] = useState(null);\n const [showConsoleErrorNotification, setShowConsoleErrorNotification] = useState(false);\n // File selection state\n const [fileSelectionMetadata, setFileSelectionMetadata] = useState(null);\n const [pendingAgentRequest, setPendingAgentRequest] = useState(null);\n // ๋ชจ๋ ๋ณ๊ฒฝ ์ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ์ ์ฅ\n useEffect(() => {\n try {\n localStorage.setItem('hdsp-agent-input-mode', inputMode);\n }\n catch {\n // ๋ก์ปฌ ์คํ ๋ฆฌ์ง ์ ๊ทผ ๋ถ๊ฐ ์ ๋ฌด์\n }\n }, [inputMode]);\n const messagesEndRef = useRef(null);\n const pendingLlmPromptRef = useRef(null);\n const allCodeBlocksRef = useRef([]);\n const currentCellIdRef = useRef(null);\n const currentCellIndexRef = useRef(null);\n const orchestratorRef = useRef(null);\n // Expose handleSendMessage via ref\n useImperativeHandle(ref, () => ({\n handleSendMessage: async () => {\n await handleSendMessage();\n },\n setInput: (value) => {\n setInput(value);\n },\n setLlmPrompt: (prompt) => {\n pendingLlmPromptRef.current = prompt;\n // Find textarea and set data attribute\n const textarea = messagesEndRef.current?.parentElement?.querySelector('.jp-agent-input');\n if (textarea) {\n textarea.setAttribute('data-llm-prompt', prompt);\n }\n },\n setCurrentCellId: (cellId) => {\n console.log('[AgentPanel] setCurrentCellId called with:', cellId);\n currentCellIdRef.current = cellId;\n },\n setCurrentCellIndex: (cellIndex) => {\n console.log('[AgentPanel] setCurrentCellIndex called with:', cellIndex);\n currentCellIndexRef.current = cellIndex;\n },\n setInputMode: (mode) => {\n console.log('[AgentPanel] setInputMode called with:', mode);\n setInputMode(mode);\n }\n }));\n // Load config on mount\n useEffect(() => {\n loadConfig();\n }, []);\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // Console ์ถ๋ ฅ ๋ชจ๋ํฐ๋ง - Python ์๋ฌ ์๋ ๊ฐ์ง\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n useEffect(() => {\n if (!consoleTracker) {\n console.log('[AgentPanel] ConsoleTracker not available');\n return;\n }\n console.log('[AgentPanel] Setting up console output monitoring');\n // Console ์ถ๋ ฅ์์ ์๋ฌ ๊ฐ์งํ๋ ํจ์\n const checkConsoleForErrors = () => {\n const currentConsole = consoleTracker.currentWidget;\n if (!currentConsole) {\n return;\n }\n try {\n // Console์ ์ถ๋ ฅ ์์ญ์์ ํ
์คํธ ์ถ์ถ\n const consoleNode = currentConsole.node;\n if (!consoleNode)\n return;\n // JupyterLab Console์ ์ถ๋ ฅ์ .jp-OutputArea-output ํด๋์ค์ ์์\n const outputAreas = consoleNode.querySelectorAll('.jp-OutputArea-output');\n if (outputAreas.length === 0)\n return;\n // ์ต๊ทผ ์ถ๋ ฅ๋ง ํ์ธ (๋ง์ง๋ง ๋ช ๊ฐ)\n const recentOutputs = Array.from(outputAreas).slice(-5);\n let combinedOutput = '';\n recentOutputs.forEach((output) => {\n const text = output.textContent || '';\n combinedOutput += text + '\\n';\n });\n // Python ์๋ฌ ๊ฐ์ง\n if (detectPythonError(combinedOutput)) {\n console.log('[AgentPanel] Python error detected in console output');\n // ์ค๋ณต ์๋ฆผ ๋ฐฉ์ง\n if (lastConsoleError !== combinedOutput) {\n setLastConsoleError(combinedOutput);\n setShowConsoleErrorNotification(true);\n // 5์ด ํ ์๋์ผ๋ก ์๋ฆผ ์จ๊ธฐ๊ธฐ\n setTimeout(() => {\n setShowConsoleErrorNotification(false);\n }, 10000);\n }\n }\n }\n catch (e) {\n console.error('[AgentPanel] Error checking console output:', e);\n }\n };\n // MutationObserver๋ก Console ์ถ๋ ฅ ๋ณ๊ฒฝ ๊ฐ์ง\n let observer = null;\n const setupObserver = () => {\n const currentConsole = consoleTracker.currentWidget;\n if (!currentConsole?.node)\n return;\n // ๊ธฐ์กด observer ์ ๋ฆฌ\n if (observer) {\n observer.disconnect();\n }\n observer = new MutationObserver((mutations) => {\n // ์ถ๋ ฅ ์์ญ์ ๋ณํ๊ฐ ์์ผ๋ฉด ์๋ฌ ์ฒดํฌ\n const hasOutputChange = mutations.some(mutation => mutation.type === 'childList' ||\n (mutation.type === 'characterData'));\n if (hasOutputChange) {\n // ์ฝ๊ฐ์ ๋๋ ์ด ํ ์ฒดํฌ (์ถ๋ ฅ์ด ์์ ํ ๋ ๋๋ง๋ ๋๊น์ง)\n setTimeout(checkConsoleForErrors, 100);\n }\n });\n // Console ์ ์ฒด๋ฅผ ๊ด์ฐฐ\n observer.observe(currentConsole.node, {\n childList: true,\n subtree: true,\n characterData: true\n });\n console.log('[AgentPanel] MutationObserver set up for console');\n };\n // ํ์ฌ Console์ observer ์ค์ \n setupObserver();\n // Console ๋ณ๊ฒฝ ์ observer ์ฌ์ค์ \n const onConsoleChanged = () => {\n console.log('[AgentPanel] Console changed, re-setting up observer');\n setupObserver();\n };\n consoleTracker.currentChanged?.connect(onConsoleChanged);\n // Cleanup\n return () => {\n if (observer) {\n observer.disconnect();\n }\n consoleTracker.currentChanged?.disconnect(onConsoleChanged);\n };\n }, [consoleTracker, lastConsoleError]);\n // Remove lastActiveNotebook state - just use currentWidget directly\n // Agent ์คํ ํธ๋ค๋ฌ\n const handleAgentExecution = useCallback(async (request) => {\n // CRITICAL: Prevent concurrent agent executions\n if (isAgentRunning) {\n const errorMessage = {\n id: Date.now().toString(),\n role: 'assistant',\n content: 'โ ๏ธ ์ด์ ์์
์ด ์์ง ์คํ ์ค์
๋๋ค. ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ ค์ฃผ์ธ์.',\n timestamp: Date.now(),\n };\n setMessages(prev => [...prev, errorMessage]);\n return;\n }\n // IMPORTANT: Use app.shell.currentWidget for reliable active tab detection\n const app = window.jupyterapp;\n let notebook = null;\n // Try to get notebook from shell.currentWidget (most reliable)\n if (app?.shell?.currentWidget) {\n const currentWidget = app.shell.currentWidget;\n if ('content' in currentWidget && currentWidget.content?.model) {\n notebook = currentWidget;\n }\n }\n // Fallback to notebookTracker\n if (!notebook) {\n notebook = notebookTracker?.currentWidget;\n }\n const sessionContext = notebook?.sessionContext;\n // ๋๋ฒ๊น
: ํ์ฌ ์ ํ๋ ๋
ธํธ๋ถ ๊ฒฝ๋ก ๋ก๊ทธ\n console.log('[AgentPanel] shell.currentWidget:', app?.shell?.currentWidget?.context?.path);\n console.log('[AgentPanel] tracker.currentWidget:', notebookTracker?.currentWidget?.context?.path);\n console.log('[AgentPanel] Using notebook:', notebook?.context?.path);\n console.log('[AgentPanel] Notebook title:', notebook?.title?.label);\n if (!notebook || !sessionContext) {\n // ๋
ธํธ๋ถ์ด ์์ผ๋ฉด ์๋ฌ ๋ฉ์์ง ํ์\n const errorMessage = {\n id: Date.now().toString(),\n role: 'assistant',\n content: '๋
ธํธ๋ถ์ ๋จผ์ ์ด์ด์ฃผ์ธ์. Agent ์คํ์ ํ์ฑ ๋
ธํธ๋ถ์ด ํ์ํฉ๋๋ค.',\n timestamp: Date.now(),\n };\n setMessages(prev => [...prev, errorMessage]);\n return;\n }\n // โ
ํ์ฌ ํ์ฑํ๋ ๋
ธํธ๋ถ์ผ๋ก AgentOrchestrator ์ฌ์์ฑ (ํญ ์ ํ ๋์)\n const config = { ...DEFAULT_AUTO_AGENT_CONFIG, executionSpeed };\n const orchestrator = new AgentOrchestrator(notebook, sessionContext, apiService, config);\n // Agent ์คํ ๋ฉ์์ง ์์ฑ\n const agentMessageId = `agent-${Date.now()}`;\n const agentMessage = {\n id: agentMessageId,\n type: 'agent_execution',\n request,\n status: { phase: 'planning', message: '์คํ ๊ณํ ์์ฑ ์ค...' },\n plan: null,\n result: null,\n completedSteps: [],\n failedSteps: [],\n timestamp: Date.now(),\n };\n setMessages(prev => [...prev, agentMessage]);\n setCurrentAgentMessageId(agentMessageId);\n setIsAgentRunning(true);\n try {\n // Get current llmConfig for the agent execution\n const currentLlmConfig = llmConfig || getLLMConfig() || getDefaultLLMConfig();\n const result = await orchestrator.executeTask(request, notebook, (newStatus) => {\n // ์ค์๊ฐ ์ํ ์
๋ฐ์ดํธ\n setMessages(prev => prev.map(msg => msg.id === agentMessageId && 'type' in msg && msg.type === 'agent_execution'\n ? {\n ...msg,\n status: newStatus,\n plan: newStatus.plan || msg.plan,\n completedSteps: newStatus.currentStep && newStatus.currentStep > 1\n ? Array.from({ length: newStatus.currentStep - 1 }, (_, i) => i + 1)\n : msg.completedSteps,\n failedSteps: newStatus.phase === 'failed' && newStatus.currentStep\n ? [...msg.failedSteps, newStatus.currentStep]\n : msg.failedSteps,\n }\n : msg));\n }, currentLlmConfig // Pass llmConfig to orchestrator\n );\n // ์ต์ข
๊ฒฐ๊ณผ ์
๋ฐ์ดํธ\n setMessages(prev => prev.map(msg => msg.id === agentMessageId && 'type' in msg && msg.type === 'agent_execution'\n ? {\n ...msg,\n status: {\n phase: result.success ? 'completed' : 'failed',\n message: result.finalAnswer || (result.success ? '์์
์๋ฃ' : '์์
์คํจ'),\n },\n result,\n completedSteps: result.plan?.steps.map(s => s.stepNumber) || [],\n }\n : msg));\n }\n catch (error) {\n console.log('[AgentPanel] Caught error:', error);\n console.log('[AgentPanel] Error name:', error.name);\n console.log('[AgentPanel] Error has fileSelectionMetadata:', !!error.fileSelectionMetadata);\n // Handle FILE_SELECTION_REQUIRED error\n if (error.name === 'FileSelectionError' && error.fileSelectionMetadata) {\n console.log('[AgentPanel] File selection required:', error.fileSelectionMetadata);\n // Show file selection dialog\n setFileSelectionMetadata(error.fileSelectionMetadata);\n setPendingAgentRequest(request);\n // Update message to show waiting state\n setMessages(prev => prev.map(msg => msg.id === agentMessageId && 'type' in msg && msg.type === 'agent_execution'\n ? {\n ...msg,\n status: {\n phase: 'executing',\n message: 'ํ์ผ ์ ํ ๋๊ธฐ ์ค...'\n },\n }\n : msg));\n // Keep isAgentRunning true to show we're paused, not failed\n return;\n }\n setMessages(prev => prev.map(msg => msg.id === agentMessageId && 'type' in msg && msg.type === 'agent_execution'\n ? {\n ...msg,\n status: { phase: 'failed', message: error.message || '์คํ ์ค ์ค๋ฅ ๋ฐ์' },\n }\n : msg));\n }\n finally {\n setIsAgentRunning(false);\n setCurrentAgentMessageId(null);\n }\n }, [notebookTracker, apiService]);\n const loadConfig = () => {\n // Load from localStorage using ApiKeyManager\n const config = getLLMConfig();\n if (!config) {\n console.log('[AgentPanel] No config in localStorage, using default');\n const defaultConfig = getDefaultLLMConfig();\n setLlmConfig(defaultConfig);\n return;\n }\n setLlmConfig(config);\n // Log loaded model configuration\n console.log('=== HDSP Agent Model Configuration (localStorage) ===');\n console.log('Provider:', config.provider);\n if (config.provider === 'gemini') {\n console.log('Gemini Model:', config.gemini?.model || 'gemini-2.5-flash (default)');\n console.log('Gemini API Key:', config.gemini?.apiKey ? 'โ Configured' : 'โ Not configured');\n }\n else if (config.provider === 'vllm') {\n console.log('vLLM Model:', config.vllm?.model || 'default');\n console.log('vLLM Endpoint:', config.vllm?.endpoint || 'http://localhost:8000');\n console.log('vLLM API Key:', config.vllm?.apiKey ? 'โ Configured' : 'โ Not configured');\n }\n else if (config.provider === 'openai') {\n console.log('OpenAI Model:', config.openai?.model || 'gpt-4');\n console.log('OpenAI API Key:', config.openai?.apiKey ? 'โ Configured' : 'โ Not configured');\n }\n console.log('====================================================');\n };\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // Python ํ์ผ ์๋ฌ ์์ ๊ด๋ จ ํจ์๋ค\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // JupyterLab Contents API๋ฅผ ํตํด ํ์ผ ๋ด์ฉ ๋ก๋\n const loadFileContent = async (filePath) => {\n try {\n // PageConfig์์ base URL ๊ฐ์ ธ์ค๊ธฐ\n const { PageConfig, URLExt } = await import('@jupyterlab/coreutils');\n const baseUrl = PageConfig.getBaseUrl();\n const apiUrl = URLExt.join(baseUrl, 'api/contents', filePath);\n console.log('[AgentPanel] Loading file:', filePath, 'from:', apiUrl);\n const response = await fetch(apiUrl, {\n method: 'GET',\n credentials: 'include',\n });\n if (!response.ok) {\n console.warn('[AgentPanel] Failed to load file:', filePath, response.status);\n return null;\n }\n const data = await response.json();\n return data.content;\n }\n catch (error) {\n console.error('[AgentPanel] Error loading file:', filePath, error);\n return null;\n }\n };\n // ํ์ผ์ ์์ ๋ ์ฝ๋ ์ ์ฅ\n const saveFileContent = async (filePath, content) => {\n try {\n const { PageConfig, URLExt } = await import('@jupyterlab/coreutils');\n const baseUrl = PageConfig.getBaseUrl();\n const apiUrl = URLExt.join(baseUrl, 'api/contents', filePath);\n console.log('[AgentPanel] Saving file:', filePath);\n const response = await fetch(apiUrl, {\n method: 'PUT',\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n type: 'file',\n format: 'text',\n content: content,\n }),\n });\n if (!response.ok) {\n console.error('[AgentPanel] Failed to save file:', filePath, response.status);\n return false;\n }\n console.log('[AgentPanel] File saved successfully:', filePath);\n return true;\n }\n catch (error) {\n console.error('[AgentPanel] Error saving file:', filePath, error);\n return false;\n }\n };\n // Python ์๋ฌ ๋ฉ์์ง ์ฒ๋ฆฌ ๋ฐ ํ์ผ ์์ ์์ฒญ\n const handlePythonErrorFix = async (errorMessage) => {\n console.log('[AgentPanel] Handling Python error fix request');\n // 1. ์๋ฌ๊ฐ ๋ฐ์ํ ํ์ผ ๊ฒฝ๋ก ์ถ์ถ\n const errorFilePath = extractErrorFilePath(errorMessage);\n const mainFilePath = extractMainFilePath(errorMessage);\n const allFilePaths = extractFilePathsFromError(errorMessage);\n console.log('[AgentPanel] Error file:', errorFilePath);\n console.log('[AgentPanel] Main file:', mainFilePath);\n console.log('[AgentPanel] All files:', allFilePaths);\n if (!errorFilePath && !mainFilePath) {\n // ํ์ผ ๊ฒฝ๋ก๋ฅผ ์ฐพ์ ์ ์์ผ๋ฉด ์ผ๋ฐ ์ฑํ
์ผ๋ก ์ฒ๋ฆฌ\n console.log('[AgentPanel] No file path found, using regular chat');\n return;\n }\n // 2. ์ฃผ์ ํ์ผ ๋ด์ฉ ๋ก๋\n const targetFile = errorFilePath || mainFilePath;\n const mainContent = await loadFileContent(targetFile);\n if (!mainContent) {\n console.warn('[AgentPanel] Could not load file content for:', targetFile);\n // ํ์ผ์ ์ฝ์ ์ ์์ผ๋ฉด ์๋ฌ ๋ฉ์์ง๋ง์ผ๋ก ์ฒ๋ฆฌ ์๋\n const errorOnlyRequest = {\n action: 'fix',\n mainFile: { path: targetFile, content: '(ํ์ผ ์ฝ๊ธฐ ์คํจ)' },\n errorOutput: errorMessage,\n };\n try {\n const result = await apiService.fileAction(errorOnlyRequest);\n handleFileFixResponse(result.response, result.fixedFiles);\n }\n catch (error) {\n console.error('[AgentPanel] File fix API error:', error);\n addErrorMessage('ํ์ผ ์์ ์์ฒญ ์คํจ: ' + error.message);\n }\n return;\n }\n // 3. ๊ด๋ จ ํ์ผ๋ค (imports) ๋ก๋\n const localImports = extractLocalImports(mainContent);\n const relatedFiles = [];\n // ์๋ฌ ๋ฉ์์ง์ ์ธ๊ธ๋ ๋ค๋ฅธ ํ์ผ๋ค๋ ๋ก๋\n for (const path of allFilePaths) {\n if (path !== targetFile) {\n const content = await loadFileContent(path);\n if (content) {\n relatedFiles.push({ path, content });\n }\n }\n }\n // ๋ก์ปฌ import ํ์ผ๋ค๋ ๋ก๋\n const baseDir = targetFile.includes('/') ? targetFile.substring(0, targetFile.lastIndexOf('/')) : '';\n for (const moduleName of localImports) {\n const modulePath = baseDir ? `${baseDir}/${moduleName}.py` : `${moduleName}.py`;\n if (!allFilePaths.includes(modulePath) && !relatedFiles.some(f => f.path === modulePath)) {\n const content = await loadFileContent(modulePath);\n if (content) {\n relatedFiles.push({ path: modulePath, content });\n }\n }\n }\n console.log('[AgentPanel] Related files loaded:', relatedFiles.length);\n // 4. ํ์ผ ์์ API ํธ์ถ\n const request = {\n action: 'fix',\n mainFile: { path: targetFile, content: mainContent },\n errorOutput: errorMessage,\n relatedFiles: relatedFiles.length > 0 ? relatedFiles : undefined,\n };\n try {\n setIsLoading(true);\n const result = await apiService.fileAction(request);\n handleFileFixResponse(result.response, result.fixedFiles);\n }\n catch (error) {\n console.error('[AgentPanel] File fix API error:', error);\n addErrorMessage('ํ์ผ ์์ ์์ฒญ ์คํจ: ' + error.message);\n }\n finally {\n setIsLoading(false);\n }\n };\n // ํ์ผ ์์ ์๋ต ์ฒ๋ฆฌ\n const handleFileFixResponse = (response, fixedFiles) => {\n console.log('[AgentPanel] File fix response received, fixed files:', fixedFiles.length);\n // Assistant ๋ฉ์์ง๋ก ์๋ต ํ์\n const assistantMessage = {\n id: Date.now().toString() + '-file-fix',\n role: 'assistant',\n content: response,\n timestamp: Date.now(),\n metadata: { type: 'file_fix', fixedFiles },\n };\n setMessages(prev => [...prev, assistantMessage]);\n // ์์ ๋ ํ์ผ์ด ์์ผ๋ฉด ์ํ์ ์ ์ฅ (์ ์ฉ ๋ฒํผ์ฉ)\n if (fixedFiles.length > 0) {\n setPendingFileFixes(fixedFiles);\n }\n };\n // ์์ ๋ ํ์ผ ์ ์ฉ\n const applyFileFix = async (fix) => {\n console.log('[AgentPanel] Applying fix to file:', fix.path);\n const success = await saveFileContent(fix.path, fix.content);\n if (success) {\n // ์ฑ๊ณต ๋ฉ์์ง\n const successMessage = {\n id: Date.now().toString() + '-apply-success',\n role: 'assistant',\n content: `โ
**${fix.path}** ํ์ผ์ด ์์ ๋์์ต๋๋ค.\\n\\nํ์ผ ์๋ํฐ์์ ๋ณ๊ฒฝ์ฌํญ์ ํ์ธํ์ธ์.`,\n timestamp: Date.now(),\n };\n setMessages(prev => [...prev, successMessage]);\n // ์ ์ฉ๋ ํ์ผ์ pending์์ ์ ๊ฑฐ\n setPendingFileFixes(prev => prev.filter(f => f.path !== fix.path));\n }\n else {\n addErrorMessage(`ํ์ผ ์ ์ฅ ์คํจ: ${fix.path}`);\n }\n };\n // ์๋ฌ ๋ฉ์์ง ์ถ๊ฐ ํฌํผ\n const addErrorMessage = (message) => {\n const errorMessage = {\n id: Date.now().toString() + '-error',\n role: 'assistant',\n content: `โ ๏ธ ${message}`,\n timestamp: Date.now(),\n };\n setMessages(prev => [...prev, errorMessage]);\n };\n const handleSaveConfig = (config) => {\n console.log('[AgentPanel] Saving config to localStorage');\n console.log('Provider:', config.provider);\n console.log('API Key configured:', hasValidApiKey(config) ? 'โ Yes' : 'โ No');\n // Save to localStorage using ApiKeyManager\n saveLLMConfig(config);\n // Update state\n setLlmConfig(config);\n console.log('[AgentPanel] Config saved successfully');\n };\n // File selection handlers\n const handleFileSelect = async (index) => {\n console.log('[AgentPanel] File selected:', index);\n if (!fileSelectionMetadata || !pendingAgentRequest) {\n console.error('[AgentPanel] Missing file selection metadata or pending request');\n return;\n }\n // Get selected file info (index is 1-based from the UI button click)\n const selectedFile = fileSelectionMetadata.options[index - 1];\n if (!selectedFile) {\n console.error('[AgentPanel] Invalid file selection index:', index);\n return;\n }\n console.log('[AgentPanel] Selected file:', selectedFile.path);\n // Close dialog\n setFileSelectionMetadata(null);\n const originalRequest = pendingAgentRequest;\n setPendingAgentRequest(null);\n // Update the agent message to show file was selected\n setMessages(prev => prev.map(msg => {\n if ('type' in msg && msg.type === 'agent_execution' && msg.status.phase === 'executing') {\n return {\n ...msg,\n status: {\n phase: 'executing',\n message: `ํ์ผ ์ ํ๋จ: ${selectedFile.relative}\\n์คํ ์ฌ๊ฐ ์ค...`\n },\n };\n }\n return msg;\n }));\n // Re-execute the agent with the selected file path explicitly mentioned\n // Modify the request to include the selected file path\n const modifiedRequest = `${originalRequest} (ํ์ผ ๊ฒฝ๋ก: ${selectedFile.path})`;\n console.log('[AgentPanel] Re-executing agent with modified request:', modifiedRequest);\n // Resume execution by calling handleAgentExecution with the modified request\n // Note: This will create a new agent message, but the existing one should be marked as cancelled\n setMessages(prev => prev.map(msg => {\n if ('type' in msg && msg.type === 'agent_execution' && msg.status.phase === 'executing') {\n return {\n ...msg,\n status: {\n phase: 'completed',\n message: `ํ์ผ ์ ํ๋จ: ${selectedFile.relative}\\n์ ์คํ์ผ๋ก ์ฌ๊ฐ๋ฉ๋๋ค...`\n },\n };\n }\n return msg;\n }));\n // Reset agent running state to allow new execution\n setIsAgentRunning(false);\n setCurrentAgentMessageId(null);\n // Start new agent execution with explicit file path\n await handleAgentExecution(modifiedRequest);\n };\n const handleFileSelectCancel = () => {\n console.log('[AgentPanel] File selection cancelled');\n // Update the agent message to show cancellation\n setMessages(prev => prev.map(msg => {\n if ('type' in msg && msg.type === 'agent_execution' && msg.status.phase === 'executing') {\n return {\n ...msg,\n status: {\n phase: 'failed',\n message: '์ฌ์ฉ์๊ฐ ํ์ผ ์ ํ์ ์ทจ์ํ์ต๋๋ค.'\n },\n };\n }\n return msg;\n }));\n setFileSelectionMetadata(null);\n setPendingAgentRequest(null);\n setIsAgentRunning(false);\n setCurrentAgentMessageId(null);\n };\n // Auto-scroll to bottom when messages change\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages]);\n // Extract and store code blocks from messages, setup button listeners\n useEffect(() => {\n // Use a small delay to ensure DOM is updated after message rendering\n const timeoutId = setTimeout(() => {\n // Find messages container - try multiple selectors\n const messagesContainer = document.querySelector('.jp-agent-messages') ||\n messagesEndRef.current?.parentElement ||\n document.querySelector('[class*=\"jp-agent-messages\"]');\n if (!messagesContainer) {\n console.log('[AgentPanel] Messages container not found');\n return;\n }\n // Extract code blocks from all assistant messages\n const codeBlocks = [];\n const containers = messagesContainer.querySelectorAll('.code-block-container');\n console.log(`[AgentPanel] Found ${containers.length} code block containers`);\n containers.forEach(container => {\n const blockId = container.getAttribute('data-block-id');\n if (!blockId) {\n console.warn('[AgentPanel] Code block container missing data-block-id');\n return;\n }\n const codeElement = container.querySelector(`#${blockId}`);\n if (!codeElement) {\n console.warn(`[AgentPanel] Code element #${blockId} not found`);\n return;\n }\n const codeText = codeElement.textContent || '';\n const langElement = container.querySelector('.code-block-language');\n const language = langElement?.textContent?.toLowerCase() || 'python';\n codeBlocks.push({\n id: blockId,\n code: codeText,\n language: language\n });\n });\n // Update code blocks ref\n allCodeBlocksRef.current = codeBlocks;\n console.log(`[AgentPanel] Stored ${codeBlocks.length} code blocks`, codeBlocks.map(b => b.id));\n // Use event delegation - attach single listener to container\n const handleContainerClick = async (e) => {\n const target = e.target;\n // Handle copy button\n if (target.classList.contains('code-block-copy') || target.closest('.code-block-copy')) {\n const button = target.classList.contains('code-block-copy')\n ? target\n : target.closest('.code-block-copy');\n e.stopPropagation();\n e.preventDefault();\n const blockId = button.getAttribute('data-block-id');\n if (!blockId)\n return;\n const block = allCodeBlocksRef.current.find(b => b.id === blockId);\n if (!block)\n return;\n try {\n await navigator.clipboard.writeText(block.code);\n const originalText = button.textContent;\n button.textContent = '๋ณต์ฌ๋จ!';\n setTimeout(() => {\n button.textContent = originalText || '๋ณต์ฌ';\n }, 2000);\n }\n catch (error) {\n console.error('Failed to copy code:', error);\n showNotification('๋ณต์ฌ์ ์คํจํ์ต๋๋ค.', 'error');\n }\n return;\n }\n // Handle apply button\n if (target.classList.contains('code-block-apply') || target.closest('.code-block-apply')) {\n const button = target.classList.contains('code-block-apply')\n ? target\n : target.closest('.code-block-apply');\n e.stopPropagation();\n e.preventDefault();\n const blockId = button.getAttribute('data-block-id');\n console.log(`[AgentPanel] Apply button clicked via delegation, blockId: ${blockId}`);\n if (!blockId) {\n showNotification('์ฝ๋ ๋ธ๋ก ID๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.', 'error');\n return;\n }\n const block = allCodeBlocksRef.current.find(b => b.id === blockId);\n if (!block) {\n console.error('[AgentPanel] Block not found!', {\n clickedId: blockId,\n availableIds: allCodeBlocksRef.current.map(b => b.id),\n blocksCount: allCodeBlocksRef.current.length\n });\n showNotification('์ฝ๋๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.', 'error');\n return;\n }\n console.log(`[AgentPanel] Applying code to cell via delegation, code length: ${block.code.length}`);\n await applyCodeToCell(block.code, blockId, button);\n return;\n }\n };\n // Attach single event listener to container\n messagesContainer.addEventListener('click', handleContainerClick);\n // Cleanup - store handler reference for cleanup\n messagesContainer._agentPanelClickHandler = handleContainerClick;\n }, 100); // Small delay to ensure DOM is ready\n // Cleanup\n return () => {\n clearTimeout(timeoutId);\n // Remove event listener on cleanup\n const messagesContainer = document.querySelector('.jp-agent-messages') ||\n messagesEndRef.current?.parentElement ||\n document.querySelector('[class*=\"jp-agent-messages\"]');\n if (messagesContainer && messagesContainer._agentPanelClickHandler) {\n messagesContainer.removeEventListener('click', messagesContainer._agentPanelClickHandler);\n delete messagesContainer._agentPanelClickHandler;\n }\n };\n }, [messages]);\n // Helper: Get notification background color\n const getNotificationColor = (type) => {\n switch (type) {\n case 'error': return '#f56565';\n case 'warning': return '#ed8936';\n default: return '#4299e1';\n }\n };\n // Helper: Create and show notification element\n const createNotificationElement = (message, backgroundColor) => {\n const notification = document.createElement('div');\n notification.style.cssText = `\n position: fixed;\n top: 20px;\n right: 20px;\n padding: 12px 16px;\n border-radius: 6px;\n color: white;\n font-size: 14px;\n font-weight: 500;\n z-index: 10001;\n opacity: 0;\n transition: opacity 0.3s ease;\n max-width: 300px;\n word-wrap: break-word;\n background: ${backgroundColor};\n `;\n notification.textContent = message;\n return notification;\n };\n // Helper: Animate notification in and out\n const animateNotification = (notification) => {\n setTimeout(() => notification.style.opacity = '1', 10);\n setTimeout(() => {\n notification.style.opacity = '0';\n setTimeout(() => {\n if (notification.parentNode) {\n notification.parentNode.removeChild(notification);\n }\n }, 300);\n }, 3000);\n };\n // Show notification\n const showNotification = (message, type = 'info') => {\n const notification = createNotificationElement(message, getNotificationColor(type));\n document.body.appendChild(notification);\n animateNotification(notification);\n };\n // Show tooltip on a specific cell\n const showCellTooltip = (cellElement, message) => {\n // Remove any existing tooltip\n const existingTooltip = document.querySelector('.jp-agent-cell-tooltip');\n if (existingTooltip) {\n existingTooltip.remove();\n }\n const tooltip = document.createElement('div');\n tooltip.className = 'jp-agent-cell-tooltip';\n tooltip.textContent = message;\n tooltip.style.cssText = `\n position: absolute;\n top: 0;\n left: 50%;\n transform: translateX(-50%);\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n padding: 8px 16px;\n border-radius: 0 0 8px 8px;\n font-size: 13px;\n font-weight: 500;\n box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);\n z-index: 1000;\n opacity: 0;\n transition: opacity 0.3s ease;\n pointer-events: none;\n white-space: nowrap;\n `;\n // Make cell position relative if not already\n const originalPosition = cellElement.style.position;\n if (!originalPosition || originalPosition === 'static') {\n cellElement.style.position = 'relative';\n }\n cellElement.appendChild(tooltip);\n // Fade in\n requestAnimationFrame(() => {\n tooltip.style.opacity = '1';\n });\n // Fade out and remove after 2 seconds\n setTimeout(() => {\n tooltip.style.opacity = '0';\n setTimeout(() => {\n tooltip.remove();\n // Restore original position\n if (!originalPosition || originalPosition === 'static') {\n cellElement.style.position = originalPosition || '';\n }\n }, 300);\n }, 2000);\n };\n // Apply code to Jupyter cell\n const applyCodeToCell = async (code, blockId, button) => {\n console.log('[AgentPanel] applyCodeToCell called', { codeLength: code.length, blockId });\n const originalText = button.textContent;\n try {\n button.disabled = true;\n button.textContent = '์ ์ฉ ์ค...';\n const app = window.jupyterapp;\n if (!app) {\n console.error('[AgentPanel] jupyterapp not found in window');\n showNotification('JupyterLab์ ์ฐพ์ ์ ์์ต๋๋ค.', 'error');\n button.disabled = false;\n button.textContent = originalText || '์
์ ์ ์ฉ';\n return;\n }\n console.log('[AgentPanel] Found jupyterapp');\n // Try to get notebook tracker from app\n // The notebookTracker is passed to cellButtonsPlugin, so we need to access it differently\n // Use shell to find current notebook widget\n const shell = app.shell;\n const currentWidget = shell.currentWidget;\n // Check if current widget is a notebook\n if (currentWidget && 'content' in currentWidget) {\n const notebook = currentWidget.content;\n // Check if it's a notebook (has model and cells)\n if (notebook && 'model' in notebook && notebook.model && 'cells' in notebook.model) {\n await applyCodeToNotebookCell(code, notebook, blockId, button, originalText);\n return;\n }\n }\n // Fallback: show cell selector dialog\n showCellSelectorDialog(code, button, originalText);\n }\n catch (error) {\n console.error('Failed to apply code to cell:', error);\n showNotification('์ฝ๋ ์ ์ฉ์ ์คํจํ์ต๋๋ค.', 'error');\n button.disabled = false;\n button.textContent = originalText || '์
์ ์ ์ฉ';\n }\n };\n // Helper: Try different methods to set cell source\n const setCellSource = (cellModel, code) => {\n if (cellModel.sharedModel && typeof cellModel.sharedModel.setSource === 'function') {\n cellModel.sharedModel.setSource(code);\n }\n else if (cellModel.setSource && typeof cellModel.setSource === 'function') {\n cellModel.setSource(code);\n }\n else if (cellModel.value && typeof cellModel.value.setText === 'function') {\n cellModel.value.setText(code);\n }\n else if (cellModel.value && cellModel.value.text !== undefined) {\n cellModel.value.text = code;\n }\n else {\n throw new Error('Unable to set cell source - no compatible method found');\n }\n };\n // Helper: Reset button state\n const resetButtonState = (button, originalText) => {\n button.disabled = false;\n button.textContent = originalText || '์
์ ์ ์ฉ';\n };\n // Apply code to a specific notebook cell\n const applyCodeToNotebookCell = async (code, notebook, blockId, button, originalText) => {\n try {\n // Get widgets from notebook\n const cells = notebook.widgets || [];\n const modelCellsLength = notebook.model?.cells?.length || 0;\n console.log('[AgentPanel] applyCodeToNotebookCell called', {\n currentCellIndex: currentCellIndexRef.current,\n currentCellId: currentCellIdRef.current,\n blockId,\n widgetsLength: cells.length,\n modelCellsLength: modelCellsLength\n });\n // Try cell index first (most reliable)\n if (currentCellIndexRef.current !== null && currentCellIndexRef.current !== undefined) {\n console.log('[AgentPanel] Using cell index:', currentCellIndexRef.current);\n // Safety check: if widgets array is empty but model has cells, there might be a rendering issue\n if (cells.length === 0 && modelCellsLength > 0) {\n console.warn('[AgentPanel] Widgets not rendered yet, model has', modelCellsLength, 'cells');\n // Fall through to show selector dialog\n }\n else if (currentCellIndexRef.current >= 0 && currentCellIndexRef.current < cells.length) {\n const cell = cells[currentCellIndexRef.current];\n const cellModel = cell.model || cell;\n console.log('[AgentPanel] Found cell at index, applying code...');\n try {\n setCellSource(cellModel, code);\n console.log('[AgentPanel] Code applied successfully!');\n // Show tooltip on the target cell\n if (cell.node) {\n showCellTooltip(cell.node, 'โ ์ฝ๋๊ฐ ์ ์ฉ๋์์ต๋๋ค');\n }\n else {\n showNotification('์ฝ๋๊ฐ ์
์ ์ ์ฉ๋์์ต๋๋ค!', 'info');\n }\n resetButtonState(button, originalText);\n // Clear the cell index after successful application\n currentCellIndexRef.current = null;\n currentCellIdRef.current = null;\n return;\n }\n catch (updateError) {\n console.error('Failed to update cell content:', updateError);\n showNotification('์
๋ด์ฉ ์
๋ฐ์ดํธ ์คํจ: ' + updateError.message, 'error');\n resetButtonState(button, originalText);\n return;\n }\n }\n else {\n console.error('[AgentPanel] Cell index out of bounds:', {\n currentIndex: currentCellIndexRef.current,\n widgetsLength: cells.length,\n modelCellsLength: modelCellsLength\n });\n // Don't show error, fall through to selector dialog\n currentCellIndexRef.current = null;\n currentCellIdRef.current = null;\n }\n }\n // Fallback: show selector dialog\n console.log('[AgentPanel] Showing cell selector dialog');\n showCellSelectorDialog(code, button, originalText);\n }\n catch (error) {\n console.error('Failed to apply code:', error);\n showNotification('์ฝ๋ ์ ์ฉ์ ์คํจํ์ต๋๋ค.', 'error');\n resetButtonState(button, originalText);\n }\n };\n // Show cell selector dialog (similar to chrome_agent)\n const showCellSelectorDialog = (code, button, originalText) => {\n try {\n const app = window.jupyterapp;\n if (!app) {\n showNotification('JupyterLab์ ์ฐพ์ ์ ์์ต๋๋ค.', 'error');\n button.disabled = false;\n button.textContent = originalText || '์
์ ์ ์ฉ';\n return;\n }\n // Find current notebook from shell\n const shell = app.shell;\n const currentWidget = shell.currentWidget;\n if (!currentWidget || !('content' in currentWidget)) {\n showNotification('ํ์ฑ ๋
ธํธ๋ถ์ ์ฐพ์ ์ ์์ต๋๋ค.', 'warning');\n button.disabled = false;\n button.textContent = originalText || '์
์ ์ ์ฉ';\n return;\n }\n const notebook = currentWidget.content;\n if (!notebook || !('model' in notebook) || !notebook.model || !('cells' in notebook.model)) {\n showNotification('ํ์ฑ ๋
ธํธ๋ถ์ ์ฐพ์ ์ ์์ต๋๋ค.', 'warning');\n button.disabled = false;\n button.textContent = originalText || '์
์ ์ ์ฉ';\n return;\n }\n const cells = notebook.widgets || [];\n const codeCells = [];\n // Collect code cells\n cells.forEach((cell, index) => {\n const cellModel = cell.model || cell;\n if (cellModel.type === 'code') {\n const cellId = cellModel.metadata?.get?.('jupyterAgentCellId') ||\n cellModel.id ||\n `cell-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n // Ensure cell has ID\n try {\n if (!cellModel.metadata?.get?.('jupyterAgentCellId')) {\n if (cellModel.metadata?.set) {\n cellModel.metadata.set('jupyterAgentCellId', cellId);\n }\n }\n }\n catch (e) {\n // Metadata might not be accessible, continue anyway\n }\n const content = (cellModel.sharedModel?.getSource?.() ||\n cellModel.value?.text ||\n '').toString();\n const preview = content.substring(0, 100).replace(/\\n/g, ' ');\n codeCells.push({\n cell,\n index,\n id: cellId,\n preview\n });\n }\n });\n if (codeCells.length === 0) {\n showNotification('์ฝ๋ ์
์ ์ฐพ์ ์ ์์ต๋๋ค.', 'warning');\n button.disabled = false;\n button.textContent = originalText || '์
์ ์ ์ฉ';\n return;\n }\n // Remove existing dialog\n const existingDialog = document.querySelector('.jp-agent-cell-selector-dialog');\n if (existingDialog) {\n existingDialog.remove();\n }\n // Create dialog overlay\n const dialogOverlay = document.createElement('div');\n dialogOverlay.className = 'jp-agent-cell-selector-dialog';\n dialogOverlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.3);\n z-index: 10000;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n // Create dialog container\n const dialogContainer = document.createElement('div');\n dialogContainer.style.cssText = `\n background: #fafafa;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n padding: 24px;\n max-width: 500px;\n width: 90%;\n max-height: 80vh;\n overflow-y: auto;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n `;\n // Create cell list HTML\n const cellListHTML = codeCells.map(({ index, id, preview }) => {\n return `\n <div class=\"jp-agent-cell-selector-item\" data-cell-id=\"${id}\" style=\"\n padding: 12px;\n margin-bottom: 8px;\n background: white;\n border: 2px solid #e0e0e0;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.2s ease;\n \">\n <div style=\"display: flex; align-items: center; gap: 8px; margin-bottom: 4px;\">\n <span style=\"\n background: #667eea;\n color: white;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n \">์
${index + 1}</span>\n </div>\n <div style=\"font-size: 12px; color: #757575; font-family: 'Menlo', monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\">\n ${escapeHtml(preview)}${preview.length >= 100 ? '...' : ''}\n </div>\n </div>\n `;\n }).join('');\n // Dialog content\n dialogContainer.innerHTML = `\n <div style=\"margin-bottom: 20px;\">\n <h3 style=\"margin: 0 0 8px 0; color: #424242; font-size: 16px; font-weight: 500;\">\n ์ฝ๋๋ฅผ ์ ์ฉํ ์
์ ํ\n </h3>\n <p style=\"margin: 0; color: #757575; font-size: 13px;\">\n AI๊ฐ ์์ฑํ ์ฝ๋๋ฅผ ์ ์ฉํ ์
์ ์ ํํ์ธ์\n </p>\n </div>\n <div class=\"jp-agent-cell-list\" style=\"margin-bottom: 20px;\">\n ${cellListHTML}\n </div>\n <div style=\"display: flex; gap: 12px; justify-content: flex-end;\">\n <button class=\"jp-agent-cell-selector-cancel-btn\" style=\"\n background: transparent;\n color: #616161;\n border: 1px solid #d1d5db;\n border-radius: 3px;\n padding: 8px 16px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n \">์ทจ์</button>\n </div>\n `;\n dialogOverlay.appendChild(dialogContainer);\n document.body.appendChild(dialogOverlay);\n // Cell item click handlers\n const cellItems = dialogContainer.querySelectorAll('.jp-agent-cell-selector-item');\n cellItems.forEach(item => {\n item.addEventListener('click', () => {\n const cellId = item.getAttribute('data-cell-id');\n if (!cellId)\n return;\n // Find the cell\n const cellInfo = codeCells.find(c => c.id === cellId);\n if (!cellInfo)\n return;\n const cellModel = cellInfo.cell.model || cellInfo.cell;\n // Apply code to cell\n try {\n setCellSource(cellModel, code);\n dialogOverlay.remove();\n // Show tooltip on the target cell\n if (cellInfo.cell.node) {\n showCellTooltip(cellInfo.cell.node, 'โ ์ฝ๋๊ฐ ์ ์ฉ๋์์ต๋๋ค');\n }\n else {\n showNotification('์ฝ๋๊ฐ ์
์ ์ ์ฉ๋์์ต๋๋ค!', 'info');\n }\n resetButtonState(button, originalText);\n }\n catch (error) {\n console.error('Failed to apply code to cell:', error);\n showNotification('์ฝ๋ ์ ์ฉ์ ์คํจํ์ต๋๋ค.', 'error');\n resetButtonState(button, originalText);\n }\n });\n // Hover effects\n item.addEventListener('mouseenter', () => {\n item.style.borderColor = '#667eea';\n item.style.background = '#f8f9ff';\n });\n item.addEventListener('mouseleave', () => {\n item.style.borderColor = '#e0e0e0';\n item.style.background = 'white';\n });\n });\n // Cancel button\n const cancelBtn = dialogContainer.querySelector('.jp-agent-cell-selector-cancel-btn');\n if (cancelBtn) {\n cancelBtn.addEventListener('click', () => {\n dialogOverlay.remove();\n button.disabled = false;\n button.textContent = originalText || '์
์ ์ ์ฉ';\n });\n cancelBtn.addEventListener('mouseenter', () => {\n cancelBtn.style.background = '#f5f5f5';\n cancelBtn.style.borderColor = '#9ca3af';\n });\n cancelBtn.addEventListener('mouseleave', () => {\n cancelBtn.style.background = 'transparent';\n cancelBtn.style.borderColor = '#d1d5db';\n });\n }\n // Close on overlay click\n dialogOverlay.addEventListener('click', (e) => {\n if (e.target === dialogOverlay) {\n dialogOverlay.remove();\n button.disabled = false;\n button.textContent = originalText || '์
์ ์ ์ฉ';\n }\n });\n // ESC key to close\n const handleEsc = (e) => {\n if (e.key === 'Escape') {\n dialogOverlay.remove();\n document.removeEventListener('keydown', handleEsc);\n button.disabled = false;\n button.textContent = originalText || '์
์ ์ ์ฉ';\n }\n };\n document.addEventListener('keydown', handleEsc);\n }\n catch (error) {\n console.error('Failed to show cell selector:', error);\n showNotification('์
์ ํ ๋ค์ด์ผ๋ก๊ทธ ํ์์ ์คํจํ์ต๋๋ค.', 'error');\n button.disabled = false;\n button.textContent = originalText || '์
์ ์ ์ฉ';\n }\n };\n // Helper function to escape HTML\n const escapeHtml = (text) => {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n };\n const handleSendMessage = async () => {\n // Check if there's an LLM prompt stored (from cell action)\n const textarea = messagesEndRef.current?.parentElement?.querySelector('.jp-agent-input');\n const llmPrompt = pendingLlmPromptRef.current || textarea?.getAttribute('data-llm-prompt');\n // Allow execution if we have an LLM prompt even if input is empty (for auto-execution)\n if ((!input.trim() && !llmPrompt) || isLoading || isStreaming || isAgentRunning)\n return;\n const currentInput = input.trim();\n // Agent ๋ชจ๋์ด๋ฉด Agent ์คํ\n if (inputMode === 'agent') {\n // Use app.shell.currentWidget for reliable active tab detection\n const app = window.jupyterapp;\n let notebook = null;\n if (app?.shell?.currentWidget) {\n const currentWidget = app.shell.currentWidget;\n if ('content' in currentWidget && currentWidget.content?.model) {\n notebook = currentWidget;\n }\n }\n if (!notebook) {\n notebook = notebookTracker?.currentWidget;\n }\n // ๋
ธํธ๋ถ์ด ์๋ ๊ฒฝ์ฐ\n if (!notebook) {\n // Python ์๋ฌ๊ฐ ๊ฐ์ง๋๋ฉด ํ์ผ ์์ ๋ชจ๋๋ก ์ ํ\n if (detectPythonError(currentInput)) {\n console.log('[AgentPanel] Agent mode: No notebook, but Python error detected - switching to file fix mode');\n // User ๋ฉ์์ง ์ถ๊ฐ\n const userMessage = {\n id: Date.now().toString(),\n role: 'user',\n content: currentInput,\n timestamp: Date.now(),\n };\n setMessages(prev => [...prev, userMessage]);\n setInput('');\n // Python ์๋ฌ ์์ ์ฒ๋ฆฌ\n await handlePythonErrorFix(currentInput);\n return;\n }\n // ํ์ผ ์์ ๊ด๋ จ ์์ฐ์ด ์์ฒญ ๊ฐ์ง (์๋ฌ, ๊ณ ์ณ, ์์ , fix ๋ฑ)\n const fileFixRequestPatterns = [\n /์๋ฌ.*ํด๊ฒฐ/i,\n /์๋ฌ.*๊ณ ์ณ/i,\n /์๋ฌ.*์์ /i,\n /์ค๋ฅ.*ํด๊ฒฐ/i,\n /์ค๋ฅ.*๊ณ ์ณ/i,\n /์ค๋ฅ.*์์ /i,\n /fix.*error/i,\n /\\.py.*์๋ฌ/i,\n /\\.py.*์ค๋ฅ/i,\n /์ฝ์.*์๋ฌ/i,\n /console.*error/i,\n /ํ์ผ.*์๋ฌ/i,\n /ํ์ผ.*์ค๋ฅ/i,\n ];\n const isFileFixRequest = fileFixRequestPatterns.some(pattern => pattern.test(currentInput));\n if (isFileFixRequest) {\n console.log('[AgentPanel] Agent mode: No notebook, file fix request detected - prompting for error details');\n // User ๋ฉ์์ง ์ถ๊ฐ\n const userMessage = {\n id: Date.now().toString(),\n role: 'user',\n content: currentInput,\n timestamp: Date.now(),\n };\n setMessages(prev => [...prev, userMessage]);\n setInput('');\n // ์๋ฌ ๋ฉ์์ง ์์ฒญ ์๋ด\n const guideMessage = {\n id: Date.now().toString() + '-guide',\n role: 'assistant',\n content: `ํ์ผ ์๋ฌ ์์ ์ ๋์๋๋ฆฌ๊ฒ ์ต๋๋ค! ๐ง\n\n**์๋ฌ ๋ฉ์์ง๋ฅผ ๋ณต์ฌํด์ ๋ถ์ฌ๋ฃ์ด ์ฃผ์ธ์.**\n\nConsole์์ ๋ฐ์ํ ์๋ฌ ์ ์ฒด๋ฅผ ๋ณต์ฌํด์ฃผ์๋ฉด:\n1. ์๋ฌ๊ฐ ๋ฐ์ํ ํ์ผ์ ์๋์ผ๋ก ์ฐพ์์ ์ฝ๊ณ \n2. ๊ด๋ จ๋ import ํ์ผ๋ค๋ ํจ๊ป ๋ถ์ํ์ฌ\n3. ์์ ๋ ์ฝ๋๋ฅผ ์ ์ํด ๋๋ฆฝ๋๋ค.\n\n์์:\n\\`\\`\\`\n$ python b.py\nTraceback (most recent call last):\n File \"a.py\", line 3\n def foo(\n ^\nSyntaxError: '(' was never closed\n\\`\\`\\``,\n timestamp: Date.now(),\n };\n setMessages(prev => [...prev, guideMessage]);\n return;\n }\n // ์ผ๋ฐ์ ์ธ ์์ฒญ์ Chat ๋ชจ๋๋ก fallback\n console.log('[AgentPanel] Agent mode: No notebook - falling back to chat mode');\n }\n else {\n // ๋
ธํธ๋ถ์ด ์์ผ๋ฉด Agent ์คํ\n // User ๋ฉ์์ง ์ถ๊ฐ\n const userMessage = {\n id: Date.now().toString(),\n role: 'user',\n content: `@agent ${currentInput}`,\n timestamp: Date.now(),\n };\n setMessages(prev => [...prev, userMessage]);\n setInput('');\n // Agent ์คํ\n await handleAgentExecution(currentInput);\n return;\n }\n }\n // Chat ๋ชจ๋์์๋ ๋ช
๋ น์ด๋ก Agent ์คํ ๊ฐ๋ฅ\n if (isAgentCommand(currentInput)) {\n const agentRequest = extractAgentRequest(currentInput);\n if (agentRequest) {\n // User ๋ฉ์์ง ์ถ๊ฐ\n const userMessage = {\n id: Date.now().toString(),\n role: 'user',\n content: currentInput,\n timestamp: Date.now(),\n };\n setMessages(prev => [...prev, userMessage]);\n setInput('');\n // Agent ์คํ\n await handleAgentExecution(agentRequest);\n return;\n }\n }\n // Python ์๋ฌ ๊ฐ์ง ๋ฐ ํ์ผ ์์ ๋ชจ๋ (Chat ๋ชจ๋์์๋ง)\n if (inputMode === 'chat' && detectPythonError(currentInput)) {\n console.log('[AgentPanel] Python error detected in message');\n // User ๋ฉ์์ง ์ถ๊ฐ\n const userMessage = {\n id: Date.now().toString(),\n role: 'user',\n content: currentInput,\n timestamp: Date.now(),\n };\n setMessages(prev => [...prev, userMessage]);\n setInput('');\n // Python ์๋ฌ ์์ ์ฒ๋ฆฌ\n await handlePythonErrorFix(currentInput);\n return;\n }\n // Check if API key is configured before sending\n let currentConfig = llmConfig;\n if (!currentConfig) {\n // Config not loaded yet, try to load from localStorage\n currentConfig = getLLMConfig() || getDefaultLLMConfig();\n setLlmConfig(currentConfig);\n }\n // Check API key using ApiKeyManager\n const hasApiKey = hasValidApiKey(currentConfig);\n if (!hasApiKey) {\n // Show error message and open settings\n const providerName = llmConfig?.provider || 'LLM';\n const errorMessage = {\n id: Date.now().toString(),\n role: 'assistant',\n content: `API Key๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.\\n\\n${providerName === 'gemini' ? 'Gemini' : providerName === 'openai' ? 'OpenAI' : 'vLLM'} API Key๋ฅผ ๋จผ์ ์ค์ ํด์ฃผ์ธ์.\\n\\n์ค์ ๋ฒํผ์ ํด๋ฆญํ์ฌ API Key๋ฅผ ์
๋ ฅํ์ธ์.`,\n timestamp: Date.now()\n };\n setMessages(prev => [...prev, errorMessage]);\n setShowSettings(true);\n return;\n }\n // Use the display prompt (input) for the user message, or use a fallback if input is empty\n const displayContent = currentInput || (llmPrompt ? '์
๋ถ์ ์์ฒญ' : '');\n const userMessage = {\n id: Date.now().toString(),\n role: 'user',\n content: displayContent,\n timestamp: Date.now()\n };\n setMessages(prev => [...prev, userMessage]);\n // Only clear input if it was manually entered, keep it for auto-execution display\n if (currentInput) {\n setInput('');\n }\n setIsLoading(true);\n setIsStreaming(true);\n // Clear the data attribute and ref after using it\n if (textarea && llmPrompt) {\n textarea.removeAttribute('data-llm-prompt');\n pendingLlmPromptRef.current = null;\n }\n // Create assistant message ID for streaming updates\n const assistantMessageId = Date.now().toString() + '-assistant';\n let streamedContent = '';\n setStreamingMessageId(assistantMessageId);\n // Add empty assistant message that will be updated during streaming\n const initialAssistantMessage = {\n id: assistantMessageId,\n role: 'assistant',\n content: '',\n timestamp: Date.now()\n };\n setMessages(prev => [...prev, initialAssistantMessage]);\n try {\n // Use LLM prompt if available, otherwise use the display content\n const messageToSend = llmPrompt || displayContent;\n await apiService.sendMessageStream({\n message: messageToSend,\n conversationId: conversationId || undefined,\n llmConfig: currentConfig // Include API keys with request\n }, \n // onChunk callback - update message content incrementally\n (chunk) => {\n streamedContent += chunk;\n setMessages(prev => prev.map(msg => msg.id === assistantMessageId && isChatMessage(msg)\n ? { ...msg, content: streamedContent }\n : msg));\n }, \n // onMetadata callback - update conversationId and metadata\n (metadata) => {\n if (metadata.conversationId && !conversationId) {\n setConversationId(metadata.conversationId);\n }\n if (metadata.provider || metadata.model) {\n setMessages(prev => prev.map(msg => msg.id === assistantMessageId && isChatMessage(msg)\n ? {\n ...msg,\n metadata: {\n ...msg.metadata,\n provider: metadata.provider,\n model: metadata.model\n }\n }\n : msg));\n }\n });\n }\n catch (error) {\n // Update the assistant message with error\n setMessages(prev => prev.map(msg => msg.id === assistantMessageId && isChatMessage(msg)\n ? {\n ...msg,\n content: streamedContent + `\\n\\nError: ${error instanceof Error ? error.message : 'Failed to send message'}`\n }\n : msg));\n }\n finally {\n setIsLoading(false);\n setIsStreaming(false);\n setStreamingMessageId(null);\n }\n };\n const handleKeyDown = (e) => {\n // Enter: ์ ์ก\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSendMessage();\n }\n // Shift+Tab: ๋ชจ๋ ์ ํ (chat โ agent)\n if (e.key === 'Tab' && e.shiftKey) {\n e.preventDefault();\n setInputMode(prev => prev === 'chat' ? 'agent' : 'chat');\n return;\n }\n // Cmd/Ctrl + . : ๋ชจ๋ ์ ํ (๋์ฒด ๋จ์ถํค)\n if (e.key === '.' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n setInputMode(prev => prev === 'chat' ? 'agent' : 'chat');\n }\n // Tab (without Shift): Agent ๋ชจ๋์ผ ๋ ๋๋กญ๋ค์ด ํ ๊ธ\n if (e.key === 'Tab' && !e.shiftKey && inputMode === 'agent') {\n e.preventDefault();\n setShowModeDropdown(prev => !prev);\n }\n };\n // ๋ชจ๋ ํ ๊ธ ํจ์\n const toggleMode = () => {\n setInputMode(prev => prev === 'chat' ? 'agent' : 'chat');\n setShowModeDropdown(false);\n };\n const clearChat = () => {\n setMessages([]);\n setConversationId('');\n };\n // Agent ์คํ ๋ฉ์์ง ๋ ๋๋ง\n const renderAgentExecutionMessage = (msg) => {\n const { status, plan, result, completedSteps, failedSteps, request } = msg;\n const isActive = ['planning', 'executing', 'tool_calling', 'self_healing', 'replanning', 'validating', 'reflecting'].includes(status.phase);\n const getStepStatus = (stepNumber) => {\n if (failedSteps.includes(stepNumber))\n return 'failed';\n if (completedSteps.includes(stepNumber))\n return 'completed';\n if (status.currentStep === stepNumber)\n return 'current';\n return 'pending';\n };\n const progressPercent = plan ? (completedSteps.length / plan.totalSteps) * 100 : 0;\n return (React.createElement(\"div\", { className: \"jp-agent-execution-message\" },\n React.createElement(\"div\", { className: \"jp-agent-execution-header\" },\n React.createElement(\"div\", { className: \"jp-agent-execution-badge\" },\n React.createElement(\"svg\", { viewBox: \"0 0 16 16\", fill: \"currentColor\", width: \"12\", height: \"12\" },\n React.createElement(\"path\", { d: \"M8 0a8 8 0 100 16A8 8 0 008 0zm0 14.5a6.5 6.5 0 110-13 6.5 6.5 0 010 13z\" }),\n React.createElement(\"path\", { d: \"M8 3a.75.75 0 01.75.75v3.5h2.5a.75.75 0 010 1.5h-3.25a.75.75 0 01-.75-.75v-4.25A.75.75 0 018 3z\" })),\n \"Agent\"),\n React.createElement(\"span\", { className: \"jp-agent-execution-request\" }, request)),\n React.createElement(\"div\", { className: `jp-agent-execution-status jp-agent-execution-status--${status.phase}` },\n isActive && React.createElement(\"div\", { className: \"jp-agent-execution-spinner\" }),\n status.phase === 'completed' && (React.createElement(\"svg\", { viewBox: \"0 0 16 16\", fill: \"currentColor\", className: \"jp-agent-execution-icon--success\" },\n React.createElement(\"path\", { d: \"M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z\" }))),\n status.phase === 'failed' && (React.createElement(\"svg\", { viewBox: \"0 0 16 16\", fill: \"currentColor\", className: \"jp-agent-execution-icon--error\" },\n React.createElement(\"path\", { d: \"M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z\" }))),\n React.createElement(\"span\", { className: \"jp-agent-execution-status-text\" }, status.phase === 'completed'\n ? '์๋ฃ'\n : status.phase === 'failed'\n ? '์คํจ'\n : (status.message || status.phase))),\n plan && (React.createElement(\"div\", { className: \"jp-agent-execution-plan\" },\n React.createElement(\"div\", { className: \"jp-agent-execution-plan-header\" },\n React.createElement(\"span\", null, \"\\uC2E4\\uD589 \\uACC4\\uD68D\"),\n React.createElement(\"span\", { className: \"jp-agent-execution-plan-progress\" },\n completedSteps.length,\n \" / \",\n plan.totalSteps)),\n React.createElement(\"div\", { className: \"jp-agent-execution-progress-bar\" },\n React.createElement(\"div\", { className: \"jp-agent-execution-progress-fill\", style: { width: `${progressPercent}%` } })),\n React.createElement(\"div\", { className: \"jp-agent-execution-steps\" }, plan.steps.map((step) => {\n const stepStatus = getStepStatus(step.stepNumber);\n return (React.createElement(\"div\", { key: step.stepNumber, className: `jp-agent-execution-step jp-agent-execution-step--${stepStatus}`, ref: (el) => {\n // ํ์ฌ ์งํ ์ค์ธ ๋จ๊ณ๋ก ์๋ ์คํฌ๋กค\n if (stepStatus === 'current' && el) {\n el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n }\n } },\n React.createElement(\"div\", { className: \"jp-agent-execution-step-indicator\" },\n stepStatus === 'completed' && (React.createElement(\"svg\", { viewBox: \"0 0 16 16\", fill: \"currentColor\" },\n React.createElement(\"path\", { d: \"M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z\" }))),\n stepStatus === 'failed' && (React.createElement(\"svg\", { viewBox: \"0 0 16 16\", fill: \"currentColor\" },\n React.createElement(\"path\", { d: \"M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z\" }))),\n stepStatus === 'current' && React.createElement(\"div\", { className: \"jp-agent-execution-step-spinner\" }),\n stepStatus === 'pending' && React.createElement(\"span\", null, step.stepNumber)),\n React.createElement(\"div\", { className: \"jp-agent-execution-step-content\" },\n React.createElement(\"span\", { className: `jp-agent-execution-step-desc ${stepStatus === 'completed' ? 'jp-agent-execution-step-desc--done' : ''}` }, step.description),\n React.createElement(\"div\", { className: \"jp-agent-execution-step-tools\" }, step.toolCalls\n .filter(tc => !['jupyter_cell', 'final_answer', 'markdown'].includes(tc.tool))\n .map((tc, i) => (React.createElement(\"span\", { key: i, className: \"jp-agent-execution-tool-tag\" }, tc.tool)))))));\n })))),\n result && (React.createElement(\"div\", { className: `jp-agent-execution-result jp-agent-execution-result--${result.success ? 'success' : 'error'}` },\n result.finalAnswer && (React.createElement(\"div\", { className: \"jp-agent-execution-result-message jp-RenderedHTMLCommon\", dangerouslySetInnerHTML: { __html: formatMarkdownToHtml(result.finalAnswer) } })),\n result.error && (React.createElement(\"p\", { className: \"jp-agent-execution-result-error\" }, result.error)),\n React.createElement(\"div\", { className: \"jp-agent-execution-result-stats\" },\n React.createElement(\"span\", null,\n result.createdCells.length,\n \"\\uAC1C \\uC140 \\uC0DD\\uC131\"),\n React.createElement(\"span\", null,\n result.modifiedCells.length,\n \"\\uAC1C \\uC140 \\uC218\\uC815\"),\n result.executionTime && (React.createElement(\"span\", null,\n (result.executionTime / 1000).toFixed(1),\n \"\\uCD08\")))))));\n };\n // ๋ฉ์์ง๊ฐ Chat ๋ฉ์์ง์ธ์ง ํ์ธ\n const isChatMessage = (msg) => {\n return !('type' in msg) || msg.type !== 'agent_execution';\n };\n return (React.createElement(\"div\", { className: \"jp-agent-panel\" },\n showSettings && (React.createElement(SettingsPanel, { onClose: () => setShowSettings(false), onSave: handleSaveConfig, currentConfig: llmConfig || undefined })),\n React.createElement(\"div\", { className: \"jp-agent-header\" },\n React.createElement(\"div\", { className: \"jp-agent-header-logo\", dangerouslySetInnerHTML: { __html: headerLogoSvg } }),\n React.createElement(\"div\", { className: \"jp-agent-header-buttons\" },\n React.createElement(\"button\", { className: \"jp-agent-clear-button\", onClick: clearChat, title: \"\\uB300\\uD654 \\uCD08\\uAE30\\uD654\" },\n React.createElement(\"svg\", { width: \"16\", height: \"16\", viewBox: \"0 0 24 24\", fill: \"none\", stroke: \"currentColor\", strokeWidth: \"2\", strokeLinecap: \"round\", strokeLinejoin: \"round\" },\n React.createElement(\"polyline\", { points: \"3 6 5 6 21 6\" }),\n React.createElement(\"path\", { d: \"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" }),\n React.createElement(\"line\", { x1: \"10\", y1: \"11\", x2: \"10\", y2: \"17\" }),\n React.createElement(\"line\", { x1: \"14\", y1: \"11\", x2: \"14\", y2: \"17\" }))),\n React.createElement(\"button\", { className: \"jp-agent-settings-button-icon\", onClick: () => setShowSettings(true), title: \"\\uC124\\uC815\" },\n React.createElement(\"svg\", { width: \"16\", height: \"16\", viewBox: \"0 0 24 24\", fill: \"none\", stroke: \"currentColor\", strokeWidth: \"2\", strokeLinecap: \"round\", strokeLinejoin: \"round\" },\n React.createElement(\"line\", { x1: \"4\", y1: \"21\", x2: \"4\", y2: \"14\" }),\n React.createElement(\"line\", { x1: \"4\", y1: \"10\", x2: \"4\", y2: \"3\" }),\n React.createElement(\"line\", { x1: \"12\", y1: \"21\", x2: \"12\", y2: \"12\" }),\n React.createElement(\"line\", { x1: \"12\", y1: \"8\", x2: \"12\", y2: \"3\" }),\n React.createElement(\"line\", { x1: \"20\", y1: \"21\", x2: \"20\", y2: \"16\" }),\n React.createElement(\"line\", { x1: \"20\", y1: \"12\", x2: \"20\", y2: \"3\" }),\n React.createElement(\"line\", { x1: \"1\", y1: \"14\", x2: \"7\", y2: \"14\" }),\n React.createElement(\"line\", { x1: \"9\", y1: \"8\", x2: \"15\", y2: \"8\" }),\n React.createElement(\"line\", { x1: \"17\", y1: \"16\", x2: \"23\", y2: \"16\" }))))),\n React.createElement(\"div\", { className: \"jp-agent-messages\" },\n messages.length === 0 ? (React.createElement(\"div\", { className: \"jp-agent-empty-state\" },\n React.createElement(\"p\", null, \"\\uC548\\uB155\\uD558\\uC138\\uC694! HDSP Agent\\uC785\\uB2C8\\uB2E4.\"),\n React.createElement(\"p\", { className: \"jp-agent-empty-hint\" }, inputMode === 'agent'\n ? '๋
ธํธ๋ถ ์์
์ ์์ฐ์ด๋ก ์์ฒญํ์ธ์. ์: \"๋ฐ์ดํฐ ์๊ฐํ ํด์ค\"'\n : '๋ฉ์์ง๋ฅผ ์
๋ ฅํ๊ฑฐ๋ ์๋ ๋ฒํผ์ผ๋ก Agent ๋ชจ๋๋ฅผ ์ ํํ์ธ์.'))) : (messages.map(msg => {\n if (isChatMessage(msg)) {\n // ์ผ๋ฐ Chat ๋ฉ์์ง\n return (React.createElement(\"div\", { key: msg.id, className: `jp-agent-message jp-agent-message-${msg.role}` },\n React.createElement(\"div\", { className: \"jp-agent-message-header\" },\n React.createElement(\"span\", { className: \"jp-agent-message-role\" }, msg.role === 'user' ? '์ฌ์ฉ์' : 'Agent'),\n React.createElement(\"span\", { className: \"jp-agent-message-time\" }, new Date(msg.timestamp).toLocaleTimeString())),\n React.createElement(\"div\", { className: `jp-agent-message-content${streamingMessageId === msg.id ? ' streaming' : ''}` }, msg.role === 'assistant' ? (\n // Assistant(AI) ๋ฉ์์ง: ๋งํฌ๋ค์ด HTML ๋ ๋๋ง + Jupyter ์คํ์ผ ์ ์ฉ\n React.createElement(\"div\", { className: \"jp-RenderedHTMLCommon\", style: { padding: '0 5px' }, dangerouslySetInnerHTML: { __html: formatMarkdownToHtml(msg.content) } })) : (\n // User(์ฌ์ฉ์) ๋ฉ์์ง: ํ
์คํธ ๊ทธ๋๋ก ์ค๋ฐ๊ฟ๋ง ์ฒ๋ฆฌ\n React.createElement(\"div\", { style: { whiteSpace: 'pre-wrap' } }, msg.content)))));\n }\n else {\n // Agent ์คํ ๋ฉ์์ง\n return (React.createElement(\"div\", { key: msg.id, className: \"jp-agent-message jp-agent-message-agent-execution\" }, renderAgentExecutionMessage(msg)));\n }\n })),\n isLoading && !isStreaming && !isAgentRunning && (React.createElement(\"div\", { className: \"jp-agent-message jp-agent-message-assistant\" },\n React.createElement(\"div\", { className: \"jp-agent-message-header\" },\n React.createElement(\"span\", { className: \"jp-agent-message-role\" }, \"Agent\")),\n React.createElement(\"div\", { className: \"jp-agent-message-content jp-agent-loading\" },\n React.createElement(\"span\", { className: \"jp-agent-loading-dot\" }, \".\"),\n React.createElement(\"span\", { className: \"jp-agent-loading-dot\" }, \".\"),\n React.createElement(\"span\", { className: \"jp-agent-loading-dot\" }, \".\")))),\n showConsoleErrorNotification && lastConsoleError && (React.createElement(\"div\", { className: \"jp-agent-console-error-notification\" },\n React.createElement(\"div\", { className: \"jp-agent-console-error-header\" },\n React.createElement(\"svg\", { viewBox: \"0 0 16 16\", fill: \"currentColor\", width: \"16\", height: \"16\" },\n React.createElement(\"path\", { d: \"M8.982 1.566a1.13 1.13 0 00-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 01-1.1 0L7.1 5.995A.905.905 0 018 5zm.002 6a1 1 0 110 2 1 1 0 010-2z\" })),\n React.createElement(\"span\", null, \"Console\\uC5D0\\uC11C Python \\uC5D0\\uB7EC\\uAC00 \\uAC10\\uC9C0\\uB418\\uC5C8\\uC2B5\\uB2C8\\uB2E4\")),\n React.createElement(\"div\", { className: \"jp-agent-console-error-preview\" },\n lastConsoleError.slice(0, 200),\n lastConsoleError.length > 200 ? '...' : ''),\n React.createElement(\"div\", { className: \"jp-agent-console-error-actions\" },\n React.createElement(\"button\", { className: \"jp-agent-console-error-fix-btn\", onClick: () => {\n // ์๋ฌ๋ฅผ ์๋์ผ๋ก ์
๋ ฅ์ฐฝ์ ๋ฃ๊ณ ํ์ผ ์์ ์์ฒญ\n setInput(`๋ค์ ์๋ฌ๋ฅผ ๋ถ์ํ๊ณ ์์ ํด์ฃผ์ธ์:\\n\\n${lastConsoleError}`);\n setShowConsoleErrorNotification(false);\n // ์
๋ ฅ์ฐฝ์ ํฌ์ปค์ค\n const textarea = document.querySelector('.jp-agent-input');\n if (textarea)\n textarea.focus();\n } }, \"\\uC5D0\\uB7EC \\uBD84\\uC11D \\uC694\\uCCAD\"),\n React.createElement(\"button\", { className: \"jp-agent-console-error-dismiss-btn\", onClick: () => setShowConsoleErrorNotification(false) }, \"\\uB2EB\\uAE30\")))),\n pendingFileFixes.length > 0 && (React.createElement(\"div\", { className: \"jp-agent-file-fixes\" },\n React.createElement(\"div\", { className: \"jp-agent-file-fixes-header\" },\n React.createElement(\"svg\", { viewBox: \"0 0 16 16\", fill: \"currentColor\", width: \"14\", height: \"14\" },\n React.createElement(\"path\", { d: \"M14 1H2a1 1 0 00-1 1v12a1 1 0 001 1h12a1 1 0 001-1V2a1 1 0 00-1-1zM2 0a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V2a2 2 0 00-2-2H2z\" }),\n React.createElement(\"path\", { d: \"M9.5 5a.5.5 0 00-1 0v3.793L6.854 7.146a.5.5 0 10-.708.708l2.5 2.5a.5.5 0 00.708 0l2.5-2.5a.5.5 0 00-.708-.708L9.5 8.793V5z\" })),\n React.createElement(\"span\", null,\n \"\\uC218\\uC815\\uB41C \\uD30C\\uC77C (\",\n pendingFileFixes.length,\n \"\\uAC1C)\")),\n React.createElement(\"div\", { className: \"jp-agent-file-fixes-list\" }, pendingFileFixes.map((fix, index) => (React.createElement(\"div\", { key: index, className: \"jp-agent-file-fix-item\" },\n React.createElement(\"div\", { className: \"jp-agent-file-fix-info\" },\n React.createElement(\"svg\", { viewBox: \"0 0 16 16\", fill: \"currentColor\", width: \"12\", height: \"12\" },\n React.createElement(\"path\", { d: \"M4 0a2 2 0 00-2 2v12a2 2 0 002 2h8a2 2 0 002-2V4.5L9.5 0H4zm5.5 1.5v2a1 1 0 001 1h2l-3-3zM4.5 8a.5.5 0 010 1h7a.5.5 0 010-1h-7zm0 2a.5.5 0 010 1h7a.5.5 0 010-1h-7zm0 2a.5.5 0 010 1h4a.5.5 0 010-1h-4z\" })),\n React.createElement(\"span\", { className: \"jp-agent-file-fix-path\" }, fix.path)),\n React.createElement(\"button\", { className: \"jp-agent-file-fix-apply\", onClick: () => applyFileFix(fix), title: `${fix.path} ํ์ผ์ ์์ ์ ์ฉ` }, \"\\uC801\\uC6A9\\uD558\\uAE30\"))))),\n React.createElement(\"button\", { className: \"jp-agent-file-fixes-dismiss\", onClick: () => setPendingFileFixes([]), title: \"\\uC218\\uC815 \\uC81C\\uC548 \\uB2EB\\uAE30\" }, \"\\uB2EB\\uAE30\"))),\n React.createElement(\"div\", { ref: messagesEndRef })),\n React.createElement(\"div\", { className: \"jp-agent-input-container\" },\n React.createElement(\"div\", { className: \"jp-agent-input-wrapper\" },\n React.createElement(\"textarea\", { className: `jp-agent-input ${inputMode === 'agent' ? 'jp-agent-input--agent-mode' : ''}`, value: input, onChange: (e) => setInput(e.target.value), onKeyDown: handleKeyDown, placeholder: inputMode === 'agent'\n ? '๋
ธํธ๋ถ ์์
์ ์
๋ ฅํ์ธ์... (์: ๋ฐ์ดํฐ ์๊ฐํ ํด์ค)'\n : '๋ฉ์์ง๋ฅผ ์
๋ ฅํ์ธ์...', rows: 3, disabled: isLoading || isAgentRunning }),\n React.createElement(\"button\", { className: \"jp-agent-send-button\", onClick: handleSendMessage, disabled: !input.trim() || isLoading || isStreaming || isAgentRunning, title: \"\\uC804\\uC1A1 (Enter)\" }, isAgentRunning ? '์คํ ์ค...' : '์ ์ก')),\n React.createElement(\"div\", { className: \"jp-agent-mode-bar\" },\n React.createElement(\"div\", { className: \"jp-agent-mode-toggle-container\" },\n React.createElement(\"button\", { className: `jp-agent-mode-toggle ${inputMode === 'agent' ? 'jp-agent-mode-toggle--active' : ''}`, onClick: toggleMode, title: `${inputMode === 'agent' ? 'Agent' : 'Chat'} ๋ชจ๋ (โงTab)` },\n React.createElement(\"svg\", { className: \"jp-agent-mode-icon\", viewBox: \"0 0 16 16\", fill: \"currentColor\", width: \"14\", height: \"14\" }, inputMode === 'agent' ? (\n // ๋ฌดํ๋ ์์ด์ฝ (Agent ๋ชจ๋)\n React.createElement(\"path\", { d: \"M4.5 8c0-1.38 1.12-2.5 2.5-2.5.9 0 1.68.48 2.12 1.2L8 8l1.12 1.3c-.44.72-1.22 1.2-2.12 1.2-1.38 0-2.5-1.12-2.5-2.5zm6.88 1.3c.44-.72 1.22-1.2 2.12-1.2 1.38 0 2.5 1.12 2.5 2.5s-1.12 2.5-2.5 2.5c-.9 0-1.68-.48-2.12-1.2L12.5 10.6c.3.24.68.4 1.1.4.83 0 1.5-.67 1.5-1.5S14.43 8 13.6 8c-.42 0-.8.16-1.1.4l-1.12 1.3zM7 9.5c-.42 0-.8-.16-1.1-.4L4.78 7.8c-.44.72-1.22 1.2-2.12 1.2C1.28 9 .17 7.88.17 6.5S1.29 4 2.67 4c.9 0 1.68.48 2.12 1.2L5.9 6.5c-.3-.24-.68-.4-1.1-.4C3.97 6.1 3.3 6.77 3.3 7.6s.67 1.5 1.5 1.5c.42 0 .8-.16 1.1-.4l1.12-1.3L8 8l-1 1.5z\" })) : (\n // ์ฑํ
์์ด์ฝ (Chat ๋ชจ๋)\n React.createElement(\"path\", { d: \"M8 1C3.58 1 0 4.13 0 8c0 1.5.5 2.88 1.34 4.04L.5 15l3.37-.92A8.56 8.56 0 008 15c4.42 0 8-3.13 8-7s-3.58-7-8-7zM4.5 9a1 1 0 110-2 1 1 0 010 2zm3.5 0a1 1 0 110-2 1 1 0 010 2zm3.5 0a1 1 0 110-2 1 1 0 010 2z\" }))),\n React.createElement(\"span\", { className: \"jp-agent-mode-label\" }, inputMode === 'agent' ? 'Agent' : 'Chat'),\n React.createElement(\"svg\", { className: \"jp-agent-mode-chevron\", viewBox: \"0 0 16 16\", fill: \"currentColor\", width: \"12\", height: \"12\" },\n React.createElement(\"path\", { d: \"M4.47 5.47a.75.75 0 011.06 0L8 7.94l2.47-2.47a.75.75 0 111.06 1.06l-3 3a.75.75 0 01-1.06 0l-3-3a.75.75 0 010-1.06z\" }))),\n showModeDropdown && (React.createElement(\"div\", { className: \"jp-agent-mode-dropdown\" },\n React.createElement(\"button\", { className: `jp-agent-mode-option ${inputMode === 'chat' ? 'jp-agent-mode-option--selected' : ''}`, onClick: () => { setInputMode('chat'); setShowModeDropdown(false); } },\n React.createElement(\"svg\", { viewBox: \"0 0 16 16\", fill: \"currentColor\", width: \"14\", height: \"14\" },\n React.createElement(\"path\", { d: \"M8 1C3.58 1 0 4.13 0 8c0 1.5.5 2.88 1.34 4.04L.5 15l3.37-.92A8.56 8.56 0 008 15c4.42 0 8-3.13 8-7s-3.58-7-8-7zM4.5 9a1 1 0 110-2 1 1 0 010 2zm3.5 0a1 1 0 110-2 1 1 0 010 2zm3.5 0a1 1 0 110-2 1 1 0 010 2z\" })),\n React.createElement(\"span\", null, \"Chat\"),\n React.createElement(\"span\", { className: \"jp-agent-mode-shortcut\" }, \"\\uC77C\\uBC18 \\uB300\\uD654\")),\n React.createElement(\"button\", { className: `jp-agent-mode-option ${inputMode === 'agent' ? 'jp-agent-mode-option--selected' : ''}`, onClick: () => { setInputMode('agent'); setShowModeDropdown(false); } },\n React.createElement(\"svg\", { viewBox: \"0 0 16 16\", fill: \"currentColor\", width: \"14\", height: \"14\" },\n React.createElement(\"path\", { d: \"M4.5 8c0-1.38 1.12-2.5 2.5-2.5.9 0 1.68.48 2.12 1.2L8 8l1.12 1.3c-.44.72-1.22 1.2-2.12 1.2-1.38 0-2.5-1.12-2.5-2.5z\" })),\n React.createElement(\"span\", null, \"Agent\"),\n React.createElement(\"span\", { className: \"jp-agent-mode-shortcut\" }, \"\\uB178\\uD2B8\\uBD81 \\uC790\\uB3D9 \\uC2E4\\uD589\"))))),\n React.createElement(\"div\", { className: \"jp-agent-mode-hints\" },\n React.createElement(\"span\", { className: \"jp-agent-mode-hint\" }, \"\\u21E7Tab \\uBAA8\\uB4DC \\uC804\\uD658\")))),\n fileSelectionMetadata && (React.createElement(FileSelectionDialog, { filename: fileSelectionMetadata.pattern, options: fileSelectionMetadata.options, message: fileSelectionMetadata.message, onSelect: handleFileSelect, onCancel: handleFileSelectCancel }))));\n});\nChatPanel.displayName = 'ChatPanel';\n/**\n * Agent Panel Widget\n */\nexport class AgentPanelWidget extends ReactWidget {\n constructor(apiService, notebookTracker, consoleTracker) {\n super();\n this.chatPanelRef = React.createRef();\n this.apiService = apiService;\n this.notebookTracker = notebookTracker;\n this.consoleTracker = consoleTracker;\n this.id = 'hdsp-agent-panel';\n this.title.caption = 'HDSP Agent Assistant';\n this.title.icon = hdspTabIcon;\n this.addClass('jp-agent-widget');\n }\n render() {\n return (React.createElement(ChatPanel, { ref: this.chatPanelRef, apiService: this.apiService, notebookTracker: this.notebookTracker, consoleTracker: this.consoleTracker }));\n }\n /**\n * Add a message from cell action\n * @param action - The action type (explain, fix, custom_prompt)\n * @param cellContent - The cell content\n * @param displayPrompt - The user-facing prompt to show in the UI\n * @param llmPrompt - The actual prompt to send to the LLM\n * @param cellId - The cell ID for applying code (optional)\n * @param cellIndex - The cell index (0-based) for applying code (optional)\n */\n addCellActionMessage(action, cellContent, displayPrompt, llmPrompt, cellId, cellIndex) {\n console.log('[AgentPanel] Cell action:', action);\n console.log('[AgentPanel] Display prompt:', displayPrompt);\n console.log('[AgentPanel] LLM prompt:', llmPrompt);\n console.log('[AgentPanel] Cell ID:', cellId);\n console.log('[AgentPanel] Cell Index:', cellIndex);\n if (!this.chatPanelRef.current) {\n console.error('[AgentPanel] ChatPanel ref not available');\n return;\n }\n // E, F, ? ๋ฒํผ ํด๋ฆญ ์ ํญ์ ์ผ๋ฐ ๋ํ(chat) ๋ชจ๋๋ก ์ ํ\n if (this.chatPanelRef.current.setInputMode) {\n this.chatPanelRef.current.setInputMode('chat');\n }\n // Store cell index for code application (preferred method)\n if (cellIndex !== undefined && this.chatPanelRef.current.setCurrentCellIndex) {\n this.chatPanelRef.current.setCurrentCellIndex(cellIndex);\n }\n // Store cell ID for code application (fallback)\n if (cellId && this.chatPanelRef.current.setCurrentCellId) {\n this.chatPanelRef.current.setCurrentCellId(cellId);\n }\n // Set the display prompt in the input field\n this.chatPanelRef.current.setInput(displayPrompt);\n // Store the LLM prompt\n this.chatPanelRef.current.setLlmPrompt(llmPrompt);\n // Automatically execute after a short delay to ensure state is updated\n setTimeout(() => {\n if (this.chatPanelRef.current) {\n this.chatPanelRef.current.handleSendMessage().catch(error => {\n console.error('[AgentPanel] Failed to send message automatically:', error);\n });\n }\n }, 100);\n }\n /**\n * Analyze entire notebook before saving\n * @param cells - Array of collected cells with content, output, and imports\n * @param onComplete - Callback to execute after analysis (perform save)\n */\n analyzeNotebook(cells, onComplete) {\n console.log('[AgentPanel] analyzeNotebook called with', cells.length, 'cells');\n if (!this.chatPanelRef.current) {\n console.error('[AgentPanel] ChatPanel ref not available');\n onComplete();\n return;\n }\n // ์ ์ฅ ์ ๊ฒ์๋ ํญ์ ์ผ๋ฐ ๋ํ(chat) ๋ชจ๋๋ก ์ ํ\n if (this.chatPanelRef.current.setInputMode) {\n this.chatPanelRef.current.setInputMode('chat');\n }\n // Create summary of notebook\n const totalCells = cells.length;\n const cellsWithErrors = cells.filter(cell => cell.output && (cell.output.includes('Error') ||\n cell.output.includes('Traceback') ||\n cell.output.includes('Exception'))).length;\n const cellsWithImports = cells.filter(cell => cell.imports && cell.imports.length > 0).length;\n const localImports = cells.reduce((acc, cell) => {\n if (cell.imports) {\n return acc + cell.imports.filter((imp) => imp.isLocal).length;\n }\n return acc;\n }, 0);\n // Create display prompt\n const displayPrompt = `์ ์ฒด ๋
ธํธ๋ถ ๊ฒ์ ์์ฒญ (${totalCells}๊ฐ ์
)`;\n // Create detailed LLM prompt with all cells\n let llmPrompt = `๋ค์์ ์ ์ฅํ๊ธฐ ์ ์ Jupyter ๋
ธํธ๋ถ ์ ์ฒด ๋ด์ฉ์
๋๋ค. ๋ชจ๋ ์
์ ๊ฒํ ํ๊ณ ๊ฐ์ ์ฌํญ์ ์ ์ํด์ฃผ์ธ์.\n\n## ๋
ธํธ๋ถ ์์ฝ\n- ์ ์ฒด ์
์: ${totalCells}๊ฐ\n- ์๋ฌ๊ฐ ์๋ ์
: ${cellsWithErrors}๊ฐ\n- Import๊ฐ ์๋ ์
: ${cellsWithImports}๊ฐ\n- ๋ก์ปฌ ๋ชจ๋ import: ${localImports}๊ฐ\n\n## ์ ์ฒด ์
๋ด์ฉ\n\n`;\n cells.forEach((cell, index) => {\n llmPrompt += `### ์
${index + 1} (ID: ${cell.id})\n\\`\\`\\`python\n${cell.content}\n\\`\\`\\`\n`;\n if (cell.output) {\n llmPrompt += `\n**์คํ ๊ฒฐ๊ณผ:**\n\\`\\`\\`\n${cell.output}\n\\`\\`\\`\n`;\n }\n if (cell.imports && cell.imports.length > 0) {\n llmPrompt += `\n**Imports:**\n`;\n cell.imports.forEach((imp) => {\n llmPrompt += `- \\`${imp.module}\\` (${imp.isLocal ? '๋ก์ปฌ' : 'ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ'})\\n`;\n });\n }\n llmPrompt += '\\n---\\n\\n';\n });\n llmPrompt += `\n## ๊ฒ์ ์์ฒญ ์ฌํญ\n\n๋ค์ ํ์์ผ๋ก ์๋ตํด์ฃผ์ธ์:\n\n### 1. ์ ๋ฐ์ ์ธ ์ฝ๋ ํ์ง ํ๊ฐ\n(๋
ธํธ๋ถ ์ ์ฒด์ ์ฝ๋ ํ์ง, ๊ตฌ์กฐ, ์ผ๊ด์ฑ ๋ฑ์ ํ๊ฐ)\n\n### 2. ๋ฐ๊ฒฌ๋ ์ฃผ์ ์ด์\n(์๋ฌ, ๊ฒฝ๊ณ , ์ ์ฌ์ ๋ฌธ์ ์ ๋ฑ์ ๋์ด)\n\n### 3. ์
๋ณ ๊ฐ์ ์ ์\n๊ฐ ์
์ ๋ํด ๊ตฌ์ฒด์ ์ธ ๊ฐ์ ์ฌํญ์ด ์๋ค๋ฉด:\n- **์
X**: (๊ฐ์ ์ฌํญ)\n \\`\\`\\`python\n (๊ฐ์ ๋ ์ฝ๋)\n \\`\\`\\`\n\n### 4. ์ ๋ฐ์ ์ธ ๊ฐ์ ๊ถ์ฅ์ฌํญ\n(๋
ธํธ๋ถ ์ ์ฒด๋ฅผ ๊ฐ์ ํ๊ธฐ ์ํ ์ผ๋ฐ์ ์ธ ์ ์)\n\n### 5. ์ ์ฅ ๊ถ์ฅ ์ฌ๋ถ\n- โ
**์ ์ฅ ๊ถ์ฅ**: (์ด์ )\n- โ ๏ธ **์์ ํ ์ ์ฅ ๊ถ์ฅ**: (์ด์ )\n- โ **์ ์ฅ ๋น๊ถ์ฅ**: (์ด์ )\n`;\n // Set the display prompt in the input field\n this.chatPanelRef.current.setInput(displayPrompt);\n // Store the LLM prompt\n this.chatPanelRef.current.setLlmPrompt(llmPrompt);\n // Automatically execute after a short delay to ensure state is updated\n setTimeout(() => {\n if (this.chatPanelRef.current) {\n this.chatPanelRef.current.handleSendMessage().catch(error => {\n console.error('[AgentPanel] Failed to send message automatically:', error);\n }).finally(() => {\n // Store the onComplete callback to be executed after user reviews the analysis\n // For now, we'll execute it immediately\n // TODO: Add UI button to allow user to review and then save\n console.log('[AgentPanel] Analysis complete, executing onComplete callback');\n onComplete();\n });\n }\n }, 100);\n }\n}\n","/**\n * File Selection Dialog Component\n *\n * Shows multiple file options to user when a filename is ambiguous\n */\nimport React from 'react';\nexport const FileSelectionDialog = ({ filename, options, message, onSelect, onCancel }) => {\n return (React.createElement(\"div\", { className: \"file-selection-dialog\" },\n React.createElement(\"div\", { className: \"file-selection-overlay\", onClick: onCancel }),\n React.createElement(\"div\", { className: \"file-selection-content\" },\n React.createElement(\"h3\", null, \"\\uD30C\\uC77C \\uC120\\uD0DD\"),\n React.createElement(\"p\", { className: \"file-selection-message\" }, message),\n React.createElement(\"div\", { className: \"file-selection-options\" }, options.map((option, idx) => (React.createElement(\"button\", { key: idx, className: \"file-option-button\", onClick: () => onSelect(idx + 1) },\n React.createElement(\"span\", { className: \"file-option-number\" }, idx + 1),\n React.createElement(\"span\", { className: \"file-option-path\" }, option.relative))))),\n React.createElement(\"div\", { className: \"file-selection-actions\" },\n React.createElement(\"button\", { className: \"file-selection-cancel\", onClick: onCancel }, \"\\uCDE8\\uC18C\"))),\n React.createElement(\"style\", null, `\n .file-selection-dialog {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 10000;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .file-selection-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n }\n\n .file-selection-content {\n position: relative;\n background: var(--jp-layout-color1);\n border: 1px solid var(--jp-border-color1);\n border-radius: 8px;\n padding: 24px;\n max-width: 600px;\n width: 90%;\n max-height: 80vh;\n overflow-y: auto;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n }\n\n .file-selection-content h3 {\n margin: 0 0 12px 0;\n color: var(--jp-ui-font-color1);\n font-size: 18px;\n font-weight: 600;\n }\n\n .file-selection-message {\n margin: 0 0 20px 0;\n color: var(--jp-ui-font-color2);\n font-size: 14px;\n white-space: pre-wrap;\n line-height: 1.6;\n }\n\n .file-selection-options {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-bottom: 20px;\n }\n\n .file-option-button {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n background: var(--jp-layout-color2);\n border: 1px solid var(--jp-border-color2);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s;\n text-align: left;\n }\n\n .file-option-button:hover {\n background: var(--jp-layout-color3);\n border-color: var(--jp-brand-color1);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n }\n\n .file-option-number {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: var(--jp-brand-color1);\n color: white;\n border-radius: 50%;\n font-weight: 600;\n font-size: 14px;\n flex-shrink: 0;\n }\n\n .file-option-path {\n flex: 1;\n color: var(--jp-ui-font-color1);\n font-family: var(--jp-code-font-family);\n font-size: 13px;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .file-selection-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n }\n\n .file-selection-cancel {\n padding: 8px 16px;\n background: transparent;\n border: 1px solid var(--jp-border-color2);\n border-radius: 4px;\n color: var(--jp-ui-font-color1);\n cursor: pointer;\n font-size: 14px;\n transition: all 0.2s;\n }\n\n .file-selection-cancel:hover {\n background: var(--jp-layout-color2);\n border-color: var(--jp-border-color1);\n }\n `)));\n};\n","/**\n * Prompt Generation Dialog Component\n * Dialog for entering prompts to generate notebooks\n */\nimport React, { useState } from 'react';\nimport { Dialog, DialogTitle, DialogContent, DialogActions, TextField, Button, Typography, Box, Chip } from '@mui/material';\nimport AutoFixHighIcon from '@mui/icons-material/AutoFixHigh';\nconst EXAMPLE_PROMPTS = [\n 'ํ์ดํ๋ ์์กด์ ์์ธก์ dask์ lgbm์ผ๋ก ์์ฑํด์ค',\n '์ฃผ์ ๋ฐ์ดํฐ ๋ถ์ ๋ฐ ์๊ฐํ ๋
ธํธ๋ถ ๋ง๋ค์ด์ค',\n 'Iris ๋ฐ์ดํฐ์
์ผ๋ก ๋ถ๋ฅ ๋ชจ๋ธ ํ์ตํ๊ธฐ',\n '์๊ณ์ด ๋ฐ์ดํฐ ๋ถ์ ๋ฐ ์์ธก ๋ชจ๋ธ ๋ง๋ค๊ธฐ'\n];\nexport const PromptGenerationDialog = ({ open, onClose, onGenerate }) => {\n const [prompt, setPrompt] = useState('');\n const [isGenerating, setIsGenerating] = useState(false);\n const [progress, setProgress] = useState(0);\n const [statusMessage, setStatusMessage] = useState('');\n const handleGenerate = () => {\n if (prompt.trim()) {\n setIsGenerating(true);\n onGenerate(prompt.trim());\n setPrompt('');\n setIsGenerating(false);\n onClose();\n }\n };\n const handleKeyPress = (event) => {\n if (event.key === 'Enter' && event.ctrlKey) {\n handleGenerate();\n }\n };\n const handleExampleClick = (example) => {\n setPrompt(example);\n };\n return (React.createElement(Dialog, { open: open, onClose: onClose, maxWidth: \"md\", fullWidth: true, PaperProps: {\n sx: {\n borderRadius: 2,\n minHeight: '400px'\n }\n } },\n React.createElement(DialogTitle, null,\n React.createElement(Box, { display: \"flex\", alignItems: \"center\", gap: 1 },\n React.createElement(AutoFixHighIcon, { color: \"primary\" }),\n React.createElement(Typography, { variant: \"h6\" }, \"HALO \\uD504\\uB86C\\uD504\\uD2B8\\uB85C \\uB178\\uD2B8\\uBD81 \\uC0DD\\uC131\"))),\n React.createElement(DialogContent, null,\n React.createElement(Box, { display: \"flex\", flexDirection: \"column\", gap: 2, mt: 1 },\n React.createElement(Typography, { variant: \"body2\", color: \"text.secondary\" }, \"\\uC6D0\\uD558\\uB294 \\uB178\\uD2B8\\uBD81\\uC758 \\uB0B4\\uC6A9\\uC744 \\uC790\\uC5F0\\uC5B4\\uB85C \\uC124\\uBA85\\uD574\\uC8FC\\uC138\\uC694. AI\\uAC00 \\uC790\\uB3D9\\uC73C\\uB85C \\uB178\\uD2B8\\uBD81\\uC744 \\uC0DD\\uC131\\uD569\\uB2C8\\uB2E4.\"),\n React.createElement(TextField, { autoFocus: true, multiline: true, rows: 6, fullWidth: true, variant: \"outlined\", placeholder: \"\\uC608: \\uD0C0\\uC774\\uD0C0\\uB2C9 \\uC0DD\\uC874\\uC790 \\uC608\\uCE21\\uC744 dask\\uC640 lgbm\\uC73C\\uB85C \\uC0DD\\uC131\\uD574\\uC918\", value: prompt, onChange: (e) => setPrompt(e.target.value), onKeyPress: handleKeyPress, disabled: isGenerating, sx: {\n '& .MuiOutlinedInput-root': {\n fontSize: '14px'\n }\n } }),\n React.createElement(Box, null,\n React.createElement(Typography, { variant: \"caption\", color: \"text.secondary\", display: \"block\", mb: 1 }, \"\\uC608\\uC2DC \\uD504\\uB86C\\uD504\\uD2B8 (\\uD074\\uB9AD\\uD558\\uC5EC \\uC0AC\\uC6A9):\"),\n React.createElement(Box, { display: \"flex\", flexWrap: \"wrap\", gap: 1 }, EXAMPLE_PROMPTS.map((example, index) => (React.createElement(Chip, { key: index, label: example, variant: \"outlined\", size: \"small\", onClick: () => handleExampleClick(example), sx: {\n cursor: 'pointer',\n '&:hover': {\n backgroundColor: 'action.hover'\n }\n } }))))),\n React.createElement(Box, { sx: {\n backgroundColor: 'action.hover',\n borderRadius: 1,\n padding: 2\n } },\n React.createElement(Typography, { variant: \"caption\", color: \"text.secondary\" },\n \"\\uD83D\\uDCA1 \",\n React.createElement(\"strong\", null, \"\\uD301:\"),\n React.createElement(\"br\", null),\n \"\\u2022 \\uC0AC\\uC6A9\\uD560 \\uB77C\\uC774\\uBE0C\\uB7EC\\uB9AC\\uB97C \\uBA85\\uC2DC\\uD558\\uBA74 \\uB354 \\uC815\\uD655\\uD569\\uB2C8\\uB2E4\",\n React.createElement(\"br\", null),\n \"\\u2022 \\uBD84\\uC11D \\uBAA9\\uC801\\uACFC \\uB370\\uC774\\uD130\\uB97C \\uAD6C\\uCCB4\\uC801\\uC73C\\uB85C \\uC124\\uBA85\\uD558\\uC138\\uC694\",\n React.createElement(\"br\", null),\n \"\\u2022 Ctrl + Enter\\uB85C \\uBE60\\uB974\\uAC8C \\uC0DD\\uC131\\uD560 \\uC218 \\uC788\\uC2B5\\uB2C8\\uB2E4\",\n React.createElement(\"br\", null),\n \"\\u2022 \\uC0DD\\uC131\\uC740 \\uBC31\\uADF8\\uB77C\\uC6B4\\uB4DC\\uC5D0\\uC11C \\uC9C4\\uD589\\uB418\\uBA70, \\uC644\\uB8CC\\uB418\\uBA74 \\uC54C\\uB9BC\\uC744 \\uBC1B\\uC2B5\\uB2C8\\uB2E4\")))),\n React.createElement(DialogActions, { sx: { padding: 2, paddingTop: 0 } },\n React.createElement(Button, { onClick: onClose, disabled: isGenerating }, \"\\uCDE8\\uC18C\"),\n React.createElement(Button, { onClick: handleGenerate, variant: \"contained\", disabled: !prompt.trim() || isGenerating, startIcon: React.createElement(AutoFixHighIcon, null) }, \"\\uC0DD\\uC131 \\uC2DC\\uC791\"))));\n};\n","/**\n * Settings Panel Component\n * Allows users to configure LLM provider settings\n *\n * API keys are stored in browser localStorage and sent with each request.\n * The Agent Server does not store API keys - it receives them with each request.\n */\nimport React, { useState, useEffect } from 'react';\nimport { getLLMConfig, saveLLMConfig, testApiKey, getDefaultLLMConfig } from '../services/ApiKeyManager';\nexport const SettingsPanel = ({ onClose, onSave, currentConfig }) => {\n // Initialize from localStorage or props\n const initConfig = currentConfig || getLLMConfig() || getDefaultLLMConfig();\n const [provider, setProvider] = useState(initConfig.provider || 'gemini');\n const [isTesting, setIsTesting] = useState(false);\n const [testResults, setTestResults] = useState({});\n // Track active key index (first valid key by default)\n const [activeKeyIndex, setActiveKeyIndex] = useState(0);\n // Gemini settings - support multiple keys (max 10)\n const [geminiApiKeys, setGeminiApiKeys] = useState(initConfig.gemini?.apiKeys?.length\n ? initConfig.gemini.apiKeys\n : initConfig.gemini?.apiKey\n ? [initConfig.gemini.apiKey]\n : ['']);\n // Legacy single key for backward compatibility\n const geminiApiKey = geminiApiKeys[0] || '';\n // Validate gemini model - only allow valid options\n const validateGeminiModel = (model) => {\n const validModels = ['gemini-2.5-pro', 'gemini-2.5-flash'];\n if (model && validModels.includes(model)) {\n return model;\n }\n return 'gemini-2.5-flash';\n };\n const [geminiModel, setGeminiModel] = useState(validateGeminiModel(initConfig.gemini?.model));\n // vLLM settings\n const [vllmEndpoint, setVllmEndpoint] = useState(initConfig.vllm?.endpoint || 'http://localhost:8000');\n const [vllmApiKey, setVllmApiKey] = useState(initConfig.vllm?.apiKey || '');\n const [vllmModel, setVllmModel] = useState(initConfig.vllm?.model || 'meta-llama/Llama-2-7b-chat-hf');\n // OpenAI settings\n const [openaiApiKey, setOpenaiApiKey] = useState(initConfig.openai?.apiKey || '');\n const [openaiModel, setOpenaiModel] = useState(initConfig.openai?.model || 'gpt-4');\n // Update state when currentConfig changes\n useEffect(() => {\n if (currentConfig) {\n setProvider(currentConfig.provider || 'gemini');\n // Handle multiple keys\n if (currentConfig.gemini?.apiKeys?.length) {\n setGeminiApiKeys(currentConfig.gemini.apiKeys);\n }\n else if (currentConfig.gemini?.apiKey) {\n setGeminiApiKeys([currentConfig.gemini.apiKey]);\n }\n else {\n setGeminiApiKeys(['']);\n }\n setGeminiModel(validateGeminiModel(currentConfig.gemini?.model));\n setVllmEndpoint(currentConfig.vllm?.endpoint || 'http://localhost:8000');\n setVllmApiKey(currentConfig.vllm?.apiKey || '');\n setVllmModel(currentConfig.vllm?.model || 'meta-llama/Llama-2-7b-chat-hf');\n setOpenaiApiKey(currentConfig.openai?.apiKey || '');\n setOpenaiModel(currentConfig.openai?.model || 'gpt-4');\n }\n }, [currentConfig]);\n // Helper: Build LLM config from state\n const buildLLMConfig = () => ({\n provider,\n gemini: {\n apiKey: geminiApiKeys[0] || '',\n apiKeys: geminiApiKeys.filter(k => k && k.trim()),\n model: geminiModel\n },\n vllm: {\n endpoint: vllmEndpoint,\n apiKey: vllmApiKey,\n model: vllmModel\n },\n openai: {\n apiKey: openaiApiKey,\n model: openaiModel\n }\n });\n // Handlers for multiple API keys\n const handleAddKey = () => {\n if (geminiApiKeys.length < 10) {\n setGeminiApiKeys([...geminiApiKeys, '']);\n }\n };\n const handleRemoveKey = (index) => {\n if (geminiApiKeys.length > 1) {\n const newKeys = geminiApiKeys.filter((_, i) => i !== index);\n setGeminiApiKeys(newKeys);\n }\n };\n const handleKeyChange = (index, value) => {\n const newKeys = [...geminiApiKeys];\n newKeys[index] = value;\n setGeminiApiKeys(newKeys);\n };\n const validKeyCount = geminiApiKeys.filter(k => k && k.trim()).length;\n const handleTest = async () => {\n setIsTesting(true);\n setTestResults({});\n if (provider === 'gemini') {\n // Test each Gemini key individually\n const validKeys = geminiApiKeys.map((k, i) => ({ key: k, index: i }))\n .filter(({ key }) => key && key.trim());\n for (const { key, index } of validKeys) {\n setTestResults(prev => ({ ...prev, [index]: 'testing' }));\n const testConfig = {\n provider: 'gemini',\n gemini: { apiKey: key, apiKeys: [key], model: geminiModel }\n };\n try {\n const result = await testApiKey(testConfig);\n setTestResults(prev => ({ ...prev, [index]: result.success ? 'success' : 'error' }));\n }\n catch {\n setTestResults(prev => ({ ...prev, [index]: 'error' }));\n }\n }\n }\n else {\n // For other providers, just test the single config\n try {\n const config = buildLLMConfig();\n const result = await testApiKey(config);\n setTestResults({ 0: result.success ? 'success' : 'error' });\n }\n catch {\n setTestResults({ 0: 'error' });\n }\n }\n setIsTesting(false);\n };\n // Handle clicking a key row to set it as active\n const handleSetActiveKey = (index) => {\n if (geminiApiKeys[index] && geminiApiKeys[index].trim()) {\n setActiveKeyIndex(index);\n }\n };\n const handleSave = () => {\n const config = buildLLMConfig();\n // Save to localStorage\n saveLLMConfig(config);\n // Notify parent component\n onSave(config);\n onClose();\n };\n // Get test status icon for a key\n const getTestStatusIcon = (index) => {\n const status = testResults[index];\n if (status === 'testing')\n return 'โณ';\n if (status === 'success')\n return 'โ
';\n if (status === 'error')\n return 'โ';\n return '';\n };\n return (React.createElement(\"div\", { className: \"jp-agent-settings-overlay\" },\n React.createElement(\"div\", { className: \"jp-agent-settings-dialog\" },\n React.createElement(\"div\", { className: \"jp-agent-settings-header\" },\n React.createElement(\"h2\", null, \"LLM \\uC124\\uC815\"),\n React.createElement(\"button\", { className: \"jp-agent-settings-close\", onClick: onClose, title: \"\\uB2EB\\uAE30\" }, \"\\u00D7\")),\n React.createElement(\"div\", { className: \"jp-agent-settings-content\" },\n React.createElement(\"div\", { className: \"jp-agent-settings-notice\" },\n React.createElement(\"span\", null, \"API \\uD0A4\\uB294 \\uBE0C\\uB77C\\uC6B0\\uC800\\uC5D0 \\uC548\\uC804\\uD558\\uAC8C \\uC800\\uC7A5\\uB418\\uBA70, \\uC694\\uCCAD \\uC2DC\\uC5D0\\uB9CC \\uC11C\\uBC84\\uB85C \\uC804\\uC1A1\\uB429\\uB2C8\\uB2E4.\")),\n React.createElement(\"div\", { className: \"jp-agent-settings-group\" },\n React.createElement(\"label\", { className: \"jp-agent-settings-label\" }, \"\\uD504\\uB85C\\uBC14\\uC774\\uB354\"),\n React.createElement(\"select\", { className: \"jp-agent-settings-select\", value: provider, onChange: (e) => setProvider(e.target.value) },\n React.createElement(\"option\", { value: \"gemini\" }, \"Google Gemini\"),\n React.createElement(\"option\", { value: \"vllm\" }, \"vLLM\"),\n React.createElement(\"option\", { value: \"openai\" }, \"OpenAI\"))),\n provider === 'gemini' && (React.createElement(\"div\", { className: \"jp-agent-settings-provider\" },\n React.createElement(\"h3\", null, \"Gemini \\uC124\\uC815\"),\n React.createElement(\"div\", { className: \"jp-agent-settings-group\" },\n React.createElement(\"label\", { className: \"jp-agent-settings-label\" },\n \"API \\uD0A4 (\",\n validKeyCount,\n \"/10)\",\n React.createElement(\"small\", { style: { fontWeight: 'normal', marginLeft: '8px', color: '#666' } }, \"Rate limit \\uC2DC \\uC790\\uB3D9 \\uB85C\\uD14C\\uC774\\uC158\")),\n geminiApiKeys.map((key, index) => (React.createElement(\"div\", { key: index, className: \"jp-agent-settings-key-row\", style: {\n display: 'flex',\n gap: '8px',\n marginBottom: '8px',\n alignItems: 'center',\n padding: '4px',\n borderRadius: '4px',\n background: activeKeyIndex === index && key && key.trim() ? 'rgba(66, 133, 244, 0.1)' : 'transparent',\n border: activeKeyIndex === index && key && key.trim() ? '1px solid rgba(66, 133, 244, 0.3)' : '1px solid transparent'\n } },\n React.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' } }),\n React.createElement(\"span\", { style: {\n minWidth: '20px',\n color: '#666',\n fontSize: '12px'\n } },\n index + 1,\n \".\"),\n React.createElement(\"input\", { type: \"password\", className: \"jp-agent-settings-input\", style: { flex: 1 }, value: key, onChange: (e) => handleKeyChange(index, e.target.value), placeholder: \"AIza...\" }),\n getTestStatusIcon(index) && (React.createElement(\"span\", { style: { fontSize: '14px', minWidth: '20px' } }, getTestStatusIcon(index))),\n geminiApiKeys.length > 1 && (React.createElement(\"button\", { type: \"button\", className: \"jp-agent-settings-button-icon\", onClick: () => handleRemoveKey(index), title: \"\\uD0A4 \\uC0AD\\uC81C\", style: {\n padding: '4px 8px',\n background: '#ff4444',\n color: 'white',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer'\n } }, \"\\u00D7\"))))),\n geminiApiKeys.length < 10 && (React.createElement(\"button\", { type: \"button\", className: \"jp-agent-settings-button jp-agent-settings-button-secondary\", onClick: handleAddKey, style: { marginTop: '8px' } }, \"+ \\uD0A4 \\uCD94\\uAC00\"))),\n React.createElement(\"div\", { className: \"jp-agent-settings-group\" },\n React.createElement(\"label\", { className: \"jp-agent-settings-label\" }, \"\\uBAA8\\uB378\"),\n React.createElement(\"select\", { className: \"jp-agent-settings-select\", value: geminiModel, onChange: (e) => setGeminiModel(e.target.value) },\n React.createElement(\"option\", { value: \"gemini-2.5-flash\" }, \"Gemini 2.5 Flash\"),\n React.createElement(\"option\", { value: \"gemini-2.5-pro\" }, \"Gemini 2.5 Pro\"))))),\n provider === 'vllm' && (React.createElement(\"div\", { className: \"jp-agent-settings-provider\" },\n React.createElement(\"h3\", null, \"vLLM \\uC124\\uC815\"),\n React.createElement(\"div\", { className: \"jp-agent-settings-group\" },\n React.createElement(\"label\", { className: \"jp-agent-settings-label\" }, \"\\uC11C\\uBC84 \\uC8FC\\uC18C\"),\n React.createElement(\"input\", { type: \"text\", className: \"jp-agent-settings-input\", value: vllmEndpoint, onChange: (e) => setVllmEndpoint(e.target.value), placeholder: \"http://localhost:8000\" })),\n React.createElement(\"div\", { className: \"jp-agent-settings-group\" },\n React.createElement(\"label\", { className: \"jp-agent-settings-label\" }, \"API \\uD0A4 (\\uC120\\uD0DD\\uC0AC\\uD56D)\"),\n React.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\" })),\n React.createElement(\"div\", { className: \"jp-agent-settings-group\" },\n React.createElement(\"label\", { className: \"jp-agent-settings-label\" }, \"\\uBAA8\\uB378 \\uC774\\uB984\"),\n React.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\" })))),\n provider === 'openai' && (React.createElement(\"div\", { className: \"jp-agent-settings-provider\" },\n React.createElement(\"h3\", null, \"OpenAI \\uC124\\uC815\"),\n React.createElement(\"div\", { className: \"jp-agent-settings-group\" },\n React.createElement(\"label\", { className: \"jp-agent-settings-label\" }, \"API \\uD0A4\"),\n React.createElement(\"input\", { type: \"password\", className: \"jp-agent-settings-input\", value: openaiApiKey, onChange: (e) => setOpenaiApiKey(e.target.value), placeholder: \"sk-...\" })),\n React.createElement(\"div\", { className: \"jp-agent-settings-group\" },\n React.createElement(\"label\", { className: \"jp-agent-settings-label\" }, \"\\uBAA8\\uB378\"),\n React.createElement(\"select\", { className: \"jp-agent-settings-select\", value: openaiModel, onChange: (e) => setOpenaiModel(e.target.value) },\n React.createElement(\"option\", { value: \"gpt-4\" }, \"GPT-4\"),\n React.createElement(\"option\", { value: \"gpt-4-turbo\" }, \"GPT-4 Turbo\"),\n React.createElement(\"option\", { value: \"gpt-3.5-turbo\" }, \"GPT-3.5 Turbo\")))))),\n React.createElement(\"div\", { className: \"jp-agent-settings-footer\" },\n React.createElement(\"button\", { className: \"jp-agent-settings-button jp-agent-settings-button-secondary\", onClick: onClose }, \"\\uCDE8\\uC18C\"),\n React.createElement(\"button\", { className: \"jp-agent-settings-button jp-agent-settings-button-test\", onClick: handleTest, disabled: isTesting }, isTesting ? 'ํ
์คํธ ์ค...' : 'API ํ
์คํธ'),\n React.createElement(\"button\", { className: \"jp-agent-settings-button jp-agent-settings-button-primary\", onClick: handleSave }, \"\\uC800\\uC7A5\")))));\n};\n","/**\n * Task Progress Widget Component\n * Floating widget showing notebook generation progress\n */\nimport React, { useState } from 'react';\nimport { Card, CardContent, Typography, LinearProgress, Box, IconButton, Collapse, Chip, Button } from '@mui/material';\nimport CloseIcon from '@mui/icons-material/Close';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport ExpandLessIcon from '@mui/icons-material/ExpandLess';\nimport CheckCircleIcon from '@mui/icons-material/CheckCircle';\nimport ErrorIcon from '@mui/icons-material/Error';\nimport CancelIcon from '@mui/icons-material/Cancel';\nexport const TaskProgressWidget = ({ taskStatus, onClose, onCancel, onOpenNotebook }) => {\n const [expanded, setExpanded] = useState(true);\n const [showDetails, setShowDetails] = useState(false);\n const { status, progress, message, prompt, error, notebookPath } = taskStatus;\n const isComplete = status === 'completed';\n const isFailed = status === 'failed';\n const isCancelled = status === 'cancelled';\n const isRunning = status === 'running';\n const isDone = isComplete || isFailed || isCancelled;\n // Helper: Map status to color\n const getStatusColor = (currentStatus) => {\n switch (currentStatus) {\n case 'completed': return 'success';\n case 'failed': return 'error';\n case 'cancelled': return 'default';\n default: return 'primary';\n }\n };\n // Helper: Map status to icon\n const getStatusIcon = (currentStatus) => {\n switch (currentStatus) {\n case 'completed': return React.createElement(CheckCircleIcon, { fontSize: \"small\" });\n case 'failed': return React.createElement(ErrorIcon, { fontSize: \"small\" });\n case 'cancelled': return React.createElement(CancelIcon, { fontSize: \"small\" });\n default: return null;\n }\n };\n // Helper: Map status to Korean text\n const getStatusText = (currentStatus) => {\n const statusTextMap = {\n 'pending': '๋๊ธฐ ์ค',\n 'running': '์์ฑ ์ค',\n 'completed': '์๋ฃ',\n 'failed': '์คํจ',\n 'cancelled': '์ทจ์๋จ'\n };\n return statusTextMap[currentStatus] || currentStatus;\n };\n return (React.createElement(Card, { sx: {\n position: 'fixed',\n bottom: 20,\n right: 20,\n width: expanded ? 380 : 320,\n maxWidth: '90vw',\n boxShadow: 3,\n zIndex: 1300,\n transition: 'all 0.3s ease'\n } },\n React.createElement(CardContent, { sx: { padding: 2, '&:last-child': { paddingBottom: 2 } } },\n React.createElement(Box, { display: \"flex\", justifyContent: \"space-between\", alignItems: \"center\", mb: 1 },\n React.createElement(Box, { display: \"flex\", alignItems: \"center\", gap: 1 },\n React.createElement(Typography, { variant: \"subtitle2\", fontWeight: \"bold\" }, \"\\uB178\\uD2B8\\uBD81 \\uC0DD\\uC131\"),\n React.createElement(Chip, { label: getStatusText(status), size: \"small\", color: getStatusColor(status), icon: getStatusIcon(status) || undefined })),\n React.createElement(Box, { display: \"flex\" },\n React.createElement(IconButton, { size: \"small\", onClick: () => setShowDetails(!showDetails) }, showDetails ? (React.createElement(ExpandLessIcon, { fontSize: \"small\" })) : (React.createElement(ExpandMoreIcon, { fontSize: \"small\" }))),\n React.createElement(IconButton, { size: \"small\", onClick: onClose },\n React.createElement(CloseIcon, { fontSize: \"small\" })))),\n !isDone && (React.createElement(Box, { mb: 2 },\n React.createElement(LinearProgress, { variant: \"determinate\", value: progress, sx: { height: 6, borderRadius: 1 } }),\n React.createElement(Box, { display: \"flex\", justifyContent: \"space-between\", mt: 0.5 },\n React.createElement(Typography, { variant: \"caption\", color: \"text.secondary\" }, message),\n React.createElement(Typography, { variant: \"caption\", color: \"text.secondary\" },\n progress,\n \"%\")))),\n isComplete && (React.createElement(Box, { mb: 2 },\n React.createElement(Typography, { variant: \"body2\", color: \"success.main\" },\n \"\\u2713 \",\n message))),\n isFailed && error && (React.createElement(Box, { mb: 2 },\n React.createElement(Typography, { variant: \"body2\", color: \"error.main\" },\n \"\\u2717 \",\n error))),\n React.createElement(Collapse, { in: showDetails },\n React.createElement(Box, { sx: {\n backgroundColor: 'action.hover',\n borderRadius: 1,\n padding: 1.5,\n mb: 2\n } },\n React.createElement(Typography, { variant: \"caption\", color: \"text.secondary\", display: \"block\", mb: 0.5 }, \"\\uD504\\uB86C\\uD504\\uD2B8:\"),\n React.createElement(Typography, { variant: \"body2\", sx: { wordBreak: 'break-word' } }, prompt),\n notebookPath && (React.createElement(React.Fragment, null,\n React.createElement(Typography, { variant: \"caption\", color: \"text.secondary\", display: \"block\", mt: 1, mb: 0.5 }, \"\\uC800\\uC7A5 \\uC704\\uCE58:\"),\n React.createElement(Typography, { variant: \"caption\", sx: { wordBreak: 'break-all', fontFamily: 'monospace' } }, notebookPath))))),\n React.createElement(Box, { display: \"flex\", gap: 1, justifyContent: \"flex-end\" },\n isRunning && (React.createElement(Button, { size: \"small\", variant: \"outlined\", onClick: onCancel }, \"\\uCDE8\\uC18C\")),\n isComplete && notebookPath && (React.createElement(Button, { size: \"small\", variant: \"contained\", onClick: onOpenNotebook }, \"\\uB178\\uD2B8\\uBD81 \\uC5F4\\uAE30\")),\n isDone && (React.createElement(Button, { size: \"small\", variant: \"text\", onClick: onClose }, \"\\uB2EB\\uAE30\"))))));\n};\n","/**\n * Jupyter Agent Extension Entry Point\n */\n// Import plugins\nimport { sidebarPlugin } from './plugins/sidebar-plugin';\nimport { cellButtonsPlugin } from './plugins/cell-buttons-plugin';\nimport { promptGenerationPlugin } from './plugins/prompt-generation-plugin';\nimport { saveInterceptorPlugin } from './plugins/save-interceptor-plugin';\n// Import styles\n// import '../style/index.css';\n/**\n * The main plugin export\n * Note: sidebarPlugin must load before cellButtonsPlugin\n * saveInterceptorPlugin loads last to intercept save operations\n */\nconst plugins = [\n sidebarPlugin,\n cellButtonsPlugin,\n promptGenerationPlugin,\n saveInterceptorPlugin\n];\nexport default plugins;\n","/**\n * Logo SVG strings for HDSP Agent\n * These are inlined to avoid webpack module resolution issues with SVG imports\n */\nexport const headerLogoSvg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1280\" height=\"552\" viewBox=\"0 0 1280 552\">\n<g>\n<path d=\"M 509.50 487.44 C489.07,492.66 475.03,491.17 456.90,481.84 C443.64,475.02 431.71,461.09 425.78,445.49 L 423.50 439.50 L 423.50 352.50 C423.50,270.60 423.61,265.16 425.35,259.64 C429.92,245.21 434.83,237.05 444.80,227.32 C451.11,221.16 454.21,219.17 490.50,198.02 C499.30,192.89 511.23,185.89 517.00,182.47 C524.42,178.07 529.21,175.00 534.39,172.87 C546.27,167.97 560.17,167.97 612.52,168.00 C616.39,168.00 620.47,168.00 624.77,168.00 C696.61,168.00 696.69,168.00 698.60,170.10 C700.45,172.15 700.51,176.37 700.76,326.52 L 701.02 480.84 L 698.37 482.92 C695.82,484.93 694.64,485.00 662.87,485.00 C660.58,485.00 658.44,485.00 656.43,485.01 C635.73,485.03 629.05,485.04 626.93,481.94 C625.92,480.46 625.95,478.27 625.98,475.05 C625.99,474.40 626.00,473.70 626.00,472.95 C626.00,464.61 624.48,459.78 621.50,458.64 C619.31,457.80 613.27,459.19 584.00,467.25 C548.33,477.08 520.07,484.73 509.50,487.44 ZM 101.50 483.17 L 95.89 488.00 L 61.94 488.00 C29.33,488.00 27.92,487.92 26.00,486.00 C24.01,484.01 24.00,482.67 24.00,280.45 L 24.00 76.91 L 28.98 71.92 L 62.97 72.21 C96.81,72.50 96.96,72.51 99.22,74.78 L 101.50 77.05 L 102.00 159.37 C102.39,224.31 102.77,242.02 103.78,243.24 C106.88,246.97 108.55,247.04 192.33,246.77 L 274.16 246.50 L 280.00 239.97 L 280.00 159.53 C280.00,102.71 280.33,78.38 281.11,76.66 C283.11,72.27 285.27,72.00 318.40,72.00 C350.66,72.00 355.11,72.47 357.02,76.04 C357.65,77.22 358.00,150.36 358.00,280.86 L 358.00 483.85 L 355.37 485.93 C352.82,487.93 351.61,488.00 318.98,488.00 C287.23,488.00 285.08,487.89 282.86,486.09 L 280.50 484.18 L 280.00 398.62 C279.50,313.37 279.49,313.05 277.40,310.96 C276.25,309.80 273.55,308.45 271.40,307.95 C265.89,306.67 113.48,306.74 108.86,308.02 C106.86,308.58 104.61,309.77 103.86,310.67 C102.75,312.01 102.41,327.79 102.00,397.74 ZM 803.53 486.27 L 804.22 489.00 L 787.86 488.99 C776.68,488.98 770.71,488.57 769.00,487.71 L 766.50 486.44 L 766.25 262.22 C766.00,39.09 766.01,37.99 768.00,36.00 C769.92,34.08 771.32,34.00 802.44,34.00 L 834.89 34.00 L 837.69 36.41 L 840.50 38.83 L 839.87 387.35 L 834.03 395.42 C820.62,413.96 809.00,435.96 804.66,451.00 C800.58,465.15 800.32,473.46 803.53,486.27 ZM 503.02 426.72 C506.36,428.40 615.07,428.57 619.88,426.89 C620.83,426.56 621.63,426.38 622.31,425.99 C626.01,423.85 626.01,415.30 626.00,340.32 C626.00,336.25 626.00,331.99 626.00,327.52 C626.00,248.50 625.79,234.42 624.54,231.43 C624.09,230.36 623.73,229.47 623.18,228.73 C620.38,225.00 612.60,225.00 563.70,225.01 L 562.28 225.01 C528.10,225.01 507.13,225.39 504.75,226.05 C503.57,226.38 502.60,226.49 501.79,226.92 C497.98,228.96 497.98,238.13 498.01,311.07 C498.01,315.99 498.01,321.19 498.01,326.70 C498.02,329.49 498.02,332.20 498.02,334.83 C498.03,416.15 498.03,423.53 501.47,425.89 C501.92,426.20 502.44,426.42 503.02,426.72 ZM 807.50 386.63 C809.71,390.01 815.16,389.94 817.00,386.51 C818.51,383.68 817.20,379.40 814.51,378.36 C809.40,376.40 804.55,382.13 807.50,386.63 Z\" fill=\"rgb(33,33,33)\"/>\n<path d=\"M 920.88 447.94 C918.34,448.49 915.13,449.38 913.74,449.91 C910.57,451.11 908.44,449.01 904.19,440.50 C899.91,431.92 898.22,426.31 897.06,416.83 C896.19,409.61 894.33,331.10 894.94,327.00 C895.06,326.17 895.51,308.62 895.93,288.00 C896.77,246.77 896.82,246.38 903.51,234.42 C909.99,222.84 915.87,217.34 946.50,194.31 C966.26,179.45 975.52,173.41 982.84,170.64 C988.30,168.58 990.25,168.49 1037.00,168.20 C1070.48,167.98 1087.98,168.25 1093.50,169.07 C1097.90,169.71 1103.07,170.46 1105.00,170.72 C1111.37,171.59 1127.50,180.68 1133.24,186.65 C1134.74,188.22 1137.78,191.34 1139.99,193.59 C1142.19,195.85 1144.00,198.04 1144.00,198.46 C1144.00,198.89 1145.53,201.77 1147.39,204.87 C1155.34,218.08 1158.67,233.11 1159.17,258.00 L 1159.50 274.50 L 1154.09 281.00 C1143.99,293.15 1136.53,301.15 1121.14,316.34 L 1104.14 333.12 C1099.09,338.11 1090.51,345.00 1089.34,345.00 C1088.24,345.00 1088.00,335.76 1088.00,292.25 C1087.99,241.70 1087.91,239.37 1086.04,236.30 C1082.06,229.77 1083.02,229.88 1028.67,229.68 L 1025.26 229.67 C983.83,229.51 976.61,229.49 973.18,233.08 C972.36,233.93 971.76,234.99 970.96,236.30 C969.06,239.41 969.01,241.96 969.00,324.18 C969.00,375.59 969.38,409.86 969.96,411.38 C971.30,414.91 975.10,417.10 981.24,417.89 L 986.50 418.57 L 982.22 421.31 C969.10,429.74 933.62,445.14 920.88,447.94 ZM 1065.75 487.50 C1060.71,488.69 1051.19,488.95 1016.50,488.86 C976.07,488.76 961.65,488.05 959.65,486.05 C959.18,485.58 964.81,482.19 972.15,478.51 C979.49,474.83 985.95,471.47 986.50,471.06 C987.05,470.65 992.00,467.93 997.50,465.04 C1006.02,460.55 1010.72,457.80 1025.42,448.69 C1051.66,432.43 1059.19,427.34 1080.42,411.50 C1083.37,409.30 1087.05,406.60 1088.60,405.50 C1091.66,403.33 1101.28,395.70 1104.50,392.90 C1105.60,391.94 1109.65,388.56 1113.50,385.38 C1117.35,382.21 1123.19,377.34 1126.49,374.56 C1132.44,369.53 1134.33,367.82 1151.50,352.03 L 1160.50 343.74 L 1161.29 354.12 C1162.30,367.25 1161.38,391.47 1159.55,400.14 C1157.35,410.57 1152.30,421.50 1146.04,429.36 C1140.26,436.61 1123.66,450.88 1104.00,465.48 C1098.22,469.77 1091.90,474.51 1089.95,476.03 C1084.46,480.28 1072.67,485.87 1065.75,487.50 ZM 1169.50 127.53 C1167.30,128.25 1163.93,128.83 1162.00,128.80 C1158.73,128.77 1158.83,128.68 1163.50,127.48 C1170.40,125.70 1174.92,125.74 1169.50,127.53 Z\" fill=\"rgb(106,105,93)\"/>\n<path d=\"M 803.53 486.27 C800.32,473.46 800.58,465.15 804.66,451.00 C809.00,435.96 820.62,413.96 834.03,395.42 L 839.87 387.35 L 840.12 246.32 C840.05,327.94 840.28,384.00 840.74,384.00 C841.22,384.00 844.07,381.00 847.06,377.33 C856.97,365.17 869.10,351.67 882.38,338.00 L 895.04 324.98 C895.00,326.15 894.96,326.85 894.94,327.00 C894.43,330.45 895.66,386.60 896.59,408.61 C896.39,405.17 896.24,401.34 896.12,397.00 C895.78,385.17 895.15,375.50 894.73,375.50 C893.01,375.50 878.71,396.18 873.64,406.00 C868.53,415.89 864.99,426.58 865.01,432.06 C865.03,443.07 873.07,451.12 885.79,452.87 C888.93,453.30 892.85,453.52 894.50,453.35 C904.27,452.39 908.17,452.12 908.83,450.52 C909.20,449.61 908.51,448.25 907.25,446.08 C909.67,449.91 911.43,450.79 913.74,449.91 C915.13,449.38 918.34,448.49 920.88,447.94 C933.62,445.14 969.10,429.74 982.22,421.31 L 986.50 418.57 L 981.24,417.89 C979.60,417.68 978.13,417.37 976.82,416.96 C978.94,417.62 981.71,418.00 984.58,418.00 C990.13,418.00 991.42,417.55 999.08,412.92 C1015.33,403.11 1046.98,381.37 1060.00,371.06 C1070.76,362.54 1086.56,349.47 1087.23,348.53 C1087.64,347.96 1087.97,323.20 1087.98,293.50 C1087.99,248.96 1087.93,241.00 1086.73,237.69 C1087.93,240.98 1087.99,248.80 1088.00,292.25 C1088.00,335.76 1088.24,345.00 1089.34,345.00 C1090.51,345.00 1099.09,338.11 1104.14,333.12 L 1121.14 316.34 C1136.53,301.15 1143.99,293.15 1154.09,281.00 L 1159.50 274.50 L 1159.29 264.13 C1159.39,265.95 1159.51,267.46 1159.64,268.39 C1160.27,272.96 1160.32,273.02 1162.27,271.28 C1165.00,268.83 1174.79,254.08 1179.70,245.00 C1185.69,233.94 1188.00,226.29 1188.00,217.57 C1188.00,210.72 1187.75,209.82 1184.70,205.83 C1180.11,199.80 1174.31,196.83 1165.98,196.23 C1157.47,195.62 1144.00,196.83 1144.00,198.20 C1144.00,198.77 1145.53,201.77 1147.39,204.87 C1145.53,201.77 1144.00,198.89 1144.00,198.46 C1144.00,198.04 1142.19,195.85 1139.99,193.59 C1137.78,191.34 1134.74,188.22 1133.24,186.65 C1127.62,180.81 1112.05,171.97 1105.41,170.78 C1107.93,170.84 1112.45,169.46 1121.24,166.00 C1138.23,159.32 1157.80,152.80 1170.50,149.59 C1218.80,137.37 1251.17,146.42 1258.57,174.24 C1267.44,207.55 1234.44,267.03 1171.32,331.50 L 1161.53 341.50 L 1161.48 357.12 C1161.43,356.07 1161.37,355.07 1161.29,354.12 L 1160.50 343.74 L 1151.50 352.03 C1134.33,367.82 1132.44,369.53 1126.49,374.56 C1123.19,377.34 1117.35,382.21 1113.50,385.38 C1109.65,388.56 1105.60,391.94 1104.50,392.90 C1101.28,395.70 1091.66,403.33 1088.60,405.50 C1087.05,406.60 1083.37,409.30 1080.42,411.50 C1059.19,427.34 1051.66,432.43 1025.42,448.69 C1010.72,457.80 1006.02,460.55 997.50,465.04 C992.00,467.93 987.05,470.65 986.50,471.06 C985.95,471.47 979.49,474.83 972.15,478.51 C964.81,482.19 959.18,485.58 959.65,486.05 C960.30,486.69 962.24,487.21 965.94,487.61 C963.89,487.44 962.44,487.26 961.50,487.06 L 955.50 485.76 L 943.50 490.80 C921.92,499.86 902.62,505.99 883.00,510.03 C871.45,512.40 842.75,513.62 835.50,512.04 C822.79,509.28 813.50,503.48 807.62,494.62 L 803.98 489.13 L 796.50 488.99 L 804.22 489.00 ZM 905.64 533.57 C896.06,535.25 896.00,535.25 896.00,534.14 C896.00,533.66 899.26,532.48 903.25,531.52 C909.70,529.96 927.81,524.08 935.25,521.14 C937.53,520.23 938.00,519.44 938.00,516.48 C938.00,509.26 943.29,504.00 950.53,504.00 C955.94,504.00 961.54,508.58 963.07,514.25 C966.26,526.10 953.28,534.63 942.95,527.47 C939.79,525.28 938.91,525.08 936.40,526.04 C931.87,527.76 914.62,531.98 905.64,533.57 ZM 1119.13 157.43 C1117.46,158.30 1114.22,159.00 1111.93,159.00 C1108.42,159.00 1107.15,158.39 1103.88,155.12 C1100.32,151.55 1100.00,150.79 1100.00,145.75 C1100.00,139.49 1102.04,136.05 1106.98,134.01 C1110.91,132.38 1117.21,133.23 1120.54,135.85 C1122.67,137.53 1123.62,137.71 1125.82,136.87 C1133.46,133.92 1155.51,128.64 1166.41,126.80 C1165.51,126.99 1164.53,127.21 1163.50,127.48 C1158.83,128.68 1158.73,128.77 1162.00,128.80 C1163.35,128.82 1165.43,128.54 1167.30,128.12 C1166.23,128.41 1165.05,128.72 1163.79,129.02 C1154.63,131.26 1133.67,138.57 1127.94,141.53 C1125.68,142.70 1125.00,143.74 1125.00,146.06 C1125.00,150.77 1122.45,155.72 1119.13,157.43 ZM 807.50 386.63 C804.55,382.13 809.40,376.40 814.51,378.36 C817.20,379.40 818.51,383.68 817.00,386.51 C815.16,389.94 809.71,390.01 807.50,386.63 ZM 766.48 471.20 C766.05,448.49 766.00,393.72 766.00,261.88 C766.00,103.18 766.01,56.97 766.73,42.79 C766.02,56.96 766.07,103.22 766.25,262.22 ZM 1156.09 227.13 C1157.94,234.97 1158.95,243.50 1159.00,252.26 C1158.60,242.47 1157.67,234.29 1156.09,227.13 ZM 1161.13 385.96 C1160.55,399.03 1159.02,404.69 1154.94,414.49 C1153.90,417.00 1152.25,420.08 1150.43,423.03 C1154.62,416.14 1157.89,408.00 1159.55,400.14 C1160.21,397.02 1160.75,391.88 1161.13,385.96 ZM 1032.93 488.87 C1052.58,488.83 1060.25,488.53 1064.58,487.74 C1060.13,488.66 1053.62,488.94 1032.93,488.87 ZM 905.87 443.73 C902.29,437.54 900.07,432.51 898.65,426.02 C899.80,430.82 901.47,435.06 904.19,440.50 C904.79,441.70 905.34,442.77 905.87,443.73 ZM 975.01 416.25 C975.42,416.45 975.88,416.64 976.38,416.82 C973.05,415.68 970.90,413.86 969.96,411.38 C969.80,410.99 969.67,408.38 969.55,403.84 C969.73,408.97 969.97,411.38 970.28,412.00 C970.97,413.38 973.10,415.29 975.01,416.25 ZM 969.00 324.18 C969.01,257.37 969.04,243.16 970.08,238.52 C969.05,243.17 969.01,257.42 969.02,324.50 C969.02,334.90 969.03,344.15 969.04,352.36 C969.02,343.71 969.00,334.28 969.00,324.18 ZM 1170.13 127.31 C1172.20,126.57 1172.32,126.19 1171.17,126.17 C1171.98,126.12 1172.49,126.15 1172.62,126.29 C1172.75,126.42 1171.79,126.80 1170.13,127.31 ZM 769.01 487.71 C768.36,487.54 767.92,487.35 767.65,487.13 C767.60,487.09 767.55,487.03 767.51,486.95 L 769.00 487.71 Z\" fill=\"rgb(216,112,44)\"/>\n</g>\n</svg>`;\nexport const tabbarLogoSvg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1024\" height=\"1024\" viewBox=\"0 0 1024 1024\">\n<g>\n<path d=\"M 318.50 710.49 C315.20,711.26 311.55,712.17 310.40,712.52 C307.71,713.33 306.05,711.65 301.13,703.18 C293.61,690.23 288.22,675.88 285.58,661.76 C282.40,644.82 281.97,629.53 282.56,555.82 C282.88,515.84 282.77,482.31 282.32,481.32 C281.87,480.32 281.75,449.12 282.06,412.00 L 282.61 344.50 L 285.27 334.50 C288.45,322.58 295.99,307.08 304.32,295.38 C314.87,280.54 322.55,273.94 380.00,230.25 C429.66,192.50 443.04,185.40 469.17,182.96 C485.43,181.44 640.59,182.24 653.00,183.91 C663.20,185.28 679.81,189.55 681.96,191.36 C682.80,192.08 685.97,193.69 689.00,194.95 C692.03,196.20 696.97,198.70 700.00,200.49 C703.03,202.28 706.94,204.59 708.69,205.62 C720.60,212.62 725.49,217.04 745.14,238.56 C759.73,254.53 769.58,277.30 775.20,308.00 C776.94,317.54 777.38,324.66 777.74,349.72 L 778.18 379.95 L 769.84 390.09 C765.25,395.66 758.09,403.89 753.92,408.36 C749.75,412.84 743.50,419.88 740.04,424.00 C736.57,428.12 728.06,437.18 721.12,444.13 C714.18,451.08 706.91,458.50 704.97,460.63 C703.02,462.76 696.56,469.00 690.59,474.50 C676.24,487.74 665.08,498.19 657.61,505.39 C651.89,510.90 646.43,514.99 644.78,515.00 C644.38,515.00 643.93,470.79 643.78,416.75 L 643.50 318.50 L 641.33 314.46 C638.38,308.94 631.03,302.38 626.35,301.08 C623.75,300.36 593.15,300.01 531.79,300.01 C442.88,300.00 440.97,300.04 435.62,302.04 C429.58,304.30 424.10,309.57 421.38,315.73 C419.85,319.19 419.71,332.47 419.61,477.50 L 419.50 635.50 L 421.71 639.62 C425.88,647.44 433.20,652.01 442.74,652.77 C446.46,653.07 448.93,653.71 448.73,654.31 C448.19,655.93 436.40,662.87 426.50,667.40 C421.55,669.66 413.55,673.66 408.71,676.28 C403.88,678.90 396.68,682.36 392.71,683.95 C388.75,685.55 382.79,688.18 379.47,689.81 C376.15,691.44 371.26,693.51 368.60,694.41 C365.94,695.32 362.80,696.58 361.63,697.21 C360.46,697.85 356.80,699.14 353.50,700.10 C350.20,701.05 342.33,703.46 336.00,705.46 C329.67,707.45 321.80,709.72 318.50,710.49 ZM 590.03 786.96 C576.83,788.58 441.72,788.11 426.00,786.40 C412.11,784.88 402.89,782.97 402.86,781.60 C402.83,780.50 407.87,777.80 434.00,764.91 C458.43,752.86 468.21,747.76 473.23,744.45 C475.28,743.10 477.22,742.00 477.55,742.00 C478.06,742.00 490.62,734.77 495.00,731.96 C495.83,731.43 497.51,730.56 498.74,730.03 C501.03,729.03 511.25,722.59 521.00,715.98 C524.03,713.93 528.75,711.06 531.50,709.60 C534.25,708.14 540.33,704.49 545.00,701.50 C549.67,698.50 554.88,695.40 556.57,694.59 C558.25,693.78 562.75,690.70 566.57,687.73 C572.88,682.81 586.92,673.39 595.22,668.51 C599.11,666.22 605.83,661.28 611.01,656.89 C614.04,654.32 619.44,650.24 623.01,647.83 C635.20,639.59 657.62,622.53 670.00,612.08 C679.61,603.97 685.79,599.08 688.60,597.38 C690.31,596.35 696.26,591.28 701.82,586.12 C707.38,580.96 714.96,574.43 718.67,571.62 C722.37,568.80 729.70,562.41 734.95,557.42 C740.20,552.42 748.55,544.78 753.50,540.43 C758.45,536.09 765.17,529.68 768.43,526.20 C774.29,519.94 779.57,516.24 780.84,517.51 C782.11,518.78 782.23,597.03 780.98,606.00 C778.42,624.31 774.06,638.87 766.75,653.50 C760.23,666.57 754.14,674.86 742.50,686.54 C726.82,702.27 680.51,739.24 645.50,763.99 C627.99,776.36 607.61,784.80 590.03,786.96 Z\" fill=\"rgb(100,102,88)\"/>\n<path d=\"M 781.70 537.56 C781.54,526.19 781.25,517.91 780.84,517.51 C779.57,516.24 774.29,519.94 768.43,526.20 C765.17,529.68 758.45,536.09 753.50,540.43 C748.55,544.78 740.20,552.42 734.95,557.42 C729.70,562.41 722.37,568.80 718.67,571.62 C714.96,574.43 707.38,580.96 701.82,586.12 C696.26,591.28 690.31,596.35 688.60,597.38 C685.79,599.08 679.61,603.97 670.00,612.08 C657.62,622.53 635.20,639.59 623.01,647.83 C619.44,650.24 614.04,654.32 611.01,656.89 C605.83,661.28 599.11,666.22 595.22,668.51 C586.92,673.39 572.88,682.81 566.57,687.73 C562.75,690.70 558.25,693.78 556.57,694.59 C554.88,695.40 549.67,698.50 545.00,701.50 C540.33,704.49 534.25,708.14 531.50,709.60 C528.75,711.06 524.03,713.93 521.00,715.98 C511.25,722.59 501.03,729.03 498.74,730.03 C497.51,730.56 495.83,731.43 495.00,731.96 C490.62,734.77 478.06,742.00 477.55,742.00 C477.22,742.00 475.28,743.10 473.23,744.45 C468.21,747.76 458.43,752.86 434.00,764.91 C407.87,777.80 402.83,780.50 402.86,781.60 C402.88,782.29 405.26,783.13 409.41,783.98 C403.38,782.89 398.48,781.78 397.22,781.09 C396.96,780.94 396.71,780.85 396.67,780.69 C396.48,780.02 400.05,778.29 422.41,767.46 L 425.35 766.03 C436.82,760.48 449.65,753.98 453.85,751.59 C458.06,749.20 470.73,742.16 482.00,735.95 C493.27,729.74 507.23,721.66 513.00,717.99 C518.78,714.32 529.58,707.57 537.00,702.99 C552.59,693.37 587.09,670.61 597.88,662.83 C601.94,659.90 609.14,654.70 613.88,651.28 C618.62,647.86 625.79,642.69 629.81,639.78 C646.64,627.62 701.04,583.66 709.50,575.38 C711.70,573.23 716.04,569.55 719.14,567.20 C722.24,564.85 729.44,558.55 735.14,553.21 C740.84,547.86 747.97,541.38 751.00,538.81 C754.03,536.24 762.12,528.64 769.00,521.92 L 781.50 509.70 ZM 643.50 318.50 L 643.78 416.75 C643.93,470.79 644.38,515.00 644.78,515.00 C646.43,514.99 651.89,510.90 657.61,505.39 C665.08,498.19 676.24,487.74 690.59,474.50 C696.56,469.00 703.02,462.76 704.97,460.63 C706.91,458.50 714.18,451.08 721.12,444.13 C728.06,437.18 736.57,428.12 740.04,424.00 C743.50,419.88 749.75,412.84 753.92,408.36 C758.09,403.89 765.25,395.66 769.84,390.09 L 778.15 379.97 L 778.17 384.09 L 775.38 387.79 C770.92,393.70 756.87,410.31 754.47,412.50 C753.27,413.60 746.65,420.80 739.76,428.50 C732.87,436.20 725.50,444.13 723.37,446.11 C721.24,448.10 716.51,452.83 712.86,456.61 C706.74,462.96 683.75,485.05 669.50,498.26 C666.20,501.32 660.58,506.55 657.00,509.89 C653.42,513.23 650.20,515.97 649.83,515.98 C649.46,515.99 647.88,517.07 646.33,518.38 L 643.50 520.76 L 643.50 318.50 ZM 318.50 710.49 C321.80,709.72 329.67,707.45 336.00,705.46 C342.33,703.46 350.20,701.05 353.50,700.10 C356.80,699.14 360.46,697.85 361.63,697.21 C362.80,696.58 365.94,695.32 368.60,694.41 C371.26,693.51 376.15,691.44 379.47,689.81 C382.79,688.18 388.75,685.55 392.71,683.95 C396.68,682.36 403.88,678.90 408.71,676.28 C413.55,673.66 421.55,669.66 426.50,667.40 C436.40,662.87 448.19,655.93 448.73,654.31 C448.93,653.71 446.46,653.07 442.74,652.77 C442.25,652.73 441.77,652.68 441.29,652.62 C443.73,652.85 446.67,652.99 449.37,652.99 C457.15,653.00 458.09,653.19 457.00,654.50 C456.32,655.33 455.25,656.00 454.63,656.00 C454.01,656.00 449.72,658.25 445.10,661.00 C440.47,663.75 436.42,666.00 436.10,666.01 C435.77,666.01 434.15,666.72 432.50,667.58 C412.88,677.87 396.05,685.98 385.00,690.48 C381.42,691.94 376.70,693.94 374.50,694.94 C372.30,695.93 365.77,698.40 360.00,700.42 C354.23,702.44 348.47,704.52 347.21,705.04 C344.40,706.21 329.70,710.39 317.12,713.60 C306.12,716.42 305.90,716.44 306.61,714.57 C306.88,713.87 305.48,710.61 303.40,706.97 C306.65,712.16 308.17,713.19 310.40,712.52 C311.55,712.17 315.20,711.26 318.50,710.49 ZM 284.60 655.99 C284.35,654.52 284.12,653.03 283.89,651.50 C282.48,642.17 280.91,588.39 280.35,530.25 C280.07,501.54 279.52,483.00 278.95,483.00 C277.33,483.00 277.91,480.39 279.94,478.56 C281.18,477.44 281.63,476.05 281.89,456.65 C281.93,471.24 282.07,480.77 282.32,481.32 C282.77,482.31 282.88,515.84 282.56,555.82 C282.03,621.19 282.32,640.61 284.60,655.99 ZM 758.58 257.58 C754.65,250.40 750.18,244.08 745.14,238.56 C725.49,217.04 720.60,212.62 708.69,205.62 C706.94,204.59 703.03,202.28 700.00,200.49 C696.97,198.70 692.03,196.20 689.00,194.95 C685.97,193.69 682.80,192.08 681.96,191.36 C680.19,189.88 668.68,186.73 658.97,184.89 C662.69,185.57 666.66,186.40 669.44,187.12 C676.94,189.03 681.06,189.14 685.18,187.51 C686.44,187.01 686.75,187.29 686.44,188.67 C686.10,190.13 688.06,191.50 696.26,195.49 C715.66,204.95 722.25,210.17 745.24,234.29 C747.30,236.45 748.73,238.63 748.41,239.14 C748.10,239.65 750.07,243.53 752.79,247.78 C754.88,251.04 756.80,254.29 758.58,257.58 ZM 280.81 873.85 C275.48,874.48 270.19,875.00 269.06,875.00 C266.03,875.00 266.55,873.31 269.75,872.73 C271.26,872.46 276.46,871.50 281.31,870.60 C286.44,869.65 290.75,869.32 291.62,869.81 C294.39,871.36 290.93,872.65 280.81,873.85 ZM 798.26 106.91 C789.36,109.48 788.09,109.51 788.27,107.12 C788.41,105.18 789.34,104.99 806.00,103.53 C810.21,103.16 810.80,103.26 808.50,103.93 C806.85,104.42 802.24,105.76 798.26,106.91 ZM 782.43 111.02 C778.94,112.35 775.85,112.20 773.73,110.59 C772.06,109.33 772.09,109.21 774.23,108.64 C777.89,107.65 785.00,107.91 785.00,109.02 C785.00,109.59 783.85,110.49 782.43,111.02 ZM 778.14 377.74 L 777.74 349.72 C777.53,335.58 777.31,327.14 776.83,320.77 C777.69,328.88 777.97,337.95 778.05,355.62 ZM 781.40 599.34 C781.72,590.47 781.87,575.02 781.86,559.90 C781.97,579.09 781.91,590.69 781.40,599.34 ZM 432.42 650.07 C427.85,647.83 424.21,644.31 421.71,639.62 L 419.50 635.50 L 422.00 639.95 C424.15,643.79 428.28,647.69 432.42,650.07 ZM 697.02 725.24 C710.23,714.79 722.38,704.75 731.50,696.72 C725.40,702.21 718.52,708.06 711.00,714.13 C706.63,717.66 701.91,721.41 697.02,725.24 ZM 421.63 785.89 C423.03,786.06 424.49,786.23 426.00,786.40 C431.73,787.02 453.28,787.48 479.02,787.73 C453.57,787.51 432.39,787.10 427.00,786.53 C425.29,786.35 423.48,786.13 421.63,785.89 ZM 749.23 679.46 C754.57,673.54 758.57,668.13 762.28,661.81 C760.95,664.10 759.56,666.33 758.13,668.50 C756.07,671.62 753.06,675.31 749.23,679.46 ZM 299.40 700.11 C295.31,692.73 292.17,685.52 289.67,677.63 C292.19,685.32 295.47,692.91 299.40,700.11 ZM 771.50 291.24 C768.94,281.46 765.84,272.64 762.18,264.73 C766.02,272.94 769.06,281.57 771.50,291.24 ZM 774.58 634.52 C777.00,627.13 778.85,619.38 780.25,610.83 C779.68,614.64 778.93,618.27 777.96,622.51 C777.05,626.48 775.92,630.50 774.58,634.52 ZM 282.56 350.91 L 282.59 344.50 L 285.27 334.50 C286.44,330.10 288.21,325.21 290.40,320.20 C294.13,311.65 299.07,302.76 304.32,295.38 C299.07,302.75 294.13,311.64 290.40,320.20 C288.22,325.20 286.45,330.10 285.27,334.50 L 282.61 344.50 Z\" fill=\"rgb(146,104,68)\"/>\n<path d=\"M 781.70 537.56 L 781.50 509.70 L 769.00 521.92 C762.12,528.64 754.03,536.24 751.00,538.81 C747.97,541.38 740.84,547.86 735.14,553.21 C729.44,558.55 722.24,564.85 719.14,567.20 C716.04,569.55 711.70,573.23 709.50,575.38 C701.04,583.66 646.64,627.62 629.81,639.78 C625.79,642.69 618.62,647.86 613.88,651.28 C609.14,654.70 601.94,659.90 597.88,662.83 C587.09,670.61 552.59,693.37 537.00,702.99 C529.58,707.57 518.78,714.32 513.00,717.99 C507.23,721.66 493.27,729.74 482.00,735.95 C470.73,742.16 458.06,749.20 453.85,751.59 C449.65,753.98 436.82,760.48 425.35,766.03 L 422.41 767.46 C400.05,778.29 396.48,780.02 396.67,780.69 C396.71,780.85 396.96,780.94 397.22,781.09 C398.14,781.59 401.00,782.32 404.83,783.10 C400.40,782.42 396.22,782.06 394.54,782.25 C392.32,782.50 384.65,785.22 377.50,788.29 C324.99,810.83 278.31,824.81 236.50,830.51 C222.36,832.44 186.45,833.29 176.60,831.93 C146.13,827.72 122.52,813.00 112.24,791.81 C107.92,782.91 104.51,770.53 103.48,760.00 C102.78,752.89 104.89,734.09 107.55,723.75 C123.45,661.92 177.67,581.88 260.13,498.50 L 280.48 477.92 C280.32,478.19 280.14,478.38 279.94,478.56 C277.91,480.39 277.33,483.00 278.95,483.00 C279.52,483.00 280.07,501.54 280.35,530.25 C280.51,547.00 280.76,563.38 281.06,578.45 C280.72,575.03 280.29,573.32 279.80,573.62 C278.84,574.22 266.21,590.12 262.02,596.02 C245.24,619.64 235.17,638.56 228.41,659.15 C226.13,666.09 225.66,669.36 225.59,678.50 C225.51,688.55 225.74,690.02 228.30,695.50 C233.60,706.86 243.51,714.27 257.60,717.42 C269.81,720.16 304.59,718.03 306.64,714.48 C306.63,714.51 306.62,714.54 306.61,714.57 C305.90,716.44 306.12,716.42 317.12,713.60 C329.70,710.39 344.40,706.21 347.21,705.04 C348.47,704.52 354.23,702.44 360.00,700.42 C365.77,698.40 372.30,695.93 374.50,694.94 C376.70,693.94 381.42,691.94 385.00,690.48 C396.05,685.98 412.88,677.87 432.50,667.58 C434.15,666.72 435.77,666.01 436.10,666.01 C436.42,666.00 440.47,663.75 445.10,661.00 C449.72,658.25 454.01,656.00 454.63,656.00 C455.25,656.00 456.32,655.33 457.00,654.50 C458.09,653.19 457.15,653.00 449.37,652.99 C446.67,652.99 443.73,652.85 441.29,652.62 C440.58,652.54 439.89,652.43 439.20,652.29 C441.95,652.69 445.60,652.94 449.18,652.96 L 458.86 653.00 L 474.18 643.88 C499.68,628.70 540.63,601.07 574.06,576.50 C589.46,565.18 608.69,549.97 635.17,528.16 L 642.84 521.84 L 643.48 514.67 C643.49,514.61 643.49,514.54 643.50,514.46 L 643.50 520.76 L 646.33 518.38 C647.88,517.07 649.46,515.99 649.83,515.98 C650.20,515.97 653.42,513.23 657.00,509.89 C660.58,506.55 666.20,501.32 669.50,498.26 C683.75,485.05 706.74,462.96 712.86,456.61 C716.51,452.83 721.24,448.10 723.37,446.11 C725.50,444.13 732.87,436.20 739.76,428.50 C746.65,420.80 753.27,413.60 754.47,412.50 C756.87,410.31 770.92,393.70 775.38,387.79 L 778.17 384.09 L 778.15 379.97 L 778.18 379.95 L 778.14 377.74 L 778.11 370.82 C778.28,378.15 778.64,380.00 779.41,380.00 C782.68,380.00 801.47,353.32 812.87,332.48 C835.22,291.62 837.69,266.88 821.15,249.67 C812.95,241.14 802.62,237.34 785.00,236.36 C774.77,235.79 750.50,238.10 748.81,239.79 C748.42,240.18 750.14,243.65 752.64,247.50 C757.04,254.29 760.75,261.20 763.90,268.56 C763.34,267.27 762.77,266.00 762.18,264.73 C761.03,262.26 759.83,259.88 758.58,257.58 L 758.58 257.58 C756.80,254.29 754.87,251.04 752.79,247.78 C750.07,243.53 748.10,239.65 748.41,239.14 C748.73,238.63 747.30,236.45 745.24,234.29 C722.25,210.17 715.66,204.95 696.26,195.49 C688.06,191.50 686.10,190.13 686.44,188.67 C686.75,187.29 686.44,187.01 685.18,187.51 C684.02,187.96 682.87,188.28 681.64,188.47 C682.98,188.11 684.41,187.50 686.31,186.63 C691.13,184.43 700.14,180.81 724.00,171.48 C736.74,166.49 769.12,155.80 781.50,152.49 C801.94,147.02 810.10,145.06 820.67,143.08 C866.29,134.55 901.31,136.66 927.50,149.50 C956.65,163.80 970.01,190.29 966.83,227.50 C964.79,251.49 956.10,277.76 939.97,308.73 C927.29,333.08 918.62,346.99 895.55,380.00 C890.20,387.66 869.70,414.27 863.58,421.50 C840.94,448.26 822.56,468.41 798.79,492.56 L 782.00 509.63 L 781.98 555.06 C781.98,563.66 781.95,570.95 781.90,577.14 C781.92,572.16 781.90,566.48 781.86,559.90 L 781.86 559.90 C781.85,552.03 781.80,544.26 781.70,537.56 ZM 274.21 871.91 C276.59,871.40 279.42,870.88 282.50,870.38 C284.70,870.03 286.95,869.40 287.50,868.99 C288.05,868.57 290.08,867.90 292.00,867.49 C303.53,865.03 332.38,855.82 349.50,849.14 L 359.50 845.23 L 360.04 837.76 C360.78,827.49 364.43,821.92 373.50,817.20 C389.33,808.95 408.27,820.03 409.74,838.40 C410.40,846.62 408.82,851.21 403.27,857.15 C397.51,863.30 391.96,865.49 384.20,864.68 C377.10,863.94 372.26,861.99 369.08,858.59 C365.99,855.29 363.89,855.34 352.11,858.94 C333.73,864.57 308.96,869.89 286.73,873.01 C292.19,872.04 293.75,871.00 291.62,869.81 C290.75,869.32 286.44,869.65 281.31,870.60 C278.86,871.05 276.32,871.52 274.21,871.91 ZM 701.98 163.75 C697.33,166.56 695.69,166.99 690.04,166.96 C679.39,166.90 672.36,162.46 667.33,152.63 C665.21,148.47 664.91,146.79 665.32,141.13 C666.03,131.16 666.55,129.36 669.93,125.08 C675.28,118.34 686.36,114.67 694.67,116.91 C698.28,117.88 700.08,118.94 707.62,124.49 C709.56,125.93 710.29,125.86 716.62,123.64 C733.17,117.83 753.19,112.39 767.00,109.94 C770.58,109.30 774.18,108.45 775.01,108.03 C775.85,107.62 780.57,106.74 785.51,106.08 C786.77,105.92 788.12,105.73 789.49,105.53 C788.48,105.93 788.32,106.40 788.27,107.12 C788.16,108.49 788.54,109.07 790.58,108.82 L 790.00 108.97 C787.42,109.65 784.99,110.30 782.67,110.93 C783.97,110.39 785.00,109.56 785.00,109.02 C785.00,107.91 777.89,107.65 774.23,108.64 C772.09,109.21 772.06,109.33 773.73,110.59 C775.22,111.72 777.20,112.14 779.46,111.81 C763.55,116.24 752.65,120.02 734.88,127.04 C720.30,132.80 716.03,134.23 714.64,137.08 C713.93,138.53 713.98,140.36 713.79,143.34 C713.17,153.07 709.67,159.11 701.98,163.75 ZM 131.60 596.60 C127.85,600.35 124.66,600.86 119.38,598.56 C115.11,596.70 113.00,593.34 113.00,588.38 C113.00,584.83 113.54,583.73 116.66,580.99 C119.99,578.07 120.78,577.82 125.35,578.26 C131.82,578.88 134.99,582.36 135.00,588.85 C135.00,592.47 134.43,593.77 131.60,596.60 ZM 427.75 786.60 C434.16,787.14 454.63,787.52 479.02,787.73 C497.78,787.92 518.78,787.99 537.47,787.94 C494.78,788.14 440.51,787.81 431.05,786.94 C430.03,786.85 428.92,786.73 427.75,786.60 ZM 803.21 105.47 C805.51,104.81 807.52,104.22 808.50,103.93 C810.80,103.26 810.21,103.16 806.00,103.53 C802.83,103.81 800.24,104.04 798.10,104.25 C798.79,104.13 799.41,104.03 799.92,103.94 C802.90,103.42 806.72,103.05 808.42,103.10 L 811.50 103.20 L 808.50 104.05 C807.79,104.25 805.86,104.77 803.21,105.47 ZM 774.58 634.52 L 774.58 634.52 C774.87,633.64 775.15,632.77 775.43,631.90 C772.09,643.14 767.72,653.05 762.01,662.27 C762.10,662.11 762.19,661.96 762.28,661.81 C763.79,659.22 765.26,656.49 766.75,653.50 C769.87,647.26 772.45,641.03 774.58,634.52 ZM 282.08 617.93 C282.36,626.68 282.67,634.14 282.98,639.89 C282.49,633.20 282.20,625.93 282.08,617.93 ZM 776.77 320.01 C777.55,326.73 777.87,333.52 777.96,345.02 C777.82,333.96 777.50,327.07 776.83,320.77 C776.81,320.51 776.79,320.26 776.77,320.01 ZM 288.38 673.48 C288.79,674.87 289.22,676.25 289.67,677.63 C292.17,685.52 295.31,692.73 299.40,700.11 C294.63,691.51 291.03,682.98 288.38,673.48 ZM 423.56 642.32 C422.97,641.53 422.44,640.74 422.00,639.95 L 419.50 635.50 L 422.00 639.91 C422.47,640.73 422.99,641.54 423.56,642.32 ZM 780.88 606.72 C780.78,607.57 780.68,608.32 780.57,609.00 C780.44,609.79 780.31,610.56 780.17,611.34 C780.20,611.17 780.22,611.00 780.25,610.83 C780.47,609.48 780.68,608.11 780.88,606.72 ZM 670.37 187.35 C670.07,187.27 669.76,187.20 669.44,187.12 C666.66,186.40 662.69,185.57 658.97,184.89 C658.76,184.85 658.55,184.81 658.35,184.77 C662.17,185.45 666.30,186.31 669.11,187.03 C669.55,187.14 669.97,187.25 670.37,187.35 ZM 781.40 599.34 C781.44,598.68 781.47,598.01 781.51,597.32 C781.45,598.70 781.39,599.96 781.33,601.11 C781.35,600.55 781.37,599.96 781.40,599.34 ZM 267.53 874.77 C267.15,874.65 267.00,874.46 267.00,874.21 C267.00,874.16 267.03,874.11 267.08,874.05 C266.98,874.33 267.12,874.59 267.53,874.77 ZM 275.15 874.48 C273.78,874.63 272.63,874.75 271.66,874.82 C272.64,874.73 273.84,874.62 275.15,874.48 Z\" fill=\"rgb(215,111,43)\"/>\n</g>\n</svg>`;\n","/**\n * Cell Buttons Plugin\n * Injects E, F, ? action buttons into notebook cells\n * Communicates with sidebar panel instead of Chrome extension\n */\nimport { INotebookTracker } from '@jupyterlab/notebook';\nimport { CellAction } from '../types';\n/**\n * Cell Buttons Plugin\n */\nexport const cellButtonsPlugin = {\n id: '@hdsp-agent/cell-buttons',\n autoStart: true,\n requires: [INotebookTracker],\n activate: (app, notebookTracker) => {\n console.log('[CellButtonsPlugin] Activated');\n // Store app reference globally for later use\n window.jupyterapp = app;\n // Handle new notebooks\n notebookTracker.widgetAdded.connect((sender, panel) => {\n console.log('[CellButtonsPlugin] Notebook widget added:', panel.id);\n // Wait for session to be ready\n panel.sessionContext.ready.then(() => {\n observeNotebook(panel);\n }).catch(err => {\n console.error('[CellButtonsPlugin] Error waiting for session:', err);\n });\n });\n // Handle current notebook if exists\n if (notebookTracker.currentWidget) {\n observeNotebook(notebookTracker.currentWidget);\n }\n // Handle notebook focus changes\n notebookTracker.currentChanged.connect((sender, panel) => {\n if (panel) {\n observeNotebook(panel);\n }\n });\n }\n};\n/**\n * Observe a notebook for cell changes and inject buttons\n */\nfunction observeNotebook(panel) {\n const notebook = panel.content;\n // Initial injection with delay to ensure cells are rendered\n setTimeout(() => {\n injectButtonsIntoAllCells(notebook, panel);\n // Retry after longer delay for cells that weren't ready\n setTimeout(() => {\n injectButtonsIntoAllCells(notebook, panel);\n }, 500);\n }, 200);\n // Watch for cell changes (add/remove/reorder)\n const cellsChangedHandler = () => {\n setTimeout(() => {\n injectButtonsIntoAllCells(notebook, panel);\n }, 100);\n };\n // Remove any previous listeners to avoid duplicates\n try {\n notebook.model?.cells.changed.disconnect(cellsChangedHandler);\n }\n catch {\n // Ignore if not connected\n }\n // Connect new listener\n notebook.model?.cells.changed.connect(cellsChangedHandler);\n}\n/**\n * Inject buttons into all cells in a notebook\n */\nfunction injectButtonsIntoAllCells(notebook, panel) {\n for (let i = 0; i < notebook.widgets.length; i++) {\n const cell = notebook.widgets[i];\n injectButtonsIntoCell(cell, panel);\n }\n}\n/**\n * Inject buttons into a single cell\n * Buttons are placed outside the cell (above), aligned with code start position\n */\nfunction injectButtonsIntoCell(cell, panel) {\n // Safety checks\n if (!cell || !cell.model) {\n return;\n }\n // Only inject buttons into code cells (not markdown, raw, etc.)\n if (cell.model.type !== 'code') {\n return;\n }\n const cellNode = cell.node;\n if (!cellNode || !cellNode.classList.contains('jp-CodeCell')) {\n return;\n }\n // Check if buttons already exist (using our unique class name)\n if (cellNode.querySelector('.jp-hdsp-cell-buttons')) {\n return;\n }\n // Find the prompt area to get the correct left offset\n const promptNode = cellNode.querySelector('.jp-InputPrompt, .jp-OutputPrompt');\n const promptWidth = promptNode ? promptNode.getBoundingClientRect().width : 64;\n // Find the input wrapper to insert before\n const inputWrapper = cellNode.querySelector('.jp-Cell-inputWrapper');\n if (!inputWrapper) {\n return;\n }\n // Create button container with unique class name to avoid conflicts\n const buttonContainer = document.createElement('div');\n buttonContainer.className = 'jp-hdsp-cell-buttons';\n buttonContainer.style.cssText = `\n display: flex;\n gap: 4px;\n padding: 4px 8px;\n padding-left: ${promptWidth}px;\n background: transparent;\n `;\n // Create E button (Explain)\n const explainBtn = createButton('E', '์ค๋ช
์์ฒญ', () => {\n handleCellAction(CellAction.EXPLAIN, cell);\n });\n // Create F button (Fix)\n const fixBtn = createButton('F', '์์ ์ ์ ์์ฒญ', () => {\n handleCellAction(CellAction.FIX, cell);\n });\n // Create ? button (Custom Prompt)\n const customBtn = createButton('?', '์ง๋ฌธํ๊ธฐ', () => {\n handleCellAction(CellAction.CUSTOM_PROMPT, cell);\n });\n buttonContainer.appendChild(explainBtn);\n buttonContainer.appendChild(fixBtn);\n buttonContainer.appendChild(customBtn);\n // Insert before the input wrapper (outside the cell, above it)\n inputWrapper.parentNode?.insertBefore(buttonContainer, inputWrapper);\n}\n/**\n * Create a button element\n */\nfunction createButton(label, title, onClick) {\n const btn = document.createElement('button');\n btn.className = 'jp-agent-button';\n btn.textContent = label;\n btn.title = title;\n btn.setAttribute('aria-label', title);\n btn.onclick = onClick;\n // Add inline styles as fallback\n btn.style.cssText = `\n width: 24px !important;\n height: 24px !important;\n border: 1px solid #ddd !important;\n border-radius: 4px !important;\n background: white !important;\n cursor: pointer !important;\n display: inline-flex !important;\n align-items: center !important;\n justify-content: center !important;\n font-size: 12px !important;\n font-weight: bold !important;\n color: #333 !important;\n padding: 0 !important;\n margin: 0 2px !important;\n opacity: 1 !important;\n visibility: visible !important;\n `;\n return btn;\n}\n/**\n * Handle cell action button click\n */\nasync function handleCellAction(action, cell) {\n const cellContent = cell?.model?.sharedModel?.getSource() || '';\n if (!cellContent.trim()) {\n showNotification('์
๋ด์ฉ์ด ๋น์ด์์ต๋๋ค.', 'warning');\n return;\n }\n const cellIndex = getCellIndex(cell);\n if (action === CellAction.CUSTOM_PROMPT) {\n // For custom prompt, show dialog (no confirmation needed)\n showCustomPromptDialog(cell);\n }\n else {\n // Get cell output\n const cellOutput = getCellOutput(cell);\n // Determine confirmation dialog content based on action\n let title = '';\n let message = '';\n switch (action) {\n case CellAction.EXPLAIN:\n title = `์
${cellIndex}๋ฒ์งธ: ์ค๋ช
์์ฒญ`;\n message = '์ด ์
์ ์ฝ๋ ์ค๋ช
์ ๋ณด์๊ฒ ์ต๋๊น?';\n break;\n case CellAction.FIX:\n title = `์
${cellIndex}๋ฒ์งธ: ์์ ์ ์ ์์ฒญ`;\n message = '์ด ์
์ ์ฝ๋ ๊ฐ์ ์ ์์ ๋ฐ์ผ์๊ฒ ์ต๋๊น?';\n break;\n }\n // Show confirmation dialog first\n const confirmed = await showConfirmDialog(title, message);\n if (confirmed) {\n // User confirmed, send to sidebar panel\n sendToSidebarPanel(action, cell, cellContent, cellIndex, cellOutput);\n }\n }\n}\n/**\n * Get the index of a cell in the notebook\n */\nfunction getCellIndex(cell) {\n const app = window.jupyterapp;\n const notebookTracker = app?.shell?.currentWidget?.content;\n if (!notebookTracker) {\n return -1;\n }\n const widgets = notebookTracker.widgets;\n for (let i = 0; i < widgets.length; i++) {\n if (widgets[i] === cell) {\n return i + 1; // Return 1-based index\n }\n }\n return -1;\n}\n/**\n * Extract output from a code cell\n */\nfunction getCellOutput(cell) {\n // cell.model์ด null์ผ ์ ์์ผ๋ฏ๋ก ์์ ํ๊ฒ ์ฒดํฌ\n if (!cell?.model || cell.model.type !== 'code') {\n return '';\n }\n const codeCell = cell;\n const outputs = codeCell.model?.outputs;\n if (!outputs || outputs.length === 0) {\n return '';\n }\n const outputTexts = [];\n for (let i = 0; i < outputs.length; i++) {\n const output = outputs.get(i);\n const outputType = output.type;\n if (outputType === 'stream') {\n // stdout, stderr\n const text = output.text;\n if (Array.isArray(text)) {\n outputTexts.push(text.join(''));\n }\n else {\n outputTexts.push(text);\n }\n }\n else if (outputType === 'execute_result' || outputType === 'display_data') {\n // Execution results or display data\n const data = output.data;\n if (data['text/plain']) {\n const text = data['text/plain'];\n if (Array.isArray(text)) {\n outputTexts.push(text.join(''));\n }\n else {\n outputTexts.push(text);\n }\n }\n }\n else if (outputType === 'error') {\n // Error output\n const traceback = output.traceback;\n if (Array.isArray(traceback)) {\n outputTexts.push(traceback.join('\\n'));\n }\n }\n }\n return outputTexts.join('\\n');\n}\n/**\n * Get or assign cell ID to a cell\n */\nfunction getOrAssignCellId(cell) {\n const cellModel = cell.model;\n let cellId;\n // Try to get cell ID from metadata\n try {\n if (cellModel.metadata && typeof cellModel.metadata.get === 'function') {\n cellId = cellModel.metadata.get('jupyterAgentCellId');\n }\n else if (cellModel.metadata?.jupyterAgentCellId) {\n cellId = cellModel.metadata.jupyterAgentCellId;\n }\n }\n catch (e) {\n // Ignore errors\n }\n if (!cellId) {\n cellId = `cell-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n // Try to set cell ID in metadata\n try {\n if (cellModel.metadata && typeof cellModel.metadata.set === 'function') {\n cellModel.metadata.set('jupyterAgentCellId', cellId);\n }\n else if (cellModel.metadata) {\n cellModel.metadata.jupyterAgentCellId = cellId;\n }\n }\n catch (e) {\n // Ignore errors\n }\n }\n return cellId;\n}\n/**\n * Send cell action to sidebar panel\n */\nfunction sendToSidebarPanel(action, cell, cellContent, cellIndex, cellOutput) {\n const agentPanel = window._hdspAgentPanel;\n if (!agentPanel) {\n console.error('[CellButtonsPlugin] Agent panel not found. Make sure sidebar plugin is loaded.');\n return;\n }\n // Get or assign cell ID\n const cellId = getOrAssignCellId(cell);\n // Activate the sidebar panel\n const app = window.jupyterapp;\n if (app) {\n app.shell.activateById(agentPanel.id);\n }\n // Create user-facing display prompt\n let displayPrompt = '';\n // Create actual LLM prompt (based on chrome_agent)\n // Note: Use original content, not escaped. JSON.stringify will handle escaping.\n let llmPrompt = '';\n switch (action) {\n case CellAction.EXPLAIN:\n // User sees: \"Cell x: ์ค๋ช
์์ฒญ\" (chrome_agent์ ๋์ผ)\n displayPrompt = `${cellIndex}๋ฒ์งธ ์
: ์ค๋ช
์์ฒญ`;\n // LLM receives: chrome_agent์ ๋์ผํ ํ๋กฌํํธ\n llmPrompt = `๋ค์ Jupyter ์
์ ๋ด์ฉ์ ์์ธํ ์ค๋ช
ํด์ฃผ์ธ์:\n\n\\`\\`\\`python\n${cellContent}\n\\`\\`\\``;\n break;\n case CellAction.FIX:\n // Check if there's an error in the output\n const hasError = cellOutput && (cellOutput.includes('Error') ||\n cellOutput.includes('Traceback') ||\n cellOutput.includes('Exception') ||\n cellOutput.includes('์๋ฌ') ||\n cellOutput.includes('์ค๋ฅ'));\n if (hasError && cellOutput) {\n // ์๋ฌ๊ฐ ์๋ ๊ฒฝ์ฐ (chrome_agent์ ๋์ผ)\n displayPrompt = `${cellIndex}๋ฒ์งธ ์
: ์๋ฌ ์์ ์์ฒญ`;\n llmPrompt = `๋ค์ Jupyter ์
์ฝ๋์ ์๋ฌ๊ฐ ๋ฐ์ํ์ต๋๋ค.\n\n์๋ณธ ์ฝ๋:\n\\`\\`\\`python\n${cellContent}\n\\`\\`\\`\n\n์๋ฌ:\n\\`\\`\\`\n${cellOutput}\n\\`\\`\\`\n\n๋ค์ ํ์์ผ๋ก ์๋ตํด์ฃผ์ธ์:\n\n## ์๋ฌ ์์ธ\n(์๋ฌ๊ฐ ๋ฐ์ํ ์์ธ์ ๊ฐ๋จํ ์ค๋ช
)\n\n## ์์ ๋ฐฉ๋ฒ\n\n### ๋ฐฉ๋ฒ 1: (์์ ๋ฐฉ๋ฒ ์ ๋ชฉ)\n(์ด ๋ฐฉ๋ฒ์ ๋ํ ๊ฐ๋จํ ์ค๋ช
)\n\\`\\`\\`python\n(์์ ๋ ์ฝ๋)\n\\`\\`\\`\n\n### ๋ฐฉ๋ฒ 2: (์์ ๋ฐฉ๋ฒ ์ ๋ชฉ)\n(์ด ๋ฐฉ๋ฒ์ ๋ํ ๊ฐ๋จํ ์ค๋ช
)\n\\`\\`\\`python\n(์์ ๋ ์ฝ๋)\n\\`\\`\\`\n\n### ๋ฐฉ๋ฒ 3: (์์ ๋ฐฉ๋ฒ ์ ๋ชฉ) (์๋ ๊ฒฝ์ฐ)\n(์ด ๋ฐฉ๋ฒ์ ๋ํ ๊ฐ๋จํ ์ค๋ช
)\n\\`\\`\\`python\n(์์ ๋ ์ฝ๋)\n\\`\\`\\`\n\n์ต์ 2๊ฐ, ์ต๋ 3๊ฐ์ ๋ค์ํ ์์ ๋ฐฉ๋ฒ์ ์ ์ํด์ฃผ์ธ์.`;\n }\n else {\n // ์๋ฌ๊ฐ ์๋ ๊ฒฝ์ฐ - ์ฝ๋ ๋ฆฌ๋ทฐ/๊ฐ์ ์ ์ (chrome_agent์ ๋์ผ)\n displayPrompt = `${cellIndex}๋ฒ์งธ ์
: ๊ฐ์ ์ ์ ์์ฒญ`;\n llmPrompt = `๋ค์ Jupyter ์
์ฝ๋๋ฅผ ๋ฆฌ๋ทฐํ๊ณ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ ์ํด์ฃผ์ธ์.\n\n์ฝ๋:\n\\`\\`\\`python\n${cellContent}\n\\`\\`\\`\n\n๋ค์ ํ์์ผ๋ก ์๋ตํด์ฃผ์ธ์:\n\n## ์ฝ๋ ๋ถ์\n(ํ์ฌ ์ฝ๋์ ๊ธฐ๋ฅ๊ณผ ํน์ง์ ๊ฐ๋จํ ์ค๋ช
)\n\n## ๊ฐ์ ๋ฐฉ๋ฒ\n\n### ๋ฐฉ๋ฒ 1: (๊ฐ์ ๋ฐฉ๋ฒ ์ ๋ชฉ)\n(์ด ๋ฐฉ๋ฒ์ ๋ํ ๊ฐ๋จํ ์ค๋ช
)\n\\`\\`\\`python\n(๊ฐ์ ๋ ์ฝ๋)\n\\`\\`\\`\n\n### ๋ฐฉ๋ฒ 2: (๊ฐ์ ๋ฐฉ๋ฒ ์ ๋ชฉ)\n(์ด ๋ฐฉ๋ฒ์ ๋ํ ๊ฐ๋จํ ์ค๋ช
)\n\\`\\`\\`python\n(๊ฐ์ ๋ ์ฝ๋)\n\\`\\`\\`\n\n### ๋ฐฉ๋ฒ 3: (๊ฐ์ ๋ฐฉ๋ฒ ์ ๋ชฉ) (์๋ ๊ฒฝ์ฐ)\n(์ด ๋ฐฉ๋ฒ์ ๋ํ ๊ฐ๋จํ ์ค๋ช
)\n\\`\\`\\`python\n(๊ฐ์ ๋ ์ฝ๋)\n\\`\\`\\`\n\n์ต์ 2๊ฐ, ์ต๋ 3๊ฐ์ ๋ค์ํ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ ์ํด์ฃผ์ธ์.`;\n }\n break;\n }\n // Send both prompts to panel with cell ID and cell index\n if (agentPanel.addCellActionMessage) {\n // cellIndex is 1-based (for display), convert to 0-based for array access\n const cellIndexZeroBased = cellIndex - 1;\n agentPanel.addCellActionMessage(action, cellContent, displayPrompt, llmPrompt, cellId, cellIndexZeroBased);\n }\n}\n/**\n * Helper: Remove existing dialog if present\n */\nfunction removeExistingDialog(className) {\n const existingDialog = document.querySelector(`.${className}`);\n if (existingDialog) {\n existingDialog.remove();\n }\n}\n/**\n * Helper: Create dialog overlay element\n */\nfunction createDialogOverlay(className) {\n const dialogOverlay = document.createElement('div');\n dialogOverlay.className = className;\n dialogOverlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.3);\n z-index: 10000;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n return dialogOverlay;\n}\n/**\n * Helper: Create dialog container element\n */\nfunction createDialogContainer(maxWidth = '400px') {\n const dialogContainer = document.createElement('div');\n dialogContainer.style.cssText = `\n background: #fafafa;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n padding: 24px;\n max-width: ${maxWidth};\n width: 90%;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n `;\n return dialogContainer;\n}\n/**\n * Show confirmation dialog\n * Based on chrome_agent's showConfirmDialog implementation\n */\nfunction showConfirmDialog(title, message) {\n return new Promise((resolve) => {\n removeExistingDialog('jp-agent-confirm-dialog');\n const dialogOverlay = createDialogOverlay('jp-agent-confirm-dialog');\n const dialogContainer = createDialogContainer();\n // Dialog content\n dialogContainer.innerHTML = `\n <div style=\"margin-bottom: 20px;\">\n <h3 style=\"margin: 0 0 12px 0; color: #424242; font-size: 16px; font-weight: 500;\">\n ${escapeHtml(title)}\n </h3>\n <p style=\"margin: 0; color: #616161; font-size: 14px; line-height: 1.5;\">\n ${escapeHtml(message)}\n </p>\n </div>\n <div style=\"display: flex; gap: 12px; justify-content: flex-end;\">\n <button class=\"jp-agent-confirm-cancel-btn\" style=\"\n background: transparent;\n color: #616161;\n border: 1px solid #d1d5db;\n border-radius: 3px;\n padding: 8px 16px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n \">์ทจ์</button>\n <button class=\"jp-agent-confirm-submit-btn\" style=\"\n background: #1976d2;\n color: white;\n border: 1px solid #1976d2;\n border-radius: 3px;\n padding: 8px 16px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n \">ํ์ธ</button>\n </div>\n `;\n dialogOverlay.appendChild(dialogContainer);\n document.body.appendChild(dialogOverlay);\n // Button event listeners\n const cancelBtn = dialogContainer.querySelector('.jp-agent-confirm-cancel-btn');\n const submitBtn = dialogContainer.querySelector('.jp-agent-confirm-submit-btn');\n // Cancel button\n cancelBtn.addEventListener('click', () => {\n dialogOverlay.remove();\n resolve(false);\n });\n cancelBtn.addEventListener('mouseenter', () => {\n cancelBtn.style.background = '#f5f5f5';\n });\n cancelBtn.addEventListener('mouseleave', () => {\n cancelBtn.style.background = 'transparent';\n });\n // Submit button\n submitBtn.addEventListener('click', () => {\n submitBtn.disabled = true;\n submitBtn.textContent = '์ฒ๋ฆฌ ์ค...';\n // Small delay to show processing state\n setTimeout(() => {\n dialogOverlay.remove();\n resolve(true);\n }, 100);\n });\n submitBtn.addEventListener('mouseenter', () => {\n if (!submitBtn.disabled) {\n submitBtn.style.background = '#1565c0';\n }\n });\n submitBtn.addEventListener('mouseleave', () => {\n if (!submitBtn.disabled) {\n submitBtn.style.background = '#1976d2';\n }\n });\n // ESC key to close\n const handleEsc = (e) => {\n if (e.key === 'Escape') {\n dialogOverlay.remove();\n document.removeEventListener('keydown', handleEsc);\n resolve(false);\n }\n };\n document.addEventListener('keydown', handleEsc);\n // Close on overlay click\n dialogOverlay.addEventListener('click', (e) => {\n if (e.target === dialogOverlay) {\n dialogOverlay.remove();\n document.removeEventListener('keydown', handleEsc);\n resolve(false);\n }\n });\n });\n}\n/**\n * Escape HTML to prevent XSS\n */\nfunction escapeHtml(text) {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n}\n/**\n * Escape content for markdown code blocks\n * Based on chrome_agent's escapeContent function\n */\nfunction escapeContent(content) {\n if (!content)\n return '';\n // ๋ฐฑ์ฌ๋์๋ฅผ ๋จผ์ escape (๋ค๋ฅธ escape ์ฒ๋ฆฌ ์ ์ ์ํ)\n let escaped = content.replace(/\\\\/g, '\\\\\\\\');\n // ๋ฐฑํฑ escape (๋งํฌ๋ค์ด ์ฝ๋ ๋ธ๋ก ์์์ ๋ฌธ์ ๋ฐฉ์ง)\n escaped = escaped.replace(/`/g, '\\\\`');\n return escaped;\n}\n/**\n * Get notification background color\n */\nfunction getNotificationColor(type) {\n switch (type) {\n case 'error': return '#f56565';\n case 'warning': return '#ed8936';\n default: return '#4299e1';\n }\n}\n/**\n * Create notification element with styles\n */\nfunction createNotificationElement(message, backgroundColor) {\n const notification = document.createElement('div');\n notification.style.cssText = `\n position: fixed;\n top: 20px;\n right: 20px;\n padding: 12px 16px;\n border-radius: 6px;\n color: white;\n font-size: 14px;\n font-weight: 500;\n z-index: 10001;\n opacity: 0;\n transition: opacity 0.3s ease;\n max-width: 300px;\n word-wrap: break-word;\n background: ${backgroundColor};\n `;\n notification.textContent = message;\n return notification;\n}\n/**\n * Animate notification appearance and removal\n */\nfunction animateNotification(notification) {\n // Show animation\n setTimeout(() => notification.style.opacity = '1', 10);\n // Remove after 3 seconds\n setTimeout(() => {\n notification.style.opacity = '0';\n setTimeout(() => {\n if (notification.parentNode) {\n notification.parentNode.removeChild(notification);\n }\n }, 300);\n }, 3000);\n}\n/**\n * Show notification (simple implementation)\n */\nfunction showNotification(message, type = 'info') {\n const notification = createNotificationElement(message, getNotificationColor(type));\n document.body.appendChild(notification);\n animateNotification(notification);\n}\n/**\n * Show custom prompt dialog\n * Based on chrome_agent's showCustomPromptDialog implementation\n */\nfunction showCustomPromptDialog(cell) {\n const cellContent = cell?.model?.sharedModel?.getSource() || '';\n const cellIndex = getCellIndex(cell);\n const cellId = getOrAssignCellId(cell);\n console.log('์ปค์คํ
ํ๋กฌํํธ ๋ค์ด์ผ๋ก๊ทธ ํ์', cellIndex, cellId);\n removeExistingDialog('jp-agent-custom-prompt-dialog');\n const dialogOverlay = createDialogOverlay('jp-agent-custom-prompt-dialog');\n const dialogContainer = createDialogContainer('500px');\n // ๋ค์ด์ผ๋ก๊ทธ ๋ด์ฉ\n dialogContainer.innerHTML = `\n <div style=\"margin-bottom: 20px;\">\n <h3 style=\"margin: 0 0 8px 0; color: #424242; font-size: 16px; font-weight: 500;\">\n ์
์ ๋ํด ์ง๋ฌธํ๊ธฐ\n </h3>\n <p style=\"margin: 0; color: #757575; font-size: 13px;\">\n ๋ฌผ๋ฆฌ์ ์์น: ์
${cellIndex + 1}๋ฒ์งธ (์์์ ์๋๋ก ์นด์ดํธ)\n </p>\n </div>\n <div style=\"margin-bottom: 20px;\">\n <textarea class=\"jp-agent-custom-prompt-input\"\n placeholder=\"์ด ์
์ ๋ํด ์ง๋ฌธํ ๋ด์ฉ์ ์
๋ ฅํ์ธ์...\"\n style=\"\n width: 100%;\n min-height: 100px;\n padding: 12px;\n border: 1px solid #d1d5db;\n border-radius: 4px;\n font-size: 14px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n resize: vertical;\n box-sizing: border-box;\n \"\n ></textarea>\n </div>\n <div style=\"display: flex; gap: 12px; justify-content: flex-end;\">\n <button class=\"jp-agent-custom-prompt-cancel-btn\" style=\"\n background: transparent;\n color: #616161;\n border: 1px solid #d1d5db;\n border-radius: 3px;\n padding: 8px 16px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n \">์ทจ์</button>\n <button class=\"jp-agent-custom-prompt-submit-btn\" style=\"\n background: transparent;\n color: #1976d2;\n border: 1px solid #1976d2;\n border-radius: 3px;\n padding: 8px 16px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n \">์ง๋ฌธ</button>\n </div>\n `;\n dialogOverlay.appendChild(dialogContainer);\n document.body.appendChild(dialogOverlay);\n // ์
๋ ฅ ํ๋์ ํฌ์ปค์ค\n const inputField = dialogContainer.querySelector('.jp-agent-custom-prompt-input');\n setTimeout(() => inputField?.focus(), 100);\n // ๋ฒํผ ์ด๋ฒคํธ ๋ฆฌ์ค๋\n const cancelBtn = dialogContainer.querySelector('.jp-agent-custom-prompt-cancel-btn');\n const submitBtn = dialogContainer.querySelector('.jp-agent-custom-prompt-submit-btn');\n // ์ทจ์ ๋ฒํผ\n cancelBtn.addEventListener('click', () => {\n dialogOverlay.remove();\n });\n cancelBtn.addEventListener('mouseenter', () => {\n cancelBtn.style.background = '#f5f5f5';\n cancelBtn.style.borderColor = '#9ca3af';\n });\n cancelBtn.addEventListener('mouseleave', () => {\n cancelBtn.style.background = 'transparent';\n cancelBtn.style.borderColor = '#d1d5db';\n });\n // ์ ์ถ ๋ฒํผ\n const handleSubmit = async () => {\n const promptText = inputField?.value.trim() || '';\n if (!promptText) {\n showNotification('์ง๋ฌธ ๋ด์ฉ์ ์
๋ ฅํด์ฃผ์ธ์.', 'warning');\n return;\n }\n dialogOverlay.remove();\n // Get cell output\n const cellOutput = getCellOutput(cell);\n // Create display prompt: \"Cell x: Custom request\"\n const displayPrompt = `${cellIndex}๋ฒ์งธ ์
: ${promptText}`;\n // Create LLM prompt with code and output\n let llmPrompt = `${promptText}\\n\\n์
๋ด์ฉ:\\n\\`\\`\\`\\n${cellContent}\\n\\`\\`\\``;\n if (cellOutput) {\n llmPrompt += `\\n\\n์คํ ๊ฒฐ๊ณผ:\\n\\`\\`\\`\\n${cellOutput}\\n\\`\\`\\``;\n }\n const agentPanel = window._hdspAgentPanel;\n if (agentPanel) {\n // Activate the sidebar panel\n const app = window.jupyterapp;\n if (app) {\n app.shell.activateById(agentPanel.id);\n }\n // Send both prompts with cell ID and cell index\n if (agentPanel.addCellActionMessage) {\n // cellIndex is 1-based (for display), convert to 0-based for array access\n const cellIndexZeroBased = cellIndex - 1;\n agentPanel.addCellActionMessage(CellAction.CUSTOM_PROMPT, cellContent, displayPrompt, llmPrompt, cellId, cellIndexZeroBased);\n }\n }\n };\n submitBtn.addEventListener('click', handleSubmit);\n submitBtn.addEventListener('mouseenter', () => {\n submitBtn.style.background = 'rgba(25, 118, 210, 0.1)';\n });\n submitBtn.addEventListener('mouseleave', () => {\n submitBtn.style.background = 'transparent';\n });\n // Enter ํค๋ก ์ ์ถ (Shift+Enter๋ ์ค๋ฐ๊ฟ)\n inputField?.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSubmit();\n }\n });\n // ์ค๋ฒ๋ ์ด ํด๋ฆญ ์ ๋ค์ด์ผ๋ก๊ทธ ๋ซ๊ธฐ\n dialogOverlay.addEventListener('click', (e) => {\n if (e.target === dialogOverlay) {\n dialogOverlay.remove();\n }\n });\n // ESC ํค๋ก ๋ค์ด์ผ๋ก๊ทธ ๋ซ๊ธฐ\n const handleEscapeKey = (e) => {\n if (e.key === 'Escape') {\n dialogOverlay.remove();\n document.removeEventListener('keydown', handleEscapeKey);\n }\n };\n document.addEventListener('keydown', handleEscapeKey);\n}\n","/**\n * Prompt Generation Plugin\n * Adds \"ํ๋กฌํํธ ์์ฑ\" to Jupyter Launcher\n */\nimport { ILauncher } from '@jupyterlab/launcher';\nimport { ICommandPalette, ReactWidget, Notification } from '@jupyterlab/apputils';\nimport { IDocumentManager } from '@jupyterlab/docmanager';\nimport { LabIcon } from '@jupyterlab/ui-components';\nimport { Widget } from '@lumino/widgets';\nimport React from 'react';\nimport { ThemeProvider, createTheme } from '@mui/material';\nimport hdspIconSvg from '../styles/icons/hdsp-icon.svg';\nimport { PromptGenerationDialog } from '../components/PromptGenerationDialog';\nimport { TaskProgressWidget } from '../components/TaskProgressWidget';\nimport { TaskService } from '../services/TaskService';\n/**\n * Plugin constants\n */\nconst PLUGIN_ID = '@hdsp-agent/prompt-generation';\nconst COMMAND_ID = 'hdsp-agent:generate-from-prompt';\nconst CATEGORY = 'HALO Agent';\n/**\n * HALO Icon\n */\nconst hdspIcon = new LabIcon({\n name: 'hdsp-agent:hdsp-icon',\n svgstr: hdspIconSvg\n});\n/**\n * Task Manager Widget\n * Manages active notebook generation tasks\n */\nclass TaskManagerWidget extends ReactWidget {\n constructor(app, docManager) {\n super();\n this.app = app;\n this.docManager = docManager;\n this.taskService = new TaskService();\n this.activeTasks = new Map();\n this.addClass('jp-TaskManagerWidget');\n }\n /**\n * Start a new notebook generation task\n */\n async startGeneration(prompt) {\n try {\n // Start generation\n const response = await this.taskService.generateNotebook({ prompt });\n const taskId = response.taskId;\n // Subscribe to progress\n this.taskService.subscribeToTaskProgress(taskId, (status) => {\n this.activeTasks.set(taskId, status);\n this.update();\n // Show notification on completion\n if (status.status === 'completed' && status.notebookPath) {\n Notification.success(`๋
ธํธ๋ถ ์์ฑ ์๋ฃ: ${status.notebookPath.split('/').pop()}`, {\n autoClose: 5000\n });\n }\n else if (status.status === 'failed') {\n Notification.error(`๋
ธํธ๋ถ ์์ฑ ์คํจ: ${status.error}`, {\n autoClose: 10000\n });\n }\n }, (error) => {\n console.error('Task progress error:', error);\n Notification.error('์งํ์ํฉ ์ฐ๊ฒฐ ์คํจ', { autoClose: 5000 });\n }, () => {\n // Task completed, keep in list for user to review\n this.update();\n });\n // Show initial notification\n Notification.info('๋
ธํธ๋ถ ์์ฑ์ ์์ํ์ต๋๋ค', { autoClose: 3000 });\n this.update();\n }\n catch (error) {\n console.error('Failed to start generation:', error);\n Notification.error(`์์ฑ ์์ ์คํจ: ${error.message}`, {\n autoClose: 5000\n });\n }\n }\n /**\n * Cancel a task\n */\n async cancelTask(taskId) {\n try {\n await this.taskService.cancelTask(taskId);\n this.activeTasks.delete(taskId);\n this.update();\n Notification.info('์์
์ ์ทจ์ํ์ต๋๋ค', { autoClose: 3000 });\n }\n catch (error) {\n console.error('Failed to cancel task:', error);\n Notification.error(`์ทจ์ ์คํจ: ${error.message}`, { autoClose: 5000 });\n }\n }\n /**\n * Close/remove task from display\n */\n closeTask(taskId) {\n this.taskService.unsubscribeFromTask(taskId);\n this.activeTasks.delete(taskId);\n this.update();\n }\n /**\n * Open generated notebook\n */\n async openNotebook(notebookPath, taskId) {\n try {\n // Extract just the filename from the path\n const filename = notebookPath.split('/').pop() || notebookPath;\n // Open the notebook\n await this.docManager.openOrReveal(filename);\n // Close the task widget after opening\n this.closeTask(taskId);\n Notification.success(`๋
ธํธ๋ถ์ ์ด์์ต๋๋ค: ${filename}`, {\n autoClose: 3000\n });\n }\n catch (error) {\n console.error('Failed to open notebook:', error);\n Notification.error(`๋
ธํธ๋ถ ์ด๊ธฐ ์คํจ: ${error.message}`, {\n autoClose: 5000\n });\n }\n }\n render() {\n const theme = createTheme();\n const tasks = Array.from(this.activeTasks.entries());\n return (React.createElement(ThemeProvider, { theme: theme },\n React.createElement(\"div\", { style: { position: 'fixed', bottom: 0, right: 0, zIndex: 1300 } }, tasks.map(([taskId, status], index) => (React.createElement(\"div\", { key: taskId, style: {\n marginBottom: index < tasks.length - 1 ? '10px' : '0'\n } },\n React.createElement(TaskProgressWidget, { taskStatus: status, onClose: () => this.closeTask(taskId), onCancel: () => this.cancelTask(taskId), onOpenNotebook: () => status.notebookPath &&\n this.openNotebook(status.notebookPath, taskId) })))))));\n }\n dispose() {\n this.taskService.dispose();\n super.dispose();\n }\n}\n/**\n * Dialog Widget for prompt input\n */\nclass PromptDialogWidget extends ReactWidget {\n constructor(onGenerate, onClose) {\n super();\n this._onGenerate = onGenerate;\n this._onClose = onClose;\n }\n render() {\n const theme = createTheme();\n return (React.createElement(ThemeProvider, { theme: theme },\n React.createElement(PromptGenerationDialog, { open: true, onClose: this._onClose, onGenerate: this._onGenerate })));\n }\n}\n/**\n * Prompt Generation Plugin\n */\nexport const promptGenerationPlugin = {\n id: PLUGIN_ID,\n autoStart: true,\n requires: [IDocumentManager],\n optional: [ILauncher, ICommandPalette],\n activate: (app, docManager, launcher, palette) => {\n console.log('[PromptGenerationPlugin] Activating');\n try {\n // Create task manager widget\n const taskManager = new TaskManagerWidget(app, docManager);\n taskManager.id = 'hdsp-agent-task-manager';\n taskManager.title.label = 'Task Manager';\n // Add to shell but keep it as a floating overlay (not in main area)\n // The widget renders itself as a fixed position element\n Widget.attach(taskManager, document.body);\n // Add command\n app.commands.addCommand(COMMAND_ID, {\n label: 'ํ๋กฌํํธ๋ก ๋
ธํธ๋ถ ๋ง๋ค๊ธฐ',\n caption: 'ํ๋กฌํํธ๋ก ๋
ธํธ๋ถ ๋ง๋ค๊ธฐ',\n icon: hdspIcon,\n execute: () => {\n // Create dialog widget\n let dialogWidget = null;\n const onGenerate = async (prompt) => {\n if (dialogWidget) {\n dialogWidget.dispose();\n dialogWidget = null;\n }\n await taskManager.startGeneration(prompt);\n };\n const onClose = () => {\n if (dialogWidget) {\n dialogWidget.dispose();\n dialogWidget = null;\n }\n };\n dialogWidget = new PromptDialogWidget(onGenerate, onClose);\n dialogWidget.id = 'hdsp-agent-prompt-dialog';\n dialogWidget.title.label = '';\n app.shell.add(dialogWidget, 'main');\n }\n });\n // Add to launcher\n if (launcher) {\n launcher.add({\n command: COMMAND_ID,\n category: 'Notebook',\n rank: 1\n });\n }\n // Add to command palette\n if (palette) {\n palette.addItem({\n command: COMMAND_ID,\n category: CATEGORY\n });\n }\n console.log('[PromptGenerationPlugin] Activated successfully');\n }\n catch (error) {\n console.error('[PromptGenerationPlugin] Failed to activate:', error);\n }\n }\n};\n","/**\n * Save Interceptor Plugin\n * Intercepts notebook save operations to offer code review before saving\n * Based on chrome_agent's save interception functionality\n */\nimport { INotebookTracker } from '@jupyterlab/notebook';\nimport { ICommandPalette } from '@jupyterlab/apputils';\n/**\n * Save Interceptor Plugin\n */\nexport const saveInterceptorPlugin = {\n id: '@hdsp-agent/save-interceptor',\n autoStart: true,\n requires: [INotebookTracker],\n optional: [ICommandPalette],\n activate: (app, notebookTracker, palette) => {\n console.log('[SaveInterceptorPlugin] Activated');\n let isSaving = false;\n let originalSaveCommand = null;\n // Store original save command and wrap it\n if (app.commands.hasCommand('docmanager:save')) {\n console.log('[SaveInterceptorPlugin] Found docmanager:save command');\n const commandRegistry = app.commands;\n const commandId = 'docmanager:save';\n // Get the original command's execute function\n const originalCommand = commandRegistry._commands.get(commandId);\n if (originalCommand) {\n originalSaveCommand = originalCommand.execute.bind(originalCommand);\n console.log('[SaveInterceptorPlugin] Stored original save command');\n // Replace the execute function\n originalCommand.execute = async (args) => {\n // Use app.shell.currentWidget to get the actually focused widget\n const currentWidget = app.shell.currentWidget;\n console.log('[SaveInterceptorPlugin] Save command triggered', {\n hasCurrentWidget: !!currentWidget,\n isSaving: isSaving,\n widgetType: currentWidget?.constructor?.name\n });\n // Only intercept for Python files (.ipynb, .py)\n if (!currentWidget) {\n console.log('[SaveInterceptorPlugin] No current widget, allowing default save');\n return originalSaveCommand(args);\n }\n // Check if the current widget has a context (is a document)\n const context = currentWidget.context;\n if (!context) {\n console.log('[SaveInterceptorPlugin] No context, allowing default save');\n return originalSaveCommand(args);\n }\n // Check if the current document is a Python file\n const path = context?.path || '';\n const isPythonFile = path.endsWith('.ipynb') || path.endsWith('.py');\n if (!isPythonFile) {\n console.log('[SaveInterceptorPlugin] Not a Python file, allowing default save', { path });\n return originalSaveCommand(args);\n }\n if (isSaving) {\n console.log('[SaveInterceptorPlugin] Already in save process, executing actual save');\n return originalSaveCommand(args);\n }\n console.log('[SaveInterceptorPlugin] Intercepting Python file save, showing modal', { path });\n await handleSaveIntercept(currentWidget, app, originalSaveCommand, args, () => isSaving = true, () => isSaving = false);\n };\n console.log('[SaveInterceptorPlugin] Wrapped save command installed');\n }\n else {\n console.error('[SaveInterceptorPlugin] Could not find original save command');\n }\n }\n // Also intercept keyboard shortcut as backup\n document.addEventListener('keydown', async (e) => {\n if ((e.ctrlKey || e.metaKey) && e.key === 's') {\n // Use app.shell.currentWidget instead of notebookTracker to get the actually focused widget\n const currentWidget = app.shell.currentWidget;\n if (!currentWidget) {\n return; // Not in a document, let default save happen\n }\n // Check if the current widget has a context (is a document)\n const context = currentWidget.context;\n if (!context) {\n return; // Not a document widget, let default save happen\n }\n // Check if the current document is a Python file\n const path = context?.path || '';\n const isPythonFile = path.endsWith('.ipynb') || path.endsWith('.py');\n if (!isPythonFile) {\n console.log('[SaveInterceptorPlugin] Not a Python file, allowing default save', { path });\n return; // Not a Python file, let default save happen\n }\n console.log('[SaveInterceptorPlugin] Save shortcut (Ctrl/Cmd+S) detected for Python file', { path });\n e.preventDefault();\n e.stopPropagation();\n if (isSaving) {\n console.log('[SaveInterceptorPlugin] Already saving, ignoring duplicate request');\n return;\n }\n if (!originalSaveCommand) {\n console.error('[SaveInterceptorPlugin] No original save command stored');\n return;\n }\n await handleSaveIntercept(currentWidget, app, originalSaveCommand, undefined, () => isSaving = true, () => isSaving = false);\n }\n }, true); // Use capture phase to intercept before JupyterLab\n console.log('[SaveInterceptorPlugin] Save interception enabled');\n }\n};\n/**\n * Handle save intercept - show modal and collect cells if needed\n */\nasync function handleSaveIntercept(panel, app, originalSaveCommand, args, setSaving, clearSaving) {\n // Show confirmation modal\n const shouldAnalyze = await showSaveConfirmModal();\n if (shouldAnalyze === null) {\n // User cancelled\n clearSaving();\n return;\n }\n if (shouldAnalyze) {\n // Collect all cells and send for analysis\n await performAnalysisSave(panel, app, originalSaveCommand, args, setSaving, clearSaving);\n }\n else {\n // Direct save without analysis\n await performDirectSave(panel, app, originalSaveCommand, args, setSaving, clearSaving);\n }\n}\n/**\n * Show save confirmation modal\n * Returns: true for analysis, false for direct save, null for cancel\n */\nfunction showSaveConfirmModal() {\n return new Promise((resolve) => {\n // Remove existing modal if any\n const existingModal = document.querySelector('.jp-agent-save-confirm-modal');\n if (existingModal) {\n existingModal.remove();\n }\n // Create modal overlay\n const modalOverlay = document.createElement('div');\n modalOverlay.className = 'jp-agent-save-confirm-modal';\n modalOverlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.3);\n z-index: 10000;\n display: flex;\n align-items: center;\n justify-content: center;\n `;\n // Create modal container\n const modalContainer = document.createElement('div');\n modalContainer.style.cssText = `\n background: var(--jp-layout-color1);\n border: 1px solid var(--jp-border-color1);\n border-radius: 4px;\n padding: 24px;\n max-width: 400px;\n width: 90%;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n font-family: var(--jp-ui-font-family);\n `;\n // Modal content\n modalContainer.innerHTML = `\n <div style=\"margin-bottom: 20px;\">\n <h3 style=\"margin: 0 0 12px 0; color: var(--jp-ui-font-color1); font-size: 16px; font-weight: 500;\">\n ์ ์ฅ ์ ์ ์ฝ๋ ๊ฒ์๋ฅผ ํ๊ฒ ์ต๋๊น?\n </h3>\n <p style=\"margin: 0; color: var(--jp-ui-font-color2); font-size: 14px; line-height: 1.5;\">\n ๋
ธํธ๋ถ์ ์ ์ฅํ๊ธฐ ์ ์ ๋ชจ๋ ์
์ ์ฝ๋์ ์ถ๋ ฅ์ ๋ถ์ํ์ฌ ์ต์ ํ ์ ์์ ๋ฐ์ผ์๊ฒ ์ต๋๊น?\n </p>\n </div>\n <div style=\"display: flex; gap: 12px; justify-content: flex-end;\">\n <button class=\"jp-agent-save-direct-btn\" style=\"\n background: transparent;\n color: var(--jp-ui-font-color2);\n border: 1px solid var(--jp-border-color2);\n border-radius: 3px;\n padding: 8px 16px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n \">๊ทธ๋ฅ ์ ์ฅํ๊ธฐ</button>\n <button class=\"jp-agent-save-analysis-btn\" style=\"\n background: var(--jp-brand-color1);\n color: white;\n border: 1px solid var(--jp-brand-color1);\n border-radius: 3px;\n padding: 8px 16px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n \">๊ฒ์ ํ ์ ์ฅํ๊ธฐ</button>\n </div>\n `;\n modalOverlay.appendChild(modalContainer);\n document.body.appendChild(modalOverlay);\n // Button event listeners\n const directSaveBtn = modalContainer.querySelector('.jp-agent-save-direct-btn');\n const analysisSaveBtn = modalContainer.querySelector('.jp-agent-save-analysis-btn');\n // Direct save button\n directSaveBtn.addEventListener('click', () => {\n console.log('[SaveInterceptorPlugin] User chose direct save');\n modalOverlay.remove();\n resolve(false);\n });\n directSaveBtn.addEventListener('mouseenter', () => {\n directSaveBtn.style.background = 'var(--jp-layout-color2)';\n });\n directSaveBtn.addEventListener('mouseleave', () => {\n directSaveBtn.style.background = 'transparent';\n });\n // Analysis save button\n analysisSaveBtn.addEventListener('click', () => {\n console.log('[SaveInterceptorPlugin] User chose analysis save');\n modalOverlay.remove();\n resolve(true);\n });\n analysisSaveBtn.addEventListener('mouseenter', () => {\n analysisSaveBtn.style.opacity = '0.9';\n });\n analysisSaveBtn.addEventListener('mouseleave', () => {\n analysisSaveBtn.style.opacity = '1';\n });\n // Close on overlay click\n modalOverlay.addEventListener('click', (e) => {\n if (e.target === modalOverlay) {\n console.log('[SaveInterceptorPlugin] User cancelled save');\n modalOverlay.remove();\n resolve(null);\n }\n });\n // ESC key to close\n const handleEscapeKey = (e) => {\n if (e.key === 'Escape') {\n console.log('[SaveInterceptorPlugin] User cancelled save with ESC');\n modalOverlay.remove();\n document.removeEventListener('keydown', handleEscapeKey);\n resolve(null);\n }\n };\n document.addEventListener('keydown', handleEscapeKey);\n });\n}\n/**\n * Perform direct save without analysis\n */\nasync function performDirectSave(panel, app, originalSaveCommand, args, setSaving, clearSaving) {\n console.log('[SaveInterceptorPlugin] Performing direct save');\n setSaving();\n try {\n // Use the original save command\n if (originalSaveCommand) {\n await originalSaveCommand(args);\n showNotification('์ ์ฅ์ด ์๋ฃ๋์์ต๋๋ค.', 'success');\n }\n else {\n // Fallback: Use JupyterLab's document manager to save\n const context = panel.context;\n if (context) {\n await context.save();\n showNotification('์ ์ฅ์ด ์๋ฃ๋์์ต๋๋ค.', 'success');\n }\n }\n }\n catch (error) {\n console.error('[SaveInterceptorPlugin] Save failed:', error);\n showNotification('์ ์ฅ์ ์คํจํ์ต๋๋ค.', 'error');\n }\n finally {\n clearSaving();\n }\n}\n/**\n * Perform analysis save - collect cells and send to AgentPanel\n */\nasync function performAnalysisSave(panel, app, originalSaveCommand, args, setSaving, clearSaving) {\n console.log('[SaveInterceptorPlugin] Performing analysis save');\n try {\n // Collect all code cells\n const cells = await collectAllCodeCells(panel);\n if (cells.length === 0) {\n showNotification('๋ถ์ํ ์ฝ๋ ์
์ด ์์ต๋๋ค. ๊ทธ๋ฅ ์ ์ฅํฉ๋๋ค.', 'warning');\n await performDirectSave(panel, app, originalSaveCommand, args, setSaving, clearSaving);\n return;\n }\n showNotification('์ฝ๋ ๋ถ์์ ์์ํฉ๋๋ค...', 'info');\n // Get AgentPanel instance\n const agentPanel = window._hdspAgentPanel;\n if (!agentPanel) {\n console.error('[SaveInterceptorPlugin] Agent panel not found');\n showNotification('Agent panel์ ์ฐพ์ ์ ์์ต๋๋ค. ๊ทธ๋ฅ ์ ์ฅํฉ๋๋ค.', 'warning');\n await performDirectSave(panel, app, originalSaveCommand, args, setSaving, clearSaving);\n return;\n }\n // Activate the sidebar panel\n if (app) {\n app.shell.activateById(agentPanel.id);\n }\n // Send cells to AgentPanel for analysis\n if (agentPanel.analyzeNotebook) {\n agentPanel.analyzeNotebook(cells, async () => {\n // Callback after analysis complete - perform save\n await performDirectSave(panel, app, originalSaveCommand, args, setSaving, clearSaving);\n });\n }\n else {\n console.error('[SaveInterceptorPlugin] analyzeNotebook method not found on AgentPanel');\n showNotification('๋ถ์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ทธ๋ฅ ์ ์ฅํฉ๋๋ค.', 'warning');\n await performDirectSave(panel, app, originalSaveCommand, args, setSaving, clearSaving);\n }\n }\n catch (error) {\n console.error('[SaveInterceptorPlugin] Analysis save failed:', error);\n showNotification('๋ถ์์ ์คํจํ์ต๋๋ค. ๊ทธ๋ฅ ์ ์ฅํฉ๋๋ค.', 'warning');\n await performDirectSave(panel, app, originalSaveCommand, args, setSaving, clearSaving);\n }\n}\n/**\n * Collect all code cells with content, output, and imports\n * Based on chrome_agent's collectAllCodeCells implementation\n */\nasync function collectAllCodeCells(panel) {\n const notebook = panel.content;\n const cells = [];\n for (let i = 0; i < notebook.widgets.length; i++) {\n const cell = notebook.widgets[i];\n // Only collect code cells - null safety ์ถ๊ฐ\n if (!cell?.model || cell.model.type !== 'code') {\n continue;\n }\n const content = cell.model.sharedModel?.getSource() || '';\n if (!content.trim()) {\n continue;\n }\n // Get or assign cell ID\n const cellId = getOrAssignCellId(cell);\n // Extract output\n const output = getCellOutput(cell);\n // Extract imports\n const imports = extractImports(content);\n // Get local module sources (simplified - would need kernel API access for full implementation)\n const localImports = imports.filter(imp => imp.isLocal);\n const localModuleSources = {};\n // Note: Full module source extraction would require kernel websocket connection\n // This is a simplified version for now\n for (const imp of localImports) {\n if (!imp.module.startsWith('.')) {\n // Could implement kernel-based source extraction here\n localModuleSources[imp.module] = `# Source for ${imp.module} would be fetched from kernel`;\n }\n }\n cells.push({\n index: i,\n id: cellId,\n content: content,\n type: 'code',\n output: output,\n imports: imports,\n localModuleSources: Object.keys(localModuleSources).length > 0 ? localModuleSources : undefined\n });\n }\n console.log(`[SaveInterceptorPlugin] Collected ${cells.length} code cells`);\n return cells;\n}\n/**\n * Get or assign cell ID to a cell\n */\nfunction getOrAssignCellId(cell) {\n const cellModel = cell.model;\n let cellId;\n // Try to get cell ID from metadata\n try {\n if (cellModel.metadata && typeof cellModel.metadata.get === 'function') {\n cellId = cellModel.metadata.get('jupyterAgentCellId');\n }\n else if (cellModel.metadata?.jupyterAgentCellId) {\n cellId = cellModel.metadata.jupyterAgentCellId;\n }\n }\n catch (e) {\n // Ignore errors\n }\n if (!cellId) {\n cellId = `cell-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n // Try to set cell ID in metadata\n try {\n if (cellModel.metadata && typeof cellModel.metadata.set === 'function') {\n cellModel.metadata.set('jupyterAgentCellId', cellId);\n }\n else if (cellModel.metadata) {\n cellModel.metadata.jupyterAgentCellId = cellId;\n }\n }\n catch (e) {\n // Ignore errors\n }\n }\n return cellId;\n}\n/**\n * Extract output from a code cell\n */\nfunction getCellOutput(cell) {\n // cell.model์ด null์ผ ์ ์์ผ๋ฏ๋ก ์์ ํ๊ฒ ์ฒดํฌ\n if (!cell?.model || cell.model.type !== 'code') {\n return '';\n }\n const codeCell = cell;\n const outputs = codeCell.model?.outputs;\n if (!outputs || outputs.length === 0) {\n return '';\n }\n const outputTexts = [];\n for (let i = 0; i < outputs.length; i++) {\n const output = outputs.get(i);\n const outputType = output.type;\n if (outputType === 'stream') {\n // stdout, stderr\n const text = output.text;\n if (Array.isArray(text)) {\n outputTexts.push(text.join(''));\n }\n else {\n outputTexts.push(text);\n }\n }\n else if (outputType === 'execute_result' || outputType === 'display_data') {\n // Execution results or display data\n const data = output.data;\n if (data['text/plain']) {\n const text = data['text/plain'];\n if (Array.isArray(text)) {\n outputTexts.push(text.join(''));\n }\n else {\n outputTexts.push(text);\n }\n }\n }\n else if (outputType === 'error') {\n // Error output\n const traceback = output.traceback;\n if (Array.isArray(traceback)) {\n outputTexts.push(traceback.join('\\n'));\n }\n }\n }\n return outputTexts.join('\\n');\n}\n/**\n * Extract imports from Python code\n * Based on chrome_agent's extractImports implementation\n */\nfunction extractImports(cellContent) {\n const imports = [];\n const lines = cellContent.split('\\n');\n for (const line of lines) {\n const trimmed = line.trim();\n // Skip comments and empty lines\n if (trimmed.startsWith('#') || trimmed === '')\n continue;\n // Relative import: from . import ... or from .. import ...\n const relativeMatch = trimmed.match(/^from\\s+(\\.+[\\w.]*)\\s+import\\s+([\\w,\\s*]+)/);\n if (relativeMatch) {\n imports.push({\n module: relativeMatch[1],\n items: relativeMatch[2],\n isLocal: true\n });\n continue;\n }\n // from X import Y form\n const fromImportMatch = trimmed.match(/^from\\s+([\\w.]+)\\s+import\\s+([\\w,\\s*]+)/);\n if (fromImportMatch) {\n const moduleName = fromImportMatch[1];\n imports.push({\n module: moduleName,\n items: fromImportMatch[2],\n isLocal: isLocalImport(moduleName)\n });\n continue;\n }\n // import X, Y, Z form\n const importMatch = trimmed.match(/^import\\s+([\\w,\\s.]+)/);\n if (importMatch) {\n const modules = importMatch[1].split(',').map(m => m.trim().split(' as ')[0]);\n modules.forEach(moduleName => {\n imports.push({\n module: moduleName,\n items: moduleName,\n isLocal: isLocalImport(moduleName)\n });\n });\n }\n }\n return imports;\n}\n/**\n * Determine if a module import is local (not a standard library)\n */\nfunction isLocalImport(moduleName) {\n // Relative paths are always local\n if (moduleName.startsWith('.')) {\n return true;\n }\n // Common Python libraries (not exhaustive)\n const commonLibraries = [\n 'numpy', 'np', 'pandas', 'pd', 'matplotlib', 'sklearn', 'scipy',\n 'torch', 'tensorflow', 'tf', 'keras', 'PIL', 'cv2', 'requests',\n 'json', 'os', 'sys', 'datetime', 'time', 'math', 'random',\n 'collections', 'itertools', 'functools', 're', 'pathlib',\n 'typing', 'dataclasses', 'abc', 'argparse', 'logging',\n 'pickle', 'csv', 'sqlite3', 'http', 'urllib', 'email',\n 'plotly', 'seaborn', 'statsmodels', 'xgboost', 'lightgbm',\n 'transformers', 'datasets', 'accelerate', 'peft',\n 'openai', 'anthropic', 'langchain', 'llama_index'\n ];\n // Get top-level module name\n const topLevelModule = moduleName.split('.')[0];\n // If not in common libraries, consider it local\n return !commonLibraries.includes(topLevelModule);\n}\n/**\n * Get notification background color based on type\n */\nfunction getNotificationColor(type) {\n const colors = {\n success: '#48bb78',\n error: '#f56565',\n warning: '#ed8936',\n info: '#4299e1'\n };\n return colors[type] || colors.info;\n}\n/**\n * Create notification element with styles\n */\nfunction createNotificationElement(message, backgroundColor) {\n const notification = document.createElement('div');\n notification.style.cssText = `\n position: fixed;\n top: 20px;\n right: 20px;\n padding: 12px 20px;\n border-radius: 8px;\n color: white;\n font-size: 14px;\n font-weight: 500;\n z-index: 10001;\n opacity: 0;\n transition: opacity 0.3s ease;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n max-width: 300px;\n word-wrap: break-word;\n background: ${backgroundColor};\n `;\n notification.textContent = message;\n return notification;\n}\n/**\n * Animate notification appearance and removal\n */\nfunction animateNotification(notification) {\n // Show animation\n setTimeout(() => {\n notification.style.opacity = '1';\n }, 10);\n // Remove after 3 seconds\n setTimeout(() => {\n notification.style.opacity = '0';\n setTimeout(() => {\n if (notification.parentNode) {\n notification.parentNode.removeChild(notification);\n }\n }, 300);\n }, 3000);\n}\n/**\n * Show notification\n */\nfunction showNotification(message, type = 'info') {\n const notification = createNotificationElement(message, getNotificationColor(type));\n document.body.appendChild(notification);\n animateNotification(notification);\n}\n","/**\n * Sidebar Plugin\n * Adds Agent panel to JupyterLab sidebar\n */\nimport { ILayoutRestorer } from '@jupyterlab/application';\nimport { ICommandPalette, WidgetTracker } from '@jupyterlab/apputils';\nimport { INotebookTracker } from '@jupyterlab/notebook';\nimport { IConsoleTracker } from '@jupyterlab/console';\nimport { AgentPanelWidget } from '../components/AgentPanel';\nimport { ApiService } from '../services/ApiService';\n/**\n * Sidebar plugin namespace\n */\nconst PLUGIN_ID = '@hdsp-agent/sidebar';\nconst COMMAND_ID = 'hdsp-agent:toggle-sidebar';\n/**\n * Agent Sidebar Plugin\n */\nexport const sidebarPlugin = {\n id: PLUGIN_ID,\n autoStart: true,\n requires: [],\n optional: [ILayoutRestorer, ICommandPalette, INotebookTracker, IConsoleTracker],\n activate: (app, restorer, palette, notebookTracker, consoleTracker) => {\n console.log('[SidebarPlugin] Activating Jupyter Agent Sidebar');\n try {\n // Create API service\n const apiService = new ApiService();\n // Create agent panel widget with notebook tracker and console tracker\n const agentPanel = new AgentPanelWidget(apiService, notebookTracker, consoleTracker);\n // Create tracker for panel state restoration if restorer available\n if (restorer) {\n const tracker = new WidgetTracker({\n namespace: 'hdsp-agent'\n });\n // Add panel to tracker\n tracker.add(agentPanel);\n // Restore panel state\n restorer.restore(tracker, {\n command: COMMAND_ID,\n name: () => 'hdsp-agent'\n });\n }\n // Add panel to right sidebar\n app.shell.add(agentPanel, 'right', { rank: 100 });\n // Add command to toggle sidebar\n app.commands.addCommand(COMMAND_ID, {\n label: 'HALO Agent ์ฌ์ด๋๋ฐ ํ ๊ธ',\n caption: 'HALO Agent ํจ๋ ํ์/์จ๊ธฐ๊ธฐ',\n execute: () => {\n if (agentPanel.isVisible) {\n agentPanel.close();\n }\n else {\n app.shell.activateById(agentPanel.id);\n }\n }\n });\n // Add command to palette\n if (palette) {\n palette.addItem({\n command: COMMAND_ID,\n category: 'HALO Agent',\n args: {}\n });\n }\n // Store reference globally for cell buttons to access\n window._hdspAgentPanel = agentPanel;\n console.log('[SidebarPlugin] HALO Agent Sidebar activated successfully');\n }\n catch (error) {\n console.error('[SidebarPlugin] Failed to activate:', error);\n }\n }\n};\n","/**\n * AgentOrchestrator - Plan-and-Execute ์ค์ผ์คํธ๋ ์ดํฐ\n *\n * HuggingFace Jupyter Agent ํจํด ๊ธฐ๋ฐ:\n * - ์ฌ์ฉ์ ์์ฒญ์ ๋จ๊ณ๋ณ ์คํ ๊ณํ์ผ๋ก ๋ถํด\n * - Tool Calling์ ํตํ ์์ฐจ ์คํ\n * - Self-Healing (์๋ฌ ๋ฐ์ ์ ์๋ ์์ ๋ฐ ์ฌ์๋)\n */\nimport { ApiService } from './ApiService';\nimport { ToolExecutor } from './ToolExecutor';\nimport { SafetyChecker } from '../utils/SafetyChecker';\nimport { StateVerifier } from './StateVerifier';\nimport { ContextManager } from './ContextManager';\nimport { CheckpointManager } from './CheckpointManager';\nimport { DEFAULT_AUTO_AGENT_CONFIG, EXECUTION_SPEED_DELAYS, } from '../types/auto-agent';\nexport class AgentOrchestrator {\n constructor(notebook, sessionContext, apiService, config) {\n this.abortController = null;\n this.isRunning = false;\n // Step-by-step ๋ชจ๋๋ฅผ ์ํ ์ํ\n this.stepByStepResolver = null;\n this.isPaused = false;\n // Validation & Reflection ์ค์ \n this.enablePreValidation = true;\n this.enableReflection = true;\n // โ
State Verification ์ค์ (Phase 1)\n this.enableStateVerification = true;\n // โ
ํ์ฌ Plan ์คํ ์ค ์ ์๋ ๋ณ์ ์ถ์ (cross-step validation์ฉ)\n this.executedStepVariables = new Set();\n // โ
ํ์ฌ Plan ์คํ ์ค import๋ ์ด๋ฆ ์ถ์ (cross-step validation์ฉ)\n this.executedStepImports = new Set();\n // โ
์คํ๋ ๋ณ์์ ์ค์ ๊ฐ ์ถ์ (finalAnswer ๋ณ์ ์นํ์ฉ)\n this.executedStepVariableValues = {};\n // ๋๋ฒ๊น
: ์์ฑ์์ ์ ๋ฌ๋ ๋
ธํธ๋ถ ๋ก๊ทธ\n console.log('[Orchestrator] Constructor - notebook path:', notebook?.context?.path);\n console.log('[Orchestrator] Constructor - notebook title:', notebook?.title?.label);\n this.notebook = notebook;\n this.apiService = apiService || new ApiService();\n this.toolExecutor = new ToolExecutor(notebook, sessionContext, this.apiService);\n this.safetyChecker = new SafetyChecker({\n enableSafetyCheck: config?.enableSafetyCheck ?? true,\n maxExecutionTime: (config?.executionTimeout ?? 30000) / 1000,\n });\n // โ
State Verifier ์ด๊ธฐํ (Phase 1)\n this.stateVerifier = new StateVerifier(this.apiService);\n // โ
Context Manager ์ด๊ธฐํ (Phase 2)\n this.contextManager = new ContextManager();\n // โ
Checkpoint Manager ์ด๊ธฐํ (Phase 3)\n this.checkpointManager = new CheckpointManager(notebook);\n this.config = { ...DEFAULT_AUTO_AGENT_CONFIG, ...config };\n console.log('[Orchestrator] Initialized with config:', {\n executionSpeed: this.config.executionSpeed,\n stepDelay: this.config.stepDelay,\n });\n // ToolExecutor์ ์๋ ์คํฌ๋กค ์ค์ ์ฐ๋\n this.toolExecutor.setAutoScroll(this.config.autoScrollToCell);\n }\n /**\n * ๋ฉ์ธ ์คํ ํจ์: ์ฌ์ฉ์ ์์ฒญ์ ๋ฐ์ ์๋ ์คํ\n */\n async executeTask(userRequest, notebook, onProgress, llmConfig) {\n if (this.isRunning) {\n return {\n success: false,\n plan: null,\n executedSteps: [],\n createdCells: [],\n modifiedCells: [],\n error: 'Auto-Agent๊ฐ ์ด๋ฏธ ์คํ ์ค์
๋๋ค',\n totalAttempts: 0,\n };\n }\n this.isRunning = true;\n this.abortController = new AbortController();\n // โ
์ ์คํ ์์ ์ ์ด์ ์คํ์์ ์ถ์ ๋ ๋ณ์/import ์ด๊ธฐํ\n this.executedStepVariables.clear();\n this.executedStepImports.clear();\n this.executedStepVariableValues = {};\n // โ
State Verification ์ด๋ ฅ ์ด๊ธฐํ (Phase 1)\n this.stateVerifier.clearHistory();\n // โ
Checkpoint Manager ์ ์ธ์
์์ (Phase 3)\n this.checkpointManager.startNewSession();\n const createdCells = [];\n const modifiedCells = [];\n const executedSteps = [];\n const startTime = Date.now();\n try {\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // PHASE 1: PLANNING - ์์
๋ถํด\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n onProgress({ phase: 'planning', message: '์์
๊ณํ ์๋ฆฝ ์ค...' });\n const notebookContext = this.extractNotebookContext(notebook);\n const planResponse = await this.apiService.generateExecutionPlan({\n request: userRequest,\n notebookContext,\n availableTools: ['jupyter_cell', 'markdown', 'final_answer'],\n llmConfig, // Include API keys with request\n });\n const plan = planResponse.plan;\n onProgress({\n phase: 'planned',\n plan,\n message: `${plan.totalSteps}๋จ๊ณ ์คํ ๊ณํ ์์ฑ๋จ`,\n });\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // PHASE 2: EXECUTION - ๋จ๊ณ๋ณ ์คํ (Adaptive Replanning ํฌํจ)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n console.log('[Orchestrator] Starting execution phase with', plan.steps.length, 'steps');\n let currentPlan = plan;\n let stepIndex = 0;\n let replanAttempts = 0;\n const MAX_REPLAN_ATTEMPTS = 3;\n while (stepIndex < currentPlan.steps.length) {\n const step = currentPlan.steps[stepIndex];\n console.log('[Orchestrator] Executing step', step.stepNumber, ':', step.description);\n // ์ค๋จ ์์ฒญ ํ์ธ\n if (this.abortController.signal.aborted) {\n return {\n success: false,\n plan: currentPlan,\n executedSteps,\n createdCells,\n modifiedCells,\n error: '์ฌ์ฉ์์ ์ํด ์ทจ์๋จ',\n totalAttempts: this.countTotalAttempts(executedSteps),\n executionTime: Date.now() - startTime,\n };\n }\n onProgress({\n phase: 'executing',\n currentStep: step.stepNumber,\n totalSteps: currentPlan.totalSteps,\n description: step.description,\n });\n const stepResult = await this.executeStepWithRetry(step, notebook, onProgress);\n // ์์ฑ/์์ ๋ ์
์ถ์ ๋ฐ ํ์ด๋ผ์ดํธ/์คํฌ๋กค\n stepResult.toolResults.forEach((tr) => {\n if (tr.cellIndex !== undefined) {\n if (tr.wasModified) {\n modifiedCells.push(tr.cellIndex);\n }\n else {\n createdCells.push(tr.cellIndex);\n }\n // ์
ํ์ด๋ผ์ดํธ ๋ฐ ์คํฌ๋กค\n this.scrollToAndHighlightCell(tr.cellIndex);\n }\n });\n // ๋จ๊ณ ์คํจ ์ Adaptive Replanning ์๋\n if (!stepResult.success) {\n // Check for FILE_SELECTION_REQUIRED - throw special error for AutoAgentPanel\n console.log('[Orchestrator] Step failed. Error:', stepResult.error);\n console.log('[Orchestrator] Tool results:', stepResult.toolResults);\n if (stepResult.error === 'FILE_SELECTION_REQUIRED') {\n const fileSelectionMetadata = stepResult.toolResults.find(r => r.metadata?.type === 'file_selection')?.metadata;\n console.log('[Orchestrator] FILE_SELECTION_REQUIRED detected, metadata:', fileSelectionMetadata);\n if (fileSelectionMetadata) {\n const error = new Error('FILE_SELECTION_REQUIRED');\n error.name = 'FileSelectionError';\n error.fileSelectionMetadata = fileSelectionMetadata;\n console.log('[Orchestrator] Throwing FileSelectionError', error);\n console.log('[Orchestrator] Error object:', { name: error.name, message: error.message, hasMetadata: !!error.fileSelectionMetadata });\n throw error;\n }\n }\n console.log('[Orchestrator] Step failed, attempting adaptive replanning');\n if (replanAttempts >= MAX_REPLAN_ATTEMPTS) {\n onProgress({\n phase: 'failed',\n message: `์ต๋ ์ฌ๊ณํ ์๋ ํ์(${MAX_REPLAN_ATTEMPTS})๋ฅผ ์ด๊ณผํ์ต๋๋ค.`,\n failedStep: step.stepNumber, // ์คํจํ step UI์ ํ์\n });\n return {\n success: false,\n plan: currentPlan,\n executedSteps,\n createdCells,\n modifiedCells,\n error: `Step ${step.stepNumber} ์คํจ: ${stepResult.error}`,\n totalAttempts: this.countTotalAttempts(executedSteps),\n executionTime: Date.now() - startTime,\n };\n }\n // ์คํจ ์ ๋ณด ๊ตฌ์ฑ (errorName ํฌํจ - ModuleNotFoundError ๋ฑ ์๋ณ์ฉ)\n const executionError = {\n type: 'runtime',\n message: stepResult.error || '์ ์ ์๋ ์ค๋ฅ',\n errorName: stepResult.toolResults.find(r => r.errorName)?.errorName,\n traceback: stepResult.toolResults.find(r => r.traceback)?.traceback || [],\n recoverable: true,\n };\n // ์๋ฌ ํ์
์์ ํต์ฌ ์ ๋ณด ์ถ์ถ\n const errorName = executionError.errorName || '๋ฐํ์ ์๋ฌ';\n const shortErrorMsg = executionError.message.length > 80\n ? executionError.message.substring(0, 80) + '...'\n : executionError.message;\n onProgress({\n phase: 'replanning',\n message: `์๋ฌ ๋ถ์ ์ค: ${errorName}`,\n currentStep: step.stepNumber,\n failedStep: step.stepNumber,\n replanInfo: {\n errorType: errorName,\n rootCause: shortErrorMsg,\n },\n });\n // ๋ง์ง๋ง ์คํ ์ถ๋ ฅ\n const lastOutput = stepResult.toolResults\n .map(r => r.output)\n .filter(Boolean)\n .join('\\n');\n try {\n const replanResponse = await this.apiService.replanExecution({\n originalPlan: currentPlan,\n currentStepIndex: stepIndex,\n error: executionError,\n executionHistory: executedSteps.map(s => ({\n stepNumber: s.stepNumber,\n success: s.success,\n attempts: s.attempts,\n })),\n previousAttempts: replanAttempts,\n previousCodes: [],\n useLlmFallback: true,\n });\n console.log('[Orchestrator] Replan decision:', replanResponse.decision);\n console.log('[Orchestrator] Replan reasoning:', replanResponse.reasoning);\n // โ
๊ฒฐ์ ๊ฒฐ๊ณผ๋ฅผ UI์ ์ฆ์ ๋ฐ์ (์๋ฌ ๋ถ์ โ ๊ฒฐ์ ์๋ฃ)\n const decisionLabel = this.getReplanDecisionLabel(replanResponse.decision);\n // ModuleNotFoundError์ผ ๋ ํจํค์ง๋ช
์ถ์ถ\n const missingPackage = errorName === 'ModuleNotFoundError'\n ? this.extractMissingPackage(executionError.message)\n : undefined;\n onProgress({\n phase: 'replanning',\n message: `๊ฒฐ์ : ${decisionLabel}`,\n currentStep: step.stepNumber,\n failedStep: step.stepNumber,\n replanInfo: {\n errorType: errorName,\n rootCause: shortErrorMsg,\n decision: replanResponse.decision,\n reasoning: replanResponse.reasoning,\n missingPackage,\n },\n });\n // ์คํจํ ์คํ
์์ ์์ฑ๋ ์
์ธ๋ฑ์ค ์ถ์ถ (์ฌ์ฌ์ฉ ์ํด)\n const failedCellIndex = stepResult.toolResults.find(r => r.cellIndex !== undefined)?.cellIndex;\n console.log('[Orchestrator] Failed cell index for reuse:', failedCellIndex);\n // Replan ๊ฒฐ๊ณผ์ ๋ฐ๋ฅธ ๊ณํ ์์ (์คํจํ ์
์ธ๋ฑ์ค ์ ๋ฌ)\n currentPlan = this.applyReplanChanges(currentPlan, stepIndex, replanResponse, failedCellIndex);\n // โ
์
๋ฐ์ดํธ๋ ๊ณํ์ UI์ ๋ฐ์ (plan item list์ ์ ์คํ
ํ์)\n onProgress({\n phase: 'planned',\n plan: currentPlan,\n message: `๊ณํ ์์ ๋จ (${this.getReplanDecisionLabel(replanResponse.decision)})`,\n currentStep: step.stepNumber,\n totalSteps: currentPlan.totalSteps,\n });\n replanAttempts++;\n // stepIndex๋ ๊ทธ๋๋ก ์ ์ง (์์ ๋ ํ์ฌ ๋จ๊ณ๋ฅผ ๋ค์ ์คํ)\n continue;\n }\n catch (replanError) {\n console.error('[Orchestrator] Replan failed:', replanError);\n onProgress({\n phase: 'failed',\n message: `Step ${step.stepNumber} ์คํจ (์ฌ๊ณํ ์คํจ): ${stepResult.error}`,\n });\n return {\n success: false,\n plan: currentPlan,\n executedSteps,\n createdCells,\n modifiedCells,\n error: `Step ${step.stepNumber} ์คํจ: ${stepResult.error}`,\n totalAttempts: this.countTotalAttempts(executedSteps),\n executionTime: Date.now() - startTime,\n };\n }\n }\n // ์ฑ๊ณตํ ๋จ๊ณ ๊ธฐ๋ก\n executedSteps.push(stepResult);\n replanAttempts = 0; // ์ฑ๊ณต ์ ์ฌ๊ณํ ์๋ ํ์ ๋ฆฌ์
\n // โ
์ฑ๊ณตํ Step์์ ์ ์๋ ๋ณ์ ์ถ์ (cross-step validation์ฉ)\n this.trackVariablesFromStep(step);\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // CHECKPOINT CREATION (Phase 3): ์ฑ๊ณต ์คํ
ํ ์ฒดํฌํฌ์ธํธ ์ ์ฅ\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n const newVars = this.extractVariablesFromCode(step.toolCalls\n .filter(tc => tc.tool === 'jupyter_cell')\n .map(tc => tc.parameters.code)\n .join('\\n'));\n this.checkpointManager.createCheckpoint(step.stepNumber, step.description, currentPlan, stepResult, newVars);\n console.log(`[Orchestrator] Checkpoint created for step ${step.stepNumber}`);\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // STATE VERIFICATION (Phase 1): ์ํ ๊ฒ์ฆ ๋ ์ด์ด\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n if (this.enableStateVerification && stepResult.toolResults.length > 0) {\n const stateVerificationResult = await this.verifyStepStateAfterExecution(step, stepResult, onProgress);\n // ๊ฒ์ฆ ๊ฒฐ๊ณผ์ ๋ฐ๋ฅธ ์ฒ๋ฆฌ\n if (stateVerificationResult) {\n const { recommendation, confidence } = stateVerificationResult;\n console.log('[Orchestrator] State verification result:', {\n confidence,\n recommendation,\n isValid: stateVerificationResult.isValid,\n });\n // ๊ถ์ฅ ์ฌํญ์ ๋ฐ๋ฅธ ์ก์
\n if (recommendation === 'replan') {\n console.log('[Orchestrator] State verification recommends replan (confidence:', confidence, ')');\n // Replan์ ์ํ ์๋ฌ ์ํ๋ก ์ ํ (๋ค์ ๋ฐ๋ณต์์ replanning ํธ๋ฆฌ๊ฑฐ)\n onProgress({\n phase: 'replanning',\n message: `์ํ ๊ฒ์ฆ ์ ๋ขฐ๋ ๋ฎ์: ${(confidence * 100).toFixed(0)}%`,\n currentStep: step.stepNumber,\n replanInfo: {\n errorType: 'StateVerificationFailed',\n rootCause: stateVerificationResult.mismatches.map(m => m.description).join('; '),\n },\n });\n // Note: ํ์ฌ๋ ๋ก๊น
๋ง ์ํ, ํฅํ ์๋ replanning ํธ๋ฆฌ๊ฑฐ ๊ตฌํ\n }\n else if (recommendation === 'escalate') {\n console.log('[Orchestrator] State verification recommends escalation (confidence:', confidence, ')');\n onProgress({\n phase: 'failed',\n message: `์ํ ๊ฒ์ฆ ์คํจ - ์ฌ์ฉ์ ๊ฐ์
ํ์: ${stateVerificationResult.mismatches.map(m => m.description).join(', ')}`,\n });\n // ์ฌ๊ฐํ ์ํ ๋ถ์ผ์น ์ ์คํ ์ค๋จ\n return {\n success: false,\n plan: currentPlan,\n executedSteps,\n createdCells,\n modifiedCells,\n error: `์ํ ๊ฒ์ฆ ์คํจ (์ ๋ขฐ๋: ${(confidence * 100).toFixed(0)}%): ${stateVerificationResult.mismatches.map(m => m.description).join('; ')}`,\n totalAttempts: this.countTotalAttempts(executedSteps),\n executionTime: Date.now() - startTime,\n };\n }\n else if (recommendation === 'warning') {\n console.log('[Orchestrator] State verification warning (confidence:', confidence, ')');\n onProgress({\n phase: 'verifying',\n message: `์ํ ๊ฒ์ฆ ๊ฒฝ๊ณ : ${(confidence * 100).toFixed(0)}% ์ ๋ขฐ๋`,\n currentStep: step.stepNumber,\n });\n }\n // 'proceed'๋ ๋ณ๋ ์ฒ๋ฆฌ ์์ด ๊ณ์ ์งํ\n }\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // REFLECTION: ์คํ ๊ฒฐ๊ณผ ๋ถ์ ๋ฐ ์ ์์ ์กฐ์ \n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n if (this.enableReflection && stepResult.toolResults.length > 0) {\n // Reflection ์์ ์๋ฆผ\n onProgress({\n phase: 'reflecting',\n reflectionStatus: 'analyzing',\n currentStep: step.stepNumber,\n message: '์คํ ๊ฒฐ๊ณผ ๋ถ์ ์ค...',\n });\n const remainingSteps = currentPlan.steps.slice(stepIndex + 1);\n const reflection = await this.performReflection(step, stepResult.toolResults, remainingSteps);\n if (reflection) {\n const { shouldContinue, action, reason } = this.shouldContinueAfterReflection(reflection);\n console.log('[Orchestrator] Reflection decision:', { shouldContinue, action, reason });\n // Reflection ๊ฒฐ๊ณผ UI ์
๋ฐ์ดํธ\n if (reflection.evaluation.checkpoint_passed) {\n onProgress({\n phase: 'reflecting',\n reflectionStatus: 'passed',\n currentStep: step.stepNumber,\n message: '๊ฒ์ฆ ํต๊ณผ',\n });\n }\n else {\n onProgress({\n phase: 'reflecting',\n reflectionStatus: 'adjusting',\n currentStep: step.stepNumber,\n message: `์กฐ์ ๊ถ๊ณ : ${reason}`,\n });\n }\n // Reflection ๊ฒฐ๊ณผ๊ฐ retry ๋๋ replan์ ์๊ตฌํ๋ฉด ํด๋น ๋ก์ง์ผ๋ก ์ด๋\n if (!shouldContinue) {\n if (action === 'replan') {\n console.log('[Orchestrator] Reflection recommends replan, triggering adaptive replanning');\n }\n else if (action === 'retry') {\n console.log('[Orchestrator] Reflection recommends retry - but step succeeded, continuing');\n }\n }\n }\n }\n // ๋ค์ ์คํ
์ ์ ์ง์ฐ ์ ์ฉ (์ฌ์ฉ์๊ฐ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์๊ฐ)\n await this.applyStepDelay();\n // final_answer ๋๊ตฌ ํธ์ถ ์ ์๋ฃ\n if (stepResult.isFinalAnswer) {\n onProgress({\n phase: 'completed',\n message: stepResult.finalAnswer || '์์
์๋ฃ',\n });\n return {\n success: true,\n plan: currentPlan,\n executedSteps,\n createdCells,\n modifiedCells,\n finalAnswer: stepResult.finalAnswer,\n totalAttempts: this.countTotalAttempts(executedSteps),\n executionTime: Date.now() - startTime,\n };\n }\n stepIndex++;\n }\n // ๋ชจ๋ ๋จ๊ณ ์ฑ๊ณต\n onProgress({\n phase: 'completed',\n message: '๋ชจ๋ ๋จ๊ณ ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ',\n });\n return {\n success: true,\n plan,\n executedSteps,\n createdCells,\n modifiedCells,\n totalAttempts: this.countTotalAttempts(executedSteps),\n executionTime: Date.now() - startTime,\n };\n }\n catch (error) {\n console.log('[Orchestrator] Caught error in executeTask:', error);\n console.log('[Orchestrator] Error name:', error.name);\n console.log('[Orchestrator] Error message:', error.message);\n // FileSelectionError๋ ๋ค์ throwํด์ AutoAgentPanel์ด ์ฒ๋ฆฌํ๋๋ก ํจ\n if (error.name === 'FileSelectionError') {\n console.log('[Orchestrator] Re-throwing FileSelectionError to AutoAgentPanel');\n this.isRunning = false;\n this.abortController = null;\n throw error;\n }\n onProgress({\n phase: 'failed',\n message: error.message || '์ ์ ์๋ ์ค๋ฅ ๋ฐ์',\n });\n return {\n success: false,\n plan: null,\n executedSteps,\n createdCells,\n modifiedCells,\n error: error.message || '์ ์ ์๋ ์ค๋ฅ ๋ฐ์',\n totalAttempts: this.countTotalAttempts(executedSteps),\n executionTime: Date.now() - startTime,\n };\n }\n finally {\n this.isRunning = false;\n this.abortController = null;\n }\n }\n /**\n * ์ถ๋ ฅ ๊ฒฐ๊ณผ๊ฐ ๋ถ์ ์ ์ธ์ง ๋ถ์ (์๋ฌ๋ ์๋์ง๋ง ์คํจ ์๋ฏธ๋ฅผ ๊ฐ์ง ์ถ๋ ฅ)\n * Fast Fail: ๋ชจ๋ ์๋ฌ โ Adaptive Replanning์ผ๋ก ์ฒ๋ฆฌ\n */\n analyzeOutputForFailure(output) {\n if (!output) {\n return { isNegative: false };\n }\n const negativePatterns = [\n // ํ๊ฒฝ/์์กด์ฑ ์๋ฌ\n { pattern: /ModuleNotFoundError/i, reason: '๋ชจ๋์ ์ฐพ์ ์ ์์ (ํจํค์ง ์ค์น ํ์)' },\n { pattern: /ImportError/i, reason: 'import ์๋ฌ (ํจํค์ง ์ค์น ํ์)' },\n { pattern: /No module named/i, reason: '๋ชจ๋์ด ์์ (ํจํค์ง ์ค์น ํ์)' },\n { pattern: /cannot import name/i, reason: 'import ์คํจ' },\n // ํ์ผ/๊ฒฝ๋ก ๊ด๋ จ ์ค๋ฅ\n { pattern: /FileNotFoundError|No such file or directory|ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค/i, reason: 'ํ์ผ์ ์ฐพ์ ์ ์์' },\n // ๋ฐํ์ ์๋ฌ\n { pattern: /NameError:\\s*name\\s*'([^']+)'\\s*is not defined/i, reason: '๋ณ์๊ฐ ์ ์๋์ง ์์' },\n { pattern: /KeyError/i, reason: 'ํค๋ฅผ ์ฐพ์ ์ ์์' },\n { pattern: /IndexError/i, reason: '์ธ๋ฑ์ค ๋ฒ์ ์ด๊ณผ' },\n { pattern: /TypeError/i, reason: 'ํ์
์ค๋ฅ' },\n { pattern: /ValueError/i, reason: '๊ฐ ์ค๋ฅ' },\n { pattern: /AttributeError/i, reason: '์์ฑ ์ค๋ฅ' },\n // ๋ฐ์ดํฐ ๊ฒ์ฆ ์๋ฌ (GridSearchCV, NaN/Inf ๋ฑ)\n { pattern: /์ฌ์ \\s*๊ฒ์ฆ.*์คํจ|์ฌ์ \\s*๊ฒ์ฆ.*์ค๋ฅ|pre-?validation.*fail|validation.*fail/i, reason: '์ฌ์ ๊ฒ์ฆ ์คํจ' },\n { pattern: /NaN.*๊ฐ|Inf.*๊ฐ|invalid value|contains NaN|contains Inf/i, reason: 'NaN ๋๋ Inf ๊ฐ ๊ฐ์ง' },\n { pattern: /์ํ๋์ง\\s*์์|was not performed|did not execute|not executed/i, reason: '์คํ๋์ง ์์' },\n { pattern: /fit.*fail|GridSearchCV.*fail|ํ์ต.*์คํจ/i, reason: '๋ชจ๋ธ ํ์ต ์คํจ' },\n // ๋ช
์์ ์คํจ ๋ฉ์์ง\n { pattern: /์คํจ|failed|Fail/i, reason: '๋ช
์์ ์ค๋ฅ ๋ฉ์์ง ๊ฐ์ง' },\n { pattern: /not found|cannot find|์ฐพ์ ์ ์/i, reason: '๋ฆฌ์์ค๋ฅผ ์ฐพ์ ์ ์์' },\n // Note: Empty DataFrame, 0 rows ๋ฑ์ ์ ์์ ์ธ ๋ถ์ ๊ฒฐ๊ณผ์ผ ์ ์์ผ๋ฏ๋ก ๋ถ์ ์ ํจํด์์ ์ ์ธ\n ];\n for (const { pattern, reason } of negativePatterns) {\n if (pattern.test(output)) {\n console.log('[Orchestrator] Negative output detected:', reason);\n return { isNegative: true, reason };\n }\n }\n return { isNegative: false };\n }\n /**\n * ๋จ๊ณ ์คํ (Fast Fail ๋ฐฉ์)\n * ์๋ฌ ๋ฐ์ ์ ์ฌ์๋ ์์ด ๋ฐ๋ก ์คํจ ๋ฐํ โ Adaptive Replanning์ผ๋ก ์ฒ๋ฆฌ\n * + Pre-Validation: ์คํ ์ Pyflakes/AST ๊ฒ์ฆ\n */\n async executeStepWithRetry(step, notebook, onProgress) {\n console.log('[Orchestrator] executeStep called for step:', step.stepNumber);\n console.log('[Orchestrator] Step toolCalls:', JSON.stringify(step.toolCalls, null, 2));\n const toolResults = [];\n try {\n // Tool Calling ์คํ\n console.log('[Orchestrator] Processing', step.toolCalls.length, 'tool calls');\n for (const toolCall of step.toolCalls) {\n console.log('[Orchestrator] Processing toolCall:', toolCall.tool);\n // ์ค๋จ ์์ฒญ ํ์ธ\n if (this.abortController?.signal.aborted) {\n return {\n success: false,\n stepNumber: step.stepNumber,\n toolResults,\n attempts: 1,\n error: '์ฌ์ฉ์์ ์ํด ์ทจ์๋จ',\n };\n }\n onProgress({\n phase: 'tool_calling',\n tool: toolCall.tool,\n attempt: 1,\n currentStep: step.stepNumber,\n });\n // jupyter_cell์ธ ๊ฒฝ์ฐ: ์์ ์ฑ ๊ฒ์ฌ + Pre-Validation\n if (toolCall.tool === 'jupyter_cell') {\n const params = toolCall.parameters;\n // 1. ์์ ์ฑ ๊ฒ์ฌ\n const safetyResult = this.safetyChecker.checkCodeSafety(params.code);\n if (!safetyResult.safe) {\n return {\n success: false,\n stepNumber: step.stepNumber,\n toolResults,\n attempts: 1,\n error: `์์ ์ฑ ๊ฒ์ฌ ์คํจ: ${safetyResult.blockedPatterns?.join(', ')}`,\n };\n }\n // 2. Pre-Validation (Pyflakes/AST ๊ธฐ๋ฐ)\n onProgress({\n phase: 'validating',\n validationStatus: 'checking',\n currentStep: step.stepNumber,\n message: '์ฝ๋ ํ์ง ๊ฒ์ฆ ์ค...',\n });\n const validation = await this.validateCodeBeforeExecution(params.code);\n if (validation) {\n if (validation.hasErrors) {\n // โ
๋๋ฒ๊น
์ฉ ์์ธ ๋ก๊ทธ (robust version)\n console.log('');\n console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');\n console.log('โ ๐ด [Orchestrator] PRE-VALIDATION FAILED โ');\n console.log('โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ');\n console.log(`โ Step: ${step.stepNumber} - ${step.description?.substring(0, 45) || 'N/A'}...`);\n console.log(`โ Summary: ${validation.summary || 'No summary'}`);\n console.log('โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ');\n console.log('โ Code:');\n console.log('โ ' + (params.code || '').split('\\n').join('\\nโ '));\n console.log('โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ');\n console.log('โ Issues:');\n if (validation.issues && validation.issues.length > 0) {\n validation.issues.forEach((issue, idx) => {\n console.log(`โ ${idx + 1}. [${issue.severity || 'unknown'}] ${issue.category || 'unknown'}: ${issue.message || 'no message'}`);\n if (issue.line)\n console.log(`โ Line ${issue.line}${issue.column ? `:${issue.column}` : ''}`);\n if (issue.code_snippet)\n console.log(`โ Snippet: ${issue.code_snippet}`);\n });\n }\n else {\n console.log('โ (No issues array available)');\n }\n if (validation.dependencies) {\n console.log('โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ');\n console.log('โ Dependencies:', JSON.stringify(validation.dependencies));\n }\n console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');\n console.log('');\n onProgress({\n phase: 'validating',\n validationStatus: 'failed',\n currentStep: step.stepNumber,\n message: `๊ฒ์ฆ ์คํจ: ${validation.summary}`,\n });\n // Fast Fail: ๊ฒ์ฆ ์ค๋ฅ โ ๋ฐ๋ก Adaptive Replanning\n return {\n success: false,\n stepNumber: step.stepNumber,\n toolResults,\n attempts: 1,\n error: `์ฌ์ ๊ฒ์ฆ ์ค๋ฅ: ${validation.summary}`,\n };\n }\n else if (validation.hasWarnings) {\n console.log('[Orchestrator] โ ๏ธ Pre-validation warnings:', validation.issues.map(i => i.message).join('; '));\n onProgress({\n phase: 'validating',\n validationStatus: 'warning',\n currentStep: step.stepNumber,\n message: `๊ฒฝ๊ณ ๊ฐ์ง: ${validation.issues.length}๊ฑด (์คํ ๊ณ์)`,\n });\n }\n else {\n console.log('[Orchestrator] โ
Pre-validation passed for step', step.stepNumber);\n onProgress({\n phase: 'validating',\n validationStatus: 'passed',\n currentStep: step.stepNumber,\n message: '์ฝ๋ ๊ฒ์ฆ ํต๊ณผ',\n });\n }\n }\n }\n // ํ์์์๊ณผ ํจ๊ป ์คํ (stepNumber ์ ๋ฌ)\n console.log('[Orchestrator] Calling toolExecutor.executeTool for:', toolCall.tool, 'step:', step.stepNumber);\n const result = await this.executeWithTimeout(() => this.toolExecutor.executeTool(toolCall, step.stepNumber), this.config.executionTimeout);\n console.log('[Orchestrator] Tool execution result:', JSON.stringify(result));\n toolResults.push(result);\n // jupyter_cell ์คํ ์คํจ ์ โ Fast Fail\n if (!result.success && toolCall.tool === 'jupyter_cell') {\n const errorMsg = result.error || '์ ์ ์๋ ์ค๋ฅ';\n console.log('[Orchestrator] jupyter_cell execution failed:', errorMsg.substring(0, 100));\n return {\n success: false,\n stepNumber: step.stepNumber,\n toolResults,\n attempts: 1,\n error: errorMsg,\n };\n }\n // final_answer ๋๊ตฌ ๊ฐ์ง\n if (toolCall.tool === 'final_answer') {\n let finalAnswerText = result.output;\n // โ
๋ณ์ ๊ฐ ์ถ์ถ ๋ฐ ์นํ\n try {\n // finalAnswer์์ {๋ณ์๋ช
} ํจํด ์ฐพ๊ธฐ\n const varPattern = /\\{(\\w+)\\}/g;\n const matches = [...finalAnswerText.matchAll(varPattern)];\n const varNames = [...new Set(matches.map(m => m[1]))];\n if (varNames.length > 0) {\n console.log('[Orchestrator] Extracting variable values for finalAnswer:', varNames);\n // Jupyter kernel์์ ๋ณ์ ๊ฐ ์ถ์ถ\n const variableValues = await this.toolExecutor.getVariableValues(varNames);\n console.log('[Orchestrator] Extracted variable values:', variableValues);\n // ๋ณ์ ์นํ\n finalAnswerText = finalAnswerText.replace(varPattern, (match, varName) => {\n return variableValues[varName] ?? match;\n });\n console.log('[Orchestrator] Final answer after substitution:', finalAnswerText);\n }\n }\n catch (error) {\n console.error('[Orchestrator] Failed to substitute variables in finalAnswer:', error);\n // ์คํจํด๋ ์๋ณธ ํ
์คํธ ์ฌ์ฉ\n }\n return {\n success: true,\n stepNumber: step.stepNumber,\n toolResults,\n attempts: 1,\n isFinalAnswer: true,\n finalAnswer: finalAnswerText,\n };\n }\n }\n // ๋ชจ๋ ๋๊ตฌ ์คํ ์ฑ๊ณต\n if (toolResults.length > 0 && toolResults.every((r) => r.success)) {\n // ์ถ๋ ฅ ๊ฒฐ๊ณผ ๋ถ์: ์คํ์ ์ฑ๊ณตํ์ง๋ง ์ถ๋ ฅ์ด ๋ถ์ ์ ์ธ ๊ฒฝ์ฐ\n const allOutputs = toolResults\n .map((r) => {\n const output = r.output;\n if (!output)\n return '';\n if (typeof output === 'string')\n return output;\n if (typeof output === 'object' && output !== null) {\n // Jupyter output format: {text/plain: ..., text/html: ...}\n if ('text/plain' in output) {\n const textPlain = output['text/plain'];\n return typeof textPlain === 'string' ? textPlain : String(textPlain || '');\n }\n try {\n return JSON.stringify(output);\n }\n catch {\n return '[object]';\n }\n }\n // Primitive types (number, boolean, etc.)\n try {\n return String(output);\n }\n catch {\n return '[unknown]';\n }\n })\n .join('\\n');\n const outputAnalysis = this.analyzeOutputForFailure(allOutputs);\n if (outputAnalysis.isNegative) {\n console.log('[Orchestrator] Negative output detected:', outputAnalysis.reason);\n // Fast Fail: ๋ถ์ ์ ์ถ๋ ฅ โ ๋ฐ๋ก Adaptive Replanning\n return {\n success: false,\n stepNumber: step.stepNumber,\n toolResults,\n attempts: 1,\n error: outputAnalysis.reason || '์ถ๋ ฅ ๊ฒฐ๊ณผ์์ ๋ฌธ์ ๊ฐ์ง',\n };\n }\n return {\n success: true,\n stepNumber: step.stepNumber,\n toolResults,\n attempts: 1,\n };\n }\n // ๋๊ตฌ ์คํ ๊ฒฐ๊ณผ๊ฐ ์๋ ๊ฒฝ์ฐ\n // Use the first tool's error message if available\n const firstToolError = toolResults.find(r => r.error)?.error;\n return {\n success: false,\n stepNumber: step.stepNumber,\n toolResults,\n attempts: 1,\n error: firstToolError || '๋๊ตฌ ์คํ ๊ฒฐ๊ณผ ์์',\n };\n }\n catch (error) {\n const isTimeout = error.message?.includes('timeout');\n if (isTimeout) {\n // ํ์์์ ์ ์ปค๋ ์ธํฐ๋ฝํธ\n await this.toolExecutor.interruptKernel();\n }\n return {\n success: false,\n stepNumber: step.stepNumber,\n toolResults,\n attempts: 1,\n error: error.message || '์ ์ ์๋ ์ค๋ฅ',\n };\n }\n }\n /**\n * ๋
ธํธ๋ถ ์ปจํ
์คํธ ์ถ์ถ\n * โ
Phase 2: ContextManager๋ฅผ ์ฌ์ฉํ์ฌ ํ ํฐ ์์ฐ ๋ด์์ ์ต์ ํ๋ ์ปจํ
์คํธ ๋ฐํ\n */\n extractNotebookContext(notebook, currentCellIndex) {\n const cells = notebook.content.model?.cells;\n const cellCount = cells?.length || 0;\n // ๋ชจ๋ ์
์ ๋ณด ์ถ์ถ (ContextManager๊ฐ ์ฐ์ ์์์ ๋ฐ๋ผ ํํฐ๋ง)\n const allCells = [];\n if (cells) {\n for (let i = 0; i < cellCount; i++) {\n const cell = cells.get(i);\n allCells.push({\n index: i,\n type: cell.type,\n source: cell.sharedModel.getSource(),\n output: this.toolExecutor.getCellOutput(i),\n });\n }\n }\n const rawContext = {\n cellCount,\n recentCells: allCells,\n importedLibraries: this.detectImportedLibraries(notebook),\n definedVariables: this.detectDefinedVariables(notebook),\n notebookPath: notebook.context?.path,\n };\n // โ
ContextManager๋ฅผ ํตํ ํ ํฐ ์์ฐ ๊ธฐ๋ฐ ์ต์ ํ\n const { context: optimizedContext, usage, pruneResult } = this.contextManager.extractOptimizedContext(rawContext, currentCellIndex);\n // ๋ก๊น
\n if (pruneResult) {\n console.log(`[Orchestrator] Context optimized: ${pruneResult.originalTokens} โ ${pruneResult.prunedTokens} tokens ` +\n `(removed: ${pruneResult.removedCellCount}, truncated: ${pruneResult.truncatedCellCount})`);\n }\n else {\n console.log(`[Orchestrator] Context usage: ${usage.totalTokens} tokens (${(usage.usagePercent * 100).toFixed(1)}%)`);\n }\n return optimizedContext;\n }\n /**\n * ์๋ณธ ๋
ธํธ๋ถ ์ปจํ
์คํธ ์ถ์ถ (์ต์ ํ ์์ด)\n * โ
Phase 2: ๋๋ฒ๊น
/ํ
์คํธ์ฉ\n */\n extractRawNotebookContext(notebook) {\n const cells = notebook.content.model?.cells;\n const cellCount = cells?.length || 0;\n const recentCells = [];\n if (cells) {\n const startIndex = Math.max(0, cellCount - 3);\n for (let i = startIndex; i < cellCount; i++) {\n const cell = cells.get(i);\n recentCells.push({\n index: i,\n type: cell.type,\n source: cell.sharedModel.getSource().slice(0, 500),\n output: this.toolExecutor.getCellOutput(i).slice(0, 300),\n });\n }\n }\n return {\n cellCount,\n recentCells,\n importedLibraries: this.detectImportedLibraries(notebook),\n definedVariables: this.detectDefinedVariables(notebook),\n notebookPath: notebook.context?.path,\n };\n }\n /**\n * import๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ์ง\n */\n detectImportedLibraries(notebook) {\n const libraries = new Set();\n const cells = notebook.content.model?.cells;\n if (!cells)\n return [];\n for (let i = 0; i < cells.length; i++) {\n const cell = cells.get(i);\n if (cell.type === 'code') {\n const source = cell.sharedModel.getSource();\n // import xxx ํจํด\n const importMatches = source.matchAll(/^import\\s+(\\w+)/gm);\n for (const match of importMatches) {\n libraries.add(match[1]);\n }\n // from xxx import ํจํด\n const fromMatches = source.matchAll(/^from\\s+(\\w+)/gm);\n for (const match of fromMatches) {\n libraries.add(match[1]);\n }\n }\n }\n return Array.from(libraries);\n }\n /**\n * ์ ์๋ ๋ณ์ ๊ฐ์ง\n *\n * โ
์์ : ์ธ๋ดํธ๋ ์ฝ๋ (try/except, with, if ๋ธ๋ก ๋ด๋ถ)์์๋ ๋ณ์ ๊ฐ์ง\n * ๊ธฐ์กด regex: /^(\\w+)\\s*=/gm - ๋ผ์ธ ์์์์๋ง ๋งค์นญ\n * ์์ regex: /^[ \\t]*(\\w+)\\s*=/gm - ์ธ๋ดํธ๋ ํ ๋น๋ฌธ๋ ๋งค์นญ\n */\n detectDefinedVariables(notebook) {\n const variables = new Set();\n const cells = notebook.content.model?.cells;\n if (!cells)\n return [];\n for (let i = 0; i < cells.length; i++) {\n const cell = cells.get(i);\n if (cell.type === 'code') {\n const source = cell.sharedModel.getSource();\n // โ
์ธ๋ดํธ ํ์ฉํ๋ ํ ๋น ํจํด: [๊ณต๋ฐฑ/ํญ]* variable = ...\n const assignMatches = source.matchAll(/^[ \\t]*(\\w+)\\s*=/gm);\n for (const match of assignMatches) {\n // ์์ฝ์ด ๋ฐ ๋น๊ต ์ฐ์ฐ์ ์ ์ธ\n // == ๋ ๋น๊ต์ฐ์ฐ์์ด๋ฏ๋ก ์ ์ธ (์: if x == 1)\n const varName = match[1];\n if (!['if', 'for', 'while', 'def', 'class', 'import', 'from', 'elif', 'return', 'yield', 'assert', 'raise', 'del', 'pass', 'break', 'continue', 'global', 'nonlocal', 'lambda', 'with', 'as', 'try', 'except', 'finally'].includes(varName)) {\n // == ๋น๊ต ์ฐ์ฐ์ ์ฒดํฌ (matchAll ๊ฒฐ๊ณผ์์ ์๋ ๋ฌธ์์ด ํ์ธ)\n const fullMatch = match[0];\n if (!fullMatch.includes('==') && !fullMatch.includes('!=') && !fullMatch.includes('<=') && !fullMatch.includes('>=')) {\n variables.add(varName);\n }\n }\n }\n // โ
์ถ๊ฐ: ํํ ์ธํจํน ํจํด๋ ๊ฐ์ง (์: x, y = func())\n const tupleMatches = source.matchAll(/^[ \\t]*(\\w+(?:\\s*,\\s*\\w+)+)\\s*=/gm);\n for (const match of tupleMatches) {\n const tupleVars = match[1].split(',').map(v => v.trim());\n for (const varName of tupleVars) {\n if (varName && /^\\w+$/.test(varName)) {\n variables.add(varName);\n }\n }\n }\n // โ
์ถ๊ฐ: for ๋ฃจํ ๋ณ์ ๊ฐ์ง (์: for x in items:, for i, v in enumerate())\n const forMatches = source.matchAll(/^[ \\t]*for\\s+(\\w+(?:\\s*,\\s*\\w+)*)\\s+in\\s+/gm);\n for (const match of forMatches) {\n const loopVars = match[1].split(',').map(v => v.trim());\n for (const varName of loopVars) {\n if (varName && /^\\w+$/.test(varName)) {\n variables.add(varName);\n }\n }\n }\n // โ
์ถ๊ฐ: with ๋ฌธ ๋ณ์ ๊ฐ์ง (์: with open() as f:)\n const withMatches = source.matchAll(/^[ \\t]*with\\s+.*\\s+as\\s+(\\w+)/gm);\n for (const match of withMatches) {\n variables.add(match[1]);\n }\n // โ
์ถ๊ฐ: except ๋ฌธ ๋ณ์ ๊ฐ์ง (์: except Exception as e:)\n const exceptMatches = source.matchAll(/^[ \\t]*except\\s+.*\\s+as\\s+(\\w+)/gm);\n for (const match of exceptMatches) {\n variables.add(match[1]);\n }\n }\n }\n return Array.from(variables);\n }\n /**\n * โ
๋จ์ผ ์ฝ๋ ๋ฌธ์์ด์์ ์ ์๋ ๋ณ์ ์ถ์ถ\n * detectDefinedVariables์ ๋์ผํ ๋ก์ง์ ๋จ์ผ ์ฝ๋ ๋ธ๋ก์ ์ ์ฉ\n */\n extractVariablesFromCode(code) {\n const variables = new Set();\n const reservedWords = ['if', 'for', 'while', 'def', 'class', 'import', 'from', 'elif', 'return', 'yield', 'assert', 'raise', 'del', 'pass', 'break', 'continue', 'global', 'nonlocal', 'lambda', 'with', 'as', 'try', 'except', 'finally'];\n // ์ธ๋ดํธ ํ์ฉํ๋ ํ ๋น ํจํด\n const assignMatches = code.matchAll(/^[ \\t]*(\\w+)\\s*=/gm);\n for (const match of assignMatches) {\n const varName = match[1];\n if (!reservedWords.includes(varName)) {\n const fullMatch = match[0];\n if (!fullMatch.includes('==') && !fullMatch.includes('!=') && !fullMatch.includes('<=') && !fullMatch.includes('>=')) {\n variables.add(varName);\n }\n }\n }\n // ํํ ์ธํจํน\n const tupleMatches = code.matchAll(/^[ \\t]*(\\w+(?:\\s*,\\s*\\w+)+)\\s*=/gm);\n for (const match of tupleMatches) {\n const tupleVars = match[1].split(',').map(v => v.trim());\n for (const varName of tupleVars) {\n if (varName && /^\\w+$/.test(varName)) {\n variables.add(varName);\n }\n }\n }\n // for ๋ฃจํ ๋ณ์\n const forMatches = code.matchAll(/^[ \\t]*for\\s+(\\w+(?:\\s*,\\s*\\w+)*)\\s+in\\s+/gm);\n for (const match of forMatches) {\n const loopVars = match[1].split(',').map(v => v.trim());\n for (const varName of loopVars) {\n if (varName && /^\\w+$/.test(varName)) {\n variables.add(varName);\n }\n }\n }\n // with ๋ฌธ ๋ณ์\n const withMatches = code.matchAll(/^[ \\t]*with\\s+.*\\s+as\\s+(\\w+)/gm);\n for (const match of withMatches) {\n variables.add(match[1]);\n }\n // except ๋ฌธ ๋ณ์\n const exceptMatches = code.matchAll(/^[ \\t]*except\\s+.*\\s+as\\s+(\\w+)/gm);\n for (const match of exceptMatches) {\n variables.add(match[1]);\n }\n return Array.from(variables);\n }\n /**\n * โ
์ฝ๋์์ import๋ ์ด๋ฆ๋ค ์ถ์ถ\n * - import xxx โ xxx\n * - import xxx as yyy โ yyy\n * - from xxx import yyy โ yyy\n * - from xxx import yyy as zzz โ zzz\n * - from xxx import * ๋ ์ ์ธ (์ถ์ ๋ถ๊ฐ)\n */\n extractImportsFromCode(code) {\n const imports = new Set();\n // import xxx ๋๋ import xxx as yyy\n const importMatches = code.matchAll(/^[ \\t]*import\\s+([\\w.]+)(?:\\s+as\\s+(\\w+))?/gm);\n for (const match of importMatches) {\n const asName = match[2]; // as ๋ณ์นญ\n const name = match[1]; // ์๋ ์ด๋ฆ\n if (asName) {\n imports.add(asName);\n }\n else {\n // import pandas.DataFrame ๊ฐ์ ๊ฒฝ์ฐ pandas๋ง ์ถ์ถ\n imports.add(name.split('.')[0]);\n }\n }\n // from xxx import yyy, zzz ๋๋ from xxx import yyy as aaa\n const fromImportMatches = code.matchAll(/^[ \\t]*from\\s+[\\w.]+\\s+import\\s+(.+)$/gm);\n for (const match of fromImportMatches) {\n const importList = match[1];\n if (importList.trim() === '*')\n continue; // from xxx import * ์ ์ธ\n // ์ฌ๋ฌ import ์ฒ๋ฆฌ (์: from sklearn import train_test_split, cross_val_score)\n const items = importList.split(',');\n for (const item of items) {\n const trimmed = item.trim();\n // as ๋ณ์นญ์ด ์๋ ๊ฒฝ์ฐ: yyy as zzz\n const asMatch = trimmed.match(/^(\\w+)\\s+as\\s+(\\w+)$/);\n if (asMatch) {\n imports.add(asMatch[2]); // ๋ณ์นญ ์ฌ์ฉ\n }\n else if (/^\\w+$/.test(trimmed)) {\n imports.add(trimmed);\n }\n }\n }\n return Array.from(imports);\n }\n /**\n * โ
์คํ๋ Step์ ์ฝ๋์์ ๋ณ์์ import๋ฅผ ์ถ์ \n */\n trackVariablesFromStep(step) {\n for (const toolCall of step.toolCalls) {\n if (toolCall.tool === 'jupyter_cell') {\n const params = toolCall.parameters;\n // ๋ณ์ ์ถ์ \n const vars = this.extractVariablesFromCode(params.code);\n vars.forEach(v => this.executedStepVariables.add(v));\n // โ
import ์ถ์ \n const imports = this.extractImportsFromCode(params.code);\n imports.forEach(i => this.executedStepImports.add(i));\n console.log('[Orchestrator] Tracked from step', step.stepNumber, '- vars:', vars, 'imports:', imports);\n }\n }\n }\n /**\n * Adaptive Replanning ๊ฒฐ๊ณผ ์ ์ฉ\n *\n * โ
์์ฐจ ์คํ ์์น: ๋ชจ๋ ์ ์
์ ํญ์ ๋งจ ๋์ ์ถ๊ฐ๋จ\n * - ๊ธฐ์กด ์
์ฌ์ฌ์ฉ(cellIndex ์ฃผ์
) ์ ๊ฑฐ โ ํญ์ ์ ์
์์ฑ\n * - ์ด๋ ๊ฒ ํ๋ฉด ์
์ด ํญ์ ์์์ ์๋๋ก ์์๋๋ก ์ถ๊ฐ๋จ\n */\n applyReplanChanges(plan, currentStepIndex, replanResponse, failedCellIndex // ์ด์ ์ฌ์ฉํ์ง ์์ (API ํธํ์ฑ ์ ์ง)\n ) {\n const { decision, changes } = replanResponse;\n const steps = [...plan.steps];\n const currentStep = steps[currentStepIndex];\n console.log('[Orchestrator] Applying replan changes:', decision, '(always append new cells)');\n switch (decision) {\n case 'refine':\n // ํ์ฌ ๋จ๊ณ์ ์ฝ๋๋ง ์์ - ๊ธฐ์กด ์
์์ (MODIFY ์์
)\n if (changes.refined_code) {\n const newToolCalls = currentStep.toolCalls.map(tc => {\n if (tc.tool === 'jupyter_cell') {\n const params = tc.parameters;\n return {\n ...tc,\n parameters: {\n ...params,\n code: changes.refined_code,\n // โ
cellIndex ๋ณด์กด: ๊ธฐ์กด ์
๋๋ ์คํจํ ์
์ ์์ \n cellIndex: params.cellIndex ?? failedCellIndex,\n operation: 'MODIFY',\n },\n };\n }\n return tc;\n });\n steps[currentStepIndex] = {\n ...currentStep,\n toolCalls: newToolCalls,\n wasReplanned: true,\n cellOperation: 'MODIFY',\n targetCellIndex: failedCellIndex,\n };\n }\n break;\n case 'insert_steps':\n // ์๋ก์ด ๋จ๊ณ๋ค์ ํ์ฌ ์์น์ ์ฝ์
(์: pip install)\n // ์คํ ์ ๋ชจ๋ ์
์ ์์ฐจ์ ์ผ๋ก ๋งจ ๋์ ์ถ๊ฐ๋จ\n if (changes.new_steps && changes.new_steps.length > 0) {\n const newSteps = changes.new_steps.map((newStep, idx) => ({\n ...newStep,\n stepNumber: currentStep.stepNumber + idx * 0.1,\n isNew: true,\n cellOperation: 'CREATE', // ์ ์
์์ฑ\n }));\n steps.splice(currentStepIndex, 0, ...newSteps);\n // ๋จ๊ณ ๋ฒํธ ์ฌ์ ๋ ฌ\n steps.forEach((step, idx) => {\n step.stepNumber = idx + 1;\n });\n }\n break;\n case 'replace_step':\n // ํ์ฌ ๋จ๊ณ๋ฅผ ์์ ํ ๊ต์ฒด - ์ ์
์์ฑ\n if (changes.replacement) {\n const replacementStep = {\n ...changes.replacement,\n stepNumber: currentStep.stepNumber,\n toolCalls: changes.replacement.toolCalls || [],\n isReplaced: true,\n cellOperation: 'CREATE', // ์ ์
์์ฑ\n };\n // cellIndex ์์ฑ ๋ช
์์ ์ ๊ฑฐ (์ ์
์์ฑ)\n replacementStep.toolCalls.forEach(tc => {\n if (tc.tool === 'jupyter_cell' && tc.parameters) {\n delete tc.parameters.cellIndex;\n tc.parameters.operation = 'CREATE';\n }\n });\n steps[currentStepIndex] = replacementStep;\n }\n break;\n case 'replan_remaining':\n // ํ์ฌ ๋จ๊ณ๋ถํฐ ๋๊น์ง ์๋ก์ด ๊ณํ์ผ๋ก ๊ต์ฒด\n if (changes.new_plan && changes.new_plan.length > 0) {\n const existingSteps = steps.slice(0, currentStepIndex);\n const newPlanSteps = changes.new_plan.map((newStep, idx) => ({\n ...newStep,\n stepNumber: currentStepIndex + idx + 1,\n isNew: true,\n cellOperation: 'CREATE', // ์ ์
์์ฑ\n }));\n // ์ ๊ณํ์ final_answer๊ฐ ์์ผ๋ฉด ๊ฒฝ๊ณ ๋ก๊ทธ\n const hasFinalAnswer = newPlanSteps.some(step => step.toolCalls?.some((tc) => tc.tool === 'final_answer'));\n if (!hasFinalAnswer) {\n console.warn('[Orchestrator] replan_remaining: new_plan does not include final_answer');\n }\n steps.length = 0;\n steps.push(...existingSteps, ...newPlanSteps);\n }\n break;\n }\n return {\n ...plan,\n steps,\n totalSteps: steps.length,\n };\n }\n /**\n * ์ด ์๋ ํ์ ๊ณ์ฐ\n */\n countTotalAttempts(steps) {\n return steps.reduce((sum, step) => sum + step.attempts, 0);\n }\n /**\n * ํ์์์ ๋ํผ\n */\n async executeWithTimeout(fn, timeoutMs) {\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject(new Error(`์คํ ํ์์์ (${timeoutMs}ms)`));\n }, timeoutMs);\n fn()\n .then((result) => {\n clearTimeout(timeoutId);\n resolve(result);\n })\n .catch((error) => {\n clearTimeout(timeoutId);\n reject(error);\n });\n });\n }\n /**\n * ์ง์ฐ ์ ํธ๋ฆฌํฐ\n */\n delay(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n /**\n * ์คํ ์ทจ์\n */\n cancel() {\n if (this.abortController) {\n this.abortController.abort();\n }\n }\n /**\n * ์คํ ์ํ ํ์ธ\n */\n getIsRunning() {\n return this.isRunning;\n }\n /**\n * ์ค์ ์
๋ฐ์ดํธ\n */\n updateConfig(config) {\n this.config = { ...this.config, ...config };\n this.safetyChecker.updateConfig({\n enableSafetyCheck: this.config.enableSafetyCheck,\n maxExecutionTime: this.config.executionTimeout / 1000,\n });\n // ToolExecutor ์๋ ์คํฌ๋กค ์ค์ ๋๊ธฐํ\n if (config.autoScrollToCell !== undefined) {\n this.toolExecutor.setAutoScroll(this.config.autoScrollToCell);\n }\n }\n /**\n * ์น์ธ ์ฝ๋ฐฑ ์ค์ (Tool Registry ์ฐ๋)\n * @param callback ์น์ธ ์์ฒญ ์ ํธ์ถ๋ ์ฝ๋ฐฑ ํจ์\n */\n setApprovalCallback(callback) {\n this.toolExecutor.setApprovalCallback(callback);\n }\n /**\n * ์น์ธ ํ์ ์ฌ๋ถ ์ค์ \n * @param required true๋ฉด ์ํ ๋๊ตฌ ์คํ ์ ์น์ธ ํ์\n */\n setApprovalRequired(required) {\n this.toolExecutor.setApprovalRequired(required);\n }\n /**\n * Tool Registry ์ธ์คํด์ค ๋ฐํ (์ธ๋ถ ๋๊ตฌ ๋ฑ๋ก์ฉ)\n */\n getToolRegistry() {\n return this.toolExecutor.getRegistry();\n }\n /**\n * ํ์ฌ ์คํ ์ค์ธ ์
๋ก ์คํฌ๋กค ๋ฐ ํ์ด๋ผ์ดํธ\n */\n scrollToAndHighlightCell(cellIndex) {\n if (!this.config.autoScrollToCell && !this.config.highlightCurrentCell) {\n return;\n }\n const notebookContent = this.notebook.content;\n const cell = notebookContent.widgets[cellIndex];\n if (!cell)\n return;\n // ์
๋ก ์คํฌ๋กค\n if (this.config.autoScrollToCell) {\n cell.node.scrollIntoView({\n behavior: 'smooth',\n block: 'center',\n });\n }\n // ์
ํ์ด๋ผ์ดํธ (CSS ํด๋์ค ์ถ๊ฐ)\n if (this.config.highlightCurrentCell) {\n // ๊ธฐ์กด ํ์ด๋ผ์ดํธ ์ ๊ฑฐ\n notebookContent.widgets.forEach((w) => {\n w.node.classList.remove('aa-cell-executing');\n });\n // ์ ํ์ด๋ผ์ดํธ ์ถ๊ฐ\n cell.node.classList.add('aa-cell-executing');\n // ์คํ ์๋ฃ ํ ํ์ด๋ผ์ดํธ ์ ๊ฑฐ (์ง์ฐ ํ)\n setTimeout(() => {\n cell.node.classList.remove('aa-cell-executing');\n }, this.getEffectiveDelay() + 500);\n }\n }\n /**\n * ํ์ฌ ์ค์ ์ ๋ง๋ ์ง์ฐ ์๊ฐ ๋ฐํ\n */\n getEffectiveDelay() {\n // executionSpeed ํ๋ฆฌ์
์ฌ์ฉ (stepDelay๋ ๋ฌด์ํ๊ณ ํ๋ฆฌ์
๊ฐ์ ์ฐ์ )\n const presetDelay = EXECUTION_SPEED_DELAYS[this.config.executionSpeed];\n if (presetDelay !== undefined) {\n return presetDelay;\n }\n // ํ๋ฆฌ์
์ด ์์ผ๋ฉด stepDelay ์ฌ์ฉ\n return this.config.stepDelay || 0;\n }\n /**\n * ์คํ
์ฌ์ด ์ง์ฐ ์ ์ฉ (step-by-step ๋ชจ๋ ํฌํจ)\n */\n async applyStepDelay() {\n const delay = this.getEffectiveDelay();\n console.log(`[Orchestrator] applyStepDelay called: speed=${this.config.executionSpeed}, delay=${delay}ms`);\n // step-by-step ๋ชจ๋: ์ฌ์ฉ์๊ฐ ๋ค์ ๋ฒํผ์ ๋๋ฅผ ๋๊น์ง ๋๊ธฐ\n if (this.config.executionSpeed === 'step-by-step' || delay < 0) {\n this.isPaused = true;\n await new Promise((resolve) => {\n this.stepByStepResolver = resolve;\n });\n this.isPaused = false;\n this.stepByStepResolver = null;\n return;\n }\n // ์ผ๋ฐ ์ง์ฐ\n if (delay > 0) {\n await this.delay(delay);\n }\n }\n /**\n * Step-by-step ๋ชจ๋์์ ๋ค์ ์คํ
์งํ\n */\n proceedToNextStep() {\n if (this.stepByStepResolver) {\n this.stepByStepResolver();\n }\n }\n /**\n * ์ผ์ ์ ์ง ์ํ ํ์ธ\n */\n getIsPaused() {\n return this.isPaused;\n }\n /**\n * ํ์ฌ ์คํ ์๋ ์ค์ ๋ฐํ\n */\n getExecutionSpeed() {\n return this.config.executionSpeed;\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // Code Validation & Reflection Methods\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n /**\n * ์คํ ์ ์ฝ๋ ๊ฒ์ฆ (Pyflakes/AST ๊ธฐ๋ฐ)\n *\n * @param code ๊ฒ์ฆํ ์ฝ๋\n * @returns ๊ฒ์ฆ ๊ฒฐ๊ณผ\n */\n async validateCodeBeforeExecution(code) {\n if (!this.enablePreValidation) {\n return null;\n }\n try {\n console.log('[Orchestrator] Pre-validation: Checking code quality');\n const notebookContext = this.extractNotebookContext(this.notebook);\n // โ
์ด์ Step์์ ์ถ์ ๋ ๋ณ์๋ค์ notebookContext์ ๋ณํฉ\n const allDefinedVariables = new Set([\n ...notebookContext.definedVariables,\n ...this.executedStepVariables,\n ]);\n notebookContext.definedVariables = Array.from(allDefinedVariables);\n // โ
์ด์ Step์์ ์ถ์ ๋ import๋ค์ notebookContext์ ๋ณํฉ\n const allImportedLibraries = new Set([\n ...notebookContext.importedLibraries,\n ...this.executedStepImports,\n ]);\n notebookContext.importedLibraries = Array.from(allImportedLibraries);\n console.log('[Orchestrator] Validation context - tracked vars:', Array.from(this.executedStepVariables));\n console.log('[Orchestrator] Validation context - tracked imports:', Array.from(this.executedStepImports));\n const validationResult = await this.apiService.validateCode({\n code,\n notebookContext,\n });\n console.log('[Orchestrator] Validation result:', {\n valid: validationResult.valid,\n hasErrors: validationResult.hasErrors,\n issueCount: validationResult.issues.length,\n });\n return validationResult;\n }\n catch (error) {\n console.warn('[Orchestrator] Pre-validation failed:', error.message);\n // ๊ฒ์ฆ ์คํจ ์์๋ ์คํ์ ๊ณ์ ์งํ (graceful degradation)\n return null;\n }\n }\n /**\n * ์คํ ํ Reflection ์ํ\n *\n * @param step ์คํ๋ ๋จ๊ณ\n * @param toolResults ๋๊ตฌ ์คํ ๊ฒฐ๊ณผ\n * @param remainingSteps ๋จ์ ๋จ๊ณ๋ค\n * @returns Reflection ๊ฒฐ๊ณผ\n */\n async performReflection(step, toolResults, remainingSteps) {\n if (!this.enableReflection) {\n return null;\n }\n try {\n // jupyter_cell ์คํ ๊ฒฐ๊ณผ ์ถ์ถ\n const jupyterResult = toolResults.find(r => r.cellIndex !== undefined);\n if (!jupyterResult) {\n return null;\n }\n // ์คํ๋ ์ฝ๋ ์ถ์ถ\n const jupyterToolCall = step.toolCalls.find(tc => tc.tool === 'jupyter_cell');\n const executedCode = jupyterToolCall\n ? jupyterToolCall.parameters.code\n : '';\n // Checkpoint ์ ๋ณด ์ถ์ถ (EnhancedPlanStep์ธ ๊ฒฝ์ฐ)\n const enhancedStep = step;\n const checkpoint = enhancedStep.checkpoint;\n // โ
ํ๋ก ํธ์๋์์ ๋จผ์ ์ถ๋ ฅ ๋ถ์ ์ํ\n const outputString = (() => {\n const output = jupyterResult.output;\n if (!output)\n return '';\n if (typeof output === 'string')\n return output;\n if (typeof output === 'object' && output !== null) {\n if ('text/plain' in output) {\n const textPlain = output['text/plain'];\n return typeof textPlain === 'string' ? textPlain : String(textPlain || '');\n }\n try {\n return JSON.stringify(output);\n }\n catch {\n return '[object]';\n }\n }\n // Primitive types (number, boolean, etc.)\n try {\n return String(output);\n }\n catch {\n return '[unknown]';\n }\n })();\n const localOutputAnalysis = this.analyzeOutputForFailure(outputString);\n // ๋ถ์ ์ ์ถ๋ ฅ์ด ๊ฐ์ง๋๋ฉด ์๋ฌ ๋ฉ์์ง์ ์ถ๊ฐ\n let effectiveErrorMessage = jupyterResult.error;\n let effectiveStatus = jupyterResult.success ? 'ok' : 'error';\n if (localOutputAnalysis.isNegative) {\n console.log('[Orchestrator] Reflection: Local output analysis detected issue:', localOutputAnalysis.reason);\n effectiveErrorMessage = effectiveErrorMessage\n ? `${effectiveErrorMessage}; ์ถ๋ ฅ ๋ถ์: ${localOutputAnalysis.reason}`\n : `์ถ๋ ฅ ๋ถ์: ${localOutputAnalysis.reason}`;\n // ์คํ์ ์ฑ๊ณตํ์ง๋ง ์ถ๋ ฅ์ด ๋ถ์ ์ ์ธ ๊ฒฝ์ฐ๋ 'error'๋ก ํ์\n if (jupyterResult.success && localOutputAnalysis.isNegative) {\n effectiveStatus = 'warning'; // ๋ฐฑ์๋์ ๊ฒฝ๊ณ ์ํ ์ ๋ฌ\n }\n }\n console.log('[Orchestrator] Performing reflection for step', step.stepNumber);\n const reflectResponse = await this.apiService.reflectOnExecution({\n stepNumber: step.stepNumber,\n stepDescription: step.description,\n executedCode,\n executionStatus: effectiveStatus,\n executionOutput: outputString,\n errorMessage: effectiveErrorMessage,\n expectedOutcome: checkpoint?.expectedOutcome,\n validationCriteria: checkpoint?.validationCriteria,\n remainingSteps,\n });\n console.log('[Orchestrator] Reflection result:', {\n checkpointPassed: reflectResponse.reflection.evaluation.checkpoint_passed,\n confidenceScore: reflectResponse.reflection.evaluation.confidence_score,\n action: reflectResponse.reflection.recommendations.action,\n });\n return reflectResponse.reflection;\n }\n catch (error) {\n console.warn('[Orchestrator] Reflection failed:', error.message);\n // Reflection ์คํจ ์์๋ ์คํ์ ๊ณ์ ์งํ\n return null;\n }\n }\n /**\n * Reflection ๊ฒฐ๊ณผ์ ๋ฐ๋ฅธ ์ก์
๊ฒฐ์ \n *\n * @param reflection Reflection ๊ฒฐ๊ณผ\n * @returns true๋ฉด ๊ณ์ ์งํ, false๋ฉด ์ฌ์๋/์ฌ๊ณํ ํ์\n */\n shouldContinueAfterReflection(reflection) {\n if (!reflection) {\n return { shouldContinue: true, action: 'continue', reason: 'No reflection data' };\n }\n const { evaluation, recommendations } = reflection;\n // Checkpoint ํต๊ณผ ๋ฐ ์ ๋ขฐ๋ 70% ์ด์์ด๋ฉด ๊ณ์ ์งํ\n if (evaluation.checkpoint_passed && evaluation.confidence_score >= 0.7) {\n return {\n shouldContinue: true,\n action: 'continue',\n reason: 'Checkpoint passed with high confidence'\n };\n }\n // Recommendation์ ๋ฐ๋ฅธ ๊ฒฐ์ \n switch (recommendations.action) {\n case 'continue':\n return {\n shouldContinue: true,\n action: 'continue',\n reason: recommendations.reasoning\n };\n case 'adjust':\n // ๊ฒฝ๋ฏธํ ์กฐ์ ์ ๊ณ์ ์งํ (๋ค์ ๋จ๊ณ์์ ๋ณด์ )\n return {\n shouldContinue: true,\n action: 'adjust',\n reason: recommendations.reasoning\n };\n case 'retry':\n return {\n shouldContinue: false,\n action: 'retry',\n reason: recommendations.reasoning\n };\n case 'replan':\n return {\n shouldContinue: false,\n action: 'replan',\n reason: recommendations.reasoning\n };\n default:\n return { shouldContinue: true, action: 'continue', reason: 'Default continue' };\n }\n }\n /**\n * ๊ฒ์ฆ ๊ฒฐ๊ณผ์ ๋ฐ๋ฅธ ์ฝ๋ ์๋ ์์ ์๋\n *\n * @param code ์๋ณธ ์ฝ๋\n * @param validation ๊ฒ์ฆ ๊ฒฐ๊ณผ\n * @returns ์์ ๋ ์ฝ๋ (์์ ๋ถ๊ฐ ์ null)\n */\n async attemptAutoFix(code, validation) {\n // ์๋ ์์ ๊ฐ๋ฅํ ๊ฒฝ์ฐ๋ง ์ฒ๋ฆฌ\n const autoFixableIssues = validation.issues.filter(issue => issue.category === 'unused_import' || issue.category === 'unused_variable');\n // ์ฌ๊ฐํ ์ค๋ฅ๊ฐ ์์ผ๋ฉด ์๋ ์์ ๋ถ๊ฐ\n if (validation.hasErrors) {\n return null;\n }\n // ๊ฒฝ๊ณ ๋ง ์๋ ๊ฒฝ์ฐ ์ฝ๋ ๊ทธ๋๋ก ๋ฐํ (์คํ ๊ฐ๋ฅ)\n if (!validation.hasErrors && autoFixableIssues.length > 0) {\n console.log('[Orchestrator] Code has warnings but is executable');\n return code;\n }\n return null;\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // STATE VERIFICATION Methods (Phase 1)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n /**\n * ์คํ
์คํ ํ ์ํ ๊ฒ์ฆ\n * @param step ์คํ๋ ์คํ
\n * @param stepResult ์คํ
์คํ ๊ฒฐ๊ณผ\n * @param onProgress ์งํ ์ํ ์ฝ๋ฐฑ\n * @returns ์ํ ๊ฒ์ฆ ๊ฒฐ๊ณผ ๋๋ null (๊ฒ์ฆ ๋ถ๊ฐ ์)\n */\n async verifyStepStateAfterExecution(step, stepResult, onProgress) {\n // jupyter_cell ์คํ ๊ฒฐ๊ณผ๋ง ๊ฒ์ฆ\n const jupyterResult = stepResult.toolResults.find(r => r.cellIndex !== undefined);\n if (!jupyterResult) {\n return null;\n }\n // Progress ์
๋ฐ์ดํธ: ๊ฒ์ฆ ์์\n onProgress({\n phase: 'verifying',\n message: '์ํ ๊ฒ์ฆ ์ค...',\n currentStep: step.stepNumber,\n });\n try {\n // ์คํ๋ ์ฝ๋ ์ถ์ถ\n const jupyterToolCall = step.toolCalls.find(tc => tc.tool === 'jupyter_cell');\n const executedCode = jupyterToolCall\n ? jupyterToolCall.parameters.code\n : '';\n // ์ถ๋ ฅ ๋ฌธ์์ด ์์ฑ\n const outputString = this.extractOutputString(jupyterResult.output);\n // ๋
ธํธ๋ถ ์ปจํ
์คํธ์์ ํ์ฌ ๋ณ์ ๋ชฉ๋ก ์ถ์ถ\n const notebookContext = this.extractNotebookContext(this.notebook);\n // ์คํ ๊ฒฐ๊ณผ ๊ฐ์ฒด ์์ฑ (StateVerifier ์ธํฐํ์ด์ค์ ๋ง์ถค)\n const executionResult = {\n status: jupyterResult.success ? 'ok' : 'error',\n stdout: outputString,\n stderr: '',\n result: jupyterResult.output ? String(jupyterResult.output) : '',\n error: jupyterResult.error ? {\n ename: jupyterResult.errorName || 'Error',\n evalue: jupyterResult.error,\n traceback: jupyterResult.traceback || [],\n } : undefined,\n executionTime: 0,\n cellIndex: jupyterResult.cellIndex ?? -1,\n };\n // ์ํ ๊ธฐ๋ ์ ๋ณด ์ถ์ถ (step.checkpoint ๋๋ expectedOutcome์ด ์๋ ๊ฒฝ์ฐ)\n const enhancedStep = step;\n const expectation = enhancedStep.checkpoint\n ? {\n stepNumber: step.stepNumber,\n expectedVariables: this.extractVariablesFromCode(executedCode),\n expectedOutputPatterns: enhancedStep.checkpoint.validationCriteria,\n }\n : undefined;\n // ๊ฒ์ฆ ์ปจํ
์คํธ ์์ฑ\n const verificationContext = {\n stepNumber: step.stepNumber,\n executionResult,\n expectation,\n previousVariables: Array.from(this.executedStepVariables),\n currentVariables: notebookContext.definedVariables,\n notebookContext,\n };\n // ์ํ ๊ฒ์ฆ ์ํ\n const verificationResult = await this.stateVerifier.verifyStepState(verificationContext);\n // Progress ์
๋ฐ์ดํธ: ๊ฒ์ฆ ์๋ฃ\n const statusMessage = verificationResult.isValid\n ? `๊ฒ์ฆ ํต๊ณผ (${(verificationResult.confidence * 100).toFixed(0)}%)`\n : `๊ฒ์ฆ ๊ฒฝ๊ณ : ${verificationResult.mismatches.length}๊ฑด ๊ฐ์ง`;\n onProgress({\n phase: 'verifying',\n message: statusMessage,\n currentStep: step.stepNumber,\n });\n return verificationResult;\n }\n catch (error) {\n console.warn('[Orchestrator] State verification failed:', error.message);\n // ๊ฒ์ฆ ์คํจ ์์๋ ์คํ์ ๊ณ์ ์งํ (graceful degradation)\n return null;\n }\n }\n /**\n * ์ถ๋ ฅ ๊ฐ์ฒด์์ ๋ฌธ์์ด ์ถ์ถ\n */\n extractOutputString(output) {\n if (!output)\n return '';\n if (typeof output === 'string')\n return output;\n if (typeof output === 'object' && output !== null) {\n if ('text/plain' in output) {\n const textPlain = output['text/plain'];\n return typeof textPlain === 'string' ? textPlain : String(textPlain || '');\n }\n try {\n return JSON.stringify(output);\n }\n catch {\n return '[object]';\n }\n }\n try {\n return String(output);\n }\n catch {\n return '[unknown]';\n }\n }\n /**\n * Validation & Reflection ์ค์ ์
๋ฐ์ดํธ\n */\n setValidationEnabled(enabled) {\n this.enablePreValidation = enabled;\n console.log('[Orchestrator] Pre-validation:', enabled ? 'enabled' : 'disabled');\n }\n setReflectionEnabled(enabled) {\n this.enableReflection = enabled;\n console.log('[Orchestrator] Reflection:', enabled ? 'enabled' : 'disabled');\n }\n /**\n * โ
State Verification ์ค์ ์
๋ฐ์ดํธ (Phase 1)\n */\n setStateVerificationEnabled(enabled) {\n this.enableStateVerification = enabled;\n console.log('[Orchestrator] State verification:', enabled ? 'enabled' : 'disabled');\n }\n /**\n * ํ์ฌ ์ค์ ํ์ธ\n */\n getValidationEnabled() {\n return this.enablePreValidation;\n }\n getReflectionEnabled() {\n return this.enableReflection;\n }\n /**\n * โ
State Verification ์ค์ ํ์ธ (Phase 1)\n */\n getStateVerificationEnabled() {\n return this.enableStateVerification;\n }\n /**\n * โ
State Verification ์ด๋ ฅ ์กฐํ (Phase 1)\n */\n getStateVerificationHistory(count = 5) {\n return this.stateVerifier.getRecentHistory(count);\n }\n /**\n * โ
State Verification ํธ๋ ๋ ๋ถ์ (Phase 1)\n */\n getStateVerificationTrend() {\n return this.stateVerifier.analyzeConfidenceTrend();\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // Context Management Methods (Phase 2)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n /**\n * โ
์ปจํ
์คํธ ์์ฐ ์ค์ ์
๋ฐ์ดํธ (Phase 2)\n * @param budget ์๋ก์ด ์์ฐ ์ค์ (๋ถ๋ถ ์
๋ฐ์ดํธ ๊ฐ๋ฅ)\n */\n updateContextBudget(budget) {\n this.contextManager.updateBudget(budget);\n console.log('[Orchestrator] Context budget updated:', this.contextManager.getBudget());\n }\n /**\n * โ
ํ์ฌ ์ปจํ
์คํธ ์์ฐ ์ค์ ๋ฐํ (Phase 2)\n */\n getContextBudget() {\n return this.contextManager.getBudget();\n }\n /**\n * โ
ํ์ฌ ํ ํฐ ์ฌ์ฉ๋ ํต๊ณ ๋ฐํ (Phase 2)\n */\n getContextUsage() {\n return this.contextManager.getLastUsage();\n }\n /**\n * โ
ํ์ฌ ๋
ธํธ๋ถ์ ์ปจํ
์คํธ ์ฌ์ฉ๋ ๋ถ์ (Phase 2)\n * ์์ฐ ์ํ์ ๊ถ์ฅ ์ฌํญ์ ๋ฐํ\n */\n analyzeContextUsage() {\n const rawContext = this.extractRawNotebookContext(this.notebook);\n const usage = this.contextManager.calculateUsage(rawContext);\n const budget = this.contextManager.getBudget();\n let status;\n let recommendation;\n if (usage.usagePercent >= 1.0) {\n status = 'critical';\n recommendation = 'ํ ํฐ ์์ฐ ์ด๊ณผ. ์ปจํ
์คํธ๊ฐ ์๋ ์ถ์๋ฉ๋๋ค.';\n }\n else if (usage.usagePercent >= budget.warningThreshold) {\n status = 'warning';\n recommendation = 'ํ ํฐ ์ฌ์ฉ๋์ด ๊ฒฝ๊ณ ์๊ณ๊ฐ์ ๊ทผ์ ํฉ๋๋ค. ํ์ ์ ์์ฐ์ ๋๋ฆฌ์ธ์.';\n }\n else {\n status = 'ok';\n recommendation = 'ํ ํฐ ์ฌ์ฉ๋์ด ์ ์ ๋ฒ์์
๋๋ค.';\n }\n return { usage, status, recommendation };\n }\n /**\n * โ
ContextManager ์ธ์คํด์ค ๋ฐํ (Phase 2)\n * ์ธ๋ถ์์ ์ง์ ์ปจํ
์คํธ ๊ด๋ฆฌ๊ฐ ํ์ํ ๊ฒฝ์ฐ\n */\n getContextManager() {\n return this.contextManager;\n }\n /**\n * Replan decision ๋ ์ด๋ธ ๋ฐํ\n */\n getReplanDecisionLabel(decision) {\n switch (decision) {\n case 'refine':\n return '์ฝ๋ ์์ ';\n case 'insert_steps':\n return '๋จ๊ณ ์ถ๊ฐ';\n case 'replace_step':\n return '๋จ๊ณ ๊ต์ฒด';\n case 'replan_remaining':\n return '๋จ์ ๊ณํ ์ฌ์๋ฆฝ';\n default:\n return decision;\n }\n }\n /**\n * ModuleNotFoundError ๋ฉ์์ง์์ ํจํค์ง ์ด๋ฆ ์ถ์ถ\n */\n extractMissingPackage(errorMessage) {\n // \"No module named 'plotly'\" ํจํด\n const match = errorMessage.match(/No module named ['\"]([\\w\\-_.]+)['\"]/);\n if (match) {\n return match[1];\n }\n // \"ModuleNotFoundError: plotly\" ํจํด\n const altMatch = errorMessage.match(/ModuleNotFoundError:\\s*([\\w\\-_.]+)/);\n if (altMatch) {\n return altMatch[1];\n }\n return undefined;\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // Checkpoint Management Methods (Phase 3)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n /**\n * โ
CheckpointManager ์ธ์คํด์ค ๋ฐํ (Phase 3)\n * ์ธ๋ถ์์ ์ง์ ์ฒดํฌํฌ์ธํธ ๊ด๋ฆฌ๊ฐ ํ์ํ ๊ฒฝ์ฐ\n */\n getCheckpointManager() {\n return this.checkpointManager;\n }\n /**\n * โ
ํน์ ์ฒดํฌํฌ์ธํธ๋ก ๋กค๋ฐฑ (Phase 3)\n * @param stepNumber ๋กค๋ฐฑํ ์คํ
๋ฒํธ\n * @returns ๋กค๋ฐฑ ๊ฒฐ๊ณผ\n */\n async rollbackToCheckpoint(stepNumber) {\n console.log(`[Orchestrator] Initiating rollback to step ${stepNumber}`);\n return this.checkpointManager.rollbackTo(stepNumber);\n }\n /**\n * โ
๋ชจ๋ ์ฒดํฌํฌ์ธํธ ์กฐํ (Phase 3)\n * @returns ์ฒดํฌํฌ์ธํธ ๋ฐฐ์ด (์คํ
๋ฒํธ ์)\n */\n getCheckpoints() {\n return this.checkpointManager.getAllCheckpoints();\n }\n /**\n * โ
๊ฐ์ฅ ์ต๊ทผ ์ฒดํฌํฌ์ธํธ ์กฐํ (Phase 3)\n * @returns ์ต์ ์ฒดํฌํฌ์ธํธ ๋๋ undefined\n */\n getLatestCheckpoint() {\n return this.checkpointManager.getLatestCheckpoint();\n }\n /**\n * โ
์ฒดํฌํฌ์ธํธ ๋งค๋์ ์ํ ์กฐํ (Phase 3)\n * @returns ์ฒดํฌํฌ์ธํธ ๋งค๋์ ์ํ ์ ๋ณด\n */\n getCheckpointState() {\n return this.checkpointManager.getState();\n }\n /**\n * โ
์ฒดํฌํฌ์ธํธ ์ค์ ์
๋ฐ์ดํธ (Phase 3)\n * @param config ์๋ก์ด ์ค์ (๋ถ๋ถ ์
๋ฐ์ดํธ ๊ฐ๋ฅ)\n */\n updateCheckpointConfig(config) {\n this.checkpointManager.updateConfig(config);\n console.log('[Orchestrator] Checkpoint config updated:', this.checkpointManager.getConfig());\n }\n /**\n * โ
ํ์ฌ ์ฒดํฌํฌ์ธํธ ์ค์ ๋ฐํ (Phase 3)\n */\n getCheckpointConfig() {\n return this.checkpointManager.getConfig();\n }\n /**\n * โ
๊ฐ์ฅ ์ต๊ทผ ์ฒดํฌํฌ์ธํธ๋ก ๋กค๋ฐฑ (Phase 3)\n * @returns ๋กค๋ฐฑ ๊ฒฐ๊ณผ\n */\n async rollbackToLatestCheckpoint() {\n console.log('[Orchestrator] Initiating rollback to latest checkpoint');\n return this.checkpointManager.rollbackToLatest();\n }\n /**\n * โ
ํน์ ์คํ
์ด์ ์ฒดํฌํฌ์ธํธ๋ก ๋กค๋ฐฑ (Phase 3)\n * @param stepNumber ์ด ์คํ
๋ฐ๋ก ์ด์ ์ฒดํฌํฌ์ธํธ๋ก ๋กค๋ฐฑ\n * @returns ๋กค๋ฐฑ ๊ฒฐ๊ณผ\n */\n async rollbackBeforeStep(stepNumber) {\n console.log(`[Orchestrator] Initiating rollback before step ${stepNumber}`);\n return this.checkpointManager.rollbackBefore(stepNumber);\n }\n /**\n * โ
๋ชจ๋ ์ฒดํฌํฌ์ธํธ ์ญ์ (Phase 3)\n */\n clearAllCheckpoints() {\n this.checkpointManager.clearAllCheckpoints();\n console.log('[Orchestrator] All checkpoints cleared');\n }\n}\nexport default AgentOrchestrator;\n","/**\n * API Key Manager Service\n *\n * Manages LLM API keys in browser localStorage.\n * Keys are stored locally and sent with each request to the Agent Server.\n *\n * IMPORTANT (Financial Security Compliance):\n * - All API keys are stored ONLY in browser localStorage\n * - Agent Server receives ONE key per request (no key storage on server)\n * - Key rotation on rate limit (429) is handled by frontend\n */\nconst STORAGE_KEY = 'hdsp-agent-llm-config';\n// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n// Key Rotation State (in-memory, not persisted)\n// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n/** Current key index for rotation (per-session, not persisted) */\nlet currentKeyIndex = 0;\n/** Set of rate-limited key indices (reset after successful request) */\nconst rateLimitedKeys = new Set();\n/** Maximum retry attempts with different keys */\nconst MAX_KEY_ROTATION_ATTEMPTS = 10;\n/**\n * Get the current LLM configuration from localStorage\n */\nexport function getLLMConfig() {\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (!stored) {\n return null;\n }\n return JSON.parse(stored);\n }\n catch (e) {\n console.error('[ApiKeyManager] Failed to parse stored config:', e);\n return null;\n }\n}\n/**\n * Save LLM configuration to localStorage\n */\nexport function saveLLMConfig(config) {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(config));\n console.log('[ApiKeyManager] Config saved to localStorage');\n }\n catch (e) {\n console.error('[ApiKeyManager] Failed to save config:', e);\n }\n}\n/**\n * Clear stored LLM configuration\n */\nexport function clearLLMConfig() {\n localStorage.removeItem(STORAGE_KEY);\n console.log('[ApiKeyManager] Config cleared from localStorage');\n}\n/**\n * Check if API key is configured for the current provider\n */\nexport function hasValidApiKey(config) {\n if (!config)\n return false;\n switch (config.provider) {\n case 'gemini':\n // Check both single key and multiple keys\n const hasMainKey = !!(config.gemini?.apiKey && config.gemini.apiKey.trim());\n const hasArrayKeys = !!(config.gemini?.apiKeys && config.gemini.apiKeys.some(k => k && k.trim()));\n return hasMainKey || hasArrayKeys;\n case 'openai':\n return !!(config.openai?.apiKey && config.openai.apiKey.trim());\n case 'vllm':\n // vLLM may not require API key\n return true;\n default:\n return false;\n }\n}\n/**\n * Get default LLM configuration\n */\nexport function getDefaultLLMConfig() {\n return {\n provider: 'gemini',\n gemini: {\n apiKey: '',\n apiKeys: [],\n model: 'gemini-2.5-flash'\n },\n openai: {\n apiKey: '',\n model: 'gpt-4'\n },\n vllm: {\n endpoint: 'http://localhost:8000',\n model: 'default'\n }\n };\n}\n/**\n * Get a random API key from the list (for load balancing)\n */\nexport function getRandomApiKey(config) {\n if (config.provider === 'gemini' && config.gemini) {\n const keys = config.gemini.apiKeys.filter(k => k && k.trim());\n if (keys.length === 0) {\n return config.gemini.apiKey || null;\n }\n // Random selection for load balancing\n const randomIndex = Math.floor(Math.random() * keys.length);\n return keys[randomIndex];\n }\n if (config.provider === 'openai' && config.openai) {\n return config.openai.apiKey || null;\n }\n if (config.provider === 'vllm' && config.vllm) {\n return config.vllm.apiKey || null;\n }\n return null;\n}\n/**\n * Get all valid API keys count\n */\nexport function getValidApiKeysCount(config) {\n if (config.provider === 'gemini' && config.gemini) {\n return config.gemini.apiKeys.filter(k => k && k.trim()).length;\n }\n if (config.provider === 'openai' && config.openai) {\n return config.openai.apiKey && config.openai.apiKey.trim() ? 1 : 0;\n }\n if (config.provider === 'vllm') {\n return 1; // vLLM doesn't require API key\n }\n return 0;\n}\n/**\n * Mask API key for display (show first 4 and last 4 characters)\n */\nexport function maskApiKey(key) {\n if (!key || key.length < 10)\n return '***';\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n}\n/**\n * Test API key by making a simple request\n */\nexport async function testApiKey(config) {\n try {\n // Simple validation - just check if key exists\n if (!hasValidApiKey(config)) {\n return { success: false, message: 'API key not configured' };\n }\n // For more thorough testing, you could make a minimal API call here\n // But for now, just validate format\n const key = config[config.provider];\n if (config.provider === 'gemini' && key?.apiKey) {\n if (!key.apiKey.startsWith('AIza')) {\n return { success: false, message: 'Invalid Gemini API key format (should start with AIza)' };\n }\n }\n if (config.provider === 'openai' && key?.apiKey) {\n if (!key.apiKey.startsWith('sk-')) {\n return { success: false, message: 'Invalid OpenAI API key format (should start with sk-)' };\n }\n }\n return { success: true, message: 'API key format is valid' };\n }\n catch (e) {\n return { success: false, message: `Error: ${e}` };\n }\n}\n// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n// Key Rotation Functions (Financial Security Compliance)\n// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n/**\n * Get all valid Gemini API keys from config\n */\nexport function getValidGeminiKeys(config) {\n if (config.provider !== 'gemini' || !config.gemini) {\n return [];\n }\n const keys = config.gemini.apiKeys?.filter(k => k && k.trim()) || [];\n // Fallback to single apiKey if no array\n if (keys.length === 0 && config.gemini.apiKey && config.gemini.apiKey.trim()) {\n return [config.gemini.apiKey];\n }\n return keys;\n}\n/**\n * Get current key index for rotation tracking\n */\nexport function getCurrentKeyIndex() {\n return currentKeyIndex;\n}\n/**\n * Reset key rotation state (call after successful request)\n */\nexport function resetKeyRotation() {\n rateLimitedKeys.clear();\n console.log('[ApiKeyManager] Key rotation state reset');\n}\n/**\n * Mark current key as rate-limited and rotate to next available key\n * @returns true if rotation successful, false if all keys exhausted\n */\nexport function rotateToNextKey(config) {\n const keys = getValidGeminiKeys(config);\n if (keys.length <= 1) {\n console.log('[ApiKeyManager] Cannot rotate - only one key available');\n return false;\n }\n // Mark current key as rate-limited\n rateLimitedKeys.add(currentKeyIndex);\n console.log(`[ApiKeyManager] Key ${currentKeyIndex + 1} marked as rate-limited`);\n // Find next available key\n for (let i = 0; i < keys.length; i++) {\n const nextIndex = (currentKeyIndex + 1 + i) % keys.length;\n if (!rateLimitedKeys.has(nextIndex)) {\n currentKeyIndex = nextIndex;\n console.log(`[ApiKeyManager] Rotated to key ${currentKeyIndex + 1}/${keys.length}`);\n return true;\n }\n }\n // All keys rate-limited\n console.log('[ApiKeyManager] All keys rate-limited');\n return false;\n}\n/**\n * Check if there are available keys (not all rate-limited)\n */\nexport function hasAvailableKeys(config) {\n const keys = getValidGeminiKeys(config);\n return keys.length > rateLimitedKeys.size;\n}\n/**\n * Get count of remaining available keys\n */\nexport function getAvailableKeyCount(config) {\n const keys = getValidGeminiKeys(config);\n return Math.max(0, keys.length - rateLimitedKeys.size);\n}\n/**\n * Build config with SINGLE current API key for server request.\n * Server receives only one key - rotation is handled by frontend.\n */\nexport function buildSingleKeyConfig(config) {\n if (config.provider !== 'gemini' || !config.gemini) {\n // Non-Gemini providers - return as-is (no rotation)\n return config;\n }\n const keys = getValidGeminiKeys(config);\n if (keys.length === 0) {\n return config;\n }\n // Ensure currentKeyIndex is within bounds\n if (currentKeyIndex >= keys.length) {\n currentKeyIndex = 0;\n }\n const currentKey = keys[currentKeyIndex];\n console.log(`[ApiKeyManager] Using key ${currentKeyIndex + 1}/${keys.length}`);\n // Return config with single apiKey (server only uses apiKey field)\n return {\n ...config,\n gemini: {\n ...config.gemini,\n apiKey: currentKey,\n // Don't send apiKeys array to server (security)\n apiKeys: [],\n },\n };\n}\n/**\n * Handle rate limit error with automatic key rotation\n * @returns New config with rotated key, or null if all keys exhausted\n */\nexport function handleRateLimitError(config) {\n if (config.provider !== 'gemini') {\n // Non-Gemini providers don't support rotation\n return null;\n }\n const rotated = rotateToNextKey(config);\n if (!rotated) {\n console.log('[ApiKeyManager] Rate limit: All keys exhausted');\n return null;\n }\n return buildSingleKeyConfig(config);\n}\n/**\n * Check if error is a rate limit error (429)\n */\nexport function isRateLimitError(error) {\n const errorMsg = typeof error === 'string' ? error : error.message;\n return errorMsg.includes('RATE_LIMIT_EXCEEDED') ||\n errorMsg.includes('429') ||\n errorMsg.toLowerCase().includes('quota exceeded') ||\n errorMsg.toLowerCase().includes('rate limit');\n}\n","/**\n * API Service Layer for REST communication with backend\n */\nimport { buildSingleKeyConfig, handleRateLimitError, isRateLimitError, resetKeyRotation, getValidGeminiKeys, getCurrentKeyIndex } from './ApiKeyManager';\n// โ
ํต์ฌ ๋ณ๊ฒฝ 1: ServerConnection ๋์ PageConfig ์ํฌํธ\nimport { URLExt, PageConfig } from '@jupyterlab/coreutils';\nexport class ApiService {\n // ์์ฑ์์์ baseUrl์ ์ ํ์ ์ผ๋ก ๋ฐ๋๋ก ํ๋, ์์ผ๋ฉด ์๋์ผ๋ก ๊ณ์ฐ\n constructor(baseUrl) {\n if (baseUrl) {\n this.baseUrl = baseUrl;\n }\n else {\n // โ
ํต์ฌ ๋ณ๊ฒฝ 2: ServerConnection ๋์ PageConfig๋ก URL ๊ฐ์ ธ์ค๊ธฐ\n // PageConfig.getBaseUrl()์ '/user/์์ด๋/ํ๋ก์ ํธ/' ํํ์ ์ฃผ์๋ฅผ ์ ํํ ๊ฐ์ ธ์ต๋๋ค.\n const serverRoot = PageConfig.getBaseUrl();\n // 3. ๊ฒฝ๋ก ํฉ์น๊ธฐ\n // ๊ฒฐ๊ณผ: /user/453467/pl2wadmprj/hdsp-agent\n this.baseUrl = URLExt.join(serverRoot, 'hdsp-agent');\n }\n console.log('[ApiService] Base URL initialized:', this.baseUrl); // ๋๋ฒ๊น
์ฉ ๋ก๊ทธ\n }\n /**\n * Get cookie value by name\n */\n getCookie(name) {\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n if (parts.length === 2) {\n return parts.pop()?.split(';').shift() || '';\n }\n return '';\n }\n /**\n * Get CSRF token from cookie\n */\n getCsrfToken() {\n return this.getCookie('_xsrf');\n }\n /**\n * Get headers with CSRF token for POST requests\n */\n getHeaders() {\n return {\n 'Content-Type': 'application/json',\n 'X-XSRFToken': this.getCsrfToken()\n };\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // Global Rate Limit Handling with Key Rotation\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n /**\n * Fetch wrapper with automatic API key rotation on rate limit (429)\n *\n * NOTE (Financial Security Compliance):\n * - API key rotation is handled by frontend (not server)\n * - Server receives ONLY ONE key per request\n * - On 429 rate limit, frontend rotates key and retries with next key\n */\n async fetchWithKeyRotation(url, request, options) {\n const MAX_RETRIES = 10;\n const originalConfig = request.llmConfig;\n let lastError = null;\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n // Build request with single key for this attempt\n const requestToSend = originalConfig\n ? { ...request, llmConfig: buildSingleKeyConfig(originalConfig) }\n : request;\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: this.getHeaders(),\n credentials: 'include',\n body: JSON.stringify(requestToSend)\n });\n if (response.ok) {\n // Success - reset key rotation state\n resetKeyRotation();\n return response.json();\n }\n // Handle error response\n const errorText = await response.text();\n // Check if rate limit error\n if (isRateLimitError(errorText) && originalConfig) {\n console.log(`[ApiService] Rate limit on attempt ${attempt + 1}, rotating key...`);\n // Try to rotate to next key\n const rotatedConfig = handleRateLimitError(originalConfig);\n if (rotatedConfig) {\n // Notify UI about key rotation\n const keys = getValidGeminiKeys(originalConfig);\n if (options?.onKeyRotation) {\n options.onKeyRotation(getCurrentKeyIndex(), keys.length);\n }\n continue; // Try next key\n }\n else {\n // All keys exhausted\n throw new Error('๋ชจ๋ API ํค๊ฐ Rate Limit ์ํ์
๋๋ค. ์ ์ ํ ๋ค์ ์๋ํด์ฃผ์ธ์.');\n }\n }\n // Not a rate limit error - parse and throw\n let errorMessage = options?.defaultErrorMessage || 'API ์์ฒญ ์คํจ';\n try {\n const errorJson = JSON.parse(errorText);\n errorMessage = errorJson.detail || errorJson.error || errorJson.message || errorMessage;\n }\n catch (e) {\n errorMessage = errorText || errorMessage;\n }\n throw new Error(errorMessage);\n }\n catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n lastError = error instanceof Error ? error : new Error(errorMsg);\n // If it's a rate limit error from the catch block, check rotation\n if (isRateLimitError(errorMsg) && originalConfig) {\n const rotatedConfig = handleRateLimitError(originalConfig);\n if (rotatedConfig) {\n const keys = getValidGeminiKeys(originalConfig);\n if (options?.onKeyRotation) {\n options.onKeyRotation(getCurrentKeyIndex(), keys.length);\n }\n continue;\n }\n throw new Error('๋ชจ๋ API ํค๊ฐ Rate Limit ์ํ์
๋๋ค. ์ ์ ํ ๋ค์ ์๋ํด์ฃผ์ธ์.');\n }\n // Not a rate limit error, throw immediately\n throw error;\n }\n }\n throw lastError || new Error('Maximum retry attempts exceeded');\n }\n /**\n * Execute cell action (explain, fix, custom)\n * Uses global rate limit handling with key rotation\n */\n async cellAction(request) {\n console.log('[ApiService] cellAction request:', request);\n return this.fetchWithKeyRotation(`${this.baseUrl}/cell/action`, request, { defaultErrorMessage: '์
์ก์
์คํจ' });\n }\n /**\n * Send chat message (non-streaming)\n * Uses global rate limit handling with key rotation\n */\n async sendMessage(request) {\n console.log('[ApiService] sendMessage request');\n return this.fetchWithKeyRotation(`${this.baseUrl}/chat/message`, request, { defaultErrorMessage: '๋ฉ์์ง ์ ์ก ์คํจ' });\n }\n /**\n * Send chat message with streaming response\n *\n * NOTE (Financial Security Compliance):\n * - API key rotation is handled by frontend (not server)\n * - Server receives ONLY ONE key per request\n * - On 429 rate limit, frontend rotates key and retries with next key\n */\n async sendMessageStream(request, onChunk, onMetadata) {\n // Maximum retry attempts (should match number of keys)\n const MAX_RETRIES = 10;\n let currentConfig = request.llmConfig;\n let lastError = null;\n for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {\n // Build request with single key for this attempt\n const requestToSend = currentConfig\n ? { ...request, llmConfig: buildSingleKeyConfig(currentConfig) }\n : request;\n try {\n await this.sendMessageStreamInternal(requestToSend, onChunk, onMetadata);\n // Success - reset key rotation state\n resetKeyRotation();\n return;\n }\n catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n lastError = error instanceof Error ? error : new Error(errorMsg);\n // Check if rate limit error and we have config to rotate\n if (isRateLimitError(errorMsg) && request.llmConfig) {\n console.log(`[ApiService] Rate limit on attempt ${attempt + 1}, trying next key...`);\n // Try to rotate to next key using ORIGINAL config (with all keys)\n const rotatedConfig = handleRateLimitError(request.llmConfig);\n if (rotatedConfig) {\n // Update currentConfig with the rotated key for next attempt\n // Note: rotatedConfig already has single key, but we need full config for next rotation\n currentConfig = request.llmConfig;\n continue; // Try next key\n }\n else {\n // All keys exhausted\n throw new Error('๋ชจ๋ API ํค๊ฐ Rate Limit ์ํ์
๋๋ค. ์ ์ ํ ๋ค์ ์๋ํด์ฃผ์ธ์.');\n }\n }\n // Not a rate limit error, throw immediately\n throw error;\n }\n }\n // Should not reach here, but just in case\n throw lastError || new Error('Maximum retry attempts exceeded');\n }\n /**\n * Build request with single API key for server\n * (Key rotation is managed by frontend for financial security compliance)\n */\n buildRequestWithSingleKey(request) {\n if (!request.llmConfig) {\n return request;\n }\n // Build config with single key (server only uses apiKey field)\n const singleKeyConfig = buildSingleKeyConfig(request.llmConfig);\n return {\n ...request,\n llmConfig: singleKeyConfig\n };\n }\n /**\n * Internal streaming implementation (without retry logic)\n */\n async sendMessageStreamInternal(request, onChunk, onMetadata) {\n const response = await fetch(`${this.baseUrl}/chat/stream`, {\n method: 'POST',\n headers: this.getHeaders(),\n credentials: 'include',\n body: JSON.stringify(request)\n });\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to send message: ${error}`);\n }\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('Response body is not readable');\n }\n const decoder = new TextDecoder();\n let buffer = '';\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done)\n break;\n buffer += decoder.decode(value, { stream: true });\n // Process complete SSE messages\n const lines = buffer.split('\\n');\n buffer = lines.pop() || ''; // Keep incomplete line in buffer\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const data = JSON.parse(line.slice(6));\n // Handle errors\n if (data.error) {\n throw new Error(data.error);\n }\n // Handle metadata (conversationId, messageId, etc.)\n if (data.conversationId && onMetadata) {\n onMetadata({\n conversationId: data.conversationId,\n messageId: data.messageId,\n provider: data.metadata?.provider,\n model: data.metadata?.model\n });\n }\n // Handle content chunks\n if (data.content) {\n onChunk(data.content);\n }\n // Final metadata update\n if (data.done && data.metadata && onMetadata) {\n onMetadata({\n provider: data.metadata.provider,\n model: data.metadata.model\n });\n }\n }\n catch (e) {\n if (e instanceof SyntaxError) {\n console.warn('Failed to parse SSE data:', line);\n }\n else {\n throw e;\n }\n }\n }\n }\n }\n }\n finally {\n reader.releaseLock();\n }\n }\n /**\n * Save configuration\n */\n async saveConfig(config) {\n const response = await fetch(`${this.baseUrl}/config`, {\n method: 'POST',\n headers: this.getHeaders(),\n credentials: 'include',\n body: JSON.stringify(config)\n });\n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: 'Failed to save configuration' }));\n throw new Error(error.message || 'Failed to save configuration');\n }\n }\n /**\n * Get current configuration\n */\n async getConfig() {\n const response = await fetch(`${this.baseUrl}/config`);\n if (!response.ok) {\n throw new Error('Failed to load configuration');\n }\n return response.json();\n }\n /**\n * Get health status\n */\n async getStatus() {\n const response = await fetch(`${this.baseUrl}/status`);\n if (!response.ok) {\n throw new Error('Failed to get status');\n }\n return response.json();\n }\n /**\n * Get available models\n */\n async getModels() {\n const response = await fetch(`${this.baseUrl}/models`);\n if (!response.ok) {\n throw new Error('Failed to load models');\n }\n return response.json();\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // Auto-Agent API Methods (All use global rate limit handling)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n /**\n * Generate execution plan for auto-agent task\n */\n async generateExecutionPlan(request, onKeyRotation) {\n console.log('[ApiService] generateExecutionPlan request:', request);\n return this.fetchWithKeyRotation(`${this.baseUrl}/auto-agent/plan`, request, { onKeyRotation, defaultErrorMessage: '๊ณํ ์์ฑ ์คํจ' });\n }\n /**\n * Refine step code after error (Self-Healing)\n */\n async refineStepCode(request, onKeyRotation) {\n console.log('[ApiService] refineStepCode request:', request);\n return this.fetchWithKeyRotation(`${this.baseUrl}/auto-agent/refine`, request, { onKeyRotation, defaultErrorMessage: '์ฝ๋ ์์ ์คํจ' });\n }\n /**\n * Adaptive Replanning - ์๋ฌ ๋ถ์ ํ ๊ณํ ์ฌ์๋ฆฝ\n */\n async replanExecution(request, onKeyRotation) {\n console.log('[ApiService] replanExecution request:', request);\n return this.fetchWithKeyRotation(`${this.baseUrl}/auto-agent/replan`, request, { onKeyRotation, defaultErrorMessage: '๊ณํ ์ฌ์๋ฆฝ ์คํจ' });\n }\n /**\n * Validate code before execution - ์ฌ์ ์ฝ๋ ํ์ง ๊ฒ์ฆ (Pyflakes/AST ๊ธฐ๋ฐ)\n * Note: This is a local validation, no LLM call, but uses wrapper for consistency\n */\n async validateCode(request) {\n console.log('[ApiService] validateCode request:', request);\n return this.fetchWithKeyRotation(`${this.baseUrl}/auto-agent/validate`, request, { defaultErrorMessage: '์ฝ๋ ๊ฒ์ฆ ์คํจ' });\n }\n /**\n * Reflect on step execution - ์คํ ๊ฒฐ๊ณผ ๋ถ์ ๋ฐ ์ ์์ ์กฐ์ \n */\n async reflectOnExecution(request, onKeyRotation) {\n console.log('[ApiService] reflectOnExecution request:', request);\n return this.fetchWithKeyRotation(`${this.baseUrl}/auto-agent/reflect`, request, { onKeyRotation, defaultErrorMessage: 'Reflection ์คํจ' });\n }\n /**\n * Verify state after step execution - ์ํ ๊ฒ์ฆ (Phase 1)\n * Note: This is a local verification, no LLM call, but uses wrapper for consistency\n */\n async verifyState(request) {\n console.log('[ApiService] verifyState request:', request);\n return this.fetchWithKeyRotation(`${this.baseUrl}/auto-agent/verify-state`, request, { defaultErrorMessage: '์ํ ๊ฒ์ฆ ์คํจ' });\n }\n /**\n * Stream execution plan generation with real-time updates\n */\n async generateExecutionPlanStream(request, onPlanUpdate, onReasoning) {\n const response = await fetch(`${this.baseUrl}/auto-agent/plan/stream`, {\n method: 'POST',\n headers: this.getHeaders(),\n body: JSON.stringify(request)\n });\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to generate plan: ${error}`);\n }\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('Response body is not readable');\n }\n const decoder = new TextDecoder();\n let buffer = '';\n let finalPlan = null;\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done)\n break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const data = JSON.parse(line.slice(6));\n if (data.error) {\n throw new Error(data.error);\n }\n if (data.reasoning && onReasoning) {\n onReasoning(data.reasoning);\n }\n if (data.plan) {\n onPlanUpdate(data.plan);\n if (data.done) {\n finalPlan = data.plan;\n }\n }\n }\n catch (e) {\n if (!(e instanceof SyntaxError)) {\n throw e;\n }\n }\n }\n }\n }\n }\n finally {\n reader.releaseLock();\n }\n if (!finalPlan) {\n throw new Error('No plan received from server');\n }\n return finalPlan;\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // File Action API Methods (Python ํ์ผ ์๋ฌ ์์ )\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n /**\n * Python ํ์ผ ์๋ฌ ์์ /๋ถ์/์ค๋ช
์์ฒญ\n */\n async fileAction(request, onKeyRotation) {\n console.log('[ApiService] fileAction request:', request);\n return this.fetchWithKeyRotation(`${this.baseUrl}/file/action`, request, { onKeyRotation, defaultErrorMessage: 'ํ์ผ ์ก์
์คํจ' });\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // File Resolution API Methods (ํ์ผ ๊ฒฝ๋ก ํด๊ฒฐ)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n /**\n * Resolve file path - ํ์ผ๋ช
๋๋ ํจํด์ผ๋ก ๊ฒฝ๋ก ๊ฒ์\n */\n async resolveFile(request) {\n console.log('[ApiService] resolveFile request:', request);\n const response = await fetch(`${this.baseUrl}/file/resolve`, {\n method: 'POST',\n headers: this.getHeaders(),\n credentials: 'include',\n body: JSON.stringify(request)\n });\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to resolve file: ${error}`);\n }\n return response.json();\n }\n /**\n * Select file from multiple options - ์ฌ์ฉ์ ์ ํ ์ฒ๋ฆฌ\n */\n async selectFile(request) {\n console.log('[ApiService] selectFile request:', request);\n const response = await fetch(`${this.baseUrl}/file/select`, {\n method: 'POST',\n headers: this.getHeaders(),\n credentials: 'include',\n body: JSON.stringify(request)\n });\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to select file: ${error}`);\n }\n return response.json();\n }\n}\n","/**\n * CheckpointManager - ์ฒดํฌํฌ์ธํธ ์์ฑ ๋ฐ ๋กค๋ฐฑ ๊ด๋ฆฌ\n *\n * ๊ฐ ์ฑ๊ณต ์คํ
ํ ์ฒดํฌํฌ์ธํธ ์ ์ฅ, ์คํจ ์ ๋กค๋ฐฑ ๊ฐ๋ฅ\n * - ์ํ ๋ฒํผ (๊ธฐ๋ณธ ์ต๋ 10๊ฐ)\n * - ์์ฑ๋ ์
์ญ์ , ์์ ๋ ์
๋ณต์\n */\nimport { DEFAULT_CHECKPOINT_CONFIG, } from '../types/auto-agent';\n/**\n * CheckpointManager ํด๋์ค\n * ์ฒดํฌํฌ์ธํธ ์์ฑ/์กฐํ/๋กค๋ฐฑ ๊ด๋ฆฌ\n */\nexport class CheckpointManager {\n constructor(notebook, config) {\n // ํ์ฌ ์คํ ์ธ์
์ ์ถ์ ์ ๋ณด\n this.createdCellIndices = new Set();\n this.modifiedCellIndices = new Set();\n this.variableNames = new Set();\n this.notebook = notebook;\n this.config = {\n ...DEFAULT_CHECKPOINT_CONFIG,\n ...config,\n };\n this.checkpoints = new Map();\n }\n /**\n * ์ค์ ์
๋ฐ์ดํธ\n */\n updateConfig(config) {\n this.config = {\n ...this.config,\n ...config,\n };\n console.log('[CheckpointManager] Config updated:', this.config);\n }\n /**\n * ํ์ฌ ์ค์ ๋ฐํ\n */\n getConfig() {\n return { ...this.config };\n }\n /**\n * ์ ์คํ ์ธ์
์์ ์ ์ด๊ธฐํ\n */\n startNewSession() {\n this.checkpoints.clear();\n this.createdCellIndices.clear();\n this.modifiedCellIndices.clear();\n this.variableNames.clear();\n console.log('[CheckpointManager] New session started');\n }\n /**\n * ์ฒดํฌํฌ์ธํธ ์์ฑ\n * ์คํ
์ฑ๊ณต ํ ํธ์ถ\n */\n createCheckpoint(stepNumber, stepDescription, plan, stepResult, newVariables = []) {\n // ์คํ
๊ฒฐ๊ณผ์์ ์์ฑ/์์ ๋ ์
์ถ์ \n stepResult.toolResults.forEach((tr) => {\n if (tr.cellIndex !== undefined) {\n if (tr.wasModified) {\n this.modifiedCellIndices.add(tr.cellIndex);\n }\n else {\n this.createdCellIndices.add(tr.cellIndex);\n }\n }\n });\n // ์ ๋ณ์๋ค ์ถ์ \n newVariables.forEach(v => this.variableNames.add(v));\n // ์
์ค๋
์ท ์์ฑ\n const cellSnapshots = this.captureCellSnapshots(stepResult);\n const checkpoint = {\n id: `cp-${stepNumber}-${Date.now()}`,\n stepNumber,\n timestamp: Date.now(),\n description: stepDescription,\n planSnapshot: { ...plan },\n cellSnapshots,\n variableNames: Array.from(this.variableNames),\n createdCellIndices: Array.from(this.createdCellIndices),\n modifiedCellIndices: Array.from(this.modifiedCellIndices),\n };\n // ์ํ ๋ฒํผ: ์ต๋ ๊ฐ์ ์ด๊ณผ ์ ๊ฐ์ฅ ์ค๋๋ ์ฒดํฌํฌ์ธํธ ์ญ์ \n if (this.checkpoints.size >= this.config.maxCheckpoints) {\n const oldestStep = Math.min(...this.checkpoints.keys());\n this.checkpoints.delete(oldestStep);\n console.log(`[CheckpointManager] Removed oldest checkpoint: step ${oldestStep}`);\n }\n this.checkpoints.set(stepNumber, checkpoint);\n console.log(`[CheckpointManager] Created checkpoint for step ${stepNumber}`);\n return checkpoint;\n }\n /**\n * ์
์ค๋
์ท ์บก์ฒ\n */\n captureCellSnapshots(stepResult) {\n const snapshots = [];\n const cells = this.notebook.content.model?.cells;\n if (!cells)\n return snapshots;\n stepResult.toolResults.forEach((tr) => {\n if (tr.cellIndex !== undefined && tr.cellIndex < cells.length) {\n const cell = cells.get(tr.cellIndex);\n const snapshot = {\n index: tr.cellIndex,\n type: cell.type,\n source: cell.sharedModel.getSource(),\n outputs: this.getCellOutputs(tr.cellIndex),\n wasCreated: !tr.wasModified,\n wasModified: tr.wasModified || false,\n previousSource: tr.previousContent,\n };\n snapshots.push(snapshot);\n }\n });\n return snapshots;\n }\n /**\n * ์
์ถ๋ ฅ ๊ฐ์ ธ์ค๊ธฐ\n */\n getCellOutputs(cellIndex) {\n const cells = this.notebook.content.model?.cells;\n if (!cells || cellIndex >= cells.length)\n return [];\n const cell = cells.get(cellIndex);\n if (cell.type !== 'code')\n return [];\n const outputs = [];\n const codeCell = cell; // ICellModel doesn't expose outputs directly\n if (codeCell.outputs) {\n for (let i = 0; i < codeCell.outputs.length; i++) {\n outputs.push(codeCell.outputs.get(i)?.toJSON?.() || {});\n }\n }\n return outputs;\n }\n /**\n * ํน์ ์ฒดํฌํฌ์ธํธ ์กฐํ\n */\n getCheckpoint(stepNumber) {\n return this.checkpoints.get(stepNumber);\n }\n /**\n * ๋ชจ๋ ์ฒดํฌํฌ์ธํธ ์กฐํ\n */\n getAllCheckpoints() {\n return Array.from(this.checkpoints.values())\n .sort((a, b) => a.stepNumber - b.stepNumber);\n }\n /**\n * ๊ฐ์ฅ ์ต๊ทผ ์ฒดํฌํฌ์ธํธ ์กฐํ\n */\n getLatestCheckpoint() {\n if (this.checkpoints.size === 0)\n return undefined;\n const maxStep = Math.max(...this.checkpoints.keys());\n return this.checkpoints.get(maxStep);\n }\n /**\n * ํน์ ์ฒดํฌํฌ์ธํธ๋ก ๋กค๋ฐฑ\n * - ํด๋น ์ฒดํฌํฌ์ธํธ ์ดํ์ ์์ฑ๋ ์
์ญ์ \n * - ํด๋น ์ฒดํฌํฌ์ธํธ ์ดํ์ ์์ ๋ ์
๋ณต์\n */\n async rollbackTo(stepNumber) {\n const checkpoint = this.checkpoints.get(stepNumber);\n if (!checkpoint) {\n return {\n success: false,\n rolledBackTo: -1,\n deletedCells: [],\n restoredCells: [],\n error: `Checkpoint for step ${stepNumber} not found`,\n };\n }\n console.log(`[CheckpointManager] Rolling back to step ${stepNumber}`);\n const cells = this.notebook.content.model?.cells;\n if (!cells) {\n return {\n success: false,\n rolledBackTo: stepNumber,\n deletedCells: [],\n restoredCells: [],\n error: 'Notebook cells not accessible',\n };\n }\n const deletedCells = [];\n const restoredCells = [];\n try {\n // 1. ์ฒดํฌํฌ์ธํธ ์ดํ์ ์์ฑ๋ ์
๋ค ์๋ณ ๋ฐ ์ญ์ \n const checkpointCreatedSet = new Set(checkpoint.createdCellIndices);\n const cellsToDelete = Array.from(this.createdCellIndices)\n .filter(idx => !checkpointCreatedSet.has(idx))\n .sort((a, b) => b - a); // ๋ค์์๋ถํฐ ์ญ์ (์ธ๋ฑ์ค ๋ณ๊ฒฝ ๋ฐฉ์ง)\n for (const cellIndex of cellsToDelete) {\n if (cellIndex < cells.length) {\n this.notebook.content.model?.sharedModel.deleteCell(cellIndex);\n deletedCells.push(cellIndex);\n console.log(`[CheckpointManager] Deleted cell at index ${cellIndex}`);\n }\n }\n // 2. ์ฒดํฌํฌ์ธํธ ์ดํ์ ์์ ๋ ์
๋ค ๋ณต์\n const laterCheckpoints = Array.from(this.checkpoints.values())\n .filter(cp => cp.stepNumber > stepNumber);\n for (const laterCp of laterCheckpoints) {\n for (const snapshot of laterCp.cellSnapshots) {\n if (snapshot.wasModified && snapshot.previousSource !== undefined) {\n // ์ญ์ ๋ก ์ธํ ์ธ๋ฑ์ค ์กฐ์ ๊ณ์ฐ\n const deletedBefore = deletedCells.filter(d => d < snapshot.index).length;\n const adjustedIndex = snapshot.index - deletedBefore;\n if (adjustedIndex >= 0 && adjustedIndex < cells.length) {\n const cell = cells.get(adjustedIndex);\n cell.sharedModel.setSource(snapshot.previousSource);\n restoredCells.push(adjustedIndex);\n console.log(`[CheckpointManager] Restored cell at index ${adjustedIndex}`);\n }\n }\n }\n }\n // 3. ์ถ์ ์ํ ์
๋ฐ์ดํธ\n this.createdCellIndices = new Set(checkpoint.createdCellIndices);\n this.modifiedCellIndices = new Set(checkpoint.modifiedCellIndices);\n this.variableNames = new Set(checkpoint.variableNames);\n // 4. ๋กค๋ฐฑ๋ ์ฒดํฌํฌ์ธํธ ์ดํ์ ์ฒดํฌํฌ์ธํธ๋ค ์ญ์ \n for (const [step, _] of this.checkpoints) {\n if (step > stepNumber) {\n this.checkpoints.delete(step);\n }\n }\n console.log(`[CheckpointManager] Rollback complete: deleted ${deletedCells.length} cells, ` +\n `restored ${restoredCells.length} cells`);\n return {\n success: true,\n rolledBackTo: stepNumber,\n deletedCells,\n restoredCells,\n };\n }\n catch (error) {\n console.error('[CheckpointManager] Rollback failed:', error);\n return {\n success: false,\n rolledBackTo: stepNumber,\n deletedCells,\n restoredCells,\n error: error.message || 'Unknown rollback error',\n };\n }\n }\n /**\n * ๊ฐ์ฅ ์ต๊ทผ ์ฒดํฌํฌ์ธํธ๋ก ๋กค๋ฐฑ\n */\n async rollbackToLatest() {\n const latest = this.getLatestCheckpoint();\n if (!latest) {\n return {\n success: false,\n rolledBackTo: -1,\n deletedCells: [],\n restoredCells: [],\n error: 'No checkpoints available',\n };\n }\n return this.rollbackTo(latest.stepNumber);\n }\n /**\n * ํน์ ์คํ
์ด์ ์ฒดํฌํฌ์ธํธ๋ก ๋กค๋ฐฑ\n */\n async rollbackBefore(stepNumber) {\n const checkpointSteps = Array.from(this.checkpoints.keys())\n .filter(step => step < stepNumber)\n .sort((a, b) => b - a);\n if (checkpointSteps.length === 0) {\n return {\n success: false,\n rolledBackTo: -1,\n deletedCells: [],\n restoredCells: [],\n error: `No checkpoint found before step ${stepNumber}`,\n };\n }\n return this.rollbackTo(checkpointSteps[0]);\n }\n /**\n * ๋ชจ๋ ์ฒดํฌํฌ์ธํธ ์ญ์ \n */\n clearAllCheckpoints() {\n this.checkpoints.clear();\n console.log('[CheckpointManager] All checkpoints cleared');\n }\n /**\n * ๊ด๋ฆฌ์ ์ํ ๋ฐํ\n */\n getState() {\n const steps = Array.from(this.checkpoints.keys()).sort((a, b) => a - b);\n return {\n config: { ...this.config },\n checkpointCount: this.checkpoints.size,\n oldestCheckpoint: steps.length > 0 ? steps[0] : undefined,\n latestCheckpoint: steps.length > 0 ? steps[steps.length - 1] : undefined,\n };\n }\n /**\n * ์ํ ์ถ๋ ฅ (๋๋ฒ๊น
์ฉ)\n */\n printStatus() {\n const state = this.getState();\n console.log('[CheckpointManager] Status:');\n console.log(` - Max checkpoints: ${state.config.maxCheckpoints}`);\n console.log(` - Checkpoint count: ${state.checkpointCount}`);\n console.log(` - Oldest: step ${state.oldestCheckpoint ?? 'N/A'}`);\n console.log(` - Latest: step ${state.latestCheckpoint ?? 'N/A'}`);\n console.log(` - Created cells: ${Array.from(this.createdCellIndices).join(', ') || 'none'}`);\n console.log(` - Modified cells: ${Array.from(this.modifiedCellIndices).join(', ') || 'none'}`);\n }\n /**\n * ํ์ฌ ์ถ์ ์ค์ธ ์์ฑ๋ ์
์ธ๋ฑ์ค๋ค ๋ฐํ\n */\n getCreatedCellIndices() {\n return Array.from(this.createdCellIndices);\n }\n /**\n * ํ์ฌ ์ถ์ ์ค์ธ ์์ ๋ ์
์ธ๋ฑ์ค๋ค ๋ฐํ\n */\n getModifiedCellIndices() {\n return Array.from(this.modifiedCellIndices);\n }\n /**\n * ํ์ฌ ์ถ์ ์ค์ธ ๋ณ์ ์ด๋ฆ๋ค ๋ฐํ\n */\n getVariableNames() {\n return Array.from(this.variableNames);\n }\n}\nexport default CheckpointManager;\n","/**\n * ContextManager - ์ปจํ
์คํธ ์๋์ฐ ๊ด๋ฆฌ\n *\n * ํ ํฐ ์์ฐ ๊ด๋ฆฌ ๋ฐ ์ ์ํ ์ปจํ
์คํธ ์ถ์๋ก LLM ํธ์ถ ์ ๋ขฐ์ฑ ํฅ์\n * - ํ ํฐ ์ถ์ (chars / 4)\n * - ์ฐ์ ์์ ๊ธฐ๋ฐ ์
๊ด๋ฆฌ\n * - ์์ฐ ์ด๊ณผ ์ ์๋ ์ถ์\n */\nimport { DEFAULT_CONTEXT_BUDGET, } from '../types/auto-agent';\n/**\n * ContextManager ํด๋์ค\n * ์ปจํ
์คํธ ์๋์ฐ ๊ด๋ฆฌ ๋ฐ ํ ํฐ ์์ฐ ๊ด๋ฆฌ\n */\nexport class ContextManager {\n constructor(budget) {\n this.lastUsage = null;\n this.budget = {\n ...DEFAULT_CONTEXT_BUDGET,\n ...budget,\n };\n }\n /**\n * ์์ฐ ์ค์ ์
๋ฐ์ดํธ\n */\n updateBudget(budget) {\n this.budget = {\n ...this.budget,\n ...budget,\n };\n console.log('[ContextManager] Budget updated:', this.budget);\n }\n /**\n * ํ์ฌ ์์ฐ ์ค์ ๋ฐํ\n */\n getBudget() {\n return { ...this.budget };\n }\n /**\n * ํ
์คํธ์ ํ ํฐ ์ ์ถ์ \n * ๊ทผ์ฌ๊ฐ: ๋ฌธ์ ์ / 4\n */\n estimateTokens(text) {\n if (!text)\n return 0;\n return Math.ceil(text.length / 4);\n }\n /**\n * ์
์ปจํ
์คํธ์ ํ ํฐ ์ ์ถ์ \n */\n estimateCellTokens(cell) {\n let tokens = this.estimateTokens(cell.source);\n if (cell.output) {\n tokens += this.estimateTokens(cell.output);\n }\n return tokens;\n }\n /**\n * ๋
ธํธ๋ถ ์ปจํ
์คํธ์ ์ ์ฒด ํ ํฐ ์ฌ์ฉ๋ ๊ณ์ฐ\n */\n calculateUsage(context) {\n const cellTokens = context.recentCells.reduce((sum, cell) => sum + this.estimateCellTokens(cell), 0);\n const variableTokens = this.estimateTokens(context.definedVariables.join(', '));\n const libraryTokens = this.estimateTokens(context.importedLibraries.join(', '));\n const totalTokens = cellTokens + variableTokens + libraryTokens;\n const availableTokens = this.budget.maxTokens - this.budget.reservedForResponse;\n const usagePercent = totalTokens / availableTokens;\n const usage = {\n totalTokens,\n cellTokens,\n variableTokens,\n libraryTokens,\n reservedTokens: this.budget.reservedForResponse,\n usagePercent,\n };\n this.lastUsage = usage;\n return usage;\n }\n /**\n * ๋ง์ง๋ง ํ ํฐ ์ฌ์ฉ๋ ๋ฐํ\n */\n getLastUsage() {\n return this.lastUsage;\n }\n /**\n * ์
๋ค์ ์ฐ์ ์์ ๋ถ์ฌ\n * - critical: currentCellIndex์ ํด๋นํ๋ ์
\n * - high: ์ต๊ทผ 3๊ฐ ์
\n * - medium: ์ต๊ทผ 5๊ฐ ์
(high ์ ์ธ)\n * - low: ๋๋จธ์ง ์
\n */\n prioritizeCells(cells, currentCellIndex) {\n if (cells.length === 0)\n return [];\n // ์ธ๋ฑ์ค ๊ธฐ์ค ๋ด๋ฆผ์ฐจ์ ์ ๋ ฌ (์ต๊ทผ ์
์ด ์์ผ๋ก)\n const sortedCells = [...cells].sort((a, b) => b.index - a.index);\n return sortedCells.map((cell, sortedIndex) => {\n let priority;\n // currentCellIndex๊ฐ ์ง์ ๋ ๊ฒฝ์ฐ ํด๋น ์
์ critical\n if (currentCellIndex !== undefined && cell.index === currentCellIndex) {\n priority = 'critical';\n }\n // ์ต๊ทผ 3๊ฐ ์
์ high\n else if (sortedIndex < 3) {\n priority = 'high';\n }\n // ๋ค์ 5๊ฐ ์
(3-7)์ medium\n else if (sortedIndex < 8) {\n priority = 'medium';\n }\n // ๋๋จธ์ง๋ low\n else {\n priority = 'low';\n }\n return {\n ...cell,\n priority,\n tokenEstimate: this.estimateCellTokens(cell),\n };\n });\n }\n /**\n * ์ฐ์ ์์ ๋ ๋ฒจ ์ซ์๊ฐ ๋ฐํ (๋น๊ต์ฉ)\n */\n getPriorityValue(priority) {\n switch (priority) {\n case 'critical':\n return 4;\n case 'high':\n return 3;\n case 'medium':\n return 2;\n case 'low':\n return 1;\n default:\n return 0;\n }\n }\n /**\n * ์ปจํ
์คํธ ์ถ์ ํ์ ์ฌ๋ถ ํ์ธ\n */\n isPruningRequired(context) {\n const usage = this.calculateUsage(context);\n const availableTokens = this.budget.maxTokens - this.budget.reservedForResponse;\n return usage.totalTokens > availableTokens;\n }\n /**\n * ๊ฒฝ๊ณ ์๊ณ๊ฐ ์ด๊ณผ ์ฌ๋ถ ํ์ธ\n */\n isWarningThresholdExceeded(context) {\n const usage = this.calculateUsage(context);\n return usage.usagePercent >= this.budget.warningThreshold;\n }\n /**\n * ์ปจํ
์คํธ ์ถ์\n * ์ฐ์ ์์๊ฐ ๋ฎ์ ์
๋ถํฐ ์ ๊ฑฐํ๊ฑฐ๋ ์ถ์\n */\n pruneContext(context, targetTokens, currentCellIndex) {\n const target = targetTokens ?? (this.budget.maxTokens - this.budget.reservedForResponse);\n const prioritizedCells = this.prioritizeCells(context.recentCells, currentCellIndex);\n // ํ์ฌ ์ฌ์ฉ๋ ๊ณ์ฐ\n const originalUsage = this.calculateUsage(context);\n const originalTokens = originalUsage.totalTokens;\n // ์ด๋ฏธ ์์ฐ ๋ด์ ์์ผ๋ฉด ๊ทธ๋๋ก ๋ฐํ\n if (originalTokens <= target) {\n return {\n context,\n result: {\n originalTokens,\n prunedTokens: originalTokens,\n removedCellCount: 0,\n truncatedCellCount: 0,\n preservedCells: context.recentCells.map(c => c.index),\n },\n };\n }\n console.log(`[ContextManager] Pruning required: ${originalTokens} โ ${target} tokens`);\n // ์ฐ์ ์์ ์์ผ๋ก ์ ๋ ฌ (๋ฎ์ ์ฐ์ ์์๊ฐ ๋จผ์ ์ ๊ฑฐ๋จ)\n const sortedByPriority = [...prioritizedCells].sort((a, b) => this.getPriorityValue(a.priority) - this.getPriorityValue(b.priority));\n const preservedCells = [];\n let currentTokens = originalUsage.variableTokens + originalUsage.libraryTokens;\n let removedCount = 0;\n let truncatedCount = 0;\n // ์ฐ์ ์์ ๋์ ๊ฒ๋ถํฐ ์ ์ง (์ญ์์ผ๋ก ์ฒ๋ฆฌ)\n for (let i = sortedByPriority.length - 1; i >= 0; i--) {\n const cell = sortedByPriority[i];\n const cellTokens = cell.tokenEstimate;\n // ์์ฐ ๋ด์ ๋ค์ด๊ฐ๋ฉด ์ ์ง\n if (currentTokens + cellTokens <= target) {\n preservedCells.push(cell);\n currentTokens += cellTokens;\n }\n // critical ๋๋ high ์ฐ์ ์์๋ ์ถ์ํด์๋ผ๋ ์ ์ง\n else if (cell.priority === 'critical' || cell.priority === 'high') {\n const remainingBudget = target - currentTokens;\n if (remainingBudget > 100) { // ์ต์ 100 ํ ํฐ ์ด์ ๋จ์์์ด์ผ ์ถ์\n const truncatedSource = this.truncateText(cell.source, remainingBudget * 4 // ํ ํฐ โ ๋ฌธ์ ๋ณํ\n );\n const truncatedCell = {\n ...cell,\n source: truncatedSource,\n output: undefined,\n tokenEstimate: this.estimateTokens(truncatedSource),\n };\n preservedCells.push(truncatedCell);\n currentTokens += truncatedCell.tokenEstimate;\n truncatedCount++;\n console.log(`[ContextManager] Truncated ${cell.priority} cell ${cell.index}: ` +\n `${cellTokens} โ ${truncatedCell.tokenEstimate} tokens`);\n }\n else {\n removedCount++;\n console.log(`[ContextManager] Removed ${cell.priority} cell ${cell.index} ` +\n `(insufficient budget: ${remainingBudget} tokens)`);\n }\n }\n // ๊ทธ ์ธ ์ฐ์ ์์๋ ์ ๊ฑฐ\n else {\n removedCount++;\n console.log(`[ContextManager] Removed ${cell.priority} cell ${cell.index}`);\n }\n }\n // ์๋ ์ธ๋ฑ์ค ์์๋ก ๋ณต์\n const prunedCells = preservedCells\n .sort((a, b) => a.index - b.index)\n .map(({ priority, tokenEstimate, ...cellContext }) => cellContext);\n const prunedContext = {\n ...context,\n recentCells: prunedCells,\n };\n const result = {\n originalTokens,\n prunedTokens: currentTokens,\n removedCellCount: removedCount,\n truncatedCellCount: truncatedCount,\n preservedCells: prunedCells.map(c => c.index),\n };\n console.log(`[ContextManager] Pruning complete: ` +\n `${originalTokens} โ ${currentTokens} tokens, ` +\n `removed ${removedCount}, truncated ${truncatedCount}`);\n return { context: prunedContext, result };\n }\n /**\n * ํ
์คํธ ์ถ์ (๋ง์ง๋ง ๋ถ๋ถ ์ ์ง)\n */\n truncateText(text, maxChars) {\n if (text.length <= maxChars)\n return text;\n // ๋ง์ง๋ง ๋ถ๋ถ ์ ์ง (์ต๊ทผ ์ฝ๋๊ฐ ๋ ์ค์)\n const truncated = text.slice(-maxChars);\n // ์ค ๊ฒฝ๊ณ์์ ์๋ฅด๊ธฐ\n const firstNewline = truncated.indexOf('\\n');\n if (firstNewline > 0 && firstNewline < maxChars * 0.2) {\n return '...\\n' + truncated.slice(firstNewline + 1);\n }\n return '...' + truncated;\n }\n /**\n * ๋
ธํธ๋ถ ์ปจํ
์คํธ ์ถ์ถ ๋ฐ ์ต์ ํ\n * ์์ฐ์ ์ด๊ณผํ๋ฉด ์๋์ผ๋ก ์ถ์\n */\n extractOptimizedContext(context, currentCellIndex) {\n // ๊ฒฝ๊ณ ์๊ณ๊ฐ ์ฒดํฌ\n if (this.isWarningThresholdExceeded(context)) {\n const usage = this.getLastUsage();\n console.log(`[ContextManager] Warning: Token usage at ${(usage.usagePercent * 100).toFixed(1)}% ` +\n `(threshold: ${this.budget.warningThreshold * 100}%)`);\n }\n // ์ถ์ ํ์ ์ฌ๋ถ ํ์ธ\n if (this.isPruningRequired(context)) {\n const { context: prunedContext, result } = this.pruneContext(context, undefined, currentCellIndex);\n const usage = this.calculateUsage(prunedContext);\n return {\n context: prunedContext,\n usage,\n pruneResult: result,\n };\n }\n return {\n context,\n usage: this.calculateUsage(context),\n };\n }\n /**\n * ๊ด๋ฆฌ์ ์ํ ๋ฐํ\n */\n getState() {\n return {\n budget: { ...this.budget },\n currentUsage: this.lastUsage ?? {\n totalTokens: 0,\n cellTokens: 0,\n variableTokens: 0,\n libraryTokens: 0,\n reservedTokens: this.budget.reservedForResponse,\n usagePercent: 0,\n },\n isPruningRequired: false,\n lastPruneTimestamp: undefined,\n };\n }\n /**\n * ์ํ ์ถ๋ ฅ (๋๋ฒ๊น
์ฉ)\n */\n printStatus() {\n console.log('[ContextManager] Status:');\n console.log(` - Max tokens: ${this.budget.maxTokens}`);\n console.log(` - Reserved for response: ${this.budget.reservedForResponse}`);\n console.log(` - Warning threshold: ${this.budget.warningThreshold * 100}%`);\n if (this.lastUsage) {\n console.log(` - Current usage: ${this.lastUsage.totalTokens} tokens`);\n console.log(` - Cells: ${this.lastUsage.cellTokens}`);\n console.log(` - Variables: ${this.lastUsage.variableTokens}`);\n console.log(` - Libraries: ${this.lastUsage.libraryTokens}`);\n console.log(` - Usage percent: ${(this.lastUsage.usagePercent * 100).toFixed(1)}%`);\n }\n }\n}\nexport default ContextManager;\n","/**\n * State Verifier Service\n * Phase 1: ์ํ ๊ฒ์ฆ ๋ ์ด์ด - ๊ฐ ๋จ๊ณ ์คํ ํ ์ํ ๊ฒ์ฆ์ผ๋ก silent failure ๊ฐ์ง\n */\nimport { CONFIDENCE_THRESHOLDS, } from '../types/auto-agent';\n// ๊ธฐ๋ณธ ๊ฐ์ค์น ์ค์ \nconst DEFAULT_WEIGHTS = {\n outputMatch: 0.3,\n variableCreation: 0.3,\n noExceptions: 0.25,\n executionComplete: 0.15,\n};\n/**\n * ์ํ ๊ฒ์ฆ ์๋น์ค\n * - ์คํ
์คํ ํ ์์ ์ํ์ ์ค์ ์ํ ๋น๊ต\n * - ์ ๋ขฐ๋ ์ ์ ๊ณ์ฐ\n * - ๋ฆฌํ๋๋ ํธ๋ฆฌ๊ฑฐ ๊ฒฐ์ \n */\nexport class StateVerifier {\n constructor(apiService) {\n this.verificationHistory = [];\n this.apiService = apiService;\n }\n /**\n * ์คํ
์คํ ๊ฒฐ๊ณผ ๊ฒ์ฆ\n * @param context ๊ฒ์ฆ ์ปจํ
์คํธ\n * @returns ๊ฒ์ฆ ๊ฒฐ๊ณผ\n */\n async verifyStepState(context) {\n console.log('[StateVerifier] Verifying step state:', {\n stepNumber: context.stepNumber,\n executionStatus: context.executionResult.status,\n });\n const mismatches = [];\n const factors = {\n outputMatch: 1.0,\n variableCreation: 1.0,\n noExceptions: 1.0,\n executionComplete: 1.0,\n };\n // 1. ์คํ ์๋ฃ ์ฌ๋ถ ํ์ธ\n if (context.executionResult.status === 'error') {\n factors.noExceptions = 0;\n factors.executionComplete = 0;\n mismatches.push({\n type: 'exception_occurred',\n severity: 'critical',\n description: `์คํ ์ค ์์ธ ๋ฐ์: ${context.executionResult.error?.ename || 'Unknown'}`,\n expected: '์๋ฌ ์์',\n actual: context.executionResult.error?.evalue || 'Unknown error',\n suggestion: this.getSuggestionForError(context.executionResult.error?.ename),\n });\n }\n // 2. ๋ณ์ ์์ฑ ๊ฒ์ฆ (expectation์ด ์๋ ๊ฒฝ์ฐ)\n if (context.expectation?.expectedVariables) {\n const createdVariables = this.getNewVariables(context.previousVariables, context.currentVariables);\n const { score, variableMismatches } = this.verifyVariables(context.expectation.expectedVariables, createdVariables);\n factors.variableCreation = score;\n mismatches.push(...variableMismatches);\n }\n // 3. ์ถ๋ ฅ ํจํด ๊ฒ์ฆ (expectation์ด ์๋ ๊ฒฝ์ฐ)\n if (context.expectation?.expectedOutputPatterns) {\n const { score, outputMismatches } = this.verifyOutputPatterns(context.expectation.expectedOutputPatterns, context.executionResult.stdout + context.executionResult.result);\n factors.outputMatch = score;\n mismatches.push(...outputMismatches);\n }\n // 4. Import ๊ฒ์ฆ\n if (context.expectation?.expectedImports) {\n const importMismatches = this.verifyImports(context.expectation.expectedImports, context.executionResult);\n mismatches.push(...importMismatches);\n }\n // 5. ์ ๋ขฐ๋ ์ ์ ๊ณ์ฐ\n const confidenceDetails = this.calculateConfidence(factors);\n // 6. ๊ถ์ฅ ์ฌํญ ๊ฒฐ์ \n const recommendation = this.determineRecommendation(confidenceDetails.overall);\n const result = {\n isValid: mismatches.filter(m => m.severity === 'critical').length === 0,\n confidence: confidenceDetails.overall,\n confidenceDetails,\n mismatches,\n recommendation,\n timestamp: Date.now(),\n };\n // ์ด๋ ฅ ์ ์ฅ\n this.verificationHistory.push(result);\n console.log('[StateVerifier] Verification result:', {\n isValid: result.isValid,\n confidence: result.confidence,\n recommendation: result.recommendation,\n mismatchCount: result.mismatches.length,\n });\n return result;\n }\n /**\n * ๋ฐฑ์๋ API๋ฅผ ํตํ ์์ธ ๊ฒ์ฆ (๋ณต์กํ ์ผ์ด์ค)\n */\n async verifyWithBackend(stepNumber, executedCode, executionResult, expectation, previousVariables = [], currentVariables = []) {\n try {\n const request = {\n stepNumber,\n executedCode,\n executionOutput: executionResult.stdout + '\\n' + JSON.stringify(executionResult.result),\n executionStatus: executionResult.status,\n errorMessage: executionResult.error?.evalue,\n expectedVariables: expectation?.expectedVariables,\n expectedOutputPatterns: expectation?.expectedOutputPatterns,\n previousVariables,\n currentVariables,\n };\n const response = await this.apiService.verifyState(request);\n return response.verification;\n }\n catch (error) {\n console.error('[StateVerifier] Backend verification failed, using local verification:', error);\n // ํด๋ฐฑ: ๋ก์ปฌ ๊ฒ์ฆ ์ํ\n return this.verifyStepState({\n stepNumber,\n executionResult,\n expectation,\n previousVariables,\n currentVariables,\n notebookContext: { cellCount: 0, recentCells: [], importedLibraries: [], definedVariables: [] },\n });\n }\n }\n /**\n * ์ ๋ขฐ๋ ์ ์ ๊ณ์ฐ\n */\n calculateConfidence(factors, weights = DEFAULT_WEIGHTS) {\n const overall = factors.outputMatch * weights.outputMatch +\n factors.variableCreation * weights.variableCreation +\n factors.noExceptions * weights.noExceptions +\n factors.executionComplete * weights.executionComplete;\n return {\n overall: Math.max(0, Math.min(1, overall)),\n factors,\n weights,\n };\n }\n /**\n * ์ ๋ขฐ๋์ ๋ฐ๋ฅธ ๊ถ์ฅ ์ฌํญ ๊ฒฐ์ \n */\n determineRecommendation(confidence) {\n if (confidence >= CONFIDENCE_THRESHOLDS.PROCEED) {\n return 'proceed';\n }\n else if (confidence >= CONFIDENCE_THRESHOLDS.WARNING) {\n return 'warning';\n }\n else if (confidence >= CONFIDENCE_THRESHOLDS.REPLAN) {\n return 'replan';\n }\n else {\n return 'escalate';\n }\n }\n /**\n * ์ด์ /์ดํ ๋ณ์ ๋ชฉ๋ก ๋น๊ตํ์ฌ ์๋ก ์์ฑ๋ ๋ณ์ ์ถ์ถ\n */\n getNewVariables(previousVars, currentVars) {\n const previousSet = new Set(previousVars);\n return currentVars.filter(v => !previousSet.has(v));\n }\n /**\n * ๋ณ์ ์์ฑ ๊ฒ์ฆ\n */\n verifyVariables(expectedVars, createdVars) {\n const mismatches = [];\n const createdSet = new Set(createdVars);\n let matchCount = 0;\n for (const expected of expectedVars) {\n if (createdSet.has(expected)) {\n matchCount++;\n }\n else {\n mismatches.push({\n type: 'variable_missing',\n severity: 'major',\n description: `์์ ๋ณ์ '${expected}'๊ฐ ์์ฑ๋์ง ์์`,\n expected,\n actual: '(์์)',\n suggestion: `๋ณ์ '${expected}'๋ฅผ ์์ฑํ๋ ์ฝ๋๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์คํ๋์๋์ง ํ์ธํ์ธ์`,\n });\n }\n }\n const score = expectedVars.length > 0 ? matchCount / expectedVars.length : 1;\n return { score, variableMismatches: mismatches };\n }\n /**\n * ์ถ๋ ฅ ํจํด ๊ฒ์ฆ\n */\n verifyOutputPatterns(patterns, output) {\n const mismatches = [];\n let matchCount = 0;\n for (const pattern of patterns) {\n try {\n const regex = new RegExp(pattern, 'i');\n if (regex.test(output)) {\n matchCount++;\n }\n else {\n mismatches.push({\n type: 'output_mismatch',\n severity: 'minor',\n description: `์ถ๋ ฅ์์ ์์ ํจํด์ ์ฐพ์ ์ ์์`,\n expected: pattern,\n actual: output.substring(0, 100) + (output.length > 100 ? '...' : ''),\n });\n }\n }\n catch (e) {\n // ์ ๊ท์ ์ค๋ฅ ์ ๋ฌธ์์ด ํฌํจ ๊ฒ์ฌ\n if (output.includes(pattern)) {\n matchCount++;\n }\n }\n }\n const score = patterns.length > 0 ? matchCount / patterns.length : 1;\n return { score, outputMismatches: mismatches };\n }\n /**\n * Import ๊ฒ์ฆ\n */\n verifyImports(expectedImports, executionResult) {\n const mismatches = [];\n // ์๋ฌ๊ฐ ModuleNotFoundError ๋๋ ImportError์ธ ๊ฒฝ์ฐ\n if (executionResult.error) {\n const errorName = executionResult.error.ename;\n const errorValue = executionResult.error.evalue;\n if (errorName === 'ModuleNotFoundError' || errorName === 'ImportError') {\n // ์ด๋ค ๋ชจ๋์ด ์คํจํ๋์ง ์ถ์ถ\n const moduleMatch = errorValue.match(/No module named '([^']+)'/);\n const failedModule = moduleMatch ? moduleMatch[1] : 'unknown';\n mismatches.push({\n type: 'import_failed',\n severity: 'critical',\n description: `๋ชจ๋ '${failedModule}' import ์คํจ`,\n expected: `${failedModule} ๋ชจ๋์ด ์ค์น๋์ด ์์ด์ผ ํจ`,\n actual: errorValue,\n suggestion: `pip install ${failedModule} ๋๋ conda install ${failedModule}๋ก ์ค์นํ์ธ์`,\n });\n }\n }\n return mismatches;\n }\n /**\n * ์๋ฌ ํ์
์ ๋ฐ๋ฅธ ๋ณต๊ตฌ ์ ์\n */\n getSuggestionForError(errorName) {\n const suggestions = {\n 'ModuleNotFoundError': '๋๋ฝ๋ ํจํค์ง๋ฅผ ์ค์นํ์ธ์ (pip install)',\n 'NameError': '๋ณ์๊ฐ ์ ์๋์๋์ง ํ์ธํ์ธ์. ์ด์ ์
์ ๋จผ์ ์คํํด์ผ ํ ์ ์์ต๋๋ค.',\n 'SyntaxError': '์ฝ๋ ๋ฌธ๋ฒ์ ํ์ธํ์ธ์',\n 'TypeError': 'ํจ์ ์ธ์ ํ์
์ ํ์ธํ์ธ์',\n 'ValueError': '์
๋ ฅ ๊ฐ์ ๋ฒ์๋ ํ์์ ํ์ธํ์ธ์',\n 'KeyError': '๋์
๋๋ฆฌ ํค๊ฐ ์กด์ฌํ๋์ง ํ์ธํ์ธ์',\n 'IndexError': '๋ฆฌ์คํธ/๋ฐฐ์ด ์ธ๋ฑ์ค๊ฐ ๋ฒ์ ๋ด์ธ์ง ํ์ธํ์ธ์',\n 'FileNotFoundError': 'ํ์ผ ๊ฒฝ๋ก๊ฐ ์ฌ๋ฐ๋ฅธ์ง ํ์ธํ์ธ์',\n 'AttributeError': '๊ฐ์ฒด์ ํด๋น ์์ฑ/๋ฉ์๋๊ฐ ์๋์ง ํ์ธํ์ธ์',\n };\n return suggestions[errorName || ''] || '์๋ฌ ๋ฉ์์ง๋ฅผ ํ์ธํ๊ณ ์ฝ๋๋ฅผ ์์ ํ์ธ์';\n }\n /**\n * ์ต๊ทผ ๊ฒ์ฆ ์ด๋ ฅ ์กฐํ\n */\n getRecentHistory(count = 5) {\n return this.verificationHistory.slice(-count);\n }\n /**\n * ์ ์ฒด ์ ๋ขฐ๋ ํธ๋ ๋ ๋ถ์\n */\n analyzeConfidenceTrend() {\n if (this.verificationHistory.length < 2) {\n return {\n average: this.verificationHistory[0]?.confidence ?? 1,\n trend: 'stable',\n criticalCount: this.verificationHistory.filter(v => !v.isValid).length,\n };\n }\n const confidences = this.verificationHistory.map(v => v.confidence);\n const average = confidences.reduce((a, b) => a + b, 0) / confidences.length;\n // ์ต๊ทผ 3๊ฐ์ ์ด์ 3๊ฐ ๋น๊ต\n const recentAvg = confidences.slice(-3).reduce((a, b) => a + b, 0) / Math.min(3, confidences.length);\n const previousAvg = confidences.slice(0, -3).reduce((a, b) => a + b, 0) / Math.max(1, confidences.length - 3);\n let trend = 'stable';\n if (recentAvg > previousAvg + 0.1) {\n trend = 'improving';\n }\n else if (recentAvg < previousAvg - 0.1) {\n trend = 'declining';\n }\n return {\n average,\n trend,\n criticalCount: this.verificationHistory.filter(v => !v.isValid).length,\n };\n }\n /**\n * ๊ฒ์ฆ ์ด๋ ฅ ์ด๊ธฐํ\n */\n clearHistory() {\n this.verificationHistory = [];\n }\n}\n","/**\n * Task Service - Handles notebook generation tasks and progress tracking\n */\nexport class TaskService {\n constructor(baseUrl = '/hdsp-agent') {\n this.baseUrl = baseUrl;\n this.eventSources = new Map();\n }\n /**\n * Get cookie value by name\n */\n getCookie(name) {\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n if (parts.length === 2) {\n return parts.pop()?.split(';').shift() || '';\n }\n return '';\n }\n /**\n * Get CSRF token from cookie\n */\n getCsrfToken() {\n return this.getCookie('_xsrf');\n }\n /**\n * Get headers with CSRF token for POST requests\n */\n getHeaders() {\n return {\n 'Content-Type': 'application/json',\n 'X-XSRFToken': this.getCsrfToken()\n };\n }\n /**\n * Start a new notebook generation task\n */\n async generateNotebook(request) {\n const response = await fetch(`${this.baseUrl}/notebook/generate`, {\n method: 'POST',\n headers: this.getHeaders(),\n body: JSON.stringify(request)\n });\n if (!response.ok) {\n const error = await response\n .json()\n .catch(() => ({ message: 'Failed to start notebook generation' }));\n throw new Error(error.message || 'Failed to start notebook generation');\n }\n return response.json();\n }\n /**\n * Get current task status\n */\n async getTaskStatus(taskId) {\n const response = await fetch(`${this.baseUrl}/task/${taskId}/status`);\n if (!response.ok) {\n const error = await response\n .json()\n .catch(() => ({ message: 'Failed to get task status' }));\n throw new Error(error.message || 'Failed to get task status');\n }\n return response.json();\n }\n /**\n * Subscribe to task progress updates via Server-Sent Events\n */\n subscribeToTaskProgress(taskId, onProgress, onError, onComplete) {\n // Close existing connection if any\n this.unsubscribeFromTask(taskId);\n const eventSource = new EventSource(`${this.baseUrl}/task/${taskId}/stream`);\n eventSource.onmessage = (event) => {\n try {\n const data = JSON.parse(event.data);\n onProgress(data);\n // Close connection if task is done\n if (['completed', 'failed', 'cancelled'].includes(data.status)) {\n this.unsubscribeFromTask(taskId);\n if (onComplete) {\n onComplete();\n }\n }\n }\n catch (error) {\n console.error('Failed to parse SSE message:', error);\n if (onError) {\n onError(error);\n }\n }\n };\n eventSource.onerror = (event) => {\n console.error('SSE connection error:', event);\n this.unsubscribeFromTask(taskId);\n if (onError) {\n onError(new Error('Connection to server lost'));\n }\n };\n this.eventSources.set(taskId, eventSource);\n // Return unsubscribe function\n return () => this.unsubscribeFromTask(taskId);\n }\n /**\n * Unsubscribe from task progress updates\n */\n unsubscribeFromTask(taskId) {\n const eventSource = this.eventSources.get(taskId);\n if (eventSource) {\n eventSource.close();\n this.eventSources.delete(taskId);\n }\n }\n /**\n * Cancel a running task\n */\n async cancelTask(taskId) {\n const response = await fetch(`${this.baseUrl}/task/${taskId}/cancel`, {\n method: 'POST',\n headers: this.getHeaders()\n });\n if (!response.ok) {\n const error = await response\n .json()\n .catch(() => ({ message: 'Failed to cancel task' }));\n throw new Error(error.message || 'Failed to cancel task');\n }\n // Close SSE connection\n this.unsubscribeFromTask(taskId);\n }\n /**\n * Clean up all active connections\n */\n dispose() {\n for (const [taskId, _] of this.eventSources) {\n this.unsubscribeFromTask(taskId);\n }\n }\n}\n","/**\n * ToolExecutor - HF Jupyter Agent ์คํ์ผ์ Tool ์คํ๊ธฐ\n *\n * 3๊ฐ์ง ๋๊ตฌ ์คํ ๋ฐ ๊ฒฐ๊ณผ ์บก์ฒ:\n * - jupyter_cell: ์ฝ๋ ์
์์ฑ/์์ /์คํ\n * - markdown: ๋งํฌ๋ค์ด ์
์์ฑ/์์ \n * - final_answer: ์์
์๋ฃ ์ ํธ\n */\nimport { NotebookActions } from '@jupyterlab/notebook';\nimport { ToolRegistry, BUILTIN_TOOL_DEFINITIONS, DANGEROUS_COMMAND_PATTERNS } from './ToolRegistry';\nexport class ToolExecutor {\n constructor(notebook, sessionContext, apiService) {\n this.autoScrollEnabled = true;\n this.apiService = null;\n /**\n * ๋ง์ง๋ง์ผ๋ก ์์ฑ๋ ์
์ธ๋ฑ์ค ์ถ์ (์์ฐจ ์ฝ์
์ฉ)\n */\n this.lastCreatedCellIndex = -1;\n // Generate unique instance ID for debugging\n this.instanceId = `ToolExecutor-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n // ๋๋ฒ๊น
: ์์ฑ์์ ์ ๋ฌ๋ ๋
ธํธ๋ถ ๋ก๊ทธ\n console.log(`[ToolExecutor ${this.instanceId}] Constructor - notebook path:`, notebook?.context?.path);\n console.log(`[ToolExecutor ${this.instanceId}] Constructor - notebook title:`, notebook?.title?.label);\n this.notebook = notebook;\n this.sessionContext = sessionContext;\n this.registry = ToolRegistry.getInstance();\n this.apiService = apiService || null;\n // ๋นํธ์ธ ๋๊ตฌ๋ค ๋ฑ๋ก\n this.registerBuiltinTools();\n }\n /**\n * Set ApiService instance (for file resolution)\n */\n setApiService(apiService) {\n this.apiService = apiService;\n }\n /**\n * Get current notebook directory\n */\n getNotebookDir() {\n const notebookPath = this.notebook.context.path;\n if (!notebookPath)\n return undefined;\n const pathParts = notebookPath.split('/');\n pathParts.pop(); // Remove filename\n return pathParts.join('/') || undefined;\n }\n /**\n * ๋
ธํธ๋ถ ๋ชจ๋ธ์ด ์ค๋น๋ ๋๊น์ง ๋๊ธฐ\n * ์ฌ์ฉ์๊ฐ ์๋ก๊ณ ์นจํ ํ์ ์์ด ์๋์ผ๋ก ๋ชจ๋ธ์ ๊ธฐ๋ค๋ฆผ\n */\n async ensureModelReady() {\n console.log(`[ToolExecutor ${this.instanceId}] ensureModelReady - notebook:`, this.notebook?.context?.path);\n console.log(`[ToolExecutor ${this.instanceId}] ensureModelReady - this:`, this);\n console.log(`[ToolExecutor ${this.instanceId}] ensureModelReady - content:`, this.notebook?.content ? 'exists' : 'null');\n console.log(`[ToolExecutor ${this.instanceId}] ensureModelReady - model:`, this.notebook?.content?.model ? 'exists' : 'null');\n if (!this.notebook.content.model) {\n console.log('[ToolExecutor] Model not ready, waiting for context.ready...');\n // ๋
ธํธ๋ถ ์ปจํ
์คํธ๊ฐ ์ค๋น๋ ๋๊น์ง ๋๊ธฐ\n await this.notebook.context.ready;\n console.log('[ToolExecutor] context.ready completed');\n }\n if (!this.notebook.content.model) {\n console.error('[ToolExecutor] Model still not available after context.ready!');\n console.error('[ToolExecutor] notebook:', this.notebook);\n console.error('[ToolExecutor] notebook.content:', this.notebook.content);\n throw new Error('Notebook model not available after waiting for context ready');\n }\n console.log('[ToolExecutor] Model ready!');\n }\n /**\n * ๋นํธ์ธ ๋๊ตฌ๋ค์ ๋ ์ง์คํธ๋ฆฌ์ ๋ฑ๋ก\n */\n registerBuiltinTools() {\n // CRITICAL: Always re-register tools to update 'this' binding for current ToolExecutor instance\n // ToolRegistry is singleton, so we must overwrite executors to use the correct instance\n // jupyter_cell ๋๊ตฌ ๋ฑ๋ก\n const jupyterCellDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'jupyter_cell');\n if (jupyterCellDef) {\n this.registry.register({\n ...jupyterCellDef,\n executor: async (params, context) => {\n return this.executeJupyterCell(params, context.stepNumber);\n },\n });\n }\n // markdown ๋๊ตฌ ๋ฑ๋ก\n const markdownDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'markdown');\n if (markdownDef) {\n this.registry.register({\n ...markdownDef,\n executor: async (params, context) => {\n return this.executeMarkdown(params, context.stepNumber);\n },\n });\n }\n // final_answer ๋๊ตฌ ๋ฑ๋ก\n const finalAnswerDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'final_answer');\n if (finalAnswerDef) {\n this.registry.register({\n ...finalAnswerDef,\n executor: async (params, _context) => {\n return this.executeFinalAnswer(params);\n },\n });\n }\n console.log(`[ToolExecutor ${this.instanceId}] Built-in tools registered (overwritten)`);\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // ํ์ฅ ๋๊ตฌ๋ค ๋ฑ๋ก\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // read_file ๋๊ตฌ ๋ฑ๋ก\n const readFileDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'read_file');\n if (readFileDef && !this.registry.hasTool('read_file')) {\n this.registry.register({\n ...readFileDef,\n executor: async (params, _context) => {\n return this.executeReadFile(params);\n },\n });\n }\n // write_file ๋๊ตฌ ๋ฑ๋ก\n const writeFileDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'write_file');\n if (writeFileDef && !this.registry.hasTool('write_file')) {\n this.registry.register({\n ...writeFileDef,\n executor: async (params, _context) => {\n return this.executeWriteFile(params);\n },\n });\n }\n // list_files ๋๊ตฌ ๋ฑ๋ก\n const listFilesDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'list_files');\n if (listFilesDef && !this.registry.hasTool('list_files')) {\n this.registry.register({\n ...listFilesDef,\n executor: async (params, _context) => {\n return this.executeListFiles(params);\n },\n });\n }\n // execute_command ๋๊ตฌ ๋ฑ๋ก (์กฐ๊ฑด๋ถ ์น์ธ)\n const executeCommandDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'execute_command');\n if (executeCommandDef && !this.registry.hasTool('execute_command')) {\n this.registry.register({\n ...executeCommandDef,\n executor: async (params, context) => {\n return this.executeCommand(params, context);\n },\n });\n }\n // search_files ๋๊ตฌ ๋ฑ๋ก\n const searchFilesDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'search_files');\n if (searchFilesDef && !this.registry.hasTool('search_files')) {\n this.registry.register({\n ...searchFilesDef,\n executor: async (params, _context) => {\n return this.executeSearchFiles(params);\n },\n });\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // Phase 2 ํ์ฅ ๋๊ตฌ๋ค ๋ฑ๋ก\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // install_package ๋๊ตฌ ๋ฑ๋ก\n const installPackageDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'install_package');\n if (installPackageDef && !this.registry.hasTool('install_package')) {\n this.registry.register({\n ...installPackageDef,\n executor: async (params, _context) => {\n return this.executeInstallPackage(params);\n },\n });\n }\n // lint_file ๋๊ตฌ ๋ฑ๋ก\n const lintFileDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'lint_file');\n if (lintFileDef && !this.registry.hasTool('lint_file')) {\n this.registry.register({\n ...lintFileDef,\n executor: async (params, _context) => {\n return this.executeLintFile(params);\n },\n });\n }\n // delete_cell ๋๊ตฌ ๋ฑ๋ก\n const deleteCellDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'delete_cell');\n if (deleteCellDef && !this.registry.hasTool('delete_cell')) {\n this.registry.register({\n ...deleteCellDef,\n executor: async (params, _context) => {\n return this.executeDeleteCell(params);\n },\n });\n }\n // get_cell_output ๋๊ตฌ ๋ฑ๋ก\n const getCellOutputDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'get_cell_output');\n if (getCellOutputDef && !this.registry.hasTool('get_cell_output')) {\n this.registry.register({\n ...getCellOutputDef,\n executor: async (params, _context) => {\n return this.executeGetCellOutput(params);\n },\n });\n }\n // create_notebook ๋๊ตฌ ๋ฑ๋ก\n const createNotebookDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'create_notebook');\n if (createNotebookDef && !this.registry.hasTool('create_notebook')) {\n this.registry.register({\n ...createNotebookDef,\n executor: async (params, _context) => {\n return this.executeCreateNotebook(params);\n },\n });\n }\n // create_folder ๋๊ตฌ ๋ฑ๋ก\n const createFolderDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'create_folder');\n if (createFolderDef && !this.registry.hasTool('create_folder')) {\n this.registry.register({\n ...createFolderDef,\n executor: async (params, _context) => {\n return this.executeCreateFolder(params);\n },\n });\n }\n // delete_file ๋๊ตฌ ๋ฑ๋ก\n const deleteFileDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'delete_file');\n if (deleteFileDef && !this.registry.hasTool('delete_file')) {\n this.registry.register({\n ...deleteFileDef,\n executor: async (params, _context) => {\n return this.executeDeleteFile(params);\n },\n });\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // Phase 3 ํ์ฅ ๋๊ตฌ๋ค ๋ฑ๋ก (Git/Test/Refactor)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // git_operations ๋๊ตฌ ๋ฑ๋ก\n const gitOperationsDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'git_operations');\n if (gitOperationsDef && !this.registry.hasTool('git_operations')) {\n this.registry.register({\n ...gitOperationsDef,\n executor: async (params, context) => {\n return this.executeGitOperations(params, context);\n },\n });\n }\n // run_tests ๋๊ตฌ ๋ฑ๋ก\n const runTestsDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'run_tests');\n if (runTestsDef && !this.registry.hasTool('run_tests')) {\n this.registry.register({\n ...runTestsDef,\n executor: async (params, _context) => {\n return this.executeRunTests(params);\n },\n });\n }\n // refactor_code ๋๊ตฌ ๋ฑ๋ก\n const refactorCodeDef = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'refactor_code');\n if (refactorCodeDef && !this.registry.hasTool('refactor_code')) {\n this.registry.register({\n ...refactorCodeDef,\n executor: async (params, _context) => {\n return this.executeRefactorCode(params);\n },\n });\n }\n console.log('[ToolExecutor] Built-in tools registered');\n this.registry.printStatus();\n }\n /**\n * ์น์ธ ์ฝ๋ฐฑ ์ค์ (ApprovalDialog ์ฐ๋์ฉ)\n */\n setApprovalCallback(callback) {\n this.registry.setApprovalCallback(callback);\n }\n /**\n * ์น์ธ ํ์ ์ฌ๋ถ ์ค์ \n */\n setApprovalRequired(required) {\n this.registry.setApprovalRequired(required);\n }\n /**\n * ๋ ์ง์คํธ๋ฆฌ ์ธ์คํด์ค ๋ฐํ (์ธ๋ถ ๋๊ตฌ ๋ฑ๋ก์ฉ)\n */\n getRegistry() {\n return this.registry;\n }\n /**\n * ์ปค๋์ด idle ์ํ๊ฐ ๋ ๋๊น์ง ๋๊ธฐ\n * @param timeout ์ต๋ ๋๊ธฐ ์๊ฐ (ms)\n * @returns true if kernel became idle, false if timeout\n */\n async waitForKernelIdle(timeout = 10000) {\n const kernel = this.sessionContext.session?.kernel;\n if (!kernel) {\n console.warn('[ToolExecutor] No kernel available');\n return false;\n }\n const startTime = Date.now();\n const pollInterval = 100; // 100ms๋ง๋ค ์ฒดํฌ\n return new Promise((resolve) => {\n const checkStatus = () => {\n const elapsed = Date.now() - startTime;\n const status = kernel.status;\n if (status === 'idle') {\n console.log('[ToolExecutor] Kernel is idle after', elapsed, 'ms');\n resolve(true);\n return;\n }\n if (elapsed >= timeout) {\n console.warn('[ToolExecutor] Kernel idle wait timeout after', timeout, 'ms, status:', status);\n resolve(false);\n return;\n }\n // ์์ง idle์ด ์๋๋ฉด ๋ค์ ์ฒดํฌ\n setTimeout(checkStatus, pollInterval);\n };\n checkStatus();\n });\n }\n /**\n * ์๋ ์คํฌ๋กค ์ค์ \n */\n setAutoScroll(enabled) {\n this.autoScrollEnabled = enabled;\n }\n /**\n * ํน์ ์
๋ก ์คํฌ๋กค ๋ฐ ํฌ์ปค์ค\n */\n scrollToCell(cellIndex) {\n if (!this.autoScrollEnabled)\n return;\n const notebookContent = this.notebook.content;\n const cell = notebookContent.widgets[cellIndex];\n if (cell) {\n // ์
๋ก ๋ถ๋๋ฝ๊ฒ ์คํฌ๋กค\n cell.node.scrollIntoView({\n behavior: 'smooth',\n block: 'center',\n });\n }\n }\n /**\n * Tool ์คํ ๋ผ์ฐํฐ (๋ ์ง์คํธ๋ฆฌ ๊ธฐ๋ฐ)\n * @param call - ๋๊ตฌ ํธ์ถ ์ ๋ณด\n * @param stepNumber - ์คํ ๊ณํ์ ๋จ๊ณ ๋ฒํธ (์
์ ํ์์ฉ)\n */\n async executeTool(call, stepNumber) {\n console.log('[ToolExecutor] executeTool called:', JSON.stringify(call, null, 2), 'stepNumber:', stepNumber);\n // ์คํ ์ปจํ
์คํธ ์์ฑ\n const context = {\n notebook: this.notebook,\n sessionContext: this.sessionContext,\n stepNumber,\n };\n // ๋ ์ง์คํธ๋ฆฌ๋ฅผ ํตํด ๋๊ตฌ ์คํ (์น์ธ ๊ฒ์ดํธ ํฌํจ)\n const result = await this.registry.executeTool(call.tool, call.parameters, context);\n console.log('[ToolExecutor] Tool result:', JSON.stringify(result, null, 2));\n return result;\n }\n /**\n * Step ๋ฒํธ ํฌ๋งทํ
(์คํํน ๋ฐฉ์ง)\n * ๊ธฐ์กด Step ์ฃผ์์ด ์์ผ๋ฉด ๊ต์ฒด, ์์ผ๋ฉด ์ถ๊ฐ\n */\n formatCodeWithStep(code, stepNumber) {\n if (stepNumber === undefined) {\n return code;\n }\n // ๊ธฐ์กด Step ์ฃผ์ ์ ๊ฑฐ (์คํํน ๋ฐฉ์ง)\n // # [Step N] ๋๋ # [Step N.M] ํจํด ๋งค์นญ\n const stepPattern = /^# \\[Step \\d+(?:\\.\\d+)?\\]\\n/;\n const cleanCode = code.replace(stepPattern, '');\n // ์ Step ์ฃผ์ ์ถ๊ฐ\n return `# [Step ${stepNumber}]\\n${cleanCode}`;\n }\n /**\n * jupyter_cell ๋๊ตฌ: ์
์์ฑ/์์ /์คํ\n * @param stepNumber - ์คํ ๊ณํ์ ๋จ๊ณ ๋ฒํธ (์
์ ์ฃผ์์ผ๋ก ํ์)\n */\n async executeJupyterCell(params, stepNumber) {\n console.log('[ToolExecutor] executeJupyterCell params:', params);\n const notebookContent = this.notebook.content;\n console.log('[ToolExecutor] notebook content available:', !!notebookContent);\n console.log('[ToolExecutor] notebook model available:', !!notebookContent?.model);\n let cellIndex;\n let wasModified = false;\n let operation = params.operation || 'CREATE';\n let previousContent;\n // Step ๋ฒํธ ํฌ๋งทํ
(์คํํน ๋ฐฉ์ง)\n const codeWithStep = this.formatCodeWithStep(params.code, stepNumber);\n try {\n // ์์
์ ํ์ ๋ฐ๋ฅธ ์
์ฒ๋ฆฌ\n if (params.cellIndex !== undefined && params.operation !== 'CREATE') {\n // MODIFY: ๊ธฐ์กด ์
์์ \n operation = 'MODIFY';\n cellIndex = params.cellIndex;\n // ์์ ์ ์๋ณธ ๋ด์ฉ ์ ์ฅ (UI/์คํ์ทจ์์ฉ)\n const existingCell = notebookContent.widgets[cellIndex];\n if (existingCell?.model?.sharedModel) {\n previousContent = existingCell.model.sharedModel.getSource();\n }\n console.log('[ToolExecutor] MODIFY: Updating cell at index:', cellIndex);\n this.updateCellContent(cellIndex, codeWithStep);\n wasModified = true;\n }\n else if (params.insertAfter !== undefined) {\n // INSERT_AFTER: ํน์ ์
๋ค์ ์ฝ์
\n operation = 'INSERT_AFTER';\n console.log('[ToolExecutor] INSERT_AFTER: Inserting after cell:', params.insertAfter);\n cellIndex = await this.insertCellAfter(codeWithStep, params.insertAfter);\n }\n else if (params.insertBefore !== undefined) {\n // INSERT_BEFORE: ํน์ ์
์์ ์ฝ์
\n operation = 'INSERT_BEFORE';\n console.log('[ToolExecutor] INSERT_BEFORE: Inserting before cell:', params.insertBefore);\n cellIndex = await this.insertCellBefore(codeWithStep, params.insertBefore);\n }\n else {\n // CREATE: ๊ธฐ๋ณธ ๋์ - ๋
ธํธ๋ถ ๋์ ์์ฑ\n operation = 'CREATE';\n console.log('[ToolExecutor] CREATE: Creating new cell at end');\n cellIndex = await this.createCodeCell(codeWithStep);\n }\n console.log('[ToolExecutor] Cell operation completed:', operation, 'at index:', cellIndex);\n // ์
์์ฑ/์์ ํ ํด๋น ์
๋ก ์คํฌ๋กค (์คํ ์ )\n this.scrollToCell(cellIndex);\n // ์
์คํ ๋ฐ ๊ฒฐ๊ณผ ์บก์ฒ\n console.log('[ToolExecutor] Executing cell at index:', cellIndex);\n const result = await this.executeCellAndCapture(cellIndex);\n console.log('[ToolExecutor] Cell execution result:', result.status);\n return {\n success: result.status === 'ok',\n output: result.result || result.stdout,\n error: result.error?.evalue,\n errorName: result.error?.ename,\n traceback: result.error?.traceback,\n cellIndex,\n wasModified,\n operation,\n previousContent,\n };\n }\n catch (error) {\n console.error('[ToolExecutor] executeJupyterCell error:', error);\n return {\n success: false,\n error: error.message || 'Failed to execute jupyter_cell',\n cellIndex: cellIndex,\n wasModified,\n operation,\n previousContent,\n };\n }\n }\n /**\n * markdown ๋๊ตฌ: ๋งํฌ๋ค์ด ์
์์ฑ/์์ \n */\n async executeMarkdown(params, stepNumber) {\n try {\n let cellIndex;\n let wasModified = false;\n // stepNumber๊ฐ ์์ผ๋ฉด ๋งํฌ๋ค์ด ๋งจ ์์ ํ์ ์ถ๊ฐ\n let contentWithStep = params.content;\n if (stepNumber !== undefined) {\n contentWithStep = `**[Step ${stepNumber}]**\\n\\n${params.content}`;\n }\n if (params.cellIndex !== undefined) {\n cellIndex = params.cellIndex;\n this.updateCellContent(cellIndex, contentWithStep);\n wasModified = true;\n }\n else {\n cellIndex = await this.createMarkdownCell(contentWithStep);\n }\n // ๋งํฌ๋ค์ด ์
๋ ์์ฑ ํ ์คํฌ๋กค\n this.scrollToCell(cellIndex);\n return {\n success: true,\n cellIndex,\n wasModified,\n };\n }\n catch (error) {\n return {\n success: false,\n error: error.message || 'Failed to execute markdown',\n };\n }\n }\n /**\n * final_answer ๋๊ตฌ: ์์
์๋ฃ ์ ํธ\n */\n async executeFinalAnswer(params) {\n return {\n success: true,\n output: params.answer,\n };\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // ํ์ฅ ๋๊ตฌ ์คํ๊ธฐ (ํ์ผ/ํฐ๋ฏธ๋ ์์
)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n /**\n * Path Traversal ๋ฐฉ์ง ๊ฒ์ฌ\n * ์๋ ๊ฒฝ๋ก๋ง ํ์ฉ, ์ ๋ ๊ฒฝ๋ก ๋ฐ .. ์ฐจ๋จ\n */\n validatePath(path) {\n // ์ ๋ ๊ฒฝ๋ก ์ฐจ๋จ\n if (path.startsWith('/') || path.startsWith('\\\\') || /^[A-Za-z]:/.test(path)) {\n return { valid: false, error: 'Absolute paths are not allowed' };\n }\n // Path traversal ์ฐจ๋จ\n if (path.includes('..')) {\n return { valid: false, error: 'Path traversal (..) is not allowed' };\n }\n return { valid: true };\n }\n /**\n * ์ํ ๋ช
๋ น ์ฌ๋ถ ํ์ธ\n */\n isDangerousCommand(command) {\n return DANGEROUS_COMMAND_PATTERNS.some(pattern => pattern.test(command));\n }\n /**\n * read_file ๋๊ตฌ: ํ์ผ ์ฝ๊ธฐ\n */\n async executeReadFile(params) {\n console.log('[ToolExecutor] executeReadFile:', params);\n // ๊ฒฝ๋ก ๊ฒ์ฆ\n const pathCheck = this.validatePath(params.path);\n if (!pathCheck.valid) {\n return { success: false, error: pathCheck.error };\n }\n const encoding = params.encoding || 'utf-8';\n const maxLines = params.maxLines || 1000;\n // Python ์ฝ๋๋ก ํ์ผ ์ฝ๊ธฐ (์ปค๋์์ ์คํ)\n const pythonCode = `\nimport json\ntry:\n with open(${JSON.stringify(params.path)}, 'r', encoding=${JSON.stringify(encoding)}) as f:\n lines = f.readlines()[:${maxLines}]\n content = ''.join(lines)\n result = {'success': True, 'content': content, 'lineCount': len(lines), 'truncated': len(lines) >= ${maxLines}}\nexcept FileNotFoundError:\n result = {'success': False, 'error': f'File not found: ${params.path}'}\nexcept PermissionError:\n result = {'success': False, 'error': f'Permission denied: ${params.path}'}\nexcept Exception as e:\n result = {'success': False, 'error': str(e)}\nprint(json.dumps(result))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n return {\n success: true,\n output: parsed.content,\n };\n }\n else {\n return { success: false, error: parsed.error };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Read failed' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * write_file ๋๊ตฌ: ํ์ผ ์ฐ๊ธฐ\n */\n async executeWriteFile(params) {\n console.log('[ToolExecutor] executeWriteFile:', params.path);\n // ๊ฒฝ๋ก ๊ฒ์ฆ\n const pathCheck = this.validatePath(params.path);\n if (!pathCheck.valid) {\n return { success: false, error: pathCheck.error };\n }\n const overwrite = params.overwrite ?? false;\n const mode = overwrite ? 'w' : 'x'; // 'x'๋ exclusive creation\n // Python ์ฝ๋๋ก ํ์ผ ์ฐ๊ธฐ (์ปค๋์์ ์คํ)\n const pythonCode = `\nimport json\nimport os\ntry:\n mode = ${JSON.stringify(mode)}\n path = ${JSON.stringify(params.path)}\n content = ${JSON.stringify(params.content)}\n\n # ๋๋ ํ ๋ฆฌ๊ฐ ์์ผ๋ฉด ์์ฑ\n dir_path = os.path.dirname(path)\n if dir_path:\n os.makedirs(dir_path, exist_ok=True)\n\n with open(path, mode, encoding='utf-8') as f:\n f.write(content)\n result = {'success': True, 'path': path, 'size': len(content)}\nexcept FileExistsError:\n result = {'success': False, 'error': f'File already exists: {path}. Set overwrite=True to overwrite.'}\nexcept PermissionError:\n result = {'success': False, 'error': f'Permission denied: {path}'}\nexcept Exception as e:\n result = {'success': False, 'error': str(e)}\nprint(json.dumps(result))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n return {\n success: true,\n output: `Written ${parsed.size} bytes to ${parsed.path}`,\n };\n }\n else {\n return { success: false, error: parsed.error };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Write failed' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * Check if pattern is an exact path (contains path separator)\n */\n isExactPath(pattern) {\n return pattern.includes('/') || pattern.includes('\\\\');\n }\n /**\n * Check file existence for exact paths\n */\n async checkFileExists(filePath, basePath = '.') {\n const fullPath = filePath.startsWith('/') ? filePath : `${basePath}/${filePath}`;\n const pythonCode = `\nimport json\nimport os\ntry:\n path = ${JSON.stringify(fullPath)}\n if os.path.exists(path):\n is_dir = os.path.isdir(path)\n size = 0 if is_dir else os.path.getsize(path)\n result = {\n 'success': True,\n 'path': path,\n 'isDir': is_dir,\n 'size': size\n }\n else:\n result = {'success': False, 'error': f'File not found: {path}'}\nexcept Exception as e:\n result = {'success': False, 'error': str(e)}\nprint(json.dumps(result))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n const icon = parsed.isDir ? '๐' : '๐';\n const sizeInfo = parsed.isDir ? '' : ` (${parsed.size} bytes)`;\n return {\n success: true,\n output: `${icon} ${parsed.path}${sizeInfo}`,\n metadata: { resolvedPath: parsed.path }\n };\n }\n return { success: false, error: parsed.error };\n }\n return { success: false, error: 'Failed to check file existence' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * Resolve file using file_resolver API\n */\n async resolveWithFileResolver(pattern, params) {\n console.log('[ToolExecutor] Resolving files locally via kernel...');\n const notebookDirRelative = this.getNotebookDir() || '.';\n const recursive = params.recursive ?? false;\n // Python code to search for files in multiple paths\n const pythonCode = `\nimport json\nimport os\nimport glob as glob_module\ntry:\n pattern = ${JSON.stringify(pattern)}\n notebook_dir_relative = ${JSON.stringify(notebookDirRelative)}\n recursive = ${recursive ? 'True' : 'False'}\n\n # For simple filename patterns (no path separators), always search recursively\n # This allows finding files in subdirectories\n is_filename_pattern = '/' not in pattern and '\\\\\\\\' not in pattern\n if is_filename_pattern:\n recursive = True\n\n # Get current working directory (may be server root or notebook dir)\n cwd = os.getcwd()\n\n # Get Jupyter server root (absolute path)\n server_root = os.getenv('JUPYTER_SERVER_ROOT') or \\\n os.getenv('JUPYTERHUB_ROOT_DIR')\n\n # Get notebook directory (absolute path)\n if notebook_dir_relative and notebook_dir_relative != '.':\n # If we have server_root, use it\n if server_root:\n notebook_dir = os.path.join(server_root, notebook_dir_relative)\n if not os.path.exists(notebook_dir):\n notebook_dir = cwd\n else:\n # No server_root env var - derive from cwd\n # If cwd ends with notebook_dir_relative, it's already the notebook dir\n if cwd.endswith(notebook_dir_relative):\n notebook_dir = cwd\n server_root = os.path.dirname(cwd)\n else:\n # cwd is probably server_root\n notebook_dir = os.path.join(cwd, notebook_dir_relative)\n server_root = cwd\n else:\n # notebook_dir_relative is '.'\n notebook_dir = cwd\n server_root = os.path.dirname(cwd) if os.path.dirname(cwd) != cwd else cwd\n\n # Search paths:\n # 1. notebook_dir (ํ์ฌ ๋
ธํธ๋ถ ๋๋ ํ ๋ฆฌ) - ์ข์ ๋ฒ์ ์ฐ์ \n # 2. server_root (JUPYTER_SERVER_ROOT, ํ๋ก์ ํธ ๋ฃจํธ) - ์ ์ฒด ํ๋ก์ ํธ\n search_paths = [notebook_dir]\n\n # Add server_root if different from notebook_dir\n if server_root != notebook_dir and os.path.exists(server_root):\n search_paths.append(server_root)\n elif notebook_dir != cwd and cwd != server_root and os.path.exists(cwd):\n search_paths.append(cwd)\n\n matches = []\n seen_paths = set() # Track unique absolute paths\n debug_info = {\n 'notebook_dir': notebook_dir,\n 'server_root': server_root,\n 'search_paths': search_paths,\n 'searches': []\n }\n\n for search_path in search_paths:\n # Construct glob pattern\n if recursive and '**' not in pattern:\n search_pattern = os.path.join(search_path, '**', pattern)\n else:\n search_pattern = os.path.join(search_path, pattern)\n\n # Find files (limit depth to avoid searching too deep)\n all_files = glob_module.glob(search_pattern, recursive=recursive)\n\n # For recursive searches, apply depth limit based on search path\n if recursive and '**' in search_pattern:\n # For notebook_dir: limit to 3 levels (focused search)\n # For server_root: limit to 5 levels (broader search)\n if search_path == notebook_dir:\n max_depth = 3\n else:\n max_depth = 5\n\n files = [f for f in all_files if f.count(os.sep) - search_path.count(os.sep) <= max_depth]\n else:\n files = all_files\n\n debug_info['searches'].append({\n 'search_path': search_path,\n 'search_pattern': search_pattern,\n 'found_count': len(files),\n 'files': files\n })\n\n for file_path in files:\n abs_path = os.path.abspath(file_path)\n # Avoid duplicates\n if abs_path not in seen_paths:\n seen_paths.add(abs_path)\n matches.append({\n 'path': abs_path,\n 'relative': file_path,\n 'dir': os.path.dirname(file_path) or '.'\n })\n\n result = {\n 'success': True,\n 'matches': matches,\n 'count': len(matches),\n 'debug': debug_info\n }\nexcept Exception as e:\n result = {'success': False, 'error': str(e)}\nprint(json.dumps(result))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n // Debug logging\n if (parsed.debug) {\n console.log('[ToolExecutor] File search debug info:', parsed.debug);\n }\n if (!parsed.success) {\n return { success: false, error: parsed.error };\n }\n const matches = parsed.matches;\n if (matches.length === 0) {\n return { success: false, error: `'${pattern}' ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค.` };\n }\n if (matches.length === 1) {\n // Single file found\n return {\n success: true,\n output: `๐ ${matches[0].relative}`,\n metadata: { resolvedPath: matches[0].path }\n };\n }\n // Multiple files found - need user selection\n return {\n success: false,\n error: 'FILE_SELECTION_REQUIRED',\n metadata: {\n type: 'file_selection',\n pattern: pattern,\n options: matches,\n message: `'${pattern}' ํจํด๊ณผ ์ผ์นํ๋ ํ์ผ์ด ${matches.length}๊ฐ ๋ฐ๊ฒฌ๋์์ต๋๋ค.\\n\\n${matches.map((m, i) => `${i + 1}. ${m.relative}`).join('\\n')}\\n\\n๋ฒํธ๋ฅผ ์ ํํด์ฃผ์ธ์ (1-${matches.length})`\n }\n };\n }\n return { success: false, error: execResult.error?.evalue || 'File resolution failed' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * list_files ๋๊ตฌ: ๋๋ ํ ๋ฆฌ ๋ชฉ๋ก ์กฐํ (MECE ๊ตฌ์กฐ)\n */\n async executeListFiles(params) {\n console.log('[ToolExecutor] executeListFiles:', params);\n // ๊ฒฝ๋ก ๊ฒ์ฆ\n const pathCheck = this.validatePath(params.path);\n if (!pathCheck.valid) {\n return { success: false, error: pathCheck.error };\n }\n const pattern = params.pattern || '*';\n // CASE 1: ์ ํํ ๊ฒฝ๋ก (์ฌ์ฉ์๊ฐ ์ง์ ๋ช
์)\n // ์: \"./titanic.csv\", \"data/train.csv\"\n if (this.isExactPath(pattern)) {\n return await this.checkFileExists(pattern, params.path);\n }\n // CASE 2: ํ์ผ๋ช
/ํจํด โ file_resolver ์๋\n // ์: \"titanic.csv\", \"*titanic*\", \"*.csv\"\n if (this.apiService) {\n try {\n return await this.resolveWithFileResolver(pattern, params);\n }\n catch (error) {\n console.warn('[ToolExecutor] file_resolver failed, falling back to glob:', error);\n // Fallback to glob search\n }\n }\n // CASE 3: Fallback - ๊ธฐ์กด glob ๊ฒ์ (apiService ์๊ฑฐ๋ ์คํจ ์)\n return await this.executeListFilesWithGlob(pattern, params);\n }\n /**\n * Glob-based file listing (fallback)\n */\n async executeListFilesWithGlob(pattern, params) {\n const recursive = params.recursive ?? false;\n const isFilenameOnly = !pattern.includes('/') && !pattern.includes('\\\\') && pattern !== '*';\n const effectiveRecursive = recursive || isFilenameOnly;\n // Python ์ฝ๋๋ก ํ์ผ ๋ชฉ๋ก ์กฐํ\n const pythonCode = `\nimport json\nimport os\nimport glob as glob_module\ntry:\n path = ${JSON.stringify(params.path)}\n pattern = ${JSON.stringify(pattern)}\n recursive = ${effectiveRecursive ? 'True' : 'False'}\n\n if recursive:\n search_pattern = os.path.join(path, '**', pattern)\n files = glob_module.glob(search_pattern, recursive=True)\n else:\n search_pattern = os.path.join(path, pattern)\n files = glob_module.glob(search_pattern)\n\n # ๊ฒฐ๊ณผ๋ฅผ ์๋ ๊ฒฝ๋ก๋ก ๋ณํ\n result_files = []\n for f in files[:500]: # ์ต๋ 500๊ฐ\n stat = os.stat(f)\n result_files.append({\n 'path': f,\n 'isDir': os.path.isdir(f),\n 'size': stat.st_size if not os.path.isdir(f) else 0\n })\n\n result = {'success': True, 'files': result_files, 'count': len(result_files)}\nexcept FileNotFoundError:\n result = {'success': False, 'error': f'Directory not found: {path}'}\nexcept PermissionError:\n result = {'success': False, 'error': f'Permission denied: {path}'}\nexcept Exception as e:\n result = {'success': False, 'error': str(e)}\nprint(json.dumps(result))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n // ํ์ผ ๋ชฉ๋ก์ ๋ณด๊ธฐ ์ข๊ฒ ํฌ๋งทํ
\n const formatted = parsed.files.map((f) => `${f.isDir ? '๐' : '๐'} ${f.path}${f.isDir ? '/' : ` (${f.size} bytes)`}`).join('\\n');\n return {\n success: true,\n output: formatted || '(empty directory)',\n };\n }\n else {\n return { success: false, error: parsed.error };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'List failed' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * execute_command ๋๊ตฌ: ์
ธ ๋ช
๋ น ์คํ (์กฐ๊ฑด๋ถ ์น์ธ)\n */\n async executeCommand(params, context) {\n console.log('[ToolExecutor] executeCommand:', params.command);\n const timeout = params.timeout || 30000;\n // ์ํ ๋ช
๋ น ๊ฒ์ฌ ๋ฐ ์กฐ๊ฑด๋ถ ์น์ธ ์์ฒญ\n if (this.isDangerousCommand(params.command)) {\n console.log('[ToolExecutor] Dangerous command detected, requesting approval');\n // ์น์ธ ์์ฒญ\n const request = {\n id: `execute_command-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n toolName: 'execute_command',\n toolDefinition: this.registry.getTool('execute_command'),\n parameters: params,\n stepNumber: context.stepNumber,\n description: `๐ด ์ํ ๋ช
๋ น ์คํ ์์ฒญ:\\n\\n\\`${params.command}\\`\\n\\n์ด ๋ช
๋ น์ ์์คํ
์ ์ํฅ์ ์ค ์ ์์ต๋๋ค.`,\n timestamp: Date.now(),\n };\n const approvalCallback = this.registry.approvalCallback;\n if (approvalCallback) {\n const approvalResult = await approvalCallback(request);\n if (!approvalResult.approved) {\n return {\n success: false,\n error: `Command execution denied: ${approvalResult.reason || 'User rejected dangerous command'}`,\n };\n }\n }\n }\n // Python subprocess๋ก ๋ช
๋ น ์คํ\n const pythonCode = `\nimport json\nimport subprocess\nimport sys\ntry:\n command = ${JSON.stringify(params.command)}\n timeout_sec = ${timeout / 1000}\n\n result = subprocess.run(\n command,\n shell=True,\n capture_output=True,\n text=True,\n timeout=timeout_sec\n )\n\n output = {\n 'success': result.returncode == 0,\n 'stdout': result.stdout,\n 'stderr': result.stderr,\n 'returncode': result.returncode\n }\nexcept subprocess.TimeoutExpired:\n output = {'success': False, 'error': f'Command timed out after {timeout_sec}s'}\nexcept Exception as e:\n output = {'success': False, 'error': str(e)}\nprint(json.dumps(output))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n return {\n success: true,\n output: parsed.stdout || '(no output)',\n };\n }\n else {\n return {\n success: false,\n error: parsed.error || parsed.stderr || `Command failed with code ${parsed.returncode}`,\n };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Command execution failed' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * search_files ๋๊ตฌ: ํ์ผ ๋ด์ฉ ๊ฒ์\n */\n async executeSearchFiles(params) {\n console.log('[ToolExecutor] executeSearchFiles:', params);\n const searchPath = params.path || '.';\n const maxResults = params.maxResults || 100;\n // ๊ฒฝ๋ก ๊ฒ์ฆ\n const pathCheck = this.validatePath(searchPath);\n if (!pathCheck.valid) {\n return { success: false, error: pathCheck.error };\n }\n // Python์ผ๋ก grep ์คํ์ผ ๊ฒ์\n const pythonCode = `\nimport json\nimport os\nimport re\ntry:\n pattern = ${JSON.stringify(params.pattern)}\n search_path = ${JSON.stringify(searchPath)}\n max_results = ${maxResults}\n\n regex = re.compile(pattern, re.IGNORECASE)\n matches = []\n\n for root, dirs, files in os.walk(search_path):\n # ์จ๊น ๋๋ ํ ๋ฆฌ ๋ฐ ์ผ๋ฐ์ ์ธ ์ ์ธ ๋์ ์คํต\n dirs[:] = [d for d in dirs if not d.startswith('.') and d not in ['node_modules', '__pycache__', '.git', 'venv', '.venv']]\n\n for filename in files:\n if len(matches) >= max_results:\n break\n\n # ๋ฐ์ด๋๋ฆฌ ํ์ผ ์คํต\n if filename.endswith(('.pyc', '.pyo', '.so', '.dll', '.exe', '.bin', '.png', '.jpg', '.gif', '.pdf', '.zip')):\n continue\n\n filepath = os.path.join(root, filename)\n try:\n with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:\n for line_num, line in enumerate(f, 1):\n if regex.search(line):\n matches.append({\n 'file': filepath,\n 'line': line_num,\n 'content': line.strip()[:200] # ์ต๋ 200์\n })\n if len(matches) >= max_results:\n break\n except (IOError, OSError):\n continue\n\n if len(matches) >= max_results:\n break\n\n result = {'success': True, 'matches': matches, 'count': len(matches), 'truncated': len(matches) >= max_results}\nexcept re.error as e:\n result = {'success': False, 'error': f'Invalid regex pattern: {e}'}\nexcept Exception as e:\n result = {'success': False, 'error': str(e)}\nprint(json.dumps(result))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n // ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ธฐ ์ข๊ฒ ํฌ๋งทํ
\n const formatted = parsed.matches.map((m) => `${m.file}:${m.line}: ${m.content}`).join('\\n');\n return {\n success: true,\n output: formatted || '(no matches found)',\n };\n }\n else {\n return { success: false, error: parsed.error };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Search failed' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // Phase 2 ํ์ฅ ๋๊ตฌ ์คํ๊ธฐ\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n /**\n * install_package ๋๊ตฌ: pip ํจํค์ง ์ค์น\n */\n async executeInstallPackage(params) {\n console.log('[ToolExecutor] executeInstallPackage:', params);\n const packageName = params.package;\n const version = params.version;\n const extras = params.extras || [];\n const upgrade = params.upgrade ?? false;\n // ํจํค์ง ์คํ ๊ตฌ์ฑ\n let packageSpec = packageName;\n if (extras.length > 0) {\n packageSpec += `[${extras.join(',')}]`;\n }\n if (version) {\n packageSpec += `==${version}`;\n }\n // pip install ๋ช
๋ น ๊ตฌ์ฑ\n const pipArgs = ['install'];\n if (upgrade) {\n pipArgs.push('--upgrade');\n }\n pipArgs.push(packageSpec);\n // Python subprocess๋ก pip ์คํ\n const pythonCode = `\nimport json\nimport subprocess\nimport sys\ntry:\n pip_args = ${JSON.stringify(pipArgs)}\n result = subprocess.run(\n [sys.executable, '-m', 'pip'] + pip_args,\n capture_output=True,\n text=True,\n timeout=300 # 5๋ถ ํ์์์\n )\n\n output = {\n 'success': result.returncode == 0,\n 'stdout': result.stdout,\n 'stderr': result.stderr,\n 'returncode': result.returncode,\n 'package': ${JSON.stringify(packageSpec)}\n }\nexcept subprocess.TimeoutExpired:\n output = {'success': False, 'error': 'Package installation timed out after 5 minutes'}\nexcept Exception as e:\n output = {'success': False, 'error': str(e)}\nprint(json.dumps(output))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n return {\n success: true,\n output: `Successfully installed ${parsed.package}\\n${parsed.stdout}`,\n };\n }\n else {\n return {\n success: false,\n error: parsed.error || parsed.stderr || `pip install failed with code ${parsed.returncode}`,\n };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Package installation failed' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * lint_file ๋๊ตฌ: Python ํ์ผ ๋ฆฐํธ ๊ฒ์ฌ\n */\n async executeLintFile(params) {\n console.log('[ToolExecutor] executeLintFile:', params);\n // ๊ฒฝ๋ก ๊ฒ์ฆ\n const pathCheck = this.validatePath(params.path);\n if (!pathCheck.valid) {\n return { success: false, error: pathCheck.error };\n }\n const fix = params.fix ?? false;\n const tool = params.tool || 'ruff';\n // ๋ฆฐํธ ๋๊ตฌ๋ณ ๋ช
๋ น ๊ตฌ์ฑ\n const pythonCode = `\nimport json\nimport subprocess\nimport shutil\ntry:\n path = ${JSON.stringify(params.path)}\n tool = ${JSON.stringify(tool)}\n fix = ${fix}\n\n # ๋๊ตฌ ์กด์ฌ ์ฌ๋ถ ํ์ธ\n tool_path = shutil.which(tool)\n if not tool_path:\n # pip๋ก ๋๊ตฌ ๊ฒ์ ์๋\n import sys\n result = subprocess.run(\n [sys.executable, '-m', tool, '--version'],\n capture_output=True, text=True\n )\n if result.returncode != 0:\n raise FileNotFoundError(f'{tool} is not installed. Run: pip install {tool}')\n tool_cmd = [sys.executable, '-m', tool]\n else:\n tool_cmd = [tool]\n\n # ๋ฆฐํธ ๋ช
๋ น ๊ตฌ์ฑ\n if tool == 'ruff':\n args = tool_cmd + ['check', path]\n if fix:\n args.append('--fix')\n elif tool == 'pylint':\n args = tool_cmd + [path]\n elif tool == 'flake8':\n args = tool_cmd + [path]\n else:\n raise ValueError(f'Unsupported lint tool: {tool}')\n\n result = subprocess.run(args, capture_output=True, text=True, timeout=60)\n\n output = {\n 'success': result.returncode == 0,\n 'stdout': result.stdout,\n 'stderr': result.stderr,\n 'returncode': result.returncode,\n 'tool': tool,\n 'fixed': fix and result.returncode == 0\n }\nexcept FileNotFoundError as e:\n output = {'success': False, 'error': str(e)}\nexcept subprocess.TimeoutExpired:\n output = {'success': False, 'error': 'Lint check timed out after 60 seconds'}\nexcept Exception as e:\n output = {'success': False, 'error': str(e)}\nprint(json.dumps(output))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n const status = parsed.fixed ? 'โ
Fixed' : 'โ
No issues';\n return {\n success: true,\n output: `${status} (${parsed.tool})\\n${parsed.stdout || '(no output)'}`,\n };\n }\n else {\n // ๋ฆฐํธ ์ด์๊ฐ ์์ด๋ ์คํ์ ์ฑ๊ณตํ ๊ฒ\n if (parsed.returncode !== undefined && parsed.stdout) {\n return {\n success: true,\n output: `โ ๏ธ Lint issues found (${parsed.tool}):\\n${parsed.stdout}${parsed.stderr ? '\\n' + parsed.stderr : ''}`,\n };\n }\n return { success: false, error: parsed.error || parsed.stderr };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Lint check failed' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * delete_cell ๋๊ตฌ: ๋
ธํธ๋ถ ์
์ญ์ \n */\n async executeDeleteCell(params) {\n console.log('[ToolExecutor] executeDeleteCell:', params);\n const { cellIndex } = params;\n const model = this.notebook.content.model;\n if (!model) {\n return { success: false, error: 'Notebook model not available' };\n }\n const cellCount = model.cells.length;\n if (cellIndex < 0 || cellIndex >= cellCount) {\n return {\n success: false,\n error: `Invalid cell index: ${cellIndex}. Valid range: 0-${cellCount - 1}`,\n };\n }\n // ์ญ์ ์ ์
๋ด์ฉ ์ ์ฅ (๋ก๊น
์ฉ)\n const cell = model.cells.get(cellIndex);\n const cellType = cell?.type || 'unknown';\n const cellSource = cell?.sharedModel.getSource().substring(0, 100);\n try {\n model.sharedModel.deleteCell(cellIndex);\n return {\n success: true,\n output: `Deleted ${cellType} cell at index ${cellIndex}${cellSource ? `: \"${cellSource}...\"` : ''}`,\n };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * get_cell_output ๋๊ตฌ: ์
์ถ๋ ฅ ์กฐํ\n */\n async executeGetCellOutput(params) {\n console.log('[ToolExecutor] executeGetCellOutput:', params);\n const { cellIndex, outputType = 'text' } = params;\n const model = this.notebook.content.model;\n if (!model) {\n return { success: false, error: 'Notebook model not available' };\n }\n const cellCount = model.cells.length;\n if (cellIndex < 0 || cellIndex >= cellCount) {\n return {\n success: false,\n error: `Invalid cell index: ${cellIndex}. Valid range: 0-${cellCount - 1}`,\n };\n }\n const cell = this.notebook.content.widgets[cellIndex];\n if (!cell || cell.model?.type !== 'code') {\n return {\n success: false,\n error: `Cell at index ${cellIndex} is not a code cell`,\n };\n }\n const cellOutputs = cell.model?.outputs;\n if (!cellOutputs || cellOutputs.length === 0) {\n return {\n success: true,\n output: '(no output)',\n };\n }\n const outputs = [];\n for (let i = 0; i < cellOutputs.length; i++) {\n const output = cellOutputs.get(i);\n const outputData = output.toJSON?.() || output;\n if (outputType === 'all') {\n outputs.push(outputData);\n }\n else {\n // text ๋ชจ๋: ํ
์คํธ๋ง ์ถ์ถ\n if (output.type === 'stream') {\n outputs.push(output.text || '');\n }\n else if (output.type === 'execute_result' || output.type === 'display_data') {\n const data = output.data;\n if (data?.['text/plain']) {\n outputs.push(data['text/plain']);\n }\n }\n else if (output.type === 'error') {\n outputs.push(`${outputData.ename}: ${outputData.evalue}`);\n }\n }\n }\n return {\n success: true,\n output: outputType === 'all' ? JSON.stringify(outputs, null, 2) : outputs.join('\\n'),\n };\n }\n /**\n * create_notebook ๋๊ตฌ: ์ ๋
ธํธ๋ถ ํ์ผ ์์ฑ\n */\n async executeCreateNotebook(params) {\n console.log('[ToolExecutor] executeCreateNotebook:', params);\n // ๊ฒฝ๋ก ๊ฒ์ฆ\n const pathCheck = this.validatePath(params.path);\n if (!pathCheck.valid) {\n return { success: false, error: pathCheck.error };\n }\n // .ipynb ํ์ฅ์ ํ์ธ\n if (!params.path.endsWith('.ipynb')) {\n return { success: false, error: 'Notebook path must end with .ipynb' };\n }\n const cells = params.cells || [];\n const kernel = params.kernel || 'python3';\n // ๋
ธํธ๋ถ JSON ๊ตฌ์กฐ ์์ฑ\n const pythonCode = `\nimport json\nimport os\ntry:\n path = ${JSON.stringify(params.path)}\n cells = ${JSON.stringify(cells)}\n kernel = ${JSON.stringify(kernel)}\n\n # ์ด๋ฏธ ์กด์ฌํ๋์ง ํ์ธ\n if os.path.exists(path):\n raise FileExistsError(f'Notebook already exists: {path}')\n\n # ๋๋ ํ ๋ฆฌ ์์ฑ\n dir_path = os.path.dirname(path)\n if dir_path:\n os.makedirs(dir_path, exist_ok=True)\n\n # ๋
ธํธ๋ถ ๊ตฌ์กฐ ์์ฑ\n notebook = {\n 'nbformat': 4,\n 'nbformat_minor': 5,\n 'metadata': {\n 'kernelspec': {\n 'name': kernel,\n 'display_name': 'Python 3',\n 'language': 'python'\n },\n 'language_info': {\n 'name': 'python',\n 'version': '3.9'\n }\n },\n 'cells': []\n }\n\n # ์
์ถ๊ฐ\n for i, cell in enumerate(cells):\n cell_type = cell.get('type', 'code')\n source = cell.get('source', '')\n notebook['cells'].append({\n 'cell_type': cell_type,\n 'source': source.split('\\\\n') if source else [],\n 'metadata': {},\n 'execution_count': None if cell_type == 'code' else None,\n 'outputs': [] if cell_type == 'code' else None\n })\n # Remove None values\n notebook['cells'][-1] = {k: v for k, v in notebook['cells'][-1].items() if v is not None}\n\n # ํ์ผ ์ ์ฅ\n with open(path, 'w', encoding='utf-8') as f:\n json.dump(notebook, f, indent=2)\n\n result = {'success': True, 'path': path, 'cellCount': len(cells)}\nexcept FileExistsError as e:\n result = {'success': False, 'error': str(e)}\nexcept Exception as e:\n result = {'success': False, 'error': str(e)}\nprint(json.dumps(result))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n return {\n success: true,\n output: `Created notebook: ${parsed.path} with ${parsed.cellCount} cells`,\n };\n }\n else {\n return { success: false, error: parsed.error };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Failed to create notebook' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * create_folder ๋๊ตฌ: ๋๋ ํ ๋ฆฌ ์์ฑ\n */\n async executeCreateFolder(params) {\n console.log('[ToolExecutor] executeCreateFolder:', params);\n // ๊ฒฝ๋ก ๊ฒ์ฆ\n const pathCheck = this.validatePath(params.path);\n if (!pathCheck.valid) {\n return { success: false, error: pathCheck.error };\n }\n const parents = params.parents ?? true;\n const pythonCode = `\nimport json\nimport os\ntry:\n path = ${JSON.stringify(params.path)}\n parents = ${parents}\n\n if os.path.exists(path):\n if os.path.isdir(path):\n result = {'success': True, 'path': path, 'existed': True}\n else:\n raise FileExistsError(f'Path exists but is not a directory: {path}')\n else:\n if parents:\n os.makedirs(path, exist_ok=True)\n else:\n os.mkdir(path)\n result = {'success': True, 'path': path, 'existed': False}\nexcept FileExistsError as e:\n result = {'success': False, 'error': str(e)}\nexcept FileNotFoundError:\n result = {'success': False, 'error': f'Parent directory does not exist: {os.path.dirname(path)}. Set parents=True to create.'}\nexcept PermissionError:\n result = {'success': False, 'error': f'Permission denied: {path}'}\nexcept Exception as e:\n result = {'success': False, 'error': str(e)}\nprint(json.dumps(result))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n const status = parsed.existed ? 'already exists' : 'created';\n return {\n success: true,\n output: `Folder ${status}: ${parsed.path}`,\n };\n }\n else {\n return { success: false, error: parsed.error };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Failed to create folder' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * delete_file ๋๊ตฌ: ํ์ผ/ํด๋ ์ญ์ \n */\n async executeDeleteFile(params) {\n console.log('[ToolExecutor] executeDeleteFile:', params);\n // ๊ฒฝ๋ก ๊ฒ์ฆ\n const pathCheck = this.validatePath(params.path);\n if (!pathCheck.valid) {\n return { success: false, error: pathCheck.error };\n }\n const recursive = params.recursive ?? false;\n const pythonCode = `\nimport json\nimport os\nimport shutil\ntry:\n path = ${JSON.stringify(params.path)}\n recursive = ${recursive}\n\n if not os.path.exists(path):\n raise FileNotFoundError(f'Path not found: {path}')\n\n if os.path.isdir(path):\n if recursive:\n shutil.rmtree(path)\n result = {'success': True, 'path': path, 'type': 'directory', 'recursive': True}\n else:\n # ๋น ๋๋ ํ ๋ฆฌ๋ง ์ญ์ \n try:\n os.rmdir(path)\n result = {'success': True, 'path': path, 'type': 'directory', 'recursive': False}\n except OSError:\n raise OSError(f'Directory not empty: {path}. Set recursive=True to delete contents.')\n else:\n os.remove(path)\n result = {'success': True, 'path': path, 'type': 'file'}\n\nexcept FileNotFoundError as e:\n result = {'success': False, 'error': str(e)}\nexcept PermissionError:\n result = {'success': False, 'error': f'Permission denied: {path}'}\nexcept OSError as e:\n result = {'success': False, 'error': str(e)}\nexcept Exception as e:\n result = {'success': False, 'error': str(e)}\nprint(json.dumps(result))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n const typeStr = parsed.type === 'directory'\n ? (parsed.recursive ? 'directory (recursively)' : 'empty directory')\n : 'file';\n return {\n success: true,\n output: `Deleted ${typeStr}: ${parsed.path}`,\n };\n }\n else {\n return { success: false, error: parsed.error };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Failed to delete' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // Phase 3 ํ์ฅ ๋๊ตฌ ์คํ๊ธฐ (Git/Test/Refactor)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n /**\n * git_operations ๋๊ตฌ: Git ๋ฒ์ ๊ด๋ฆฌ ์์
\n */\n async executeGitOperations(params, context) {\n console.log('[ToolExecutor] executeGitOperations:', params);\n const { operation, files, message, branch, count = 10, all } = params;\n // ์ํํ ์์
(push, commit)์ ์น์ธ ์์ฒญ\n const dangerousOps = ['push', 'commit'];\n if (dangerousOps.includes(operation)) {\n const request = {\n id: `git_operations-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n toolName: 'git_operations',\n toolDefinition: this.registry.getTool('git_operations'),\n parameters: params,\n stepNumber: context.stepNumber,\n description: `๐ถ Git ${operation} ์์
์์ฒญ:\\n\\n${operation === 'commit' ? `๋ฉ์์ง: \"${message}\"` : `๋ธ๋์น: ${branch || 'current'}`}`,\n timestamp: Date.now(),\n };\n const approvalCallback = this.registry.approvalCallback;\n if (approvalCallback && this.registry.isApprovalRequired()) {\n const approvalResult = await approvalCallback(request);\n if (!approvalResult.approved) {\n return {\n success: false,\n error: `Git ${operation} denied: ${approvalResult.reason || 'User rejected'}`,\n };\n }\n }\n }\n // Git ๋ช
๋ น ๊ตฌ์ฑ\n let gitCommand = '';\n switch (operation) {\n case 'status':\n gitCommand = 'git status --short';\n break;\n case 'diff':\n gitCommand = files?.length ? `git diff ${files.join(' ')}` : 'git diff';\n break;\n case 'log':\n gitCommand = `git log --oneline -n ${count}`;\n break;\n case 'add':\n if (all) {\n gitCommand = 'git add --all';\n }\n else if (files?.length) {\n gitCommand = `git add ${files.join(' ')}`;\n }\n else {\n return { success: false, error: 'git add requires files or all=true' };\n }\n break;\n case 'commit':\n if (!message) {\n return { success: false, error: 'git commit requires a message' };\n }\n gitCommand = `git commit -m \"${message.replace(/\"/g, '\\\\\"')}\"`;\n break;\n case 'push':\n gitCommand = all ? 'git push --all' : 'git push';\n break;\n case 'pull':\n gitCommand = 'git pull';\n break;\n case 'branch':\n if (branch) {\n gitCommand = `git branch ${branch}`;\n }\n else {\n gitCommand = 'git branch --list';\n }\n break;\n case 'checkout':\n if (!branch) {\n return { success: false, error: 'git checkout requires a branch' };\n }\n gitCommand = `git checkout ${branch}`;\n break;\n case 'stash':\n gitCommand = 'git stash';\n break;\n default:\n return { success: false, error: `Unknown git operation: ${operation}` };\n }\n // Python subprocess๋ก git ์คํ\n const pythonCode = `\nimport json\nimport subprocess\ntry:\n command = ${JSON.stringify(gitCommand)}\n result = subprocess.run(\n command,\n shell=True,\n capture_output=True,\n text=True,\n timeout=60\n )\n\n output = {\n 'success': result.returncode == 0,\n 'stdout': result.stdout,\n 'stderr': result.stderr,\n 'returncode': result.returncode,\n 'operation': ${JSON.stringify(operation)}\n }\nexcept subprocess.TimeoutExpired:\n output = {'success': False, 'error': 'Git operation timed out after 60 seconds'}\nexcept Exception as e:\n output = {'success': False, 'error': str(e)}\nprint(json.dumps(output))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n return {\n success: true,\n output: `git ${parsed.operation}:\\n${parsed.stdout || '(no output)'}`,\n };\n }\n else {\n return {\n success: false,\n error: parsed.error || parsed.stderr || `git ${operation} failed`,\n };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Git operation failed' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * run_tests ๋๊ตฌ: pytest/unittest ์คํ\n */\n async executeRunTests(params) {\n console.log('[ToolExecutor] executeRunTests:', params);\n const path = params.path || '.';\n const pattern = params.pattern;\n const verbose = params.verbose ?? true;\n const coverage = params.coverage ?? false;\n const framework = params.framework || 'pytest';\n // ๊ฒฝ๋ก ๊ฒ์ฆ\n const pathCheck = this.validatePath(path);\n if (!pathCheck.valid) {\n return { success: false, error: pathCheck.error };\n }\n // ํ
์คํธ ๋ช
๋ น ๊ตฌ์ฑ\n const pythonCode = `\nimport json\nimport subprocess\nimport sys\ntry:\n framework = ${JSON.stringify(framework)}\n path = ${JSON.stringify(path)}\n pattern = ${JSON.stringify(pattern)}\n verbose = ${verbose}\n coverage = ${coverage}\n\n if framework == 'pytest':\n args = [sys.executable, '-m', 'pytest', path]\n if verbose:\n args.append('-v')\n if coverage:\n args.extend(['--cov', '--cov-report=term-missing'])\n if pattern:\n args.extend(['-k', pattern])\n else: # unittest\n args = [sys.executable, '-m', 'unittest', 'discover', '-s', path]\n if verbose:\n args.append('-v')\n if pattern:\n args.extend(['-p', pattern])\n\n result = subprocess.run(\n args,\n capture_output=True,\n text=True,\n timeout=300 # 5๋ถ ํ์์์\n )\n\n # ํ
์คํธ ๊ฒฐ๊ณผ ํ์ฑ\n output_text = result.stdout + '\\\\n' + result.stderr\n\n # pytest ๊ฒฐ๊ณผ์์ ํต๊ณ ์ถ์ถ\n passed = failed = errors = skipped = 0\n import re\n if framework == 'pytest':\n match = re.search(r'(\\\\d+) passed', output_text)\n if match:\n passed = int(match.group(1))\n match = re.search(r'(\\\\d+) failed', output_text)\n if match:\n failed = int(match.group(1))\n match = re.search(r'(\\\\d+) error', output_text)\n if match:\n errors = int(match.group(1))\n match = re.search(r'(\\\\d+) skipped', output_text)\n if match:\n skipped = int(match.group(1))\n\n output = {\n 'success': result.returncode == 0,\n 'stdout': result.stdout,\n 'stderr': result.stderr,\n 'returncode': result.returncode,\n 'framework': framework,\n 'stats': {\n 'passed': passed,\n 'failed': failed,\n 'errors': errors,\n 'skipped': skipped\n }\n }\nexcept subprocess.TimeoutExpired:\n output = {'success': False, 'error': 'Test execution timed out after 5 minutes'}\nexcept Exception as e:\n output = {'success': False, 'error': str(e)}\nprint(json.dumps(output))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n const stats = parsed.stats || {};\n const summary = `โ
${stats.passed || 0} passed, โ ${stats.failed || 0} failed, โ ๏ธ ${stats.errors || 0} errors, โญ๏ธ ${stats.skipped || 0} skipped`;\n if (parsed.success) {\n return {\n success: true,\n output: `${summary}\\n\\n${parsed.stdout}`,\n };\n }\n else {\n return {\n success: false,\n error: `Tests failed: ${summary}\\n\\n${parsed.stdout}\\n${parsed.stderr}`,\n };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Test execution failed' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * refactor_code ๋๊ตฌ: ์ฝ๋ ๋ฆฌํฉํ ๋ง\n * ๊ฐ๋จํ ํ
์คํธ ๊ธฐ๋ฐ ๋ฆฌํฉํ ๋ง (LSP ์์ด)\n */\n async executeRefactorCode(params) {\n console.log('[ToolExecutor] executeRefactorCode:', params);\n // ๊ฒฝ๋ก ๊ฒ์ฆ\n const pathCheck = this.validatePath(params.path);\n if (!pathCheck.valid) {\n return { success: false, error: pathCheck.error };\n }\n const { operation, path, oldName, newName, lineStart, lineEnd } = params;\n // ์์
๋ณ ๊ฒ์ฆ\n if ((operation === 'rename_variable' || operation === 'rename_function') && (!oldName || !newName)) {\n return { success: false, error: `${operation} requires oldName and newName` };\n }\n if (operation === 'extract_function' && (!newName || lineStart === undefined || lineEnd === undefined)) {\n return { success: false, error: 'extract_function requires newName, lineStart, and lineEnd' };\n }\n const pythonCode = `\nimport json\nimport re\nimport os\ntry:\n path = ${JSON.stringify(path)}\n operation = ${JSON.stringify(operation)}\n old_name = ${JSON.stringify(oldName || '')}\n new_name = ${JSON.stringify(newName || '')}\n line_start = ${lineStart ?? 'None'}\n line_end = ${lineEnd ?? 'None'}\n\n # ํ์ผ ์ฝ๊ธฐ\n with open(path, 'r', encoding='utf-8') as f:\n content = f.read()\n lines = content.split('\\\\n')\n\n original_content = content\n changes_made = 0\n\n if operation == 'rename_variable':\n # ๋ณ์๋ช
๋ฆฌ๋ค์ (๋จ์ด ๊ฒฝ๊ณ ๊ณ ๋ ค)\n pattern = r'\\\\b' + re.escape(old_name) + r'\\\\b'\n new_content, count = re.subn(pattern, new_name, content)\n content = new_content\n changes_made = count\n\n elif operation == 'rename_function':\n # ํจ์๋ช
๋ฆฌ๋ค์ (def, ํธ์ถ๋ถ ๋ชจ๋)\n pattern = r'\\\\b' + re.escape(old_name) + r'\\\\b'\n new_content, count = re.subn(pattern, new_name, content)\n content = new_content\n changes_made = count\n\n elif operation == 'extract_function':\n # ํจ์ ์ถ์ถ (์ง์ ๋ ์ค ๋ฒ์๋ฅผ ์ ํจ์๋ก)\n if line_start is not None and line_end is not None:\n extract_lines = lines[line_start-1:line_end]\n indent = len(extract_lines[0]) - len(extract_lines[0].lstrip())\n\n # ์ ํจ์ ์์ฑ\n func_def = ' ' * indent + f'def {new_name}():\\\\n'\n func_body = '\\\\n'.join(' ' + line.lstrip() if line.strip() else line for line in extract_lines)\n new_func = func_def + func_body + '\\\\n'\n\n # ์๋ ์์น์ ํจ์ ํธ์ถ๋ก ๋์ฒด\n call_line = ' ' * indent + f'{new_name}()\\\\n'\n\n # ํ์ผ ์์ \n new_lines = lines[:line_start-1] + [call_line.rstrip()] + lines[line_end:]\n # ํ์ผ ๋์ ์ ํจ์ ์ถ๊ฐ\n new_lines.append('')\n new_lines.append(new_func.rstrip())\n content = '\\\\n'.join(new_lines)\n changes_made = 1\n\n elif operation == 'inline_variable':\n # ๋ณ์ ์ธ๋ผ์ธ (๊ฐ๋จํ ๊ตฌํ)\n # ๋ณ์ ์ ์๋ฅผ ์ฐพ์์ ์ฌ์ฉ์ฒ์ ๊ฐ์ ์ง์ ๋์
\n pattern = rf'{re.escape(old_name)}\\\\s*=\\\\s*(.+)'\n match = re.search(pattern, content)\n if match:\n value = match.group(1).strip()\n # ์ ์ ์ ๊ฑฐ\n content = re.sub(pattern + r'\\\\n?', '', content, count=1)\n # ์ฌ์ฉ์ฒ ๋์ฒด\n content, count = re.subn(r'\\\\b' + re.escape(old_name) + r'\\\\b', value, content)\n changes_made = count\n\n if changes_made > 0:\n # ํ์ผ ์ ์ฅ\n with open(path, 'w', encoding='utf-8') as f:\n f.write(content)\n\n result = {\n 'success': True,\n 'operation': operation,\n 'path': path,\n 'changes': changes_made,\n 'oldName': old_name,\n 'newName': new_name\n }\n else:\n result = {\n 'success': False,\n 'error': f'No changes made. Pattern \"{old_name}\" not found in {path}'\n }\n\nexcept FileNotFoundError:\n result = {'success': False, 'error': f'File not found: {path}'}\nexcept Exception as e:\n result = {'success': False, 'error': str(e)}\nprint(json.dumps(result))\n`.trim();\n try {\n const execResult = await this.executeInKernel(pythonCode);\n if (execResult.status === 'ok' && execResult.stdout) {\n const parsed = JSON.parse(execResult.stdout.trim());\n if (parsed.success) {\n let desc = '';\n if (parsed.operation === 'rename_variable' || parsed.operation === 'rename_function') {\n desc = `Renamed \"${parsed.oldName}\" โ \"${parsed.newName}\"`;\n }\n else if (parsed.operation === 'extract_function') {\n desc = `Extracted function \"${parsed.newName}\"`;\n }\n else if (parsed.operation === 'inline_variable') {\n desc = `Inlined variable \"${parsed.oldName}\"`;\n }\n return {\n success: true,\n output: `${desc} (${parsed.changes} changes in ${parsed.path})`,\n };\n }\n else {\n return { success: false, error: parsed.error };\n }\n }\n return { success: false, error: execResult.error?.evalue || 'Refactoring failed' };\n }\n catch (error) {\n return { success: false, error: error.message };\n }\n }\n /**\n * ์ปค๋์์ ์์ ์ฝ๋ ์คํ (๊ฒฐ๊ณผ ์บก์ฒ์ฉ)\n * ์
์ ์์ฑํ์ง ์๊ณ ์ง์ ์ปค๋์์ ์คํ\n */\n async executeInKernel(code) {\n const model = this.notebook.content.model;\n if (!model) {\n throw new Error('Notebook model is not available');\n }\n const startTime = Date.now();\n const tempCellIndex = model.cells.length;\n // ์์ ์ฝ๋ ์
์์ฑ\n model.sharedModel.insertCell(tempCellIndex, {\n cell_type: 'code',\n source: code,\n });\n try {\n // ์คํ ๋ฐ ๊ฒฐ๊ณผ ์บก์ฒ\n const result = await this.executeCellAndCapture(tempCellIndex);\n return result;\n }\n finally {\n // ์์ ์
์ญ์ (์ฑ๊ณต/์คํจ ๊ด๊ณ์์ด)\n model.sharedModel.deleteCell(tempCellIndex);\n }\n }\n /**\n * Jupyter kernel์์ ๋ณ์ ๊ฐ๋ค์ ์ถ์ถ\n * @param varNames ์ถ์ถํ ๋ณ์๋ช
๋ฐฐ์ด\n * @returns ๋ณ์๋ช
-> ๊ฐ ๋งคํ ๊ฐ์ฒด\n */\n async getVariableValues(varNames) {\n if (varNames.length === 0) {\n return {};\n }\n try {\n // JSON์ผ๋ก ๋ณ์ ๊ฐ๋ค์ ์ถ์ถํ๋ Python ์ฝ๋ ์์ฑ\n // DataFrame ๋ฑ ๋ณต์กํ ํ์
์ HTML table๋ก ๋ณํํ๋ ํฌํผ ํจ์ ํฌํจ\n const code = `\nimport json\n\ndef _format_value(v):\n \"\"\"๋ณ์ ๊ฐ์ ์ ์ ํ ํํ๋ก ํฌ๋งทํ
\"\"\"\n try:\n # 1. DataFrame โ HTML table (pandas, modin ๋ฑ)\n if hasattr(v, 'to_html'):\n try:\n html = v.to_html(index=False, max_rows=100)\n return f\"<!--DFHTML-->{html}<!--/DFHTML-->\"\n except:\n pass\n\n # 2. Lazy DataFrame (dask) - ์ํ๋ง ๋ณํ\n if hasattr(v, 'compute'):\n try:\n sample = v.head(100).compute()\n if hasattr(sample, 'to_html'):\n html = sample.to_html(index=False)\n return f\"<!--DFHTML-->{html}<!--/DFHTML-->\"\n except:\n pass\n\n # 3. Spark DataFrame\n if hasattr(v, 'toPandas'):\n try:\n sample = v.limit(100).toPandas()\n if hasattr(sample, 'to_html'):\n html = sample.to_html(index=False)\n return f\"<!--DFHTML-->{html}<!--/DFHTML-->\"\n except:\n pass\n\n # 4. DataFrame with to_pandas conversion (polars, cudf, vaex ๋ฑ)\n for method in ['to_pandas', 'to_pandas_df']:\n if hasattr(v, method):\n try:\n converted = getattr(v, method)()\n if hasattr(converted, 'to_html'):\n html = converted.to_html(index=False, max_rows=100)\n return f\"<!--DFHTML-->{html}<!--/DFHTML-->\"\n except:\n continue\n\n # 5. Series - to_string()\n if hasattr(v, 'to_string'):\n try:\n return v.to_string(max_rows=100)\n except:\n pass\n\n # 6. ๊ธฐ๋ณธ str()\n return str(v)\n except:\n return str(v)\n\n# ๋ณ์ ๊ฐ ์ถ์ถ\nresult = {}\n${varNames.map(v => `\nif '${v}' in locals() or '${v}' in globals():\n val = locals().get('${v}', globals().get('${v}'))\n result['${v}'] = _format_value(val)\nelse:\n result['${v}'] = None`).join('')}\n\nprint(json.dumps(result))\n`.trim();\n // ์์ ์
์์ฑํ์ฌ ์คํ\n const model = this.notebook.content.model;\n if (!model) {\n throw new Error('Notebook model is not available');\n }\n const tempCellIndex = model.cells.length;\n // ์ฝ๋ ์
์ฝ์
\n model.sharedModel.insertCell(tempCellIndex, {\n cell_type: 'code',\n source: code,\n });\n // ์คํ ๋ฐ ๊ฒฐ๊ณผ ์บก์ฒ\n const result = await this.executeCellAndCapture(tempCellIndex);\n // ์์ ์
์ญ์ \n model.sharedModel.deleteCell(tempCellIndex);\n // stdout์์ JSON ํ์ฑ\n if (result.stdout) {\n const variables = JSON.parse(result.stdout.trim());\n // null ๊ฐ ์ ๊ฑฐ\n const filtered = {};\n for (const [key, value] of Object.entries(variables)) {\n if (value !== null) {\n filtered[key] = value;\n }\n }\n return filtered;\n }\n return {};\n }\n catch (error) {\n console.error('[ToolExecutor] Failed to extract variable values:', error);\n return {};\n }\n }\n /**\n * ์์ฐจ ์คํ ์์ ์ ํธ์ถ (๋ง์ง๋ง ์
์ธ๋ฑ์ค ์ด๊ธฐํ)\n */\n resetSequentialExecution() {\n const model = this.notebook.content.model;\n // ํ์ฌ ๋
ธํธ๋ถ ๋งจ ๋ ์
์ธ๋ฑ์ค๋ก ์ด๊ธฐํ\n this.lastCreatedCellIndex = model ? model.cells.length - 1 : -1;\n console.log('[ToolExecutor] Reset sequential execution, lastCreatedCellIndex:', this.lastCreatedCellIndex);\n }\n /**\n * ์ฝ๋ ์
์์ฑ (ํญ์ ์์ฐจ์ ์ผ๋ก ๋งจ ๋์ ์ถ๊ฐ)\n */\n async createCodeCell(code, insertAfter) {\n await this.ensureModelReady();\n const notebookContent = this.notebook.content;\n const model = notebookContent.model;\n if (!model) {\n throw new Error('Notebook model not available');\n }\n // ๋
ธํธ๋ถ ๋งจ ๋์ ํ์ฑ ์
์ด ๋น ์ฝ๋ ์
์ด๋ฉด ์ฌ์ฌ์ฉ (์ฒซ ์
์์ฑ ์์๋ง)\n const activeIndex = notebookContent.activeCellIndex;\n const isAtEnd = activeIndex === model.cells.length - 1;\n if (activeIndex >= 0 && insertAfter === undefined && isAtEnd) {\n const activeCell = model.cells.get(activeIndex);\n if (activeCell && activeCell.type === 'code') {\n const source = activeCell.sharedModel.getSource().trim();\n if (source === '') {\n // ๋น ์
์ฌ์ฌ์ฉ\n activeCell.sharedModel.setSource(code);\n this.lastCreatedCellIndex = activeIndex;\n return activeIndex;\n }\n }\n }\n // โ
์์ฐจ ์ฝ์
: ํญ์ ๋
ธํธ๋ถ ๋งจ ๋์ ์ถ๊ฐ (์ค๊ฐ ์ฝ์
๊ธ์ง)\n // ์ด๋ ๊ฒ ํ๋ฉด ์
์ด ํญ์ ์๋๋ก๋ง ์ถ๊ฐ๋จ\n const insertIndex = model.cells.length;\n // ์ ์ฝ๋ ์
์์ฑ\n model.sharedModel.insertCell(insertIndex, {\n cell_type: 'code',\n source: code,\n metadata: {},\n });\n // ๋ง์ง๋ง ์์ฑ ์
์ธ๋ฑ์ค ์
๋ฐ์ดํธ\n this.lastCreatedCellIndex = insertIndex;\n // ์ ์
๋ก ํฌ์ปค์ค ์ด๋\n notebookContent.activeCellIndex = insertIndex;\n console.log('[ToolExecutor] Created cell at index:', insertIndex, '(always at end)');\n return insertIndex;\n }\n /**\n * ํน์ ์
๋ค์ ์ ์ฝ๋ ์
์ฝ์
(INSERT_AFTER)\n * @param code - ์ฝ์
ํ ์ฝ๋\n * @param afterIndex - ์ด ์
๋ค์ ์ฝ์
\n */\n async insertCellAfter(code, afterIndex) {\n await this.ensureModelReady();\n const model = this.notebook.content.model;\n if (!model)\n throw new Error('Notebook model not available');\n // ์ฝ์
์์น: afterIndex + 1 (afterIndex ๋ฐ๋ก ๋ค)\n const insertIndex = Math.min(afterIndex + 1, model.cells.length);\n model.sharedModel.insertCell(insertIndex, {\n cell_type: 'code',\n source: code,\n metadata: { hdsp_inserted: true }, // Agent์ ์ํด ์ฝ์
๋จ ํ์\n });\n this.lastCreatedCellIndex = insertIndex;\n this.notebook.content.activeCellIndex = insertIndex;\n console.log('[ToolExecutor] INSERT_AFTER: Inserted cell after index:', afterIndex, 'at:', insertIndex);\n return insertIndex;\n }\n /**\n * ํน์ ์
์์ ์ ์ฝ๋ ์
์ฝ์
(INSERT_BEFORE)\n * @param code - ์ฝ์
ํ ์ฝ๋\n * @param beforeIndex - ์ด ์
์์ ์ฝ์
\n */\n async insertCellBefore(code, beforeIndex) {\n await this.ensureModelReady();\n const model = this.notebook.content.model;\n if (!model)\n throw new Error('Notebook model not available');\n // ์ฝ์
์์น: beforeIndex (beforeIndex ๋ฐ๋ก ์)\n const insertIndex = Math.max(0, beforeIndex);\n model.sharedModel.insertCell(insertIndex, {\n cell_type: 'code',\n source: code,\n metadata: { hdsp_inserted: true }, // Agent์ ์ํด ์ฝ์
๋จ ํ์\n });\n this.lastCreatedCellIndex = insertIndex;\n this.notebook.content.activeCellIndex = insertIndex;\n console.log('[ToolExecutor] INSERT_BEFORE: Inserted cell before index:', beforeIndex, 'at:', insertIndex);\n return insertIndex;\n }\n /**\n * ๋งํฌ๋ค์ด ์
์์ฑ (ํญ์ ์์ฐจ์ ์ผ๋ก ๋งจ ๋์ ์ถ๊ฐ)\n */\n async createMarkdownCell(content, insertAfter) {\n await this.ensureModelReady();\n const notebookContent = this.notebook.content;\n const model = notebookContent.model;\n if (!model) {\n throw new Error('Notebook model not available');\n }\n // โ
์์ฐจ ์ฝ์
: ํญ์ ๋
ธํธ๋ถ ๋งจ ๋์ ์ถ๊ฐ (์ค๊ฐ ์ฝ์
๊ธ์ง)\n const insertIndex = model.cells.length;\n // ์ ๋งํฌ๋ค์ด ์
์์ฑ\n model.sharedModel.insertCell(insertIndex, {\n cell_type: 'markdown',\n source: content,\n metadata: {},\n });\n // ๋งํฌ๋ค์ด ์
๋ ๋๋ง\n const cell = notebookContent.widgets[insertIndex];\n if (cell && cell.rendered !== undefined) {\n cell.rendered = true;\n }\n // ๋ง์ง๋ง ์์ฑ ์
์ธ๋ฑ์ค ์
๋ฐ์ดํธ\n this.lastCreatedCellIndex = insertIndex;\n // ์ ์
๋ก ํ์ฑ ์
์
๋ฐ์ดํธ\n notebookContent.activeCellIndex = insertIndex;\n console.log('[ToolExecutor] Created markdown cell at index:', insertIndex, '(always at end)');\n return insertIndex;\n }\n /**\n * ์
๋ด์ฉ ์
๋ฐ์ดํธ\n */\n updateCellContent(cellIndex, content) {\n const notebookContent = this.notebook.content;\n const cell = notebookContent.widgets[cellIndex];\n if (!cell || !cell.model?.sharedModel) {\n throw new Error(`Cell at index ${cellIndex} not found or model not available`);\n }\n cell.model.sharedModel.setSource(content);\n }\n /**\n * ์
์คํ ๋ฐ ๊ฒฐ๊ณผ ์บก์ฒ\n * NotebookActions.run()์ ์ฌ์ฉํ์ฌ ์ ์์ผ๋ก ์
์คํ (execution_count ์
๋ฐ์ดํธ ํฌํจ)\n */\n async executeCellAndCapture(cellIndex) {\n const notebookContent = this.notebook.content;\n const cell = notebookContent.widgets[cellIndex];\n if (!cell) {\n throw new Error(`Cell at index ${cellIndex} not found`);\n }\n const startTime = Date.now();\n // ํด๋น ์
์ ํ\n notebookContent.activeCellIndex = cellIndex;\n // NotebookActions.run()์ ์ฌ์ฉํ์ฌ ์ ์ ์คํ (execution_count ์
๋ฐ์ดํธ๋จ)\n const runSuccess = await NotebookActions.run(notebookContent, this.sessionContext);\n console.log('[ToolExecutor] NotebookActions.run() success:', runSuccess);\n // ์ปค๋์ด idle ์ํ๊ฐ ๋ ๋๊น์ง ๋๊ธฐ (์ถ๋ ฅ์ด ์์ ํ ์
๋ฐ์ดํธ๋๋๋ก)\n // NotebookActions.run()์ด false๋ฅผ ๋ฐํํด๋ ์ปค๋์ ์์ง busy ์ํ์ผ ์ ์์\n const kernelIdled = await this.waitForKernelIdle(10000);\n console.log('[ToolExecutor] Kernel idle wait result:', kernelIdled);\n // ์ถ๊ฐ ์์ ํ ๋๊ธฐ (์ถ๋ ฅ ๋ชจ๋ธ ๋๊ธฐํ)\n await new Promise(resolve => setTimeout(resolve, 200));\n // ์คํ ์๋ฃ ํ ๊ฒฐ๊ณผ ์บก์ฒ\n const executionTime = Date.now() - startTime;\n // ์
์ถ๋ ฅ ๋ถ์\n let stdout = '';\n let stderr = '';\n let result = null;\n let error = undefined;\n // cell.model๊ณผ outputs๊ฐ ์กด์ฌํ๋์ง ์์ ํ๊ฒ ์ฒดํฌ\n const outputs = cell.model?.outputs;\n console.log('[ToolExecutor] After kernel idle - outputs count:', outputs?.length ?? 0, '| runSuccess:', runSuccess);\n if (outputs && outputs.length > 0) {\n for (let i = 0; i < outputs.length; i++) {\n const output = outputs.get(i);\n // ๋ ์์ธํ ๋๋ฒ๊น
: ์ ์ฒด output ๊ตฌ์กฐ ํ์ธ\n console.log(`[ToolExecutor] Output ${i} type:`, output.type);\n try {\n // toJSON์ด ์์ผ๋ฉด ์ ์ฒด ๊ตฌ์กฐ ํ์ธ\n const outputJson = output.toJSON?.() || output;\n console.log(`[ToolExecutor] Output ${i} full structure:`, JSON.stringify(outputJson, null, 2));\n }\n catch (e) {\n console.log(`[ToolExecutor] Output ${i} raw:`, output);\n }\n if (output.type === 'stream') {\n // CRITICAL: toJSON()์ผ๋ก ์ค์ ๋ฐ์ดํฐ ์ถ์ถ (์ง์ ํ๋กํผํฐ ์ ๊ทผ์ undefined ๋ฐํ ๊ฐ๋ฅ)\n const streamOutput = output.toJSON?.() || output;\n if (streamOutput.name === 'stdout') {\n stdout += streamOutput.text || '';\n }\n else if (streamOutput.name === 'stderr') {\n stderr += streamOutput.text || '';\n }\n }\n else if (output.type === 'execute_result' || output.type === 'display_data') {\n const data = output.data;\n if (!result) {\n result = data;\n }\n }\n else if (output.type === 'error') {\n // CRITICAL: output ๋ชจ๋ธ ๊ฐ์ฒด๋ toJSON()์ผ๋ก ์ค์ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํด์ผ ํจ\n // ์ง์ ํ๋กํผํฐ ์ ๊ทผ(output.ename)์ undefined๋ฅผ ๋ฐํํ ์ ์์\n const errorData = output.toJSON?.() || output;\n console.log('[ToolExecutor] Error output detected:', JSON.stringify(errorData));\n // ์ค์ ๋ก ์๋ฌ ๋ด์ฉ์ด ์๋ ๊ฒฝ์ฐ์๋ง ์๋ฌ๋ก ์ฒ๋ฆฌ\n if (errorData.ename || errorData.evalue) {\n error = {\n ename: errorData.ename,\n evalue: errorData.evalue,\n traceback: errorData.traceback || [],\n };\n console.log('[ToolExecutor] Error captured:', error.ename, '-', error.evalue);\n }\n }\n }\n }\n // NotebookActions.run()์ด false๋ฅผ ๋ฐํํ๊ฑฐ๋ error output์ด ์์ผ๋ฉด ์คํจ\n // runSuccess๊ฐ false๋ฉด ์๋ฌ output์ด ์์ด๋ ์คํจ๋ก ์ฒ๋ฆฌ\n const status = (error || !runSuccess) ? 'error' : 'ok';\n // ๋๋ฒ๊น
: ์คํจ ๊ฐ์ง ์์ธ ๋ก๊ทธ\n console.log('[ToolExecutor] Final status:', status);\n console.log('[ToolExecutor] - runSuccess:', runSuccess);\n console.log('[ToolExecutor] - error detected:', !!error);\n if (error) {\n console.log('[ToolExecutor] - error.ename:', error.ename);\n console.log('[ToolExecutor] - error.evalue:', error.evalue);\n }\n // runSuccess๊ฐ false์ธ๋ฐ error๊ฐ ์์ผ๋ฉด stdout/stderr์์ ์๋ฌ ํจํด ์ถ์ถ ์๋\n if (!runSuccess && !error) {\n console.warn('[ToolExecutor] NotebookActions.run() failed but no error output captured!');\n console.log('[ToolExecutor] Attempting to extract error from stdout/stderr...');\n // stdout์์ ์๋ฌ ํจํด ๊ฒ์ (Python traceback ํ์)\n const combinedOutput = stdout + '\\n' + stderr;\n const extractedError = this.extractErrorFromOutput(combinedOutput);\n if (extractedError) {\n console.log('[ToolExecutor] Extracted error from output:', extractedError);\n error = extractedError;\n }\n else {\n error = {\n ename: 'ExecutionError',\n evalue: 'Cell execution failed (NotebookActions.run returned false)',\n traceback: [],\n };\n }\n }\n return {\n status,\n stdout,\n stderr,\n result,\n error,\n executionTime,\n cellIndex,\n };\n }\n /**\n * ํ์ฌ ๋
ธํธ๋ถ์ ์
๊ฐ์ ๋ฐํ\n */\n getCellCount() {\n return this.notebook.content.model?.cells.length || 0;\n }\n /**\n * ํน์ ์
์ ๋ด์ฉ ๋ฐํ\n */\n getCellContent(cellIndex) {\n const cell = this.notebook.content.widgets[cellIndex];\n return cell?.model?.sharedModel?.getSource() || '';\n }\n /**\n * ํน์ ์
์ ์ถ๋ ฅ ๋ฐํ\n */\n getCellOutput(cellIndex) {\n const cell = this.notebook.content.widgets[cellIndex];\n // cell, cell.model, cell.model.outputs ๋ชจ๋ ์์ ํ๊ฒ ์ฒดํฌ\n const cellOutputs = cell?.model?.outputs;\n if (!cell || !cellOutputs) {\n return '';\n }\n const outputs = [];\n for (let i = 0; i < cellOutputs.length; i++) {\n const output = cellOutputs.get(i);\n if (output.type === 'stream') {\n outputs.push(output.text || '');\n }\n else if (output.type === 'execute_result' || output.type === 'display_data') {\n const data = output.data;\n if (data?.['text/plain']) {\n outputs.push(data['text/plain']);\n }\n }\n else if (output.type === 'error') {\n const errorOutput = output;\n outputs.push(`${errorOutput.ename}: ${errorOutput.evalue}`);\n }\n }\n return outputs.join('\\n');\n }\n /**\n * ์ปค๋ ์ธํฐ๋ฝํธ\n */\n async interruptKernel() {\n const kernel = this.sessionContext.session?.kernel;\n if (kernel) {\n await kernel.interrupt();\n }\n }\n /**\n * ์ถ๋ ฅ ํ
์คํธ์์ Python ์๋ฌ ํจํด์ ์ถ์ถ\n * error ํ์
์ถ๋ ฅ์ด ์บก์ฒ๋์ง ์์์ ๋ stdout/stderr์์ ์๋ฌ ์ถ์ถ ์๋\n */\n extractErrorFromOutput(output) {\n if (!output)\n return undefined;\n // ์๋ฌ ํ์
ํจํด๋ค (Python ํ์ค ์๋ฌ๋ค)\n const errorPatterns = [\n /^(ModuleNotFoundError):\\s*(.+)$/m,\n /^(ImportError):\\s*(.+)$/m,\n /^(SyntaxError):\\s*(.+)$/m,\n /^(TypeError):\\s*(.+)$/m,\n /^(ValueError):\\s*(.+)$/m,\n /^(KeyError):\\s*(.+)$/m,\n /^(IndexError):\\s*(.+)$/m,\n /^(AttributeError):\\s*(.+)$/m,\n /^(NameError):\\s*(.+)$/m,\n /^(FileNotFoundError):\\s*(.+)$/m,\n /^(ZeroDivisionError):\\s*(.+)$/m,\n /^(RuntimeError):\\s*(.+)$/m,\n /^(PermissionError):\\s*(.+)$/m,\n /^(OSError):\\s*(.+)$/m,\n /^(IOError):\\s*(.+)$/m,\n /^(ConnectionError):\\s*(.+)$/m,\n /^(TimeoutError):\\s*(.+)$/m,\n ];\n for (const pattern of errorPatterns) {\n const match = output.match(pattern);\n if (match) {\n return {\n ename: match[1],\n evalue: match[2].trim(),\n traceback: [], // traceback ์ถ์ถ์ ๋ณต์กํ๋ฏ๋ก ์๋ต\n };\n }\n }\n // Traceback์ด ์์ผ๋ฉด ๋ง์ง๋ง ์๋ฌ ๋ผ์ธ ์ถ์ถ ์๋\n if (output.includes('Traceback (most recent call last):')) {\n // ๋ง์ง๋ง ์ค์์ ์๋ฌ ํ์
: ๋ฉ์์ง ํจํด ์ฐพ๊ธฐ\n const lines = output.split('\\n').filter(l => l.trim());\n for (let i = lines.length - 1; i >= 0; i--) {\n const line = lines[i].trim();\n const errorMatch = line.match(/^(\\w+Error):\\s*(.+)$/);\n if (errorMatch) {\n return {\n ename: errorMatch[1],\n evalue: errorMatch[2].trim(),\n traceback: [],\n };\n }\n }\n }\n return undefined;\n }\n /**\n * ์
์ญ์ \n */\n deleteCell(cellIndex) {\n const model = this.notebook.content.model;\n if (model && cellIndex >= 0 && cellIndex < model.cells.length) {\n model.sharedModel.deleteCell(cellIndex);\n }\n }\n /**\n * ์ฌ๋ฌ ์
์คํ (์์ฐจ)\n */\n async executeMultipleCells(cellIndices) {\n const results = [];\n for (const index of cellIndices) {\n const result = await this.executeCellAndCapture(index);\n results.push(result);\n if (result.status === 'error') {\n break; // ์๋ฌ ๋ฐ์ ์ ์ค๋จ\n }\n }\n return results;\n }\n}\nexport default ToolExecutor;\n","/**\n * ToolRegistry - ๋์ ๋๊ตฌ ๋ฑ๋ก ๋ฐ ๊ด๋ฆฌ\n *\n * ๊ธฐ์กด switch๋ฌธ ๊ธฐ๋ฐ ๋๊ตฌ ๋ผ์ฐํ
์ Map ๊ธฐ๋ฐ ๋ ์ง์คํธ๋ฆฌ๋ก ๋์ฒด\n * - ๋์ ๋๊ตฌ ๋ฑ๋ก/ํด์ \n * - ์ํ ์์ค๋ณ ๋ถ๋ฅ\n * - ์นดํ
๊ณ ๋ฆฌ๋ณ ์กฐํ\n */\n/**\n * ๊ธฐ๋ณธ ์น์ธ ์ฝ๋ฐฑ - ํญ์ ์น์ธ (๊ฐ๋ฐ/ํ
์คํธ์ฉ)\n */\nconst defaultApprovalCallback = async (request) => ({\n approved: true,\n requestId: request.id,\n timestamp: Date.now(),\n});\n/**\n * ToolRegistry ํด๋์ค\n * ์ฑ๊ธํค ํจํด์ผ๋ก ๊ตฌํ (์ ์ญ ๋ ์ง์คํธ๋ฆฌ)\n */\nexport class ToolRegistry {\n constructor() {\n this.tools = new Map();\n this.approvalCallback = defaultApprovalCallback;\n this.approvalRequired = true;\n }\n /**\n * ์ฑ๊ธํค ์ธ์คํด์ค ๋ฐํ\n */\n static getInstance() {\n if (!ToolRegistry.instance) {\n ToolRegistry.instance = new ToolRegistry();\n }\n return ToolRegistry.instance;\n }\n /**\n * ํ
์คํธ์ฉ ์ธ์คํด์ค ๋ฆฌ์
\n */\n static resetInstance() {\n ToolRegistry.instance = new ToolRegistry();\n }\n /**\n * ๋๊ตฌ ๋ฑ๋ก\n */\n register(definition) {\n if (this.tools.has(definition.name)) {\n console.warn(`[ToolRegistry] Tool '${definition.name}' already registered, overwriting`);\n }\n this.tools.set(definition.name, definition);\n console.log(`[ToolRegistry] Registered tool: ${definition.name} (${definition.riskLevel})`);\n }\n /**\n * ๋๊ตฌ ํด์ \n */\n unregister(name) {\n const result = this.tools.delete(name);\n if (result) {\n console.log(`[ToolRegistry] Unregistered tool: ${name}`);\n }\n return result;\n }\n /**\n * ๋๊ตฌ ์กฐํ\n */\n getTool(name) {\n return this.tools.get(name);\n }\n /**\n * ๋๊ตฌ ์กด์ฌ ์ฌ๋ถ ํ์ธ\n */\n hasTool(name) {\n return this.tools.has(name);\n }\n /**\n * ๋ฑ๋ก๋ ๋ชจ๋ ๋๊ตฌ ๋ฐํ\n */\n getAllTools() {\n return Array.from(this.tools.values());\n }\n /**\n * ์นดํ
๊ณ ๋ฆฌ๋ณ ๋๊ตฌ ์กฐํ\n */\n getToolsByCategory(category) {\n return this.getAllTools().filter(tool => tool.category === category);\n }\n /**\n * ์ํ ์์ค๋ณ ๋๊ตฌ ์กฐํ\n */\n getToolsByRiskLevel(riskLevel) {\n return this.getAllTools().filter(tool => tool.riskLevel === riskLevel);\n }\n /**\n * ์น์ธ์ด ํ์ํ ๋๊ตฌ๋ค ์กฐํ\n */\n getToolsRequiringApproval() {\n return this.getAllTools().filter(tool => tool.requiresApproval);\n }\n /**\n * ๋ฑ๋ก๋ ๋๊ตฌ ์ด๋ฆ๋ค ๋ฐํ\n */\n getToolNames() {\n return Array.from(this.tools.keys());\n }\n /**\n * ์น์ธ ์ฝ๋ฐฑ ์ค์ \n */\n setApprovalCallback(callback) {\n this.approvalCallback = callback;\n console.log('[ToolRegistry] Approval callback updated');\n }\n /**\n * ์น์ธ ํ์ ์ฌ๋ถ ์ค์ \n */\n setApprovalRequired(required) {\n this.approvalRequired = required;\n console.log(`[ToolRegistry] Approval requirement set to: ${required}`);\n }\n /**\n * ์น์ธ ํ์ ์ฌ๋ถ ํ์ธ\n */\n isApprovalRequired() {\n return this.approvalRequired;\n }\n /**\n * ๋๊ตฌ ์คํ (์น์ธ ๊ฒ์ดํธ ํฌํจ)\n */\n async executeTool(name, params, context) {\n const tool = this.getTool(name);\n if (!tool) {\n return {\n success: false,\n error: `Unknown tool: ${name}`,\n };\n }\n // ์น์ธ์ด ํ์ํ ๋๊ตฌ์ธ ๊ฒฝ์ฐ ์น์ธ ์์ฒญ\n if (this.approvalRequired && tool.requiresApproval) {\n const request = {\n id: `${name}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n toolName: name,\n toolDefinition: tool,\n parameters: params,\n stepNumber: context.stepNumber,\n description: this.formatToolDescription(tool, params),\n timestamp: Date.now(),\n };\n console.log(`[ToolRegistry] Requesting approval for tool: ${name}`);\n const approvalResult = await this.approvalCallback(request);\n if (!approvalResult.approved) {\n console.log(`[ToolRegistry] Tool execution denied: ${name}, reason: ${approvalResult.reason}`);\n return {\n success: false,\n error: `Tool execution denied: ${approvalResult.reason || 'User rejected'}`,\n };\n }\n console.log(`[ToolRegistry] Tool approved: ${name}`);\n }\n // ๋๊ตฌ ์คํ\n try {\n console.log(`[ToolRegistry] Executing tool: ${name}`);\n return await tool.executor(params, context);\n }\n catch (error) {\n console.error(`[ToolRegistry] Tool execution failed: ${name}`, error);\n return {\n success: false,\n error: error.message || `Failed to execute tool: ${name}`,\n };\n }\n }\n /**\n * ๋๊ตฌ ์ค๋ช
ํฌ๋งทํ
(์น์ธ ๋ค์ด์ผ๋ก๊ทธ์ฉ)\n */\n formatToolDescription(tool, params) {\n const riskEmoji = {\n low: '๐ข',\n medium: '๐ก',\n high: '๐ ',\n critical: '๐ด',\n };\n let description = `${riskEmoji[tool.riskLevel]} ${tool.description}`;\n // ํ๋ผ๋ฏธํฐ ์์ฝ ์ถ๊ฐ\n if (params) {\n const paramSummary = Object.entries(params)\n .map(([key, value]) => {\n const valueStr = typeof value === 'string'\n ? value.length > 50 ? value.substring(0, 50) + '...' : value\n : JSON.stringify(value);\n return `${key}: ${valueStr}`;\n })\n .join(', ');\n if (paramSummary) {\n description += `\\nํ๋ผ๋ฏธํฐ: ${paramSummary}`;\n }\n }\n return description;\n }\n /**\n * ๋ ์ง์คํธ๋ฆฌ ์ํ ์ถ๋ ฅ (๋๋ฒ๊น
์ฉ)\n */\n printStatus() {\n console.log('[ToolRegistry] Status:');\n console.log(` - Registered tools: ${this.tools.size}`);\n console.log(` - Approval required: ${this.approvalRequired}`);\n console.log(' - Tools:');\n for (const [name, tool] of this.tools) {\n console.log(` * ${name} (${tool.category}, ${tool.riskLevel}, approval: ${tool.requiresApproval})`);\n }\n }\n}\n/**\n * ๊ธฐ๋ณธ ๋๊ตฌ ์ ์๋ค (๋นํธ์ธ)\n * ToolExecutor์ ๋ฉ์๋๋ค์ executor๋ก ์ฐ๊ฒฐํ๊ธฐ ์ํด ๋์ค์ ์ด๊ธฐํ\n */\nexport const BUILTIN_TOOL_DEFINITIONS = [\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // ๊ธฐ๋ณธ ๋๊ตฌ (Cell ์์
)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n {\n name: 'jupyter_cell',\n description: 'Jupyter ์ฝ๋ ์
์์ฑ/์์ /์คํ',\n riskLevel: 'medium',\n requiresApproval: false,\n category: 'cell',\n },\n {\n name: 'markdown',\n description: 'Jupyter ๋งํฌ๋ค์ด ์
์์ฑ/์์ ',\n riskLevel: 'low',\n requiresApproval: false,\n category: 'cell',\n },\n {\n name: 'final_answer',\n description: '์์
์๋ฃ ๋ฐ ์ต์ข
๋ต๋ณ ๋ฐํ',\n riskLevel: 'low',\n requiresApproval: false,\n category: 'answer',\n },\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // ํ์ฅ ๋๊ตฌ (ํ์ผ ์์คํ
)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n {\n name: 'read_file',\n description: 'ํ์ผ ๋ด์ฉ ์ฝ๊ธฐ (์ฝ๊ธฐ ์ ์ฉ)',\n riskLevel: 'low',\n requiresApproval: false,\n category: 'file',\n },\n {\n name: 'write_file',\n description: 'ํ์ผ์ ๋ด์ฉ ์ฐ๊ธฐ (๋ฎ์ด์ฐ๊ธฐ ๊ฐ๋ฅ)',\n riskLevel: 'high',\n requiresApproval: true,\n category: 'file',\n },\n {\n name: 'list_files',\n description: '๋๋ ํ ๋ฆฌ ๋ด ํ์ผ/ํด๋ ๋ชฉ๋ก ์กฐํ',\n riskLevel: 'low',\n requiresApproval: false,\n category: 'file',\n },\n {\n name: 'search_files',\n description: 'ํ์ผ ๋ด์ฉ ๊ฒ์ (grep/ripgrep ์คํ์ผ)',\n riskLevel: 'medium',\n requiresApproval: false,\n category: 'file',\n },\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // ํ์ฅ ๋๊ตฌ (์์คํ
)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n {\n name: 'execute_command',\n description: '์
ธ ๋ช
๋ น ์คํ (์ํ ๋ช
๋ น๋ง ์น์ธ ํ์)',\n riskLevel: 'critical',\n requiresApproval: false,\n category: 'system',\n },\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // ํ์ฅ ๋๊ตฌ Phase 2 (ํจํค์ง/๋ฆฐํธ/์
/๋
ธํธ๋ถ/ํด๋/์ญ์ )\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n {\n name: 'install_package',\n description: 'pip ํจํค์ง ์ค์น (๋ฒ์ ์ง์ ๊ฐ๋ฅ)',\n riskLevel: 'high',\n requiresApproval: true,\n category: 'system',\n },\n {\n name: 'lint_file',\n description: 'Python ํ์ผ ๋ฆฐํธ ๊ฒ์ฌ ๋ฐ ์๋ ์์ (ruff/pylint/flake8)',\n riskLevel: 'medium',\n requiresApproval: false,\n category: 'file',\n },\n {\n name: 'delete_cell',\n description: 'Jupyter ๋
ธํธ๋ถ ์
์ญ์ ',\n riskLevel: 'medium',\n requiresApproval: true,\n category: 'cell',\n },\n {\n name: 'get_cell_output',\n description: 'ํน์ ์
์ ์คํ ์ถ๋ ฅ ์กฐํ',\n riskLevel: 'low',\n requiresApproval: false,\n category: 'cell',\n },\n {\n name: 'create_notebook',\n description: '์ Jupyter ๋
ธํธ๋ถ ํ์ผ ์์ฑ',\n riskLevel: 'medium',\n requiresApproval: false,\n category: 'file',\n },\n {\n name: 'create_folder',\n description: '์ ํด๋(๋๋ ํ ๋ฆฌ) ์์ฑ',\n riskLevel: 'low',\n requiresApproval: false,\n category: 'file',\n },\n {\n name: 'delete_file',\n description: 'ํ์ผ ๋๋ ํด๋ ์ญ์ ',\n riskLevel: 'critical',\n requiresApproval: true,\n category: 'file',\n },\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n // ํ์ฅ ๋๊ตฌ Phase 3 (Git/Test/Refactor)\n // โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n {\n name: 'git_operations',\n description: 'Git ๋ฒ์ ๊ด๋ฆฌ ์์
(status, diff, commit, push, pull ๋ฑ)',\n riskLevel: 'high',\n requiresApproval: false,\n category: 'system',\n },\n {\n name: 'run_tests',\n description: 'ํ
์คํธ ์คํ (pytest/unittest) ๋ฐ ๊ฒฐ๊ณผ ํ์ฑ',\n riskLevel: 'medium',\n requiresApproval: false,\n category: 'system',\n },\n {\n name: 'refactor_code',\n description: '์ฝ๋ ๋ฆฌํฉํ ๋ง (๋ณ์/ํจ์ ๋ฆฌ๋ค์, ํจ์ ์ถ์ถ)',\n riskLevel: 'high',\n requiresApproval: true,\n category: 'file',\n },\n];\n/**\n * ์ํํ ์
ธ ๋ช
๋ น ํจํด๋ค\n * execute_command์์ ์ด ํจํด์ ๋งค์นญ๋๋ ๋ช
๋ น์ ์ฌ์ฉ์ ์น์ธ ํ์\n */\nexport const DANGEROUS_COMMAND_PATTERNS = [\n // ํ์ผ ์ญ์ /์ ๊ฑฐ\n /\\brm\\s+(-[rRfF]+\\s+)?/i,\n /\\brmdir\\b/i,\n // ๊ถํ ์์น/๋ณ๊ฒฝ\n /\\bsudo\\b/i,\n /\\bsu\\b/i,\n /\\bchmod\\s+7[0-7][0-7]/i,\n /\\bchown\\b/i,\n // ์์คํ
ํ๊ดด\n />\\s*\\/dev\\//i,\n /\\bmkfs\\b/i,\n /\\bdd\\b/i,\n // ์๊ฒฉ ์ฝ๋ ์คํ\n /\\bcurl\\s+.*\\|\\s*(ba)?sh/i,\n /\\bwget\\s+.*\\|\\s*(ba)?sh/i,\n /\\beval\\s+/i,\n // ๋คํธ์ํฌ ์ํ\n /\\bnc\\s+-[el]/i,\n /\\biptables\\b/i, // iptables ์กฐ์\n];\n/**\n * ์ํ ์์ค ์ฐ์ ์์ (๋น๊ต์ฉ)\n */\nexport const RISK_LEVEL_PRIORITY = {\n low: 0,\n medium: 1,\n high: 2,\n critical: 3,\n};\n/**\n * ์ํ ์์ค ๋น๊ต\n */\nexport function compareRiskLevels(a, b) {\n return RISK_LEVEL_PRIORITY[a] - RISK_LEVEL_PRIORITY[b];\n}\n/**\n * ํน์ ์ํ ์์ค ์ด์์ธ์ง ํ์ธ\n */\nexport function isRiskLevelAtLeast(level, threshold) {\n return RISK_LEVEL_PRIORITY[level] >= RISK_LEVEL_PRIORITY[threshold];\n}\nexport default ToolRegistry;\n","/**\n * Auto-Agent Type Definitions\n * HuggingFace Jupyter Agent ํจํด ๊ธฐ๋ฐ Tool Calling ๊ตฌ์กฐ\n */\n// ์๋ ํ๋ฆฌ์
(ms ๋จ์ ์ง์ฐ) - ์ ๋ฐ์ ์ผ๋ก ๋๋ฆฌ๊ฒ ์กฐ์ \nexport const EXECUTION_SPEED_DELAYS = {\n 'instant': 0,\n 'fast': 800,\n 'normal': 1500,\n 'slow': 3000,\n 'step-by-step': -1, // -1์ ์๋ ์งํ ์๋ฏธ\n};\nexport const DEFAULT_AUTO_AGENT_CONFIG = {\n maxRetriesPerStep: 3,\n executionTimeout: 30000,\n enableSafetyCheck: true,\n showDetailedProgress: true,\n executionSpeed: 'normal',\n stepDelay: 1500,\n autoScrollToCell: true,\n highlightCurrentCell: true,\n};\n// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n// State Verification Types (Phase 1: ์ํ ๊ฒ์ฆ ๋ ์ด์ด)\n// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n/**\n * ์ ๋ขฐ๋ ์๊ณ๊ฐ ์์\n * - PROCEED (0.8): ๊ณ์ ์งํ\n * - WARNING (0.6): ๊ฒฝ๊ณ ๋ก๊ทธ, ์งํ\n * - REPLAN (0.4): ๋ฆฌํ๋๋ ํธ๋ฆฌ๊ฑฐ\n * - ESCALATE (0.2): ์ฌ์ฉ์ ๊ฐ์
ํ์\n */\nexport const CONFIDENCE_THRESHOLDS = {\n PROCEED: 0.8,\n WARNING: 0.6,\n REPLAN: 0.4,\n ESCALATE: 0.2,\n};\n/**\n * ๊ธฐ๋ณธ ์ปจํ
์คํธ ์์ฐ ์ค์ \n */\nexport const DEFAULT_CONTEXT_BUDGET = {\n maxTokens: 8000,\n warningThreshold: 0.75,\n reservedForResponse: 2000,\n};\n/**\n * ๊ธฐ๋ณธ ์ฒดํฌํฌ์ธํธ ์ค์ \n */\nexport const DEFAULT_CHECKPOINT_CONFIG = {\n maxCheckpoints: 10,\n autoSave: true,\n saveToNotebookMetadata: false,\n};\n","/**\n * Core type definitions for Jupyter Agent extension\n */\nexport var CellAction;\n(function (CellAction) {\n CellAction[\"EXPLAIN\"] = \"explain\";\n CellAction[\"FIX\"] = \"fix\";\n CellAction[\"CUSTOM_PROMPT\"] = \"custom_prompt\";\n})(CellAction || (CellAction = {}));\nexport var AgentEvent;\n(function (AgentEvent) {\n AgentEvent[\"CELL_ACTION\"] = \"hdsp-agent:cell-action\";\n AgentEvent[\"CONFIG_CHANGED\"] = \"hdsp-agent:config-changed\";\n AgentEvent[\"MESSAGE_SENT\"] = \"hdsp-agent:message-sent\";\n AgentEvent[\"MESSAGE_RECEIVED\"] = \"hdsp-agent:message-received\";\n})(AgentEvent || (AgentEvent = {}));\n// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n// File Action Types (Python ํ์ผ ์๋ฌ ์์ ์ฉ)\n// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\nexport var FileAction;\n(function (FileAction) {\n FileAction[\"FIX\"] = \"fix\";\n FileAction[\"EXPLAIN\"] = \"explain\";\n FileAction[\"CUSTOM\"] = \"custom\";\n})(FileAction || (FileAction = {}));\n","/**\n * SafetyChecker - ์ฝ๋ ์์ ๊ฒ์ฌ๊ธฐ\n *\n * ์ํํ ์ฝ๋ ํจํด์ ์ฌ์ ์ ๊ฒ์ถํ์ฌ ์คํ ์ ๊ฒฝ๊ณ \n * NBI (Notebook Intelligence) ํจํด ์ฐธ์กฐ\n */\nconst DANGEROUS_PATTERNS = [\n // ์์คํ
๋ช
๋ น ๊ด๋ จ\n {\n pattern: /rm\\s+-rf\\s+[\\/~]/,\n description: '์ฌ๊ท ์ญ์ ๋ช
๋ น (rm -rf)',\n severity: 'critical',\n category: 'system',\n },\n {\n pattern: /os\\.system\\s*\\(/,\n description: '์์คํ
๋ช
๋ น ์คํ (os.system)',\n severity: 'critical',\n category: 'system',\n },\n {\n pattern: /subprocess\\.(run|call|Popen|check_output)\\s*\\(/,\n description: '์๋ธํ๋ก์ธ์ค ์คํ (subprocess)',\n severity: 'warning',\n category: 'system',\n },\n {\n pattern: /os\\.exec\\w*\\s*\\(/,\n description: 'OS exec ๋ช
๋ น ์คํ',\n severity: 'critical',\n category: 'system',\n },\n // ๋์ ์ฝ๋ ์คํ\n {\n pattern: /\\beval\\s*\\(/,\n description: '๋์ ์ฝ๋ ์คํ (eval)',\n severity: 'critical',\n category: 'security',\n },\n {\n pattern: /\\bexec\\s*\\(/,\n description: '๋์ ์ฝ๋ ์คํ (exec)',\n severity: 'critical',\n category: 'security',\n },\n {\n pattern: /__import__\\s*\\(/,\n description: '๋์ ๋ชจ๋ ์ํฌํธ (__import__)',\n severity: 'warning',\n category: 'security',\n },\n {\n pattern: /compile\\s*\\([^)]*exec/,\n description: '๋์ ์ฝ๋ ์ปดํ์ผ (compile)',\n severity: 'critical',\n category: 'security',\n },\n // ํ์ผ ์์คํ
๊ด๋ จ\n {\n pattern: /open\\s*\\([^)]*,\\s*['\"]w/,\n description: 'ํ์ผ ์ฐ๊ธฐ ๋ชจ๋ ์ด๊ธฐ',\n severity: 'warning',\n category: 'file',\n },\n {\n pattern: /shutil\\.(rmtree|move|copy)/,\n description: 'ํ์ผ/๋๋ ํ ๋ฆฌ ์กฐ์ (shutil)',\n severity: 'warning',\n category: 'file',\n },\n {\n pattern: /os\\.(remove|unlink|rmdir|makedirs|rename)/,\n description: 'ํ์ผ ์์คํ
๋ณ๊ฒฝ (os)',\n severity: 'warning',\n category: 'file',\n },\n {\n pattern: /pathlib\\.Path[^)]*\\.(unlink|rmdir|write)/,\n description: 'ํ์ผ ์์คํ
๋ณ๊ฒฝ (pathlib)',\n severity: 'warning',\n category: 'file',\n },\n // ๋คํธ์ํฌ ๊ด๋ จ\n {\n pattern: /requests\\.(get|post|put|delete|patch)\\s*\\([^)]*\\)/,\n description: 'HTTP ์์ฒญ (requests)',\n severity: 'info',\n category: 'network',\n },\n {\n pattern: /urllib\\.(request|urlopen)/,\n description: 'URL ์์ฒญ (urllib)',\n severity: 'info',\n category: 'network',\n },\n {\n pattern: /socket\\./,\n description: '์์ผ ํต์ (socket)',\n severity: 'warning',\n category: 'network',\n },\n // ๋ฌดํ ๋ฃจํ ํจํด\n {\n pattern: /while\\s+True\\s*:/,\n description: '๋ฌดํ ๋ฃจํ (while True)',\n severity: 'warning',\n category: 'loop',\n },\n {\n pattern: /while\\s+1\\s*:/,\n description: '๋ฌดํ ๋ฃจํ (while 1)',\n severity: 'warning',\n category: 'loop',\n },\n {\n pattern: /for\\s+\\w+\\s+in\\s+iter\\s*\\(\\s*int\\s*,/,\n description: '๋ฌดํ ๋ฐ๋ณต์ (iter(int, ...))',\n severity: 'warning',\n category: 'loop',\n },\n // ๋ฏผ๊ฐ ์ ๋ณด ๊ด๋ จ\n {\n pattern: /os\\.environ\\s*\\[/,\n description: 'ํ๊ฒฝ ๋ณ์ ์ ๊ทผ',\n severity: 'info',\n category: 'security',\n },\n {\n pattern: /(password|secret|api_key|token)\\s*=\\s*['\"][^'\"]+['\"]/i,\n description: 'ํ๋์ฝ๋ฉ๋ ๋ฏผ๊ฐ ์ ๋ณด',\n severity: 'warning',\n category: 'security',\n },\n // ์ํํ ๋ชจ๋\n {\n pattern: /import\\s+pickle|from\\s+pickle\\s+import/,\n description: 'Pickle ๋ชจ๋ (์ญ์ง๋ ฌํ ์ทจ์ฝ์ )',\n severity: 'info',\n category: 'security',\n },\n {\n pattern: /import\\s+ctypes|from\\s+ctypes\\s+import/,\n description: 'ctypes ๋ชจ๋ (์ ์์ค ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ)',\n severity: 'warning',\n category: 'security',\n },\n];\nexport class SafetyChecker {\n constructor(config) {\n this.config = {\n enableSafetyCheck: true,\n blockDangerousPatterns: false,\n requireConfirmation: true,\n maxExecutionTime: 30,\n ...config,\n };\n }\n /**\n * ์ฝ๋ ์์ ์ฑ ๊ฒ์ฌ\n */\n checkCodeSafety(code) {\n if (!this.config.enableSafetyCheck) {\n return { safe: true, warnings: [] };\n }\n const warnings = [];\n const blockedPatterns = [];\n for (const dangerous of DANGEROUS_PATTERNS) {\n if (dangerous.pattern.test(code)) {\n const message = `[${dangerous.severity.toUpperCase()}] ${dangerous.description}`;\n if (dangerous.severity === 'critical' && this.config.blockDangerousPatterns) {\n blockedPatterns.push(message);\n }\n else {\n warnings.push(message);\n }\n }\n }\n const safe = blockedPatterns.length === 0;\n return {\n safe,\n warnings,\n blockedPatterns: blockedPatterns.length > 0 ? blockedPatterns : undefined,\n };\n }\n /**\n * ์ฌ๋ฌ ์ฝ๋ ๋ธ๋ก ๊ฒ์ฌ\n */\n checkMultipleCodeBlocks(codes) {\n const allWarnings = [];\n const allBlockedPatterns = [];\n for (let i = 0; i < codes.length; i++) {\n const result = this.checkCodeSafety(codes[i]);\n result.warnings.forEach((w) => allWarnings.push(`[Block ${i + 1}] ${w}`));\n if (result.blockedPatterns) {\n result.blockedPatterns.forEach((b) => allBlockedPatterns.push(`[Block ${i + 1}] ${b}`));\n }\n }\n return {\n safe: allBlockedPatterns.length === 0,\n warnings: allWarnings,\n blockedPatterns: allBlockedPatterns.length > 0 ? allBlockedPatterns : undefined,\n };\n }\n /**\n * ๋ฌดํ ๋ฃจํ ๊ฐ๋ฅ์ฑ ๊ฒ์ฌ\n */\n checkInfiniteLoopRisk(code) {\n const loopPatterns = DANGEROUS_PATTERNS.filter((p) => p.category === 'loop');\n return loopPatterns.some((p) => p.pattern.test(code));\n }\n /**\n * ํ์ผ ์์คํ
๋ณ๊ฒฝ ์ํ ๊ฒ์ฌ\n */\n checkFileSystemRisk(code) {\n const filePatterns = DANGEROUS_PATTERNS.filter((p) => p.category === 'file');\n return filePatterns.some((p) => p.pattern.test(code));\n }\n /**\n * ๋คํธ์ํฌ ํ๋ ๊ฒ์ฌ\n */\n checkNetworkActivity(code) {\n const networkPatterns = DANGEROUS_PATTERNS.filter((p) => p.category === 'network');\n return networkPatterns.some((p) => p.pattern.test(code));\n }\n /**\n * ์คํ ์๊ฐ ์ ํ ๊ฐ ๋ฐํ\n */\n getMaxExecutionTime() {\n return this.config.maxExecutionTime * 1000; // ms๋ก ๋ณํ\n }\n /**\n * ํ์ธ ํ์ ์ฌ๋ถ\n */\n requiresConfirmation(result) {\n if (!this.config.requireConfirmation) {\n return false;\n }\n return result.warnings.length > 0 || (result.blockedPatterns?.length || 0) > 0;\n }\n /**\n * ์ค์ ์
๋ฐ์ดํธ\n */\n updateConfig(config) {\n this.config = { ...this.config, ...config };\n }\n /**\n * ํ์ฌ ์ค์ ๋ฐํ\n */\n getConfig() {\n return { ...this.config };\n }\n /**\n * ์ฌ์ฉ์ ์นํ์ ๊ฒฝ๊ณ ๋ฉ์์ง ์์ฑ\n */\n formatWarningsForDisplay(result) {\n if (result.warnings.length === 0 && !result.blockedPatterns?.length) {\n return '';\n }\n const lines = [];\n if (result.blockedPatterns && result.blockedPatterns.length > 0) {\n lines.push('โ ์ฐจ๋จ๋ ํจํด:');\n result.blockedPatterns.forEach((p) => lines.push(` โข ${p}`));\n }\n if (result.warnings.length > 0) {\n lines.push('โ ๏ธ ๊ฒฝ๊ณ :');\n result.warnings.forEach((w) => lines.push(` โข ${w}`));\n }\n return lines.join('\\n');\n }\n}\nexport default SafetyChecker;\n","/**\n * Markdown to HTML converter with syntax highlighting\n * Based on chrome_agent's formatMarkdownToHtml implementation\n */\n/**\n * Simple hash function for generating stable IDs from content\n * Uses djb2 algorithm for fast string hashing\n */\nfunction simpleHash(str) {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) + hash) + str.charCodeAt(i);\n hash = hash & hash; // Convert to 32-bit integer\n }\n // Convert to positive hex string\n return Math.abs(hash).toString(36);\n}\n/**\n * Escape HTML special characters\n */\nexport function escapeHtml(text) {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n}\n/**\n * Normalize indentation in code blocks\n */\nexport function normalizeIndentation(code) {\n const lines = code.split('\\n');\n // Find minimum indent from non-empty lines\n let minIndent = Infinity;\n const nonEmptyLines = [];\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line.trim().length > 0) {\n const match = line.match(/^(\\s*)/);\n const indent = match ? match[1].length : 0;\n minIndent = Math.min(minIndent, indent);\n nonEmptyLines.push(i);\n }\n }\n // If no indent or no non-empty lines, return original\n if (minIndent === Infinity || minIndent === 0) {\n return code;\n }\n // Remove minimum indent from all lines\n const normalized = lines.map(line => {\n if (line.trim().length === 0) {\n return '';\n }\n return line.substring(minIndent);\n });\n return normalized.join('\\n');\n}\n/**\n * Highlight Python code with inline styles\n */\nexport function highlightPython(code) {\n let highlighted = code;\n // Color styles (matching chrome_agent)\n const styles = {\n COMMENT: 'color: #6a9955; font-style: italic;',\n STRING: 'color: #ce9178;',\n NUMBER: 'color: #b5cea8;',\n KEYWORD: 'color: #c586c0; font-weight: bold;',\n BUILTIN: 'color: #dcdcaa;',\n FUNCTION: 'color: #4fc1ff; font-weight: bold;',\n OPERATOR: 'color: #d4d4d4;',\n BRACKET: 'color: #d4d4d4;'\n };\n // Use placeholders to preserve order\n const placeholders = [];\n let placeholderIndex = 0;\n // Comments (process first)\n highlighted = highlighted.replace(/(#.*$)/gm, (match) => {\n const id = `__PH${placeholderIndex++}__`;\n placeholders.push({\n id,\n html: `<span style=\"${styles.COMMENT}\">${escapeHtml(match)}</span>`\n });\n return id;\n });\n // Triple-quoted strings\n highlighted = highlighted.replace(/(['\"]{3})([\\s\\S]*?)(\\1)/g, (match) => {\n const id = `__PH${placeholderIndex++}__`;\n placeholders.push({\n id,\n html: `<span style=\"${styles.STRING}\">${escapeHtml(match)}</span>`\n });\n return id;\n });\n // Regular strings\n highlighted = highlighted.replace(/(['\"])([^'\"]*?)(\\1)/g, (match) => {\n const id = `__PH${placeholderIndex++}__`;\n placeholders.push({\n id,\n html: `<span style=\"${styles.STRING}\">${escapeHtml(match)}</span>`\n });\n return id;\n });\n // Numbers\n highlighted = highlighted.replace(/\\b(\\d+\\.?\\d*)\\b/g, (match) => {\n const id = `__PH${placeholderIndex++}__`;\n placeholders.push({\n id,\n html: `<span style=\"${styles.NUMBER}\">${match}</span>`\n });\n return id;\n });\n // Python keywords\n const keywords = [\n 'def', 'class', 'if', 'elif', 'else', 'for', 'while', 'return', 'import',\n 'from', 'as', 'try', 'except', 'finally', 'with', 'lambda', 'yield',\n 'async', 'await', 'pass', 'break', 'continue', 'raise', 'assert', 'del',\n 'global', 'nonlocal', 'True', 'False', 'None', 'and', 'or', 'not', 'in', 'is'\n ];\n keywords.forEach(keyword => {\n const regex = new RegExp(`\\\\b${keyword}\\\\b`, 'g');\n highlighted = highlighted.replace(regex, (match) => {\n const id = `__PH${placeholderIndex++}__`;\n placeholders.push({\n id,\n html: `<span style=\"${styles.KEYWORD}\">${match}</span>`\n });\n return id;\n });\n });\n // Built-in functions\n const builtins = [\n 'print', 'len', 'range', 'str', 'int', 'float', 'list', 'dict', 'tuple',\n 'set', 'bool', 'type', 'isinstance', 'issubclass', 'hasattr', 'getattr',\n 'setattr', 'delattr', 'dir', 'vars', 'locals', 'globals', 'input', 'open',\n 'file', 'abs', 'all', 'any', 'bin', 'chr', 'ord', 'hex', 'oct', 'pow',\n 'round', 'sum', 'min', 'max', 'sorted', 'reversed', 'enumerate', 'zip',\n 'map', 'filter', 'reduce'\n ];\n builtins.forEach(builtin => {\n const regex = new RegExp(`\\\\b${builtin}\\\\b`, 'g');\n highlighted = highlighted.replace(regex, (match) => {\n const id = `__PH${placeholderIndex++}__`;\n placeholders.push({\n id,\n html: `<span style=\"${styles.BUILTIN}\">${match}</span>`\n });\n return id;\n });\n });\n // Function definitions - def keyword followed by function name\n highlighted = highlighted.replace(/(__PH\\d+__\\s+)([a-zA-Z_][a-zA-Z0-9_]*)/g, (match, defPart, funcName) => {\n const defPlaceholder = placeholders.find(p => p.id === defPart.trim());\n if (defPlaceholder && defPlaceholder.html.includes('def')) {\n const id = `__PH${placeholderIndex++}__`;\n placeholders.push({\n id,\n html: `<span style=\"${styles.FUNCTION}\">${funcName}</span>`\n });\n return defPart + id;\n }\n return match;\n });\n // Process remaining text - escape HTML and handle operators/brackets\n highlighted = highlighted.split(/(__PH\\d+__)/g).map(part => {\n if (part.match(/^__PH\\d+__$/)) {\n return part; // Keep placeholder as is\n }\n // Escape HTML\n part = escapeHtml(part);\n // Operators\n part = part.replace(/([+\\-*/%=<>!&|^~]+)/g, `<span style=\"${styles.OPERATOR}\">$1</span>`);\n // Brackets and delimiters\n part = part.replace(/([()[\\]{}])/g, `<span style=\"${styles.BRACKET}\">$1</span>`);\n return part;\n }).join('');\n // Replace placeholders with actual HTML\n placeholders.forEach(ph => {\n highlighted = highlighted.replace(ph.id, ph.html);\n });\n return highlighted;\n}\n/**\n * Highlight JavaScript code\n */\nexport function highlightJavaScript(code) {\n const escaped = escapeHtml(code);\n const lines = escaped.split('\\n');\n const keywords = [\n 'function', 'const', 'let', 'var', 'if', 'else', 'for', 'while',\n 'return', 'class', 'import', 'export', 'from', 'async', 'await',\n 'new', 'this', 'null', 'undefined', 'true', 'false', 'typeof'\n ];\n let inMultilineComment = false;\n const highlightedLines = lines.map(line => {\n // Check for multiline comment continuation\n if (inMultilineComment) {\n const endIndex = line.indexOf('*/');\n if (endIndex !== -1) {\n inMultilineComment = false;\n return `<span style=\"color: #6a9955; font-style: italic;\">${line.substring(0, endIndex + 2)}</span>` +\n highlightJSTokens(line.substring(endIndex + 2), keywords);\n }\n return `<span style=\"color: #6a9955; font-style: italic;\">${line}</span>`;\n }\n // Single-line comment\n const commentMatch = line.match(/^(\\s*)(\\/\\/.*)$/);\n if (commentMatch) {\n return commentMatch[1] + `<span style=\"color: #6a9955; font-style: italic;\">${commentMatch[2]}</span>`;\n }\n // Multiline comment start\n const multiCommentStart = line.indexOf('/*');\n if (multiCommentStart !== -1) {\n const multiCommentEnd = line.indexOf('*/', multiCommentStart);\n if (multiCommentEnd !== -1) {\n return highlightJSTokens(line.substring(0, multiCommentStart), keywords) +\n `<span style=\"color: #6a9955; font-style: italic;\">${line.substring(multiCommentStart, multiCommentEnd + 2)}</span>` +\n highlightJSTokens(line.substring(multiCommentEnd + 2), keywords);\n }\n else {\n inMultilineComment = true;\n return highlightJSTokens(line.substring(0, multiCommentStart), keywords) +\n `<span style=\"color: #6a9955; font-style: italic;\">${line.substring(multiCommentStart)}</span>`;\n }\n }\n // Comment in middle of line\n const commentIndex = line.indexOf('//');\n if (commentIndex !== -1) {\n return highlightJSTokens(line.substring(0, commentIndex), keywords) +\n `<span style=\"color: #6a9955; font-style: italic;\">${line.substring(commentIndex)}</span>`;\n }\n return highlightJSTokens(line, keywords);\n });\n return highlightedLines.join('\\n');\n}\n/**\n * Highlight JavaScript tokens (keywords, strings, numbers)\n */\nfunction highlightJSTokens(line, keywords) {\n const container = document.createElement('span');\n let i = 0;\n while (i < line.length) {\n // String check (template literal, double quote, single quote)\n if (line[i] === '`') {\n let j = i + 1;\n let escaped = false;\n while (j < line.length) {\n if (line[j] === '\\\\' && !escaped) {\n escaped = true;\n j++;\n continue;\n }\n if (line[j] === '`' && !escaped)\n break;\n escaped = false;\n j++;\n }\n if (j < line.length && line[j] === '`') {\n const span = document.createElement('span');\n span.style.color = '#ce9178';\n span.textContent = line.substring(i, j + 1);\n container.appendChild(span);\n i = j + 1;\n continue;\n }\n }\n if (line[i] === '\"') {\n let j = i + 1;\n let escaped = false;\n while (j < line.length) {\n if (line[j] === '\\\\' && !escaped) {\n escaped = true;\n j++;\n continue;\n }\n if (line[j] === '\"' && !escaped)\n break;\n escaped = false;\n j++;\n }\n if (j < line.length && line[j] === '\"') {\n const span = document.createElement('span');\n span.style.color = '#ce9178';\n span.textContent = line.substring(i, j + 1);\n container.appendChild(span);\n i = j + 1;\n continue;\n }\n // Unclosed string - treat rest as string\n const span = document.createElement('span');\n span.style.color = '#ce9178';\n span.textContent = line.substring(i);\n container.appendChild(span);\n break;\n }\n if (line[i] === '\\'') {\n let j = i + 1;\n let escaped = false;\n while (j < line.length) {\n if (line[j] === '\\\\' && !escaped) {\n escaped = true;\n j++;\n continue;\n }\n if (line[j] === '\\'' && !escaped)\n break;\n escaped = false;\n j++;\n }\n if (j < line.length && line[j] === '\\'') {\n const span = document.createElement('span');\n span.style.color = '#ce9178';\n span.textContent = line.substring(i, j + 1);\n container.appendChild(span);\n i = j + 1;\n continue;\n }\n // Unclosed string\n const span = document.createElement('span');\n span.style.color = '#ce9178';\n span.textContent = line.substring(i);\n container.appendChild(span);\n break;\n }\n // Number check\n if (/\\d/.test(line[i])) {\n let j = i;\n while (j < line.length && /[\\d.]/.test(line[j])) {\n j++;\n }\n const span = document.createElement('span');\n span.style.color = '#b5cea8';\n span.textContent = line.substring(i, j);\n container.appendChild(span);\n i = j;\n continue;\n }\n // Word check (keyword or identifier)\n if (/[a-zA-Z_$]/.test(line[i])) {\n let j = i;\n while (j < line.length && /[a-zA-Z0-9_$]/.test(line[j])) {\n j++;\n }\n const word = line.substring(i, j);\n if (keywords.includes(word)) {\n const span = document.createElement('span');\n span.style.color = '#569cd6';\n span.style.fontWeight = '500';\n span.textContent = word;\n container.appendChild(span);\n }\n else {\n const textNode = document.createTextNode(word);\n container.appendChild(textNode);\n }\n i = j;\n continue;\n }\n // Regular character\n const textNode = document.createTextNode(line[i]);\n container.appendChild(textNode);\n i++;\n }\n return container.innerHTML;\n}\n/**\n * Format inline markdown (bold, italic, inline code) within text\n */\nexport function formatInlineMarkdown(text) {\n let html = escapeHtml(text);\n // Inline code first (to protect from other transformations)\n html = html.replace(/`([^`]+)`/g, '<code class=\"inline-code\">$1</code>');\n // Bold text (**text**)\n html = html.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');\n // Italic text (*text*)\n html = html.replace(/\\*([^*]+)\\*/g, '<em>$1</em>');\n return html;\n}\n/**\n * Parse markdown table to HTML\n */\nexport function parseMarkdownTable(tableText) {\n const lines = tableText.trim().split('\\n');\n if (lines.length < 2)\n return escapeHtml(tableText);\n // Check if it's a valid table (has header separator)\n const separatorIndex = lines.findIndex(line => /^\\|?\\s*[-:]+[-|\\s:]+\\s*\\|?$/.test(line));\n if (separatorIndex === -1 || separatorIndex === 0)\n return escapeHtml(tableText);\n const headerLines = lines.slice(0, separatorIndex);\n const separatorLine = lines[separatorIndex];\n const bodyLines = lines.slice(separatorIndex + 1);\n // Parse alignment from separator\n const alignments = [];\n const separatorCells = separatorLine.split('|').filter(cell => cell.trim());\n separatorCells.forEach(cell => {\n const trimmed = cell.trim();\n if (trimmed.startsWith(':') && trimmed.endsWith(':')) {\n alignments.push('center');\n }\n else if (trimmed.endsWith(':')) {\n alignments.push('right');\n }\n else {\n alignments.push('left');\n }\n });\n // Build HTML table with wrapper for horizontal scroll\n let html = '<div class=\"markdown-table-wrapper\"><table class=\"markdown-table\">';\n // Header\n html += '<thead>';\n headerLines.forEach(line => {\n html += '<tr>';\n const cells = line.split('|').filter((cell, idx, arr) => {\n // Filter out empty cells from leading/trailing |\n if (idx === 0 && cell.trim() === '')\n return false;\n if (idx === arr.length - 1 && cell.trim() === '')\n return false;\n return true;\n });\n cells.forEach((cell, idx) => {\n const align = alignments[idx] || 'left';\n html += `<th style=\"text-align: ${align};\">${formatInlineMarkdown(cell.trim())}</th>`;\n });\n html += '</tr>';\n });\n html += '</thead>';\n // Body\n if (bodyLines.length > 0) {\n html += '<tbody>';\n bodyLines.forEach(line => {\n if (!line.trim())\n return;\n html += '<tr>';\n const cells = line.split('|').filter((cell, idx, arr) => {\n if (idx === 0 && cell.trim() === '')\n return false;\n if (idx === arr.length - 1 && cell.trim() === '')\n return false;\n return true;\n });\n cells.forEach((cell, idx) => {\n const align = alignments[idx] || 'left';\n html += `<td style=\"text-align: ${align};\">${formatInlineMarkdown(cell.trim())}</td>`;\n });\n html += '</tr>';\n });\n html += '</tbody>';\n }\n html += '</table></div>';\n return html;\n}\n/**\n * Format markdown text to HTML with syntax highlighting\n */\nexport function formatMarkdownToHtml(text) {\n // Decode HTML entities if present\n const textarea = document.createElement('textarea');\n textarea.innerHTML = text;\n let html = textarea.value;\n // Step 0.5: Protect DataFrame HTML tables (must be before code blocks)\n const dataframeHtmlPlaceholders = [];\n html = html.replace(/<!--DFHTML-->([\\s\\S]*?)<!--\\/DFHTML-->/g, (match, tableHtml) => {\n const placeholder = '__DATAFRAME_HTML_' + Math.random().toString(36).substr(2, 9) + '__';\n dataframeHtmlPlaceholders.push({\n placeholder: placeholder,\n html: tableHtml\n });\n return placeholder;\n });\n // Step 1: Protect code blocks by replacing with placeholders\n const codeBlocks = [];\n const codeBlockPlaceholders = [];\n html = html.replace(/```(\\w+)?\\n([\\s\\S]*?)```/g, (match, language, code) => {\n const lang = (language || 'python').toLowerCase();\n const trimmedCode = normalizeIndentation(code.trim());\n // Use content-based hash for stable ID across re-renders\n const contentHash = simpleHash(trimmedCode + lang);\n const blockId = 'code-block-' + contentHash;\n const placeholder = '__CODE_BLOCK_' + blockId + '__';\n codeBlocks.push({\n id: blockId,\n code: trimmedCode,\n language: lang\n });\n // Create HTML for code block\n const highlightedCode = lang === 'python' || lang === 'py'\n ? highlightPython(trimmedCode)\n : lang === 'javascript' || lang === 'js'\n ? highlightJavaScript(trimmedCode)\n : escapeHtml(trimmedCode);\n const htmlBlock = '<div class=\"code-block-container\" data-block-id=\"' + blockId + '\">' +\n '<div class=\"code-block-header\">' +\n '<span class=\"code-block-language\">' + escapeHtml(lang) + '</span>' +\n '<div class=\"code-block-actions\">' +\n '<button class=\"code-block-apply\" data-block-id=\"' + blockId + '\" title=\"์
์ ์ ์ฉ\">์
์ ์ ์ฉ</button>' +\n '<button class=\"code-block-copy\" data-block-id=\"' + blockId + '\" title=\"๋ณต์ฌ\">๋ณต์ฌ</button>' +\n '</div>' +\n '</div>' +\n '<pre class=\"code-block language-' + escapeHtml(lang) + '\"><code id=\"' + blockId + '\">' + highlightedCode + '</code></pre>' +\n '</div>';\n codeBlockPlaceholders.push({\n placeholder: placeholder,\n html: htmlBlock\n });\n return placeholder;\n });\n // Step 2: Protect inline code\n const inlineCodePlaceholders = [];\n html = html.replace(/`([^`]+)`/g, (match, code) => {\n const placeholder = '__INLINE_CODE_' + Math.random().toString(36).substr(2, 9) + '__';\n inlineCodePlaceholders.push({\n placeholder: placeholder,\n html: '<code class=\"inline-code\">' + escapeHtml(code) + '</code>'\n });\n return placeholder;\n });\n // Step 3: Parse and protect markdown tables\n const tablePlaceholders = [];\n // Improved table detection: look for lines with | separators and a separator row\n // Match pattern: header row(s), separator row (with ---), body rows\n // More flexible regex to handle various table formats\n const tableRegex = /(?:^|\\n)((?:\\|[^\\n]+\\|\\n?)+\\|[-:| ]+\\|(?:\\n\\|[^\\n]+\\|)*)/gm;\n html = html.replace(tableRegex, (match, tableBlock) => {\n const placeholder = '__TABLE_' + Math.random().toString(36).substr(2, 9) + '__';\n const tableHtml = parseMarkdownTable(tableBlock.trim());\n tablePlaceholders.push({\n placeholder: placeholder,\n html: tableHtml\n });\n return '\\n' + placeholder + '\\n';\n });\n // Alternative: tables without leading/trailing | (GFM style)\n // Pattern: \"header | header\\n---|---\\ndata | data\"\n const gfmTableRegex = /(?:^|\\n)((?:[^\\n|]+\\|[^\\n]+\\n)+[-:|\\s]+[-|]+\\n(?:[^\\n|]+\\|[^\\n]+\\n?)*)/gm;\n html = html.replace(gfmTableRegex, (match, tableBlock) => {\n // Skip if already processed (contains placeholder)\n if (tableBlock.includes('__TABLE_'))\n return match;\n const placeholder = '__TABLE_' + Math.random().toString(36).substr(2, 9) + '__';\n const tableHtml = parseMarkdownTable(tableBlock.trim());\n tablePlaceholders.push({\n placeholder: placeholder,\n html: tableHtml\n });\n return '\\n' + placeholder + '\\n';\n });\n // Third pattern: catch any remaining tables with | characters and --- separator\n const fallbackTableRegex = /(?:^|\\n)(\\|[^\\n]*\\|\\n\\|[-:| ]*\\|(?:\\n\\|[^\\n]*\\|)*)/gm;\n html = html.replace(fallbackTableRegex, (match, tableBlock) => {\n if (tableBlock.includes('__TABLE_'))\n return match;\n const placeholder = '__TABLE_' + Math.random().toString(36).substr(2, 9) + '__';\n const tableHtml = parseMarkdownTable(tableBlock.trim());\n tablePlaceholders.push({\n placeholder: placeholder,\n html: tableHtml\n });\n return '\\n' + placeholder + '\\n';\n });\n // Step 4: Escape HTML for non-placeholder text\n html = html.split(/(__(?:DATAFRAME_HTML|CODE_BLOCK|INLINE_CODE|TABLE)_[a-z0-9-]+__)/gi)\n .map((part, index) => {\n // Odd indices are placeholders - keep as is\n if (index % 2 === 1)\n return part;\n // Even indices are regular text - escape HTML\n return escapeHtml(part);\n })\n .join('');\n // Step 5: Convert markdown to HTML\n // Headings (process from h6 to h1 to avoid conflicts)\n html = html.replace(/^###### (.*$)/gim, '<h6>$1</h6>');\n html = html.replace(/^##### (.*$)/gim, '<h5>$1</h5>');\n html = html.replace(/^#### (.*$)/gim, '<h4>$1</h4>');\n html = html.replace(/^### (.*$)/gim, '<h3>$1</h3>');\n html = html.replace(/^## (.*$)/gim, '<h2>$1</h2>');\n html = html.replace(/^# (.*$)/gim, '<h1>$1</h1>');\n // Horizontal rule (---)\n html = html.replace(/^---+$/gim, '<hr>');\n // Links [text](url)\n html = html.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\">$1</a>');\n // Lists - process BEFORE bold/italic to handle \"* item\" correctly\n // Unordered lists: - or * at start of line\n html = html.replace(/^[\\-\\*]\\s+(.*$)/gim, '<li>$1</li>');\n // Numbered lists: 1. 2. etc\n html = html.replace(/^\\d+\\.\\s+(.*$)/gim, '<li>$1</li>');\n // Bold text (must be before italic)\n html = html.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');\n // Italic text - only match single * not at line start (to avoid conflict with lists)\n html = html.replace(/(?<!\\*)\\*([^*\\n]+)\\*(?!\\*)/g, '<em>$1</em>');\n // Line breaks\n html = html.replace(/\\n/g, '<br>');\n // Step 6: Restore table placeholders\n tablePlaceholders.forEach(item => {\n html = html.replace(item.placeholder, item.html);\n });\n // Step 6.5: Restore DataFrame HTML tables\n dataframeHtmlPlaceholders.forEach(item => {\n html = html.replace(item.placeholder, item.html);\n });\n // Step 7: Restore inline code placeholders\n inlineCodePlaceholders.forEach(item => {\n html = html.replace(item.placeholder, item.html);\n });\n // Step 8: Restore code block placeholders\n codeBlockPlaceholders.forEach(item => {\n html = html.replace(item.placeholder, item.html);\n });\n return html;\n}\n","\"use client\";\n\nimport createSvgIcon from \"./utils/createSvgIcon.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default createSvgIcon(/*#__PURE__*/_jsx(\"path\", {\n d: \"M7.5 5.6 10 7 8.6 4.5 10 2 7.5 3.4 5 2l1.4 2.5L5 7zm12 9.8L17 14l1.4 2.5L17 19l2.5-1.4L22 19l-1.4-2.5L22 14zM22 2l-2.5 1.4L17 2l1.4 2.5L17 7l2.5-1.4L22 7l-1.4-2.5zm-7.63 5.29a.996.996 0 0 0-1.41 0L1.29 18.96c-.39.39-.39 1.02 0 1.41l2.34 2.34c.39.39 1.02.39 1.41 0L16.7 11.05c.39-.39.39-1.02 0-1.41zm-1.03 5.49-2.12-2.12 2.44-2.44 2.12 2.12z\"\n}), 'AutoFixHigh');","\"use client\";\n\nimport createSvgIcon from \"./utils/createSvgIcon.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default createSvgIcon(/*#__PURE__*/_jsx(\"path\", {\n d: \"M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2m5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12z\"\n}), 'Cancel');","\"use client\";\n\nimport createSvgIcon from \"./utils/createSvgIcon.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default createSvgIcon(/*#__PURE__*/_jsx(\"path\", {\n d: \"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m-2 15-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8z\"\n}), 'CheckCircle');","\"use client\";\n\nimport createSvgIcon from \"./utils/createSvgIcon.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default createSvgIcon(/*#__PURE__*/_jsx(\"path\", {\n d: \"M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"\n}), 'Close');","\"use client\";\n\nimport createSvgIcon from \"./utils/createSvgIcon.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default createSvgIcon(/*#__PURE__*/_jsx(\"path\", {\n d: \"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m1 15h-2v-2h2zm0-4h-2V7h2z\"\n}), 'Error');","\"use client\";\n\nimport createSvgIcon from \"./utils/createSvgIcon.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default createSvgIcon(/*#__PURE__*/_jsx(\"path\", {\n d: \"m12 8-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z\"\n}), 'ExpandLess');","\"use client\";\n\nimport createSvgIcon from \"./utils/createSvgIcon.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default createSvgIcon(/*#__PURE__*/_jsx(\"path\", {\n d: \"M16.59 8.59 12 13.17 7.41 8.59 6 10l6 6 6-6z\"\n}), 'ExpandMore');"],"names":[],"ignoreList":[],"sourceRoot":""}
|