hdsp-jupyter-extension 2.0.10__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 (70) hide show
  1. agent_server/core/notebook_generator.py +4 -4
  2. agent_server/langchain/custom_middleware.py +95 -9
  3. agent_server/langchain/hitl_config.py +5 -0
  4. agent_server/langchain/llm_factory.py +1 -85
  5. agent_server/langchain/prompts.py +105 -128
  6. agent_server/prompts/file_action_prompts.py +8 -8
  7. agent_server/routers/langchain_agent.py +78 -12
  8. hdsp_agent_core/__init__.py +46 -47
  9. hdsp_agent_core/factory.py +6 -10
  10. hdsp_agent_core/interfaces.py +4 -2
  11. hdsp_agent_core/knowledge/__init__.py +5 -5
  12. hdsp_agent_core/knowledge/chunking.py +87 -61
  13. hdsp_agent_core/knowledge/loader.py +103 -101
  14. hdsp_agent_core/llm/service.py +192 -107
  15. hdsp_agent_core/managers/config_manager.py +16 -22
  16. hdsp_agent_core/managers/session_manager.py +5 -4
  17. hdsp_agent_core/models/__init__.py +12 -12
  18. hdsp_agent_core/models/agent.py +15 -8
  19. hdsp_agent_core/models/common.py +1 -2
  20. hdsp_agent_core/models/rag.py +48 -111
  21. hdsp_agent_core/prompts/__init__.py +12 -12
  22. hdsp_agent_core/prompts/cell_action_prompts.py +9 -7
  23. hdsp_agent_core/services/agent_service.py +10 -8
  24. hdsp_agent_core/services/chat_service.py +10 -6
  25. hdsp_agent_core/services/rag_service.py +3 -6
  26. hdsp_agent_core/tests/conftest.py +4 -1
  27. hdsp_agent_core/tests/test_factory.py +2 -2
  28. hdsp_agent_core/tests/test_services.py +12 -19
  29. {hdsp_jupyter_extension-2.0.10.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/build_log.json +1 -1
  30. {hdsp_jupyter_extension-2.0.10.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/package.json +2 -2
  31. hdsp_jupyter_extension-2.0.10.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.dc6434bee96ab03a0539.js → hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.58c1e128ba0b76f41f04.js +81 -77
  32. hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.58c1e128ba0b76f41f04.js.map +1 -0
  33. hdsp_jupyter_extension-2.0.10.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.4a252df3ade74efee8d6.js → hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.9da31d1134a53b0c4af5.js +3 -3
  34. jupyter_ext/labextension/static/remoteEntry.4a252df3ade74efee8d6.js.map → hdsp_jupyter_extension-2.0.11.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.9da31d1134a53b0c4af5.js.map +1 -1
  35. {hdsp_jupyter_extension-2.0.10.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/METADATA +1 -1
  36. {hdsp_jupyter_extension-2.0.10.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/RECORD +68 -68
  37. jupyter_ext/__init__.py +21 -11
  38. jupyter_ext/_version.py +1 -1
  39. jupyter_ext/handlers.py +69 -50
  40. jupyter_ext/labextension/build_log.json +1 -1
  41. jupyter_ext/labextension/package.json +2 -2
  42. jupyter_ext/labextension/static/{lib_index_js.dc6434bee96ab03a0539.js → lib_index_js.58c1e128ba0b76f41f04.js} +81 -77
  43. jupyter_ext/labextension/static/lib_index_js.58c1e128ba0b76f41f04.js.map +1 -0
  44. jupyter_ext/labextension/static/{remoteEntry.4a252df3ade74efee8d6.js → remoteEntry.9da31d1134a53b0c4af5.js} +3 -3
  45. hdsp_jupyter_extension-2.0.10.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.4a252df3ade74efee8d6.js.map → jupyter_ext/labextension/static/remoteEntry.9da31d1134a53b0c4af5.js.map +1 -1
  46. hdsp_jupyter_extension-2.0.10.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.dc6434bee96ab03a0539.js.map +0 -1
  47. jupyter_ext/labextension/static/lib_index_js.dc6434bee96ab03a0539.js.map +0 -1
  48. {hdsp_jupyter_extension-2.0.10.data → hdsp_jupyter_extension-2.0.11.data}/data/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +0 -0
  49. {hdsp_jupyter_extension-2.0.10.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/install.json +0 -0
  50. {hdsp_jupyter_extension-2.0.10.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2d9fb488c82498c45c2d.js +0 -0
  51. {hdsp_jupyter_extension-2.0.10.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2d9fb488c82498c45c2d.js.map +0 -0
  52. {hdsp_jupyter_extension-2.0.10.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
  53. {hdsp_jupyter_extension-2.0.10.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
  54. {hdsp_jupyter_extension-2.0.10.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
  55. {hdsp_jupyter_extension-2.0.10.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
  56. {hdsp_jupyter_extension-2.0.10.data → hdsp_jupyter_extension-2.0.11.data}/data/share/jupyter/labextensions/hdsp-agent/static/style.js +0 -0
  57. {hdsp_jupyter_extension-2.0.10.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
  58. {hdsp_jupyter_extension-2.0.10.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
  59. {hdsp_jupyter_extension-2.0.10.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
  60. {hdsp_jupyter_extension-2.0.10.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
  61. {hdsp_jupyter_extension-2.0.10.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
  62. {hdsp_jupyter_extension-2.0.10.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
  63. {hdsp_jupyter_extension-2.0.10.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
  64. {hdsp_jupyter_extension-2.0.10.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
  65. {hdsp_jupyter_extension-2.0.10.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
  66. {hdsp_jupyter_extension-2.0.10.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
  67. {hdsp_jupyter_extension-2.0.10.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
  68. {hdsp_jupyter_extension-2.0.10.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
  69. {hdsp_jupyter_extension-2.0.10.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/WHEEL +0 -0
  70. {hdsp_jupyter_extension-2.0.10.dist-info → hdsp_jupyter_extension-2.0.11.dist-info}/licenses/LICENSE +0 -0
@@ -5,19 +5,19 @@ Keyword matching + regex based library detection for loading appropriate API gui
5
5
  (No LLM calls - saves tokens and improves reliability)
6
6
  """
7
7
 
8
- from pathlib import Path
9
- from typing import List, Dict, Optional, Set
10
8
  import re
9
+ from pathlib import Path
10
+ from typing import Dict, List, Optional, Set
11
11
 
12
12
  # Library descriptions (reference)
13
13
  LIBRARY_DESCRIPTIONS: Dict[str, str] = {
14
- 'matplotlib': 'Visualization, graphs, charts, plot, histogram, scatter plot, EDA, data visualization, used with seaborn',
15
- 'dask': 'Large-scale data processing, pandas replacement, distributed processing, lazy evaluation, dd.read_csv',
16
- 'polars': 'High-performance DataFrame, pandas replacement, Rust-based, pl.read_csv',
17
- 'pyspark': 'Spark-based distributed processing, big data, SparkSession',
18
- 'vaex': 'Large-scale data exploration, out-of-core processing',
19
- 'modin': 'pandas acceleration, parallel processing',
20
- 'ray': 'Distributed computing, parallel processing framework',
14
+ "matplotlib": "Visualization, graphs, charts, plot, histogram, scatter plot, EDA, data visualization, used with seaborn",
15
+ "dask": "Large-scale data processing, pandas replacement, distributed processing, lazy evaluation, dd.read_csv",
16
+ "polars": "High-performance DataFrame, pandas replacement, Rust-based, pl.read_csv",
17
+ "pyspark": "Spark-based distributed processing, big data, SparkSession",
18
+ "vaex": "Large-scale data exploration, out-of-core processing",
19
+ "modin": "pandas acceleration, parallel processing",
20
+ "ray": "Distributed computing, parallel processing framework",
21
21
  }
22
22
 
23
23
 
@@ -29,90 +29,90 @@ class LibraryDetector:
29
29
 
30
30
  # Explicit library mention patterns (highest priority)
31
31
  EXPLICIT_PATTERNS: Dict[str, str] = {
32
- r'\bdask\b': 'dask',
33
- r'\bpolars\b': 'polars',
34
- r'\bpyspark\b': 'pyspark',
35
- r'\bvaex\b': 'vaex',
36
- r'\bmodin\b': 'modin',
37
- r'\bray\b': 'ray',
38
- r'\bmatplotlib\b': 'matplotlib',
39
- r'\bseaborn\b': 'matplotlib', # seaborn -> matplotlib guide
40
- r'\bplt\.': 'matplotlib',
41
- r'\bdd\.read': 'dask',
42
- r'\bpl\.read': 'polars',
43
- r'\bpl\.DataFrame': 'polars',
32
+ r"\bdask\b": "dask",
33
+ r"\bpolars\b": "polars",
34
+ r"\bpyspark\b": "pyspark",
35
+ r"\bvaex\b": "vaex",
36
+ r"\bmodin\b": "modin",
37
+ r"\bray\b": "ray",
38
+ r"\bmatplotlib\b": "matplotlib",
39
+ r"\bseaborn\b": "matplotlib", # seaborn -> matplotlib guide
40
+ r"\bplt\.": "matplotlib",
41
+ r"\bdd\.read": "dask",
42
+ r"\bpl\.read": "polars",
43
+ r"\bpl\.DataFrame": "polars",
44
44
  }
45
45
 
46
46
  # Keyword scores per library (0.0 ~ 1.0)
47
47
  KEYWORD_SCORES: Dict[str, Dict[str, float]] = {
48
- 'dask': {
49
- '대용량': 0.7,
50
- 'big data': 0.7,
51
- 'bigdata': 0.7,
52
- '빅데이터': 0.7,
53
- 'lazy': 0.8,
54
- 'lazy evaluation': 0.9,
55
- 'out-of-core': 0.9,
56
- 'out of core': 0.9,
57
- '분산 처리': 0.6,
58
- 'distributed': 0.6,
59
- 'parallel dataframe': 0.8,
60
- '병렬 데이터프레임': 0.8,
48
+ "dask": {
49
+ "대용량": 0.7,
50
+ "big data": 0.7,
51
+ "bigdata": 0.7,
52
+ "빅데이터": 0.7,
53
+ "lazy": 0.8,
54
+ "lazy evaluation": 0.9,
55
+ "out-of-core": 0.9,
56
+ "out of core": 0.9,
57
+ "분산 처리": 0.6,
58
+ "distributed": 0.6,
59
+ "parallel dataframe": 0.8,
60
+ "병렬 데이터프레임": 0.8,
61
61
  },
62
- 'polars': {
63
- 'rust 기반': 0.9,
64
- 'rust-based': 0.9,
65
- 'fast dataframe': 0.7,
66
- '고성능 dataframe': 0.7,
67
- '빠른 데이터프레임': 0.7,
62
+ "polars": {
63
+ "rust 기반": 0.9,
64
+ "rust-based": 0.9,
65
+ "fast dataframe": 0.7,
66
+ "고성능 dataframe": 0.7,
67
+ "빠른 데이터프레임": 0.7,
68
68
  },
69
- 'matplotlib': {
70
- '시각화': 0.7,
71
- 'visualization': 0.7,
72
- 'visualize': 0.7,
73
- 'plot': 0.7,
74
- 'chart': 0.7,
75
- 'graph': 0.6,
76
- '그래프': 0.6,
77
- '차트': 0.7,
78
- 'histogram': 0.8,
79
- '히스토그램': 0.8,
80
- 'scatter': 0.8,
81
- '산점도': 0.8,
82
- 'line plot': 0.8,
83
- '라인 플롯': 0.8,
84
- 'bar chart': 0.8,
85
- '막대 그래프': 0.8,
86
- 'eda': 0.5,
87
- '탐색적 데이터 분석': 0.6,
88
- 'figure': 0.5,
89
- 'subplot': 0.8,
90
- 'heatmap': 0.7,
91
- '히트맵': 0.7,
69
+ "matplotlib": {
70
+ "시각화": 0.7,
71
+ "visualization": 0.7,
72
+ "visualize": 0.7,
73
+ "plot": 0.7,
74
+ "chart": 0.7,
75
+ "graph": 0.6,
76
+ "그래프": 0.6,
77
+ "차트": 0.7,
78
+ "histogram": 0.8,
79
+ "히스토그램": 0.8,
80
+ "scatter": 0.8,
81
+ "산점도": 0.8,
82
+ "line plot": 0.8,
83
+ "라인 플롯": 0.8,
84
+ "bar chart": 0.8,
85
+ "막대 그래프": 0.8,
86
+ "eda": 0.5,
87
+ "탐색적 데이터 분석": 0.6,
88
+ "figure": 0.5,
89
+ "subplot": 0.8,
90
+ "heatmap": 0.7,
91
+ "히트맵": 0.7,
92
92
  },
93
- 'pyspark': {
94
- 'spark': 0.9,
95
- 'sparksession': 0.95,
96
- 'spark session': 0.95,
97
- 'rdd': 0.9,
98
- 'hadoop': 0.7,
99
- '클러스터': 0.6,
100
- 'cluster': 0.6,
93
+ "pyspark": {
94
+ "spark": 0.9,
95
+ "sparksession": 0.95,
96
+ "spark session": 0.95,
97
+ "rdd": 0.9,
98
+ "hadoop": 0.7,
99
+ "클러스터": 0.6,
100
+ "cluster": 0.6,
101
101
  },
102
- 'vaex': {
103
- 'vaex': 1.0,
104
- 'memory mapping': 0.8,
105
- '메모리 매핑': 0.8,
102
+ "vaex": {
103
+ "vaex": 1.0,
104
+ "memory mapping": 0.8,
105
+ "메모리 매핑": 0.8,
106
106
  },
107
- 'modin': {
108
- 'modin': 1.0,
109
- 'pandas 가속': 0.8,
110
- 'pandas acceleration': 0.8,
107
+ "modin": {
108
+ "modin": 1.0,
109
+ "pandas 가속": 0.8,
110
+ "pandas acceleration": 0.8,
111
111
  },
112
- 'ray': {
113
- 'ray': 0.9,
114
- '분산 컴퓨팅': 0.7,
115
- 'distributed computing': 0.7,
112
+ "ray": {
113
+ "ray": 0.9,
114
+ "분산 컴퓨팅": 0.7,
115
+ "distributed computing": 0.7,
116
116
  },
117
117
  }
118
118
 
@@ -123,7 +123,7 @@ class LibraryDetector:
123
123
  self,
124
124
  request: str,
125
125
  available_libraries: List[str],
126
- imported_libraries: List[str] = None
126
+ imported_libraries: List[str] = None,
127
127
  ) -> List[str]:
128
128
  """
129
129
  Detect required libraries from user request.
@@ -141,7 +141,9 @@ class LibraryDetector:
141
141
 
142
142
  # Step 1: Explicit pattern matching (highest priority)
143
143
  for pattern, lib in self.EXPLICIT_PATTERNS.items():
144
- if lib in available_libraries and re.search(pattern, request, re.IGNORECASE):
144
+ if lib in available_libraries and re.search(
145
+ pattern, request, re.IGNORECASE
146
+ ):
145
147
  detected.add(lib)
146
148
 
147
149
  # Step 2: Keyword scoring
@@ -162,8 +164,8 @@ class LibraryDetector:
162
164
  for lib in imported_libraries:
163
165
  lib_lower = lib.lower()
164
166
  # seaborn -> matplotlib
165
- if lib_lower == 'seaborn' and 'matplotlib' in available_libraries:
166
- detected.add('matplotlib')
167
+ if lib_lower == "seaborn" and "matplotlib" in available_libraries:
168
+ detected.add("matplotlib")
167
169
  elif lib_lower in available_libraries:
168
170
  detected.add(lib_lower)
169
171
 
@@ -183,7 +185,7 @@ def get_library_detector() -> LibraryDetector:
183
185
 
184
186
 
185
187
  # LLM library detection prompt
186
- LIBRARY_DETECTION_PROMPT = '''Analyze the user's request and determine which libraries to use for code generation.
188
+ LIBRARY_DETECTION_PROMPT = """Analyze the user's request and determine which libraries to use for code generation.
187
189
 
188
190
  ## Available Library API Guides:
189
191
  {library_list}
@@ -205,7 +207,7 @@ LIBRARY_DETECTION_PROMPT = '''Analyze the user's request and determine which lib
205
207
  {{"libraries": ["library1", "library2"]}}
206
208
 
207
209
  Empty array is also valid: {{"libraries": []}}
208
- '''
210
+ """
209
211
 
210
212
 
211
213
  class KnowledgeBase:
@@ -216,7 +218,7 @@ class KnowledgeBase:
216
218
  self.knowledge_dir = Path(knowledge_dir)
217
219
  else:
218
220
  # Default path: knowledge/libraries
219
- self.knowledge_dir = Path(__file__).parent / 'libraries'
221
+ self.knowledge_dir = Path(__file__).parent / "libraries"
220
222
 
221
223
  self._cache: Dict[str, str] = {}
222
224
 
@@ -225,19 +227,19 @@ class KnowledgeBase:
225
227
  available = self.list_available_libraries()
226
228
  lines = []
227
229
  for lib in available:
228
- desc = LIBRARY_DESCRIPTIONS.get(lib, 'Other library')
230
+ desc = LIBRARY_DESCRIPTIONS.get(lib, "Other library")
229
231
  lines.append(f"- **{lib}**: {desc}")
230
232
  return "\n".join(lines)
231
233
 
232
- def get_detection_prompt(self, request: str, imported_libraries: List[str] = None) -> str:
234
+ def get_detection_prompt(
235
+ self, request: str, imported_libraries: List[str] = None
236
+ ) -> str:
233
237
  """Generate LLM library detection prompt"""
234
238
  library_list = self.get_library_list_for_prompt()
235
239
  imported = ", ".join(imported_libraries) if imported_libraries else "None"
236
240
 
237
241
  return LIBRARY_DETECTION_PROMPT.format(
238
- library_list=library_list,
239
- request=request,
240
- imported_libraries=imported
242
+ library_list=library_list, request=request, imported_libraries=imported
241
243
  )
242
244
 
243
245
  def load_library_guide(self, library: str) -> Optional[str]:
@@ -255,9 +257,9 @@ class KnowledgeBase:
255
257
  return self._cache[library]
256
258
 
257
259
  # Load file
258
- file_path = self.knowledge_dir / f'{library}.md'
260
+ file_path = self.knowledge_dir / f"{library}.md"
259
261
  if file_path.exists():
260
- content = file_path.read_text(encoding='utf-8')
262
+ content = file_path.read_text(encoding="utf-8")
261
263
  self._cache[library] = content
262
264
  return content
263
265
 
@@ -274,7 +276,7 @@ class KnowledgeBase:
274
276
  Combined guide string
275
277
  """
276
278
  if not libraries:
277
- return ''
279
+ return ""
278
280
 
279
281
  guides = []
280
282
  for lib in sorted(libraries):
@@ -283,7 +285,7 @@ class KnowledgeBase:
283
285
  guides.append(f"## {lib.upper()} Library API Guide\n\n{guide}")
284
286
 
285
287
  if not guides:
286
- return ''
288
+ return ""
287
289
 
288
290
  return "\n\n---\n\n".join(guides)
289
291
 
@@ -300,7 +302,7 @@ class KnowledgeBase:
300
302
  knowledge = self.load_libraries_knowledge(libraries)
301
303
 
302
304
  if not knowledge:
303
- return ''
305
+ return ""
304
306
 
305
307
  return f"""
306
308
  ## 📚 Library API Reference (MUST follow!)
@@ -317,7 +319,7 @@ Follow the API usage in the guides below. Avoid ❌ incorrect code and use ✅ c
317
319
  if not self.knowledge_dir.exists():
318
320
  return []
319
321
 
320
- return [f.stem for f in self.knowledge_dir.glob('*.md')]
322
+ return [f.stem for f in self.knowledge_dir.glob("*.md")]
321
323
 
322
324
 
323
325
  # Singleton instance