hdsp-jupyter-extension 2.0.8__py3-none-any.whl → 2.0.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent_server/core/notebook_generator.py +4 -4
- agent_server/core/rag_manager.py +12 -3
- agent_server/core/retriever.py +2 -1
- agent_server/core/vllm_embedding_service.py +8 -5
- agent_server/langchain/ARCHITECTURE.md +7 -51
- agent_server/langchain/agent.py +31 -20
- agent_server/langchain/custom_middleware.py +234 -31
- agent_server/langchain/hitl_config.py +5 -8
- agent_server/langchain/logging_utils.py +7 -7
- agent_server/langchain/prompts.py +106 -120
- agent_server/langchain/tools/__init__.py +1 -10
- agent_server/langchain/tools/file_tools.py +9 -61
- agent_server/langchain/tools/jupyter_tools.py +0 -1
- agent_server/langchain/tools/lsp_tools.py +8 -8
- agent_server/langchain/tools/resource_tools.py +12 -12
- agent_server/langchain/tools/search_tools.py +3 -158
- agent_server/prompts/file_action_prompts.py +8 -8
- agent_server/routers/langchain_agent.py +200 -125
- hdsp_agent_core/__init__.py +46 -47
- hdsp_agent_core/factory.py +6 -10
- hdsp_agent_core/interfaces.py +4 -2
- hdsp_agent_core/knowledge/__init__.py +5 -5
- hdsp_agent_core/knowledge/chunking.py +87 -61
- hdsp_agent_core/knowledge/loader.py +103 -101
- hdsp_agent_core/llm/service.py +192 -107
- hdsp_agent_core/managers/config_manager.py +16 -22
- hdsp_agent_core/managers/session_manager.py +5 -4
- hdsp_agent_core/models/__init__.py +12 -12
- hdsp_agent_core/models/agent.py +15 -8
- hdsp_agent_core/models/common.py +1 -2
- hdsp_agent_core/models/rag.py +48 -111
- hdsp_agent_core/prompts/__init__.py +12 -12
- hdsp_agent_core/prompts/cell_action_prompts.py +9 -7
- hdsp_agent_core/services/agent_service.py +10 -8
- hdsp_agent_core/services/chat_service.py +10 -6
- hdsp_agent_core/services/rag_service.py +3 -6
- hdsp_agent_core/tests/conftest.py +4 -1
- hdsp_agent_core/tests/test_factory.py +2 -2
- hdsp_agent_core/tests/test_services.py +12 -19
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/build_log.json +1 -1
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/package.json +2 -2
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.8740a527757068814573.js → hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2d9fb488c82498c45c2d.js +93 -4
- hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2d9fb488c82498c45c2d.js.map +1 -0
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.e4ff4b5779b5e049f84c.js → hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.58c1e128ba0b76f41f04.js +153 -130
- hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.58c1e128ba0b76f41f04.js.map +1 -0
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.020cdb0b864cfaa4e41e.js → hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.9da31d1134a53b0c4af5.js +6 -6
- hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.9da31d1134a53b0c4af5.js.map +1 -0
- {hdsp_jupyter_extension-2.0.8.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/METADATA +1 -3
- hdsp_jupyter_extension-2.0.11.dist-info/RECORD +144 -0
- jupyter_ext/__init__.py +21 -11
- jupyter_ext/_version.py +1 -1
- jupyter_ext/handlers.py +69 -50
- jupyter_ext/labextension/build_log.json +1 -1
- jupyter_ext/labextension/package.json +2 -2
- jupyter_ext/labextension/static/{frontend_styles_index_js.8740a527757068814573.js → frontend_styles_index_js.2d9fb488c82498c45c2d.js} +93 -4
- jupyter_ext/labextension/static/frontend_styles_index_js.2d9fb488c82498c45c2d.js.map +1 -0
- jupyter_ext/labextension/static/{lib_index_js.e4ff4b5779b5e049f84c.js → lib_index_js.58c1e128ba0b76f41f04.js} +153 -130
- jupyter_ext/labextension/static/lib_index_js.58c1e128ba0b76f41f04.js.map +1 -0
- jupyter_ext/labextension/static/{remoteEntry.020cdb0b864cfaa4e41e.js → remoteEntry.9da31d1134a53b0c4af5.js} +6 -6
- jupyter_ext/labextension/static/remoteEntry.9da31d1134a53b0c4af5.js.map +1 -0
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.8740a527757068814573.js.map +0 -1
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.e4ff4b5779b5e049f84c.js.map +0 -1
- hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.020cdb0b864cfaa4e41e.js.map +0 -1
- hdsp_jupyter_extension-2.0.8.dist-info/RECORD +0 -144
- jupyter_ext/labextension/static/frontend_styles_index_js.8740a527757068814573.js.map +0 -1
- jupyter_ext/labextension/static/lib_index_js.e4ff4b5779b5e049f84c.js.map +0 -1
- jupyter_ext/labextension/static/remoteEntry.020cdb0b864cfaa4e41e.js.map +0 -1
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/install.json +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b80.c095373419d05e6f141a.js +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b80.c095373419d05e6f141a.js.map +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b81.61e75fb98ecff46cf836.js +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b81.61e75fb98ecff46cf836.js.map +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/style.js +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_babel_runtime_helpers_esm_extends_js-node_modules_emotion_serialize_dist-051195.e2553aab0c3963b83dd7.js +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_babel_runtime_helpers_esm_extends_js-node_modules_emotion_serialize_dist-051195.e2553aab0c3963b83dd7.js.map +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js.24edcc52a1c014a8a5f0.js +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js.24edcc52a1c014a8a5f0.js.map +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.19ecf6babe00caff6b8a.js +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.19ecf6babe00caff6b8a.js.map +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js.map +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js.map +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.1f5038488cdfd8b3a85d.js +0 -0
- {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.1f5038488cdfd8b3a85d.js.map +0 -0
- {hdsp_jupyter_extension-2.0.8.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/WHEEL +0 -0
- {hdsp_jupyter_extension-2.0.8.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,7 +8,7 @@ import json
|
|
|
8
8
|
import os
|
|
9
9
|
import tempfile
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import
|
|
11
|
+
from typing import Any, Dict
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class ConfigManager:
|
|
@@ -20,13 +20,13 @@ class ConfigManager:
|
|
|
20
20
|
def __init__(self):
|
|
21
21
|
try:
|
|
22
22
|
# 1순위: 환경변수
|
|
23
|
-
jupyter_config_dir = os.environ.get(
|
|
23
|
+
jupyter_config_dir = os.environ.get("JUPYTER_CONFIG_DIR")
|
|
24
24
|
|
|
25
25
|
# 2순위: 홈 디렉토리 ~/.jupyter
|
|
26
26
|
if not jupyter_config_dir:
|
|
27
27
|
# expanduser가 실패할 경우를 대비
|
|
28
28
|
try:
|
|
29
|
-
jupyter_config_dir = os.path.expanduser(
|
|
29
|
+
jupyter_config_dir = os.path.expanduser("~/.jupyter")
|
|
30
30
|
except Exception:
|
|
31
31
|
jupyter_config_dir = None
|
|
32
32
|
|
|
@@ -35,22 +35,22 @@ class ConfigManager:
|
|
|
35
35
|
config_path = Path(jupyter_config_dir)
|
|
36
36
|
try:
|
|
37
37
|
config_path.mkdir(parents=True, exist_ok=True)
|
|
38
|
-
self._config_file = config_path /
|
|
38
|
+
self._config_file = config_path / "hdsp_agent_config.json"
|
|
39
39
|
except Exception as e:
|
|
40
40
|
print(f"Warning: Cannot write to {jupyter_config_dir}: {e}")
|
|
41
41
|
self._config_file = None
|
|
42
42
|
|
|
43
43
|
# 3순위 (비상용): 쓰기 실패했거나 경로가 없으면 /tmp 사용
|
|
44
44
|
if not self._config_file:
|
|
45
|
-
tmp_dir = Path(tempfile.gettempdir()) /
|
|
45
|
+
tmp_dir = Path(tempfile.gettempdir()) / "jupyter_hdsp_agent"
|
|
46
46
|
tmp_dir.mkdir(parents=True, exist_ok=True)
|
|
47
|
-
self._config_file = tmp_dir /
|
|
47
|
+
self._config_file = tmp_dir / "hdsp_agent_config.json"
|
|
48
48
|
print(f"Using temporary config path: {self._config_file}")
|
|
49
49
|
|
|
50
50
|
except Exception as e:
|
|
51
51
|
# 최악의 경우: 메모리에서만 동작하도록 가짜 경로 설정 (서버 다운 방지)
|
|
52
52
|
print(f"Critical Error in ConfigManager init: {e}")
|
|
53
|
-
self._config_file = Path(
|
|
53
|
+
self._config_file = Path("/tmp/hdsp_agent_config_fallback.json")
|
|
54
54
|
|
|
55
55
|
self._config = self._load_config()
|
|
56
56
|
|
|
@@ -72,7 +72,7 @@ class ConfigManager:
|
|
|
72
72
|
return self._default_config()
|
|
73
73
|
|
|
74
74
|
try:
|
|
75
|
-
with open(self._config_file,
|
|
75
|
+
with open(self._config_file, "r") as f:
|
|
76
76
|
return json.load(f)
|
|
77
77
|
except (json.JSONDecodeError, IOError) as e:
|
|
78
78
|
print(f"Error loading config: {e}")
|
|
@@ -81,20 +81,14 @@ class ConfigManager:
|
|
|
81
81
|
def _default_config(self) -> Dict[str, Any]:
|
|
82
82
|
"""Get default configuration"""
|
|
83
83
|
return {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
"provider": "gemini",
|
|
85
|
+
"gemini": {"apiKey": "", "model": "gemini-2.5-pro"},
|
|
86
|
+
"vllm": {
|
|
87
|
+
"endpoint": "http://localhost:8000",
|
|
88
|
+
"apiKey": "",
|
|
89
|
+
"model": "meta-llama/Llama-2-7b-chat-hf",
|
|
88
90
|
},
|
|
89
|
-
|
|
90
|
-
'endpoint': 'http://localhost:8000',
|
|
91
|
-
'apiKey': '',
|
|
92
|
-
'model': 'meta-llama/Llama-2-7b-chat-hf'
|
|
93
|
-
},
|
|
94
|
-
'openai': {
|
|
95
|
-
'apiKey': '',
|
|
96
|
-
'model': 'gpt-4'
|
|
97
|
-
}
|
|
91
|
+
"openai": {"apiKey": "", "model": "gpt-4"},
|
|
98
92
|
}
|
|
99
93
|
|
|
100
94
|
def get_config(self) -> Dict[str, Any]:
|
|
@@ -113,7 +107,7 @@ class ConfigManager:
|
|
|
113
107
|
|
|
114
108
|
# Write to file
|
|
115
109
|
try:
|
|
116
|
-
with open(self._config_file,
|
|
110
|
+
with open(self._config_file, "w") as f:
|
|
117
111
|
json.dump(self._config, f, indent=2)
|
|
118
112
|
except IOError as e:
|
|
119
113
|
raise RuntimeError(f"Failed to save config: {e}")
|
|
@@ -6,12 +6,12 @@ history to survive server restarts.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import json
|
|
9
|
+
import logging
|
|
9
10
|
import uuid
|
|
10
|
-
from
|
|
11
|
-
from dataclasses import dataclass, asdict, field
|
|
12
|
-
from typing import List, Dict, Optional
|
|
11
|
+
from dataclasses import asdict, dataclass, field
|
|
13
12
|
from datetime import datetime
|
|
14
|
-
import
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Dict, List, Optional
|
|
15
15
|
|
|
16
16
|
logger = logging.getLogger(__name__)
|
|
17
17
|
|
|
@@ -193,6 +193,7 @@ class SessionManager:
|
|
|
193
193
|
# Lazy import to avoid circular dependency
|
|
194
194
|
try:
|
|
195
195
|
from hdsp_agent_core.core.context_condenser import get_context_condenser
|
|
196
|
+
|
|
196
197
|
condenser = get_context_condenser()
|
|
197
198
|
msg_dicts = [{"role": m.role, "content": m.content} for m in messages]
|
|
198
199
|
compressed, _stats = condenser.condense(msg_dicts, target_tokens)
|
|
@@ -4,16 +4,6 @@ HDSP Agent Core - Pydantic Models
|
|
|
4
4
|
Shared data models for the HDSP Agent system.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from .common import (
|
|
8
|
-
APIResponse,
|
|
9
|
-
ErrorInfo,
|
|
10
|
-
GeminiConfig,
|
|
11
|
-
LLMConfig,
|
|
12
|
-
NotebookContext,
|
|
13
|
-
OpenAIConfig,
|
|
14
|
-
ToolCall,
|
|
15
|
-
VLLMConfig,
|
|
16
|
-
)
|
|
17
7
|
from .agent import (
|
|
18
8
|
DependencyInfo,
|
|
19
9
|
ExecutionPlan,
|
|
@@ -22,14 +12,14 @@ from .agent import (
|
|
|
22
12
|
PlanStep,
|
|
23
13
|
RefineRequest,
|
|
24
14
|
RefineResponse,
|
|
25
|
-
ReflectRequest,
|
|
26
|
-
ReflectResponse,
|
|
27
15
|
ReflectionAdjustment,
|
|
28
16
|
ReflectionAnalysis,
|
|
29
17
|
ReflectionEvaluation,
|
|
30
18
|
ReflectionImpact,
|
|
31
19
|
ReflectionRecommendations,
|
|
32
20
|
ReflectionResult,
|
|
21
|
+
ReflectRequest,
|
|
22
|
+
ReflectResponse,
|
|
33
23
|
ReplanRequest,
|
|
34
24
|
ReplanResponse,
|
|
35
25
|
ReportExecutionRequest,
|
|
@@ -45,6 +35,16 @@ from .chat import (
|
|
|
45
35
|
ChatResponse,
|
|
46
36
|
StreamChunk,
|
|
47
37
|
)
|
|
38
|
+
from .common import (
|
|
39
|
+
APIResponse,
|
|
40
|
+
ErrorInfo,
|
|
41
|
+
GeminiConfig,
|
|
42
|
+
LLMConfig,
|
|
43
|
+
NotebookContext,
|
|
44
|
+
OpenAIConfig,
|
|
45
|
+
ToolCall,
|
|
46
|
+
VLLMConfig,
|
|
47
|
+
)
|
|
48
48
|
from .rag import (
|
|
49
49
|
ChunkingConfig,
|
|
50
50
|
EmbeddingConfig,
|
hdsp_agent_core/models/agent.py
CHANGED
|
@@ -155,9 +155,7 @@ class ReflectionImpact(BaseModel):
|
|
|
155
155
|
affected_steps: List[int] = Field(
|
|
156
156
|
default_factory=list, description="Step numbers affected"
|
|
157
157
|
)
|
|
158
|
-
severity: str = Field(
|
|
159
|
-
description="Impact severity: none, minor, major, critical"
|
|
160
|
-
)
|
|
158
|
+
severity: str = Field(description="Impact severity: none, minor, major, critical")
|
|
161
159
|
description: str = Field(description="Impact description")
|
|
162
160
|
|
|
163
161
|
|
|
@@ -169,13 +167,17 @@ class ReflectionAdjustment(BaseModel):
|
|
|
169
167
|
description="Change type: modify_code, add_step, remove_step, change_approach"
|
|
170
168
|
)
|
|
171
169
|
description: str = Field(description="Adjustment description")
|
|
172
|
-
new_content: Optional[str] = Field(
|
|
170
|
+
new_content: Optional[str] = Field(
|
|
171
|
+
default=None, description="New content if applicable"
|
|
172
|
+
)
|
|
173
173
|
|
|
174
174
|
|
|
175
175
|
class ReflectionRecommendations(BaseModel):
|
|
176
176
|
"""Reflection recommendations"""
|
|
177
177
|
|
|
178
|
-
action: str = Field(
|
|
178
|
+
action: str = Field(
|
|
179
|
+
description="Recommended action: continue, adjust, retry, replan"
|
|
180
|
+
)
|
|
179
181
|
adjustments: List[ReflectionAdjustment] = Field(
|
|
180
182
|
default_factory=list, description="Specific adjustments"
|
|
181
183
|
)
|
|
@@ -187,7 +189,9 @@ class ReflectionResult(BaseModel):
|
|
|
187
189
|
|
|
188
190
|
evaluation: ReflectionEvaluation = Field(description="Evaluation results")
|
|
189
191
|
analysis: ReflectionAnalysis = Field(description="Analysis details")
|
|
190
|
-
impact_on_remaining: ReflectionImpact = Field(
|
|
192
|
+
impact_on_remaining: ReflectionImpact = Field(
|
|
193
|
+
description="Impact on remaining steps"
|
|
194
|
+
)
|
|
191
195
|
recommendations: ReflectionRecommendations = Field(description="Recommendations")
|
|
192
196
|
|
|
193
197
|
|
|
@@ -199,7 +203,9 @@ class ReflectRequest(BaseModel):
|
|
|
199
203
|
executedCode: str = Field(description="Code that was executed")
|
|
200
204
|
executionStatus: str = Field(description="Execution status (success/error/warning)")
|
|
201
205
|
executionOutput: str = Field(description="Output from execution")
|
|
202
|
-
errorMessage: Optional[str] = Field(
|
|
206
|
+
errorMessage: Optional[str] = Field(
|
|
207
|
+
default=None, description="Error message if any"
|
|
208
|
+
)
|
|
203
209
|
expectedOutcome: Optional[str] = Field(
|
|
204
210
|
default=None, description="Expected outcome description"
|
|
205
211
|
)
|
|
@@ -297,7 +303,8 @@ class ValidateRequest(BaseModel):
|
|
|
297
303
|
|
|
298
304
|
code: str = Field(description="Code to validate")
|
|
299
305
|
notebookContext: Optional[NotebookContext] = Field(
|
|
300
|
-
default=None,
|
|
306
|
+
default=None,
|
|
307
|
+
description="Current notebook context (for variable/import tracking)",
|
|
301
308
|
)
|
|
302
309
|
|
|
303
310
|
|
hdsp_agent_core/models/common.py
CHANGED
|
@@ -60,8 +60,7 @@ class GeminiConfig(BaseModel):
|
|
|
60
60
|
|
|
61
61
|
apiKey: str = Field(description="Primary Gemini API key")
|
|
62
62
|
apiKeys: Optional[List[str]] = Field(
|
|
63
|
-
default=None,
|
|
64
|
-
description="Multiple API keys for rate limit rotation (max 10)"
|
|
63
|
+
default=None, description="Multiple API keys for rate limit rotation (max 10)"
|
|
65
64
|
)
|
|
66
65
|
model: str = Field(default="gemini-2.5-flash", description="Model name")
|
|
67
66
|
|
hdsp_agent_core/models/rag.py
CHANGED
|
@@ -10,7 +10,8 @@ Defines configuration schemas for the Local RAG system including:
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
import os
|
|
13
|
-
from typing import
|
|
13
|
+
from typing import Any, Dict, List, Literal, Optional
|
|
14
|
+
|
|
14
15
|
from pydantic import BaseModel, Field
|
|
15
16
|
|
|
16
17
|
|
|
@@ -19,26 +20,22 @@ class QdrantConfig(BaseModel):
|
|
|
19
20
|
|
|
20
21
|
mode: Literal["local", "server", "cloud"] = Field(
|
|
21
22
|
default="local",
|
|
22
|
-
description="Deployment mode: local (file-based), server (Docker), cloud"
|
|
23
|
+
description="Deployment mode: local (file-based), server (Docker), cloud",
|
|
23
24
|
)
|
|
24
25
|
# Local mode settings
|
|
25
26
|
local_path: Optional[str] = Field(
|
|
26
27
|
default=None,
|
|
27
|
-
description="Path for local Qdrant storage. Defaults to ~/.hdsp_agent/qdrant"
|
|
28
|
+
description="Path for local Qdrant storage. Defaults to ~/.hdsp_agent/qdrant",
|
|
28
29
|
)
|
|
29
30
|
# Server mode settings
|
|
30
31
|
url: Optional[str] = Field(
|
|
31
32
|
default="http://localhost:6333",
|
|
32
|
-
description="Qdrant server URL for server/cloud mode"
|
|
33
|
-
)
|
|
34
|
-
api_key: Optional[str] = Field(
|
|
35
|
-
default=None,
|
|
36
|
-
description="API key for cloud mode"
|
|
33
|
+
description="Qdrant server URL for server/cloud mode",
|
|
37
34
|
)
|
|
35
|
+
api_key: Optional[str] = Field(default=None, description="API key for cloud mode")
|
|
38
36
|
# Collection settings
|
|
39
37
|
collection_name: str = Field(
|
|
40
|
-
default="hdsp_knowledge",
|
|
41
|
-
description="Vector collection name"
|
|
38
|
+
default="hdsp_knowledge", description="Vector collection name"
|
|
42
39
|
)
|
|
43
40
|
|
|
44
41
|
def get_mode(self) -> str:
|
|
@@ -72,24 +69,20 @@ class EmbeddingConfig(BaseModel):
|
|
|
72
69
|
|
|
73
70
|
model_name: str = Field(
|
|
74
71
|
default="intfloat/multilingual-e5-small",
|
|
75
|
-
description="HuggingFace model name for embeddings"
|
|
72
|
+
description="HuggingFace model name for embeddings",
|
|
76
73
|
)
|
|
77
74
|
device: Literal["cpu", "cuda", "mps"] = Field(
|
|
78
|
-
default="cpu",
|
|
79
|
-
description="Device for embedding computation"
|
|
75
|
+
default="cpu", description="Device for embedding computation"
|
|
80
76
|
)
|
|
81
77
|
batch_size: int = Field(
|
|
82
|
-
default=32,
|
|
83
|
-
description="Batch size for embedding generation"
|
|
78
|
+
default=32, description="Batch size for embedding generation"
|
|
84
79
|
)
|
|
85
80
|
cache_folder: Optional[str] = Field(
|
|
86
|
-
default=None,
|
|
87
|
-
description="Model cache folder. Defaults to ~/.cache/huggingface"
|
|
81
|
+
default=None, description="Model cache folder. Defaults to ~/.cache/huggingface"
|
|
88
82
|
)
|
|
89
83
|
# Model-specific settings
|
|
90
84
|
normalize_embeddings: bool = Field(
|
|
91
|
-
default=True,
|
|
92
|
-
description="Normalize embeddings for cosine similarity"
|
|
85
|
+
default=True, description="Normalize embeddings for cosine similarity"
|
|
93
86
|
)
|
|
94
87
|
|
|
95
88
|
def get_model_name(self) -> str:
|
|
@@ -104,59 +97,45 @@ class EmbeddingConfig(BaseModel):
|
|
|
104
97
|
class ChunkingConfig(BaseModel):
|
|
105
98
|
"""Document chunking configuration"""
|
|
106
99
|
|
|
107
|
-
chunk_size: int = Field(
|
|
108
|
-
default=512,
|
|
109
|
-
description="Target chunk size in characters"
|
|
110
|
-
)
|
|
100
|
+
chunk_size: int = Field(default=512, description="Target chunk size in characters")
|
|
111
101
|
chunk_overlap: int = Field(
|
|
112
|
-
default=50,
|
|
113
|
-
description="Overlap between chunks in characters"
|
|
102
|
+
default=50, description="Overlap between chunks in characters"
|
|
114
103
|
)
|
|
115
104
|
split_by_header: bool = Field(
|
|
116
|
-
default=True,
|
|
117
|
-
description="Split markdown by headers for semantic boundaries"
|
|
105
|
+
default=True, description="Split markdown by headers for semantic boundaries"
|
|
118
106
|
)
|
|
119
107
|
min_chunk_size: int = Field(
|
|
120
|
-
default=100,
|
|
121
|
-
description="Minimum chunk size to include"
|
|
108
|
+
default=100, description="Minimum chunk size to include"
|
|
122
109
|
)
|
|
123
110
|
max_chunk_size: int = Field(
|
|
124
|
-
default=2000,
|
|
125
|
-
description="Maximum chunk size (hard limit)"
|
|
111
|
+
default=2000, description="Maximum chunk size (hard limit)"
|
|
126
112
|
)
|
|
127
113
|
|
|
128
114
|
|
|
129
115
|
class WatchdogConfig(BaseModel):
|
|
130
116
|
"""File monitoring configuration"""
|
|
131
117
|
|
|
132
|
-
enabled: bool = Field(
|
|
133
|
-
default=True,
|
|
134
|
-
description="Enable file system monitoring"
|
|
135
|
-
)
|
|
118
|
+
enabled: bool = Field(default=True, description="Enable file system monitoring")
|
|
136
119
|
debounce_seconds: float = Field(
|
|
137
|
-
default=2.0,
|
|
138
|
-
description="Debounce time for file change events"
|
|
120
|
+
default=2.0, description="Debounce time for file change events"
|
|
139
121
|
)
|
|
140
122
|
patterns: List[str] = Field(
|
|
141
123
|
default=["*.md", "*.py", "*.txt", "*.json"],
|
|
142
|
-
description="File patterns to monitor"
|
|
124
|
+
description="File patterns to monitor",
|
|
143
125
|
)
|
|
144
126
|
ignore_patterns: List[str] = Field(
|
|
145
127
|
default=[".*", "__pycache__", "*.pyc", "*.egg-info"],
|
|
146
|
-
description="Patterns to ignore"
|
|
128
|
+
description="Patterns to ignore",
|
|
147
129
|
)
|
|
148
130
|
|
|
149
131
|
|
|
150
132
|
class RAGConfig(BaseModel):
|
|
151
133
|
"""Main RAG system configuration"""
|
|
152
134
|
|
|
153
|
-
enabled: bool = Field(
|
|
154
|
-
default=True,
|
|
155
|
-
description="Enable RAG system"
|
|
156
|
-
)
|
|
135
|
+
enabled: bool = Field(default=True, description="Enable RAG system")
|
|
157
136
|
knowledge_base_path: Optional[str] = Field(
|
|
158
137
|
default=None,
|
|
159
|
-
description="Path to knowledge base. Defaults to built-in libraries/"
|
|
138
|
+
description="Path to knowledge base. Defaults to built-in libraries/",
|
|
160
139
|
)
|
|
161
140
|
qdrant: QdrantConfig = Field(default_factory=QdrantConfig)
|
|
162
141
|
embedding: EmbeddingConfig = Field(default_factory=EmbeddingConfig)
|
|
@@ -164,17 +143,12 @@ class RAGConfig(BaseModel):
|
|
|
164
143
|
watchdog: WatchdogConfig = Field(default_factory=WatchdogConfig)
|
|
165
144
|
|
|
166
145
|
# Retrieval settings
|
|
167
|
-
top_k: int = Field(
|
|
168
|
-
default=5,
|
|
169
|
-
description="Number of chunks to retrieve"
|
|
170
|
-
)
|
|
146
|
+
top_k: int = Field(default=5, description="Number of chunks to retrieve")
|
|
171
147
|
score_threshold: float = Field(
|
|
172
|
-
default=0.3,
|
|
173
|
-
description="Minimum similarity score threshold"
|
|
148
|
+
default=0.3, description="Minimum similarity score threshold"
|
|
174
149
|
)
|
|
175
150
|
max_context_tokens: int = Field(
|
|
176
|
-
default=1500,
|
|
177
|
-
description="Maximum tokens for RAG context injection"
|
|
151
|
+
default=1500, description="Maximum tokens for RAG context injection"
|
|
178
152
|
)
|
|
179
153
|
|
|
180
154
|
def is_enabled(self) -> bool:
|
|
@@ -203,35 +177,22 @@ class RAGConfig(BaseModel):
|
|
|
203
177
|
class SearchRequest(BaseModel):
|
|
204
178
|
"""Request body for explicit RAG search"""
|
|
205
179
|
|
|
206
|
-
query: str = Field(
|
|
207
|
-
|
|
208
|
-
)
|
|
209
|
-
top_k: Optional[int] = Field(
|
|
210
|
-
default=None,
|
|
211
|
-
description="Override default top_k"
|
|
212
|
-
)
|
|
180
|
+
query: str = Field(description="Search query")
|
|
181
|
+
top_k: Optional[int] = Field(default=None, description="Override default top_k")
|
|
213
182
|
filters: Optional[Dict[str, Any]] = Field(
|
|
214
|
-
default=None,
|
|
215
|
-
description="Metadata filters (e.g., {'source_type': 'library'})"
|
|
183
|
+
default=None, description="Metadata filters (e.g., {'source_type': 'library'})"
|
|
216
184
|
)
|
|
217
185
|
include_score: bool = Field(
|
|
218
|
-
default=True,
|
|
219
|
-
description="Include relevance scores in results"
|
|
186
|
+
default=True, description="Include relevance scores in results"
|
|
220
187
|
)
|
|
221
188
|
|
|
222
189
|
|
|
223
190
|
class SearchResult(BaseModel):
|
|
224
191
|
"""Single search result"""
|
|
225
192
|
|
|
226
|
-
content: str = Field(
|
|
227
|
-
|
|
228
|
-
)
|
|
229
|
-
score: float = Field(
|
|
230
|
-
description="Relevance score (0-1)"
|
|
231
|
-
)
|
|
232
|
-
metadata: Dict[str, Any] = Field(
|
|
233
|
-
description="Chunk metadata (source, type, etc.)"
|
|
234
|
-
)
|
|
193
|
+
content: str = Field(description="Chunk content")
|
|
194
|
+
score: float = Field(description="Relevance score (0-1)")
|
|
195
|
+
metadata: Dict[str, Any] = Field(description="Chunk metadata (source, type, etc.)")
|
|
235
196
|
|
|
236
197
|
|
|
237
198
|
class SearchResponse(BaseModel):
|
|
@@ -240,35 +201,21 @@ class SearchResponse(BaseModel):
|
|
|
240
201
|
results: List[SearchResult] = Field(
|
|
241
202
|
description="Search results sorted by relevance"
|
|
242
203
|
)
|
|
243
|
-
query: str = Field(
|
|
244
|
-
|
|
245
|
-
)
|
|
246
|
-
total_results: int = Field(
|
|
247
|
-
description="Total matching chunks"
|
|
248
|
-
)
|
|
204
|
+
query: str = Field(description="Original query")
|
|
205
|
+
total_results: int = Field(description="Total matching chunks")
|
|
249
206
|
|
|
250
207
|
|
|
251
208
|
class IndexStatusResponse(BaseModel):
|
|
252
209
|
"""Response body for index status"""
|
|
253
210
|
|
|
254
|
-
ready: bool = Field(
|
|
255
|
-
|
|
256
|
-
)
|
|
257
|
-
total_documents: int = Field(
|
|
258
|
-
default=0,
|
|
259
|
-
description="Total indexed documents"
|
|
260
|
-
)
|
|
261
|
-
total_chunks: int = Field(
|
|
262
|
-
default=0,
|
|
263
|
-
description="Total indexed chunks"
|
|
264
|
-
)
|
|
211
|
+
ready: bool = Field(description="Whether RAG system is ready")
|
|
212
|
+
total_documents: int = Field(default=0, description="Total indexed documents")
|
|
213
|
+
total_chunks: int = Field(default=0, description="Total indexed chunks")
|
|
265
214
|
last_updated: Optional[str] = Field(
|
|
266
|
-
default=None,
|
|
267
|
-
description="Last index update timestamp"
|
|
215
|
+
default=None, description="Last index update timestamp"
|
|
268
216
|
)
|
|
269
217
|
knowledge_base_path: Optional[str] = Field(
|
|
270
|
-
default=None,
|
|
271
|
-
description="Current knowledge base path"
|
|
218
|
+
default=None, description="Current knowledge base path"
|
|
272
219
|
)
|
|
273
220
|
|
|
274
221
|
|
|
@@ -276,30 +223,21 @@ class ReindexRequest(BaseModel):
|
|
|
276
223
|
"""Request body for manual reindexing"""
|
|
277
224
|
|
|
278
225
|
force: bool = Field(
|
|
279
|
-
default=False,
|
|
280
|
-
description="Force full reindex even if files unchanged"
|
|
226
|
+
default=False, description="Force full reindex even if files unchanged"
|
|
281
227
|
)
|
|
282
228
|
path: Optional[str] = Field(
|
|
283
|
-
default=None,
|
|
284
|
-
description="Specific file or directory to reindex"
|
|
229
|
+
default=None, description="Specific file or directory to reindex"
|
|
285
230
|
)
|
|
286
231
|
|
|
287
232
|
|
|
288
233
|
class ReindexResponse(BaseModel):
|
|
289
234
|
"""Response body for reindex operation"""
|
|
290
235
|
|
|
291
|
-
success: bool = Field(
|
|
292
|
-
|
|
293
|
-
)
|
|
294
|
-
indexed: int = Field(
|
|
295
|
-
description="Number of files indexed"
|
|
296
|
-
)
|
|
297
|
-
skipped: int = Field(
|
|
298
|
-
description="Number of files skipped (unchanged)"
|
|
299
|
-
)
|
|
236
|
+
success: bool = Field(description="Whether reindex completed successfully")
|
|
237
|
+
indexed: int = Field(description="Number of files indexed")
|
|
238
|
+
skipped: int = Field(description="Number of files skipped (unchanged)")
|
|
300
239
|
errors: List[Dict[str, str]] = Field(
|
|
301
|
-
default=[],
|
|
302
|
-
description="List of indexing errors"
|
|
240
|
+
default=[], description="List of indexing errors"
|
|
303
241
|
)
|
|
304
242
|
|
|
305
243
|
|
|
@@ -374,9 +312,8 @@ def get_default_rag_config() -> RAGConfig:
|
|
|
374
312
|
enabled=True,
|
|
375
313
|
qdrant=QdrantConfig(mode="local"),
|
|
376
314
|
embedding=EmbeddingConfig(
|
|
377
|
-
model_name="intfloat/multilingual-e5-small",
|
|
378
|
-
device="cpu"
|
|
315
|
+
model_name="intfloat/multilingual-e5-small", device="cpu"
|
|
379
316
|
),
|
|
380
317
|
chunking=ChunkingConfig(),
|
|
381
|
-
watchdog=WatchdogConfig()
|
|
318
|
+
watchdog=WatchdogConfig(),
|
|
382
319
|
)
|
|
@@ -5,32 +5,32 @@ Prompt templates for Auto-Agent and Cell Actions.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from .auto_agent_prompts import (
|
|
8
|
-
|
|
8
|
+
ADAPTIVE_REPLAN_PROMPT,
|
|
9
9
|
CODE_GENERATION_PROMPT,
|
|
10
|
+
ERROR_ANALYSIS_PROMPT,
|
|
10
11
|
ERROR_REFINEMENT_PROMPT,
|
|
11
|
-
ADAPTIVE_REPLAN_PROMPT,
|
|
12
|
-
STRUCTURED_PLAN_PROMPT,
|
|
13
|
-
REFLECTION_PROMPT,
|
|
14
12
|
FINAL_ANSWER_PROMPT,
|
|
15
|
-
ERROR_ANALYSIS_PROMPT,
|
|
16
13
|
PIP_INDEX_OPTION,
|
|
14
|
+
PLAN_GENERATION_PROMPT,
|
|
15
|
+
REFLECTION_PROMPT,
|
|
16
|
+
STRUCTURED_PLAN_PROMPT,
|
|
17
|
+
format_error_analysis_prompt,
|
|
18
|
+
format_final_answer_prompt,
|
|
17
19
|
format_plan_prompt,
|
|
18
20
|
format_refine_prompt,
|
|
19
|
-
|
|
21
|
+
format_reflection_prompt,
|
|
20
22
|
format_replan_prompt,
|
|
21
23
|
format_structured_plan_prompt,
|
|
22
|
-
format_reflection_prompt,
|
|
23
|
-
format_error_analysis_prompt,
|
|
24
24
|
)
|
|
25
25
|
from .cell_action_prompts import (
|
|
26
|
-
EXPLAIN_CODE_PROMPT,
|
|
27
|
-
FIX_CODE_PROMPT,
|
|
28
26
|
CUSTOM_REQUEST_PROMPT,
|
|
29
27
|
DEFAULT_SYSTEM_PROMPT,
|
|
28
|
+
EXPLAIN_CODE_PROMPT,
|
|
29
|
+
FIX_CODE_PROMPT,
|
|
30
|
+
format_chat_prompt,
|
|
31
|
+
format_custom_prompt,
|
|
30
32
|
format_explain_prompt,
|
|
31
33
|
format_fix_prompt,
|
|
32
|
-
format_custom_prompt,
|
|
33
|
-
format_chat_prompt,
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
__all__ = [
|
|
@@ -66,6 +66,7 @@ DEFAULT_SYSTEM_PROMPT = "당신은 도움이 되는 AI 어시스턴트입니다.
|
|
|
66
66
|
# 유틸리티 함수
|
|
67
67
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
68
68
|
|
|
69
|
+
|
|
69
70
|
def format_explain_prompt(cell_content: str) -> str:
|
|
70
71
|
"""코드 설명 프롬프트 포맷팅"""
|
|
71
72
|
return EXPLAIN_CODE_PROMPT.format(cell_content=cell_content)
|
|
@@ -79,8 +80,7 @@ def format_fix_prompt(cell_content: str) -> str:
|
|
|
79
80
|
def format_custom_prompt(custom_prompt: str, cell_content: str) -> str:
|
|
80
81
|
"""커스텀 요청 프롬프트 포맷팅"""
|
|
81
82
|
return CUSTOM_REQUEST_PROMPT.format(
|
|
82
|
-
custom_prompt=custom_prompt,
|
|
83
|
-
cell_content=cell_content
|
|
83
|
+
custom_prompt=custom_prompt, cell_content=cell_content
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
|
|
@@ -88,11 +88,13 @@ def format_chat_prompt(message: str, context: dict = None) -> str:
|
|
|
88
88
|
"""채팅 프롬프트 포맷팅"""
|
|
89
89
|
prompt = message
|
|
90
90
|
|
|
91
|
-
if context and context.get(
|
|
92
|
-
cells_text =
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
if context and context.get("selectedCells"):
|
|
92
|
+
cells_text = "\n\n".join(
|
|
93
|
+
[
|
|
94
|
+
f"셀 {i + 1}:\n```python\n{cell}\n```"
|
|
95
|
+
for i, cell in enumerate(context["selectedCells"])
|
|
96
|
+
]
|
|
97
|
+
)
|
|
96
98
|
prompt = f"{message}\n\n노트북 컨텍스트:\n{cells_text}"
|
|
97
99
|
|
|
98
100
|
return prompt
|