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.
Files changed (88) hide show
  1. agent_server/core/notebook_generator.py +4 -4
  2. agent_server/core/rag_manager.py +12 -3
  3. agent_server/core/retriever.py +2 -1
  4. agent_server/core/vllm_embedding_service.py +8 -5
  5. agent_server/langchain/ARCHITECTURE.md +7 -51
  6. agent_server/langchain/agent.py +31 -20
  7. agent_server/langchain/custom_middleware.py +234 -31
  8. agent_server/langchain/hitl_config.py +5 -8
  9. agent_server/langchain/logging_utils.py +7 -7
  10. agent_server/langchain/prompts.py +106 -120
  11. agent_server/langchain/tools/__init__.py +1 -10
  12. agent_server/langchain/tools/file_tools.py +9 -61
  13. agent_server/langchain/tools/jupyter_tools.py +0 -1
  14. agent_server/langchain/tools/lsp_tools.py +8 -8
  15. agent_server/langchain/tools/resource_tools.py +12 -12
  16. agent_server/langchain/tools/search_tools.py +3 -158
  17. agent_server/prompts/file_action_prompts.py +8 -8
  18. agent_server/routers/langchain_agent.py +200 -125
  19. hdsp_agent_core/__init__.py +46 -47
  20. hdsp_agent_core/factory.py +6 -10
  21. hdsp_agent_core/interfaces.py +4 -2
  22. hdsp_agent_core/knowledge/__init__.py +5 -5
  23. hdsp_agent_core/knowledge/chunking.py +87 -61
  24. hdsp_agent_core/knowledge/loader.py +103 -101
  25. hdsp_agent_core/llm/service.py +192 -107
  26. hdsp_agent_core/managers/config_manager.py +16 -22
  27. hdsp_agent_core/managers/session_manager.py +5 -4
  28. hdsp_agent_core/models/__init__.py +12 -12
  29. hdsp_agent_core/models/agent.py +15 -8
  30. hdsp_agent_core/models/common.py +1 -2
  31. hdsp_agent_core/models/rag.py +48 -111
  32. hdsp_agent_core/prompts/__init__.py +12 -12
  33. hdsp_agent_core/prompts/cell_action_prompts.py +9 -7
  34. hdsp_agent_core/services/agent_service.py +10 -8
  35. hdsp_agent_core/services/chat_service.py +10 -6
  36. hdsp_agent_core/services/rag_service.py +3 -6
  37. hdsp_agent_core/tests/conftest.py +4 -1
  38. hdsp_agent_core/tests/test_factory.py +2 -2
  39. hdsp_agent_core/tests/test_services.py +12 -19
  40. {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
  41. {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/package.json +2 -2
  42. 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
  43. hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2d9fb488c82498c45c2d.js.map +1 -0
  44. 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
  45. hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.58c1e128ba0b76f41f04.js.map +1 -0
  46. 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
  47. hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.9da31d1134a53b0c4af5.js.map +1 -0
  48. {hdsp_jupyter_extension-2.0.8.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/METADATA +1 -3
  49. hdsp_jupyter_extension-2.0.11.dist-info/RECORD +144 -0
  50. jupyter_ext/__init__.py +21 -11
  51. jupyter_ext/_version.py +1 -1
  52. jupyter_ext/handlers.py +69 -50
  53. jupyter_ext/labextension/build_log.json +1 -1
  54. jupyter_ext/labextension/package.json +2 -2
  55. jupyter_ext/labextension/static/{frontend_styles_index_js.8740a527757068814573.js → frontend_styles_index_js.2d9fb488c82498c45c2d.js} +93 -4
  56. jupyter_ext/labextension/static/frontend_styles_index_js.2d9fb488c82498c45c2d.js.map +1 -0
  57. jupyter_ext/labextension/static/{lib_index_js.e4ff4b5779b5e049f84c.js → lib_index_js.58c1e128ba0b76f41f04.js} +153 -130
  58. jupyter_ext/labextension/static/lib_index_js.58c1e128ba0b76f41f04.js.map +1 -0
  59. jupyter_ext/labextension/static/{remoteEntry.020cdb0b864cfaa4e41e.js → remoteEntry.9da31d1134a53b0c4af5.js} +6 -6
  60. jupyter_ext/labextension/static/remoteEntry.9da31d1134a53b0c4af5.js.map +1 -0
  61. hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.8740a527757068814573.js.map +0 -1
  62. hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.e4ff4b5779b5e049f84c.js.map +0 -1
  63. hdsp_jupyter_extension-2.0.8.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.020cdb0b864cfaa4e41e.js.map +0 -1
  64. hdsp_jupyter_extension-2.0.8.dist-info/RECORD +0 -144
  65. jupyter_ext/labextension/static/frontend_styles_index_js.8740a527757068814573.js.map +0 -1
  66. jupyter_ext/labextension/static/lib_index_js.e4ff4b5779b5e049f84c.js.map +0 -1
  67. jupyter_ext/labextension/static/remoteEntry.020cdb0b864cfaa4e41e.js.map +0 -1
  68. {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
  69. {hdsp_jupyter_extension-2.0.8.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/install.json +0 -0
  70. {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
  71. {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
  72. {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
  73. {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
  74. {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
  75. {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
  76. {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
  77. {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
  78. {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
  79. {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
  80. {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
  81. {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
  82. {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
  83. {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
  84. {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
  85. {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
  86. {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
  87. {hdsp_jupyter_extension-2.0.8.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/WHEEL +0 -0
  88. {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 Dict, Any
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('JUPYTER_CONFIG_DIR')
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('~/.jupyter')
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 / 'hdsp_agent_config.json'
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()) / 'jupyter_hdsp_agent'
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 / 'hdsp_agent_config.json'
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('/tmp/hdsp_agent_config_fallback.json')
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, 'r') as f:
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
- 'provider': 'gemini',
85
- 'gemini': {
86
- 'apiKey': '',
87
- 'model': 'gemini-2.5-pro'
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
- 'vllm': {
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, 'w') as f:
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 pathlib import Path
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 logging
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,
@@ -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(default=None, description="New content if applicable")
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(description="Recommended action: continue, adjust, retry, replan")
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(description="Impact on remaining steps")
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(default=None, description="Error message if any")
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, description="Current notebook context (for variable/import tracking)"
306
+ default=None,
307
+ description="Current notebook context (for variable/import tracking)",
301
308
  )
302
309
 
303
310
 
@@ -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
 
@@ -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 Optional, List, Literal, Dict, Any
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
- description="Search query"
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
- description="Chunk content"
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
- description="Original query"
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
- description="Whether RAG system is ready"
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
- description="Whether reindex completed successfully"
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
- PLAN_GENERATION_PROMPT,
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
- format_final_answer_prompt,
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('selectedCells'):
92
- cells_text = '\n\n'.join([
93
- f"셀 {i+1}:\n```python\n{cell}\n```"
94
- for i, cell in enumerate(context['selectedCells'])
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