codebuff-agent 2.1.74__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.
Files changed (217) hide show
  1. codebuff_agent-2.1.74.data/data/etc/jupyter/jupyter_server_config.d/codebuff_agent.json +7 -0
  2. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/package.json +157 -0
  3. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/104.2b8f20f9d1ac2c9db01b.js +1 -0
  4. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/150.39fa98117cc8ca590465.js +1 -0
  5. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/166.386ff9b2c37ac865fdee.js +1 -0
  6. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/216.25cf81131bf7274dabf4.js +1 -0
  7. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/353.581bd1cb00746399b62e.js +1 -0
  8. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/367.575f9621b63c9a641aa9.js +1 -0
  9. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/421.11dac223a2c2da1b09f5.js +1 -0
  10. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/432.8513b4c6cc1d1232d165.js +2 -0
  11. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/432.8513b4c6cc1d1232d165.js.LICENSE.txt +19 -0
  12. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/439.ba5b5ef70ec6de214b8c.js +2 -0
  13. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/439.ba5b5ef70ec6de214b8c.js.LICENSE.txt +8 -0
  14. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/481.cc2dec9fa869d66f1407.js +1 -0
  15. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/487.0796e931d6e651482c14.js +1 -0
  16. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/49.d326f554b6f9ccde6580.js +1 -0
  17. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/541.26897ea32845659e36be.js +1 -0
  18. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/579.e569d3edd8391fd8fbb3.js +1 -0
  19. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/58.eb7cc679f7535cc8a2f1.js +2 -0
  20. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/58.eb7cc679f7535cc8a2f1.js.LICENSE.txt +8 -0
  21. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/666.d9bfdb23f98489d0a188.js +1 -0
  22. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/677.d266c39dbed33bc388b3.js +2 -0
  23. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/677.d266c39dbed33bc388b3.js.LICENSE.txt +8 -0
  24. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/68.26b6f59c8454adb17f20.js +204 -0
  25. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/694.4ac443814260057e68f7.js +1 -0
  26. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/791.61affb8d3480d3d60e0d.js +1 -0
  27. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/848.4d2db09cfbb09374b299.js +2 -0
  28. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/848.4d2db09cfbb09374b299.js.LICENSE.txt +9 -0
  29. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/868.5cfe7e1a348ec5af1b8c.js +1 -0
  30. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/97.ea559a5b8a9a09f17c6b.js +1 -0
  31. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/remoteEntry.5292fc9c6df7e7920cc8.js +1 -0
  32. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/style.js +4 -0
  33. codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/third-party-licenses.json +724 -0
  34. codebuff_agent-2.1.74.dist-info/METADATA +142 -0
  35. codebuff_agent-2.1.74.dist-info/RECORD +217 -0
  36. codebuff_agent-2.1.74.dist-info/WHEEL +4 -0
  37. codebuff_agent-2.1.74.dist-info/licenses/LICENSE +21 -0
  38. codebuff_core/__init__.py +153 -0
  39. codebuff_core/codebuff_config_defaults.json +64 -0
  40. codebuff_core/core/__init__.py +35 -0
  41. codebuff_core/core/code_validator.py +1238 -0
  42. codebuff_core/core/error_classifier.py +579 -0
  43. codebuff_core/core/exceptions.py +49 -0
  44. codebuff_core/data/tiktoken_cache/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +100256 -0
  45. codebuff_core/directory_policy.py +32 -0
  46. codebuff_core/factory.py +155 -0
  47. codebuff_core/interfaces.py +197 -0
  48. codebuff_core/knowledge/__init__.py +31 -0
  49. codebuff_core/knowledge/chunking.py +375 -0
  50. codebuff_core/knowledge/loader.py +339 -0
  51. codebuff_core/knowledge/watchdog_service.py +354 -0
  52. codebuff_core/legacy_paths.py +69 -0
  53. codebuff_core/llm/__init__.py +13 -0
  54. codebuff_core/llm/service.py +407 -0
  55. codebuff_core/managers/__init__.py +22 -0
  56. codebuff_core/managers/config_manager.py +690 -0
  57. codebuff_core/managers/remote_config.py +673 -0
  58. codebuff_core/managers/remote_skills.py +539 -0
  59. codebuff_core/managers/session_manager.py +255 -0
  60. codebuff_core/middleware/__init__.py +3 -0
  61. codebuff_core/middleware/error_recovery.py +394 -0
  62. codebuff_core/middleware/logging_utils.py +33 -0
  63. codebuff_core/models/__init__.py +111 -0
  64. codebuff_core/models/agent.py +306 -0
  65. codebuff_core/models/chat.py +57 -0
  66. codebuff_core/models/common.py +82 -0
  67. codebuff_core/models/rag.py +300 -0
  68. codebuff_core/platform_rules.py +127 -0
  69. codebuff_core/prompts/__init__.py +44 -0
  70. codebuff_core/prompts/auto_agent_prompts.py +1278 -0
  71. codebuff_core/services/__init__.py +30 -0
  72. codebuff_core/services/agent_service.py +345 -0
  73. codebuff_core/services/analytics_aggregate.py +837 -0
  74. codebuff_core/services/chat_service.py +898 -0
  75. codebuff_core/services/context_condenser.py +306 -0
  76. codebuff_core/services/pii_guardrail.py +393 -0
  77. codebuff_core/services/rag_chat_agent.py +2993 -0
  78. codebuff_core/services/rag_collections.py +2740 -0
  79. codebuff_core/services/rag_manager.py +890 -0
  80. codebuff_core/services/rag_service.py +145 -0
  81. codebuff_core/services/retriever.py +260 -0
  82. codebuff_core/services/vllm_embedding_service.py +290 -0
  83. codebuff_core/tests/__init__.py +1 -0
  84. codebuff_core/tests/conftest.py +81 -0
  85. codebuff_core/tests/test_error_recovery.py +647 -0
  86. codebuff_core/tests/test_factory.py +135 -0
  87. codebuff_core/tests/test_services.py +150 -0
  88. jupyter_ext/__init__.py +266 -0
  89. jupyter_ext/_version.py +4 -0
  90. jupyter_ext/agent/__init__.py +49 -0
  91. jupyter_ext/agent/agent_factory.py +2270 -0
  92. jupyter_ext/agent/ast_tools.py +451 -0
  93. jupyter_ext/agent/autofix_middleware.py +481 -0
  94. jupyter_ext/agent/background_procs.py +372 -0
  95. jupyter_ext/agent/code_history_middleware.py +211 -0
  96. jupyter_ext/agent/codex_autofix.py +160 -0
  97. jupyter_ext/agent/codex_bridge.py +3339 -0
  98. jupyter_ext/agent/codex_hooks.py +320 -0
  99. jupyter_ext/agent/codex_slash.py +685 -0
  100. jupyter_ext/agent/codex_threads.py +114 -0
  101. jupyter_ext/agent/content_injection.py +377 -0
  102. jupyter_ext/agent/continuation_middleware.py +548 -0
  103. jupyter_ext/agent/custom_skills.py +335 -0
  104. jupyter_ext/agent/file_diffs.py +99 -0
  105. jupyter_ext/agent/git_history.py +188 -0
  106. jupyter_ext/agent/guardrail_middleware.py +421 -0
  107. jupyter_ext/agent/json_repair_utils.py +54 -0
  108. jupyter_ext/agent/langchain_tools.py +2673 -0
  109. jupyter_ext/agent/mermaid_fixer.py +289 -0
  110. jupyter_ext/agent/mermaid_middleware.py +135 -0
  111. jupyter_ext/agent/middleware.py +359 -0
  112. jupyter_ext/agent/middleware_prompts.py +53 -0
  113. jupyter_ext/agent/observability.py +334 -0
  114. jupyter_ext/agent/patch_tool_calls.py +57 -0
  115. jupyter_ext/agent/prompts.py +112 -0
  116. jupyter_ext/agent/skill_middleware.py +257 -0
  117. jupyter_ext/agent/skills/airflow_dag_development.md +36 -0
  118. jupyter_ext/agent/skills/anomaly_detection.md +12 -0
  119. jupyter_ext/agent/skills/athena_sql.md +156 -0
  120. jupyter_ext/agent/skills/bdp_table_search.md +33 -0
  121. jupyter_ext/agent/skills/bigquery.md +65 -0
  122. jupyter_ext/agent/skills/bigquery_oracle.md +231 -0
  123. jupyter_ext/agent/skills/bigquery_tuning.md +307 -0
  124. jupyter_ext/agent/skills/classification_evaluation.md +11 -0
  125. jupyter_ext/agent/skills/clustering_analysis.md +12 -0
  126. jupyter_ext/agent/skills/comprehensive_eda.md +11 -0
  127. jupyter_ext/agent/skills/data_analysis.md +236 -0
  128. jupyter_ext/agent/skills/data_cleaning_pipeline.md +12 -0
  129. jupyter_ext/agent/skills/data_loading.md +158 -0
  130. jupyter_ext/agent/skills/data_quality_report.md +13 -0
  131. jupyter_ext/agent/skills/dimensionality_reduction.md +12 -0
  132. jupyter_ext/agent/skills/emr_script_development.md +17 -0
  133. jupyter_ext/agent/skills/experiment_tracking.md +13 -0
  134. jupyter_ext/agent/skills/feature_importance_analysis.md +10 -0
  135. jupyter_ext/agent/skills/hyperparameter_tuning.md +12 -0
  136. jupyter_ext/agent/skills/hypothesis_testing.md +12 -0
  137. jupyter_ext/agent/skills/imbalanced_data_handling.md +12 -0
  138. jupyter_ext/agent/skills/inference.md +392 -0
  139. jupyter_ext/agent/skills/lambda_function_development.md +19 -0
  140. jupyter_ext/agent/skills/model_comparison.md +11 -0
  141. jupyter_ext/agent/skills/model_explainability.md +12 -0
  142. jupyter_ext/agent/skills/model_training.md +318 -0
  143. jupyter_ext/agent/skills/pyspark.md +352 -0
  144. jupyter_ext/agent/skills/python_code_quality.md +35 -0
  145. jupyter_ext/agent/skills/regression_evaluation.md +12 -0
  146. jupyter_ext/agent/skills/spring_java_development.md +35 -0
  147. jupyter_ext/agent/skills/text_preprocessing.md +12 -0
  148. jupyter_ext/agent/skills/time_series_analysis.md +13 -0
  149. jupyter_ext/agent/skills/unit_testing.md +203 -0
  150. jupyter_ext/agent/todo_prompts.py +57 -0
  151. jupyter_ext/agent/tool_report.py +45 -0
  152. jupyter_ext/analytics_ingest.py +599 -0
  153. jupyter_ext/etc/jupyter/jupyter_server_config.d/codebuff_agent.json +7 -0
  154. jupyter_ext/handlers/__init__.py +8 -0
  155. jupyter_ext/handlers/analytics_handler.py +170 -0
  156. jupyter_ext/handlers/benchmark_handler.py +794 -0
  157. jupyter_ext/handlers/eda_benchmark_handler.py +1328 -0
  158. jupyter_ext/handlers/rag_admin_handler.py +689 -0
  159. jupyter_ext/handlers/websocket.py +497 -0
  160. jupyter_ext/http_handlers.py +8744 -0
  161. jupyter_ext/idle_monitor.py +346 -0
  162. jupyter_ext/labextension/package.json +157 -0
  163. jupyter_ext/labextension/static/104.2b8f20f9d1ac2c9db01b.js +1 -0
  164. jupyter_ext/labextension/static/150.39fa98117cc8ca590465.js +1 -0
  165. jupyter_ext/labextension/static/166.386ff9b2c37ac865fdee.js +1 -0
  166. jupyter_ext/labextension/static/216.25cf81131bf7274dabf4.js +1 -0
  167. jupyter_ext/labextension/static/353.581bd1cb00746399b62e.js +1 -0
  168. jupyter_ext/labextension/static/367.575f9621b63c9a641aa9.js +1 -0
  169. jupyter_ext/labextension/static/421.11dac223a2c2da1b09f5.js +1 -0
  170. jupyter_ext/labextension/static/432.8513b4c6cc1d1232d165.js +2 -0
  171. jupyter_ext/labextension/static/432.8513b4c6cc1d1232d165.js.LICENSE.txt +19 -0
  172. jupyter_ext/labextension/static/439.ba5b5ef70ec6de214b8c.js +2 -0
  173. jupyter_ext/labextension/static/439.ba5b5ef70ec6de214b8c.js.LICENSE.txt +8 -0
  174. jupyter_ext/labextension/static/481.cc2dec9fa869d66f1407.js +1 -0
  175. jupyter_ext/labextension/static/487.0796e931d6e651482c14.js +1 -0
  176. jupyter_ext/labextension/static/49.d326f554b6f9ccde6580.js +1 -0
  177. jupyter_ext/labextension/static/541.26897ea32845659e36be.js +1 -0
  178. jupyter_ext/labextension/static/579.e569d3edd8391fd8fbb3.js +1 -0
  179. jupyter_ext/labextension/static/58.eb7cc679f7535cc8a2f1.js +2 -0
  180. jupyter_ext/labextension/static/58.eb7cc679f7535cc8a2f1.js.LICENSE.txt +8 -0
  181. jupyter_ext/labextension/static/666.d9bfdb23f98489d0a188.js +1 -0
  182. jupyter_ext/labextension/static/677.d266c39dbed33bc388b3.js +2 -0
  183. jupyter_ext/labextension/static/677.d266c39dbed33bc388b3.js.LICENSE.txt +8 -0
  184. jupyter_ext/labextension/static/68.26b6f59c8454adb17f20.js +204 -0
  185. jupyter_ext/labextension/static/694.4ac443814260057e68f7.js +1 -0
  186. jupyter_ext/labextension/static/791.61affb8d3480d3d60e0d.js +1 -0
  187. jupyter_ext/labextension/static/848.4d2db09cfbb09374b299.js +2 -0
  188. jupyter_ext/labextension/static/848.4d2db09cfbb09374b299.js.LICENSE.txt +9 -0
  189. jupyter_ext/labextension/static/868.5cfe7e1a348ec5af1b8c.js +1 -0
  190. jupyter_ext/labextension/static/97.ea559a5b8a9a09f17c6b.js +1 -0
  191. jupyter_ext/labextension/static/remoteEntry.5292fc9c6df7e7920cc8.js +1 -0
  192. jupyter_ext/labextension/static/style.js +4 -0
  193. jupyter_ext/labextension/static/third-party-licenses.json +724 -0
  194. jupyter_ext/log_paths.py +113 -0
  195. jupyter_ext/resource_usage.py +519 -0
  196. jupyter_ext/secrets_bootstrap.py +116 -0
  197. jupyter_ext/team_access.py +105 -0
  198. jupyter_ext/tests/__init__.py +1 -0
  199. jupyter_ext/tests/test_context.py +234 -0
  200. jupyter_ext/tests/test_factory.py +563 -0
  201. jupyter_ext/tests/test_file_finder.py +139 -0
  202. jupyter_ext/tests/test_handlers.py +58 -0
  203. jupyter_ext/tests/test_mcp_selftest.py +204 -0
  204. jupyter_ext/tests/test_mermaid_fixer.py +272 -0
  205. jupyter_ext/tests/test_resource_tiers.py +298 -0
  206. jupyter_ext/tools/__init__.py +15 -0
  207. jupyter_ext/tools/base.py +90 -0
  208. jupyter_ext/tools/context.py +268 -0
  209. jupyter_ext/tools/dir_complete.py +86 -0
  210. jupyter_ext/tools/file_finder.py +303 -0
  211. jupyter_ext/tools/file_tools.py +244 -0
  212. jupyter_ext/tools/jupyter_tools.py +296 -0
  213. jupyter_ext/tools/registry.py +159 -0
  214. jupyter_ext/tools/search_tools.py +230 -0
  215. jupyter_ext/tools/security_tools.py +657 -0
  216. jupyter_ext/tools/shell_tools.py +109 -0
  217. jupyter_ext/tools/user_tools.py +132 -0
@@ -0,0 +1,30 @@
1
+ """
2
+ Codebuff Core - Service Implementations
3
+ """
4
+
5
+ from .agent_service import EmbeddedAgentService
6
+ from .chat_service import EmbeddedChatService
7
+ from .rag_service import EmbeddedRAGService
8
+
9
+ __all__ = [
10
+ "EmbeddedAgentService",
11
+ "EmbeddedChatService",
12
+ "EmbeddedRAGService",
13
+ ]
14
+
15
+
16
+ # Lazy imports for RAG subsystem (heavy dependencies)
17
+ def __getattr__(name):
18
+ if name == "RAGManager":
19
+ from .rag_manager import RAGManager
20
+
21
+ return RAGManager
22
+ if name == "get_rag_manager":
23
+ from .rag_manager import get_rag_manager
24
+
25
+ return get_rag_manager
26
+ if name == "CodeValidator":
27
+ from codebuff_core.core.code_validator import CodeValidator
28
+
29
+ return CodeValidator
30
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,345 @@
1
+ """
2
+ 에이전트 서비스 구현
3
+
4
+ IAgentService의 Embedded 구현.
5
+ """
6
+
7
+ import json
8
+ import logging
9
+ import re
10
+ import subprocess
11
+ from typing import Any, Dict, List, Optional
12
+
13
+ from codebuff_core.interfaces import IAgentService
14
+ from codebuff_core.llm import LLMService
15
+ from codebuff_core.managers import get_config_manager
16
+ from codebuff_core.models.agent import (
17
+ PlanRequest,
18
+ PlanResponse,
19
+ RefineRequest,
20
+ RefineResponse,
21
+ ReplanRequest,
22
+ ReplanResponse,
23
+ )
24
+ from codebuff_core.platform_rules import platform_rules_block
25
+ from codebuff_core.prompts import format_plan_prompt, format_refine_prompt
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ class EmbeddedAgentService(IAgentService):
31
+ """
32
+ 에이전트 서비스 구현.
33
+
34
+ 인프로세스에서 직접 에이전트 로직을 실행합니다.
35
+ """
36
+
37
+ def __init__(self):
38
+ """Embedded 에이전트 서비스 초기화"""
39
+ self._config_manager = get_config_manager()
40
+ logger.info("EmbeddedAgentService 초기화됨")
41
+
42
+ def _get_config(self) -> Dict[str, Any]:
43
+ """현재 LLM 설정 반환"""
44
+ return self._config_manager.get_config()
45
+
46
+ def _build_llm_config(self, llm_config) -> Dict[str, Any]:
47
+ """LLM 설정 — 서버가 해석한 값만 쓴다 (이슈 #113). 인자는 호출부 호환용이다."""
48
+ return self._get_config()
49
+
50
+ async def _call_llm(self, prompt: str, llm_config=None) -> str:
51
+ """프롬프트로 LLM 호출"""
52
+ config = self._build_llm_config(llm_config)
53
+ llm_service = LLMService(config)
54
+ # 사내 BDP 규칙은 앞에 둔다 — JSON 응답 형식 지시가 끝에 남아야 한다 (이슈 #120)
55
+ rules = platform_rules_block()
56
+ if rules:
57
+ prompt = rules + "\n\n" + prompt
58
+ return await llm_service.generate_response(prompt)
59
+
60
+ def _parse_json_response(self, response: str) -> Dict[str, Any]:
61
+ """LLM 응답에서 JSON 추출"""
62
+ try:
63
+ return json.loads(response)
64
+ except json.JSONDecodeError:
65
+ pass
66
+
67
+ json_patterns = [
68
+ r"```json\s*([\s\S]*?)\s*```",
69
+ r"```\s*([\s\S]*?)\s*```",
70
+ r"\{[\s\S]*\}",
71
+ ]
72
+
73
+ for pattern in json_patterns:
74
+ matches = re.findall(pattern, response)
75
+ for match in matches:
76
+ try:
77
+ return json.loads(match)
78
+ except json.JSONDecodeError:
79
+ continue
80
+
81
+ return {}
82
+
83
+ def _sanitize_tool_calls(self, data: Dict[str, Any]) -> Dict[str, Any]:
84
+ """도구 호출의 code 매개변수에서 마크다운 코드 블록 제거"""
85
+
86
+ def clean_code(code: str) -> str:
87
+ if not code:
88
+ return code
89
+ code = re.sub(r"^```(?:python)?\s*\n?", "", code)
90
+ code = re.sub(r"\n?```\s*$", "", code)
91
+ return code.strip()
92
+
93
+ if "plan" in data and "steps" in data["plan"]:
94
+ for step in data["plan"]["steps"]:
95
+ for tc in step.get("toolCalls", []):
96
+ if tc.get("tool") == "jupyter_cell":
97
+ params = tc.get("parameters", {})
98
+ if "code" in params:
99
+ params["code"] = clean_code(params["code"])
100
+
101
+ if "toolCalls" in data:
102
+ for tc in data["toolCalls"]:
103
+ if tc.get("tool") == "jupyter_cell":
104
+ params = tc.get("parameters", {})
105
+ if "code" in params:
106
+ params["code"] = clean_code(params["code"])
107
+
108
+ return data
109
+
110
+ def _detect_required_libraries(
111
+ self, request: str, imported_libraries: List[str]
112
+ ) -> List[str]:
113
+ """결정론적 라이브러리 감지"""
114
+ from codebuff_core.knowledge import get_knowledge_base, get_library_detector
115
+
116
+ knowledge_base = get_knowledge_base()
117
+ library_detector = get_library_detector()
118
+
119
+ available = knowledge_base.list_available_libraries()
120
+ if not available:
121
+ return []
122
+
123
+ return library_detector.detect(
124
+ request=request,
125
+ available_libraries=available,
126
+ imported_libraries=imported_libraries,
127
+ )
128
+
129
+ def _get_installed_packages(self) -> List[str]:
130
+ """설치된 Python 패키지 목록 반환"""
131
+ try:
132
+ result = subprocess.run(
133
+ ["pip", "list", "--format=freeze"],
134
+ capture_output=True,
135
+ text=True,
136
+ timeout=10,
137
+ )
138
+ packages = []
139
+ for line in result.stdout.strip().split("\n"):
140
+ if "==" in line:
141
+ packages.append(line.split("==")[0].lower())
142
+ return packages[:100]
143
+ except Exception:
144
+ return []
145
+
146
+ async def generate_plan(self, request: PlanRequest) -> PlanResponse:
147
+ """실행 계획 생성"""
148
+ logger.info(f"[Embedded] 계획 생성: {request.request[:100]}...")
149
+
150
+ imported_libs = request.notebookContext.importedLibraries
151
+ detected_libraries = self._detect_required_libraries(
152
+ request.request, imported_libs
153
+ )
154
+ logger.info(f"감지된 라이브러리: {detected_libraries}")
155
+
156
+ # 가능한 경우 RAG 컨텍스트 가져오기
157
+ rag_context = None
158
+ try:
159
+ from codebuff_core.factory import get_service_factory
160
+
161
+ rag_service = get_service_factory().get_rag_service()
162
+ if rag_service.is_ready():
163
+ rag_context = await rag_service.get_context_for_query(
164
+ query=request.request, detected_libraries=detected_libraries
165
+ )
166
+ except Exception as e:
167
+ logger.warning(f"RAG 컨텍스트 조회 실패: {e}")
168
+
169
+ # 프롬프트 구성
170
+ prompt = format_plan_prompt(
171
+ request=request.request,
172
+ cell_count=request.notebookContext.cellCount,
173
+ imported_libraries=imported_libs,
174
+ defined_variables=request.notebookContext.definedVariables,
175
+ recent_cells=request.notebookContext.recentCells,
176
+ available_libraries=self._get_installed_packages(),
177
+ detected_libraries=detected_libraries,
178
+ rag_context=rag_context,
179
+ )
180
+
181
+ # LLM 호출
182
+ response = await self._call_llm(prompt, request.llmConfig)
183
+ logger.info(f"LLM 응답 길이: {len(response)}")
184
+
185
+ # 응답 파싱
186
+ plan_data = self._parse_json_response(response)
187
+
188
+ if not plan_data or "plan" not in plan_data:
189
+ raise ValueError(f"LLM 응답에서 계획 파싱 실패: {response[:200]}")
190
+
191
+ # 정리 및 goal 보장
192
+ plan_data = self._sanitize_tool_calls(plan_data)
193
+ if "goal" not in plan_data["plan"]:
194
+ plan_data["plan"]["goal"] = request.request
195
+
196
+ return PlanResponse(
197
+ plan=plan_data["plan"],
198
+ reasoning=plan_data.get("reasoning", ""),
199
+ )
200
+
201
+ async def refine_code(self, request: RefineRequest) -> RefineResponse:
202
+ """오류 발생 후 코드 개선"""
203
+ logger.info(f"[Embedded] 코드 개선: 시도 {request.attempt}")
204
+
205
+ # 이전 코드 추출
206
+ previous_code = request.previousCode or ""
207
+ if not previous_code and request.step.get("toolCalls"):
208
+ for tc in request.step["toolCalls"]:
209
+ if tc.get("tool") == "jupyter_cell":
210
+ previous_code = tc.get("parameters", {}).get("code", "")
211
+ break
212
+
213
+ # 트레이스백 처리
214
+ traceback_data = request.error.traceback or []
215
+ traceback_str = (
216
+ "\n".join(traceback_data)
217
+ if isinstance(traceback_data, list)
218
+ else str(traceback_data)
219
+ )
220
+
221
+ # 프롬프트 구성
222
+ prompt = format_refine_prompt(
223
+ original_code=previous_code,
224
+ error_type=request.error.type,
225
+ error_message=request.error.message,
226
+ traceback=traceback_str,
227
+ attempt=request.attempt,
228
+ max_attempts=3,
229
+ available_libraries=self._get_installed_packages(),
230
+ defined_variables=[],
231
+ )
232
+
233
+ # LLM 호출
234
+ response = await self._call_llm(prompt, request.llmConfig)
235
+
236
+ # 응답 파싱
237
+ refine_data = self._parse_json_response(response)
238
+
239
+ if not refine_data or "toolCalls" not in refine_data:
240
+ # 코드 직접 추출 시도
241
+ code_match = re.search(r"```(?:python)?\s*([\s\S]*?)\s*```", response)
242
+ if code_match:
243
+ refine_data = {
244
+ "toolCalls": [
245
+ {
246
+ "tool": "jupyter_cell",
247
+ "parameters": {"code": code_match.group(1).strip()},
248
+ }
249
+ ],
250
+ "reasoning": "",
251
+ }
252
+ else:
253
+ raise ValueError("개선된 코드 생성 실패")
254
+
255
+ refine_data = self._sanitize_tool_calls(refine_data)
256
+
257
+ return RefineResponse(
258
+ toolCalls=refine_data["toolCalls"],
259
+ reasoning=refine_data.get("reasoning", ""),
260
+ )
261
+
262
+ async def replan(self, request: ReplanRequest) -> ReplanResponse:
263
+ """실패한 단계 처리 방법 결정"""
264
+ logger.info(
265
+ f"[Embedded] 단계 {request.currentStepIndex} 재계획 "
266
+ f"(시도: {request.previousAttempts})"
267
+ )
268
+
269
+ # 결정론적 분류를 위해 오류 분류기 사용
270
+ try:
271
+ from codebuff_core.managers.error_classifier import get_error_classifier
272
+
273
+ classifier = get_error_classifier()
274
+ except ImportError:
275
+ # error_classifier가 아직 마이그레이션되지 않은 경우 폴백
276
+ logger.warning("오류 분류기 사용 불가, 단순 휴리스틱 사용")
277
+ return ReplanResponse(
278
+ decision="refine",
279
+ analysis={
280
+ "root_cause": "오류 발생",
281
+ "is_approach_problem": False,
282
+ "missing_prerequisites": [],
283
+ },
284
+ reasoning="오류 분류기 사용 불가",
285
+ changes={},
286
+ usedLlm=False,
287
+ confidence=0.5,
288
+ )
289
+
290
+ traceback_data = request.error.traceback or []
291
+ traceback_str = (
292
+ "\n".join(traceback_data)
293
+ if isinstance(traceback_data, list)
294
+ else str(traceback_data)
295
+ )
296
+
297
+ analysis = classifier.classify(
298
+ error_type=request.error.type,
299
+ error_message=request.error.message,
300
+ traceback=traceback_str,
301
+ )
302
+
303
+ return ReplanResponse(
304
+ decision=analysis.decision.value,
305
+ analysis=analysis.to_dict()["analysis"],
306
+ reasoning=analysis.reasoning,
307
+ changes=analysis.changes,
308
+ usedLlm=analysis.used_llm,
309
+ confidence=analysis.confidence,
310
+ )
311
+
312
+ async def validate_code(
313
+ self, code: str, notebook_context: Optional[Dict] = None
314
+ ) -> Dict[str, Any]:
315
+ """실행 전 코드 검증"""
316
+ logger.info(f"[Embedded] 코드 검증: {len(code)} 문자")
317
+
318
+ try:
319
+ from codebuff_core.managers.code_validator import CodeValidator
320
+
321
+ notebook_ctx = notebook_context or {}
322
+ validator = CodeValidator(notebook_context=notebook_ctx)
323
+ result = validator.full_validation(code)
324
+
325
+ return {
326
+ "valid": result.is_valid,
327
+ "issues": [issue.to_dict() for issue in result.issues],
328
+ "dependencies": result.dependencies.to_dict()
329
+ if result.dependencies
330
+ else None,
331
+ "hasErrors": result.has_errors,
332
+ "hasWarnings": result.has_warnings,
333
+ "summary": result.summary,
334
+ }
335
+ except ImportError:
336
+ # code_validator가 아직 마이그레이션되지 않은 경우 폴백
337
+ logger.warning("코드 검증기 사용 불가")
338
+ return {
339
+ "valid": True,
340
+ "issues": [],
341
+ "dependencies": None,
342
+ "hasErrors": False,
343
+ "hasWarnings": False,
344
+ "summary": "검증 건너뜀 (검증기 사용 불가)",
345
+ }