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.
- codebuff_agent-2.1.74.data/data/etc/jupyter/jupyter_server_config.d/codebuff_agent.json +7 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/package.json +157 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/104.2b8f20f9d1ac2c9db01b.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/150.39fa98117cc8ca590465.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/166.386ff9b2c37ac865fdee.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/216.25cf81131bf7274dabf4.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/353.581bd1cb00746399b62e.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/367.575f9621b63c9a641aa9.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/421.11dac223a2c2da1b09f5.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/432.8513b4c6cc1d1232d165.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/432.8513b4c6cc1d1232d165.js.LICENSE.txt +19 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/439.ba5b5ef70ec6de214b8c.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/439.ba5b5ef70ec6de214b8c.js.LICENSE.txt +8 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/481.cc2dec9fa869d66f1407.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/487.0796e931d6e651482c14.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/49.d326f554b6f9ccde6580.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/541.26897ea32845659e36be.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/579.e569d3edd8391fd8fbb3.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/58.eb7cc679f7535cc8a2f1.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/58.eb7cc679f7535cc8a2f1.js.LICENSE.txt +8 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/666.d9bfdb23f98489d0a188.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/677.d266c39dbed33bc388b3.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/677.d266c39dbed33bc388b3.js.LICENSE.txt +8 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/68.26b6f59c8454adb17f20.js +204 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/694.4ac443814260057e68f7.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/791.61affb8d3480d3d60e0d.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/848.4d2db09cfbb09374b299.js +2 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/848.4d2db09cfbb09374b299.js.LICENSE.txt +9 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/868.5cfe7e1a348ec5af1b8c.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/97.ea559a5b8a9a09f17c6b.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/remoteEntry.5292fc9c6df7e7920cc8.js +1 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/style.js +4 -0
- codebuff_agent-2.1.74.data/data/share/jupyter/labextensions/codebuff/static/third-party-licenses.json +724 -0
- codebuff_agent-2.1.74.dist-info/METADATA +142 -0
- codebuff_agent-2.1.74.dist-info/RECORD +217 -0
- codebuff_agent-2.1.74.dist-info/WHEEL +4 -0
- codebuff_agent-2.1.74.dist-info/licenses/LICENSE +21 -0
- codebuff_core/__init__.py +153 -0
- codebuff_core/codebuff_config_defaults.json +64 -0
- codebuff_core/core/__init__.py +35 -0
- codebuff_core/core/code_validator.py +1238 -0
- codebuff_core/core/error_classifier.py +579 -0
- codebuff_core/core/exceptions.py +49 -0
- codebuff_core/data/tiktoken_cache/9b5ad71b2ce5302211f9c61530b329a4922fc6a4 +100256 -0
- codebuff_core/directory_policy.py +32 -0
- codebuff_core/factory.py +155 -0
- codebuff_core/interfaces.py +197 -0
- codebuff_core/knowledge/__init__.py +31 -0
- codebuff_core/knowledge/chunking.py +375 -0
- codebuff_core/knowledge/loader.py +339 -0
- codebuff_core/knowledge/watchdog_service.py +354 -0
- codebuff_core/legacy_paths.py +69 -0
- codebuff_core/llm/__init__.py +13 -0
- codebuff_core/llm/service.py +407 -0
- codebuff_core/managers/__init__.py +22 -0
- codebuff_core/managers/config_manager.py +690 -0
- codebuff_core/managers/remote_config.py +673 -0
- codebuff_core/managers/remote_skills.py +539 -0
- codebuff_core/managers/session_manager.py +255 -0
- codebuff_core/middleware/__init__.py +3 -0
- codebuff_core/middleware/error_recovery.py +394 -0
- codebuff_core/middleware/logging_utils.py +33 -0
- codebuff_core/models/__init__.py +111 -0
- codebuff_core/models/agent.py +306 -0
- codebuff_core/models/chat.py +57 -0
- codebuff_core/models/common.py +82 -0
- codebuff_core/models/rag.py +300 -0
- codebuff_core/platform_rules.py +127 -0
- codebuff_core/prompts/__init__.py +44 -0
- codebuff_core/prompts/auto_agent_prompts.py +1278 -0
- codebuff_core/services/__init__.py +30 -0
- codebuff_core/services/agent_service.py +345 -0
- codebuff_core/services/analytics_aggregate.py +837 -0
- codebuff_core/services/chat_service.py +898 -0
- codebuff_core/services/context_condenser.py +306 -0
- codebuff_core/services/pii_guardrail.py +393 -0
- codebuff_core/services/rag_chat_agent.py +2993 -0
- codebuff_core/services/rag_collections.py +2740 -0
- codebuff_core/services/rag_manager.py +890 -0
- codebuff_core/services/rag_service.py +145 -0
- codebuff_core/services/retriever.py +260 -0
- codebuff_core/services/vllm_embedding_service.py +290 -0
- codebuff_core/tests/__init__.py +1 -0
- codebuff_core/tests/conftest.py +81 -0
- codebuff_core/tests/test_error_recovery.py +647 -0
- codebuff_core/tests/test_factory.py +135 -0
- codebuff_core/tests/test_services.py +150 -0
- jupyter_ext/__init__.py +266 -0
- jupyter_ext/_version.py +4 -0
- jupyter_ext/agent/__init__.py +49 -0
- jupyter_ext/agent/agent_factory.py +2270 -0
- jupyter_ext/agent/ast_tools.py +451 -0
- jupyter_ext/agent/autofix_middleware.py +481 -0
- jupyter_ext/agent/background_procs.py +372 -0
- jupyter_ext/agent/code_history_middleware.py +211 -0
- jupyter_ext/agent/codex_autofix.py +160 -0
- jupyter_ext/agent/codex_bridge.py +3339 -0
- jupyter_ext/agent/codex_hooks.py +320 -0
- jupyter_ext/agent/codex_slash.py +685 -0
- jupyter_ext/agent/codex_threads.py +114 -0
- jupyter_ext/agent/content_injection.py +377 -0
- jupyter_ext/agent/continuation_middleware.py +548 -0
- jupyter_ext/agent/custom_skills.py +335 -0
- jupyter_ext/agent/file_diffs.py +99 -0
- jupyter_ext/agent/git_history.py +188 -0
- jupyter_ext/agent/guardrail_middleware.py +421 -0
- jupyter_ext/agent/json_repair_utils.py +54 -0
- jupyter_ext/agent/langchain_tools.py +2673 -0
- jupyter_ext/agent/mermaid_fixer.py +289 -0
- jupyter_ext/agent/mermaid_middleware.py +135 -0
- jupyter_ext/agent/middleware.py +359 -0
- jupyter_ext/agent/middleware_prompts.py +53 -0
- jupyter_ext/agent/observability.py +334 -0
- jupyter_ext/agent/patch_tool_calls.py +57 -0
- jupyter_ext/agent/prompts.py +112 -0
- jupyter_ext/agent/skill_middleware.py +257 -0
- jupyter_ext/agent/skills/airflow_dag_development.md +36 -0
- jupyter_ext/agent/skills/anomaly_detection.md +12 -0
- jupyter_ext/agent/skills/athena_sql.md +156 -0
- jupyter_ext/agent/skills/bdp_table_search.md +33 -0
- jupyter_ext/agent/skills/bigquery.md +65 -0
- jupyter_ext/agent/skills/bigquery_oracle.md +231 -0
- jupyter_ext/agent/skills/bigquery_tuning.md +307 -0
- jupyter_ext/agent/skills/classification_evaluation.md +11 -0
- jupyter_ext/agent/skills/clustering_analysis.md +12 -0
- jupyter_ext/agent/skills/comprehensive_eda.md +11 -0
- jupyter_ext/agent/skills/data_analysis.md +236 -0
- jupyter_ext/agent/skills/data_cleaning_pipeline.md +12 -0
- jupyter_ext/agent/skills/data_loading.md +158 -0
- jupyter_ext/agent/skills/data_quality_report.md +13 -0
- jupyter_ext/agent/skills/dimensionality_reduction.md +12 -0
- jupyter_ext/agent/skills/emr_script_development.md +17 -0
- jupyter_ext/agent/skills/experiment_tracking.md +13 -0
- jupyter_ext/agent/skills/feature_importance_analysis.md +10 -0
- jupyter_ext/agent/skills/hyperparameter_tuning.md +12 -0
- jupyter_ext/agent/skills/hypothesis_testing.md +12 -0
- jupyter_ext/agent/skills/imbalanced_data_handling.md +12 -0
- jupyter_ext/agent/skills/inference.md +392 -0
- jupyter_ext/agent/skills/lambda_function_development.md +19 -0
- jupyter_ext/agent/skills/model_comparison.md +11 -0
- jupyter_ext/agent/skills/model_explainability.md +12 -0
- jupyter_ext/agent/skills/model_training.md +318 -0
- jupyter_ext/agent/skills/pyspark.md +352 -0
- jupyter_ext/agent/skills/python_code_quality.md +35 -0
- jupyter_ext/agent/skills/regression_evaluation.md +12 -0
- jupyter_ext/agent/skills/spring_java_development.md +35 -0
- jupyter_ext/agent/skills/text_preprocessing.md +12 -0
- jupyter_ext/agent/skills/time_series_analysis.md +13 -0
- jupyter_ext/agent/skills/unit_testing.md +203 -0
- jupyter_ext/agent/todo_prompts.py +57 -0
- jupyter_ext/agent/tool_report.py +45 -0
- jupyter_ext/analytics_ingest.py +599 -0
- jupyter_ext/etc/jupyter/jupyter_server_config.d/codebuff_agent.json +7 -0
- jupyter_ext/handlers/__init__.py +8 -0
- jupyter_ext/handlers/analytics_handler.py +170 -0
- jupyter_ext/handlers/benchmark_handler.py +794 -0
- jupyter_ext/handlers/eda_benchmark_handler.py +1328 -0
- jupyter_ext/handlers/rag_admin_handler.py +689 -0
- jupyter_ext/handlers/websocket.py +497 -0
- jupyter_ext/http_handlers.py +8744 -0
- jupyter_ext/idle_monitor.py +346 -0
- jupyter_ext/labextension/package.json +157 -0
- jupyter_ext/labextension/static/104.2b8f20f9d1ac2c9db01b.js +1 -0
- jupyter_ext/labextension/static/150.39fa98117cc8ca590465.js +1 -0
- jupyter_ext/labextension/static/166.386ff9b2c37ac865fdee.js +1 -0
- jupyter_ext/labextension/static/216.25cf81131bf7274dabf4.js +1 -0
- jupyter_ext/labextension/static/353.581bd1cb00746399b62e.js +1 -0
- jupyter_ext/labextension/static/367.575f9621b63c9a641aa9.js +1 -0
- jupyter_ext/labextension/static/421.11dac223a2c2da1b09f5.js +1 -0
- jupyter_ext/labextension/static/432.8513b4c6cc1d1232d165.js +2 -0
- jupyter_ext/labextension/static/432.8513b4c6cc1d1232d165.js.LICENSE.txt +19 -0
- jupyter_ext/labextension/static/439.ba5b5ef70ec6de214b8c.js +2 -0
- jupyter_ext/labextension/static/439.ba5b5ef70ec6de214b8c.js.LICENSE.txt +8 -0
- jupyter_ext/labextension/static/481.cc2dec9fa869d66f1407.js +1 -0
- jupyter_ext/labextension/static/487.0796e931d6e651482c14.js +1 -0
- jupyter_ext/labextension/static/49.d326f554b6f9ccde6580.js +1 -0
- jupyter_ext/labextension/static/541.26897ea32845659e36be.js +1 -0
- jupyter_ext/labextension/static/579.e569d3edd8391fd8fbb3.js +1 -0
- jupyter_ext/labextension/static/58.eb7cc679f7535cc8a2f1.js +2 -0
- jupyter_ext/labextension/static/58.eb7cc679f7535cc8a2f1.js.LICENSE.txt +8 -0
- jupyter_ext/labextension/static/666.d9bfdb23f98489d0a188.js +1 -0
- jupyter_ext/labextension/static/677.d266c39dbed33bc388b3.js +2 -0
- jupyter_ext/labextension/static/677.d266c39dbed33bc388b3.js.LICENSE.txt +8 -0
- jupyter_ext/labextension/static/68.26b6f59c8454adb17f20.js +204 -0
- jupyter_ext/labextension/static/694.4ac443814260057e68f7.js +1 -0
- jupyter_ext/labextension/static/791.61affb8d3480d3d60e0d.js +1 -0
- jupyter_ext/labextension/static/848.4d2db09cfbb09374b299.js +2 -0
- jupyter_ext/labextension/static/848.4d2db09cfbb09374b299.js.LICENSE.txt +9 -0
- jupyter_ext/labextension/static/868.5cfe7e1a348ec5af1b8c.js +1 -0
- jupyter_ext/labextension/static/97.ea559a5b8a9a09f17c6b.js +1 -0
- jupyter_ext/labextension/static/remoteEntry.5292fc9c6df7e7920cc8.js +1 -0
- jupyter_ext/labextension/static/style.js +4 -0
- jupyter_ext/labextension/static/third-party-licenses.json +724 -0
- jupyter_ext/log_paths.py +113 -0
- jupyter_ext/resource_usage.py +519 -0
- jupyter_ext/secrets_bootstrap.py +116 -0
- jupyter_ext/team_access.py +105 -0
- jupyter_ext/tests/__init__.py +1 -0
- jupyter_ext/tests/test_context.py +234 -0
- jupyter_ext/tests/test_factory.py +563 -0
- jupyter_ext/tests/test_file_finder.py +139 -0
- jupyter_ext/tests/test_handlers.py +58 -0
- jupyter_ext/tests/test_mcp_selftest.py +204 -0
- jupyter_ext/tests/test_mermaid_fixer.py +272 -0
- jupyter_ext/tests/test_resource_tiers.py +298 -0
- jupyter_ext/tools/__init__.py +15 -0
- jupyter_ext/tools/base.py +90 -0
- jupyter_ext/tools/context.py +268 -0
- jupyter_ext/tools/dir_complete.py +86 -0
- jupyter_ext/tools/file_finder.py +303 -0
- jupyter_ext/tools/file_tools.py +244 -0
- jupyter_ext/tools/jupyter_tools.py +296 -0
- jupyter_ext/tools/registry.py +159 -0
- jupyter_ext/tools/search_tools.py +230 -0
- jupyter_ext/tools/security_tools.py +657 -0
- jupyter_ext/tools/shell_tools.py +109 -0
- 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
|
+
}
|