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
@@ -1,19 +1,16 @@
1
1
  """
2
2
  Search Tools for LangChain Agent
3
3
 
4
- Provides tools for searching code in workspace and notebooks.
5
- These tools return pending_execution status and are executed on the client (Jupyter) side
6
- using subprocess (find/grep/ripgrep).
4
+ Provides tools for searching notebook cells.
5
+ For file searching, use execute_command_tool with find/grep commands.
7
6
 
8
7
  Key features:
9
8
  - Returns command info for client-side execution via subprocess
10
- - Supports ripgrep (rg) if available, falls back to grep
11
9
  - Executes immediately without user approval
12
10
  - Shows the command being executed in status messages
13
11
  """
14
12
 
15
13
  import logging
16
- import shutil
17
14
  from typing import Any, Dict, List, Optional
18
15
 
19
16
  from langchain_core.tools import tool
@@ -22,23 +19,6 @@ from pydantic import BaseModel, Field
22
19
  logger = logging.getLogger(__name__)
23
20
 
24
21
 
25
- class SearchWorkspaceInput(BaseModel):
26
- """Input schema for search_workspace tool"""
27
-
28
- pattern: str = Field(description="Search pattern (regex or text)")
29
- file_types: List[str] = Field(
30
- default=["*.py", "*.ipynb"],
31
- description="File patterns to search (e.g., ['*.py', '*.ipynb'])",
32
- )
33
- path: str = Field(default=".", description="Directory to search in")
34
- max_results: int = Field(default=50, description="Maximum number of results")
35
- case_sensitive: bool = Field(default=False, description="Case-sensitive search")
36
- execution_result: Optional[Dict[str, Any]] = Field(
37
- default=None,
38
- description="Execution result payload from the client",
39
- )
40
-
41
-
42
22
  class SearchNotebookCellsInput(BaseModel):
43
23
  """Input schema for search_notebook_cells tool"""
44
24
 
@@ -58,72 +38,6 @@ class SearchNotebookCellsInput(BaseModel):
58
38
  )
59
39
 
60
40
 
61
- def _is_ripgrep_available() -> bool:
62
- """Check if ripgrep (rg) is installed and available."""
63
- return shutil.which("rg") is not None
64
-
65
-
66
- def _build_grep_command(
67
- pattern: str,
68
- file_types: List[str],
69
- path: str,
70
- case_sensitive: bool,
71
- max_results: int,
72
- ) -> tuple[str, str]:
73
- """
74
- Build a grep/ripgrep command for searching files.
75
-
76
- Returns:
77
- Tuple of (command_string, tool_name) where tool_name is 'rg' or 'grep'
78
- """
79
- # Check ripgrep availability (this check will also be done on client)
80
- use_ripgrep = _is_ripgrep_available()
81
-
82
- if use_ripgrep:
83
- # Build ripgrep command
84
- cmd_parts = ["rg", "--line-number", "--with-filename"]
85
-
86
- if not case_sensitive:
87
- cmd_parts.append("--ignore-case")
88
-
89
- # Add file type filters using glob patterns
90
- for ft in file_types:
91
- cmd_parts.extend(["--glob", ft])
92
-
93
- # Limit results
94
- cmd_parts.extend(["--max-count", str(max_results)])
95
-
96
- # Escape pattern for shell
97
- escaped_pattern = pattern.replace("'", "'\\''")
98
- cmd_parts.append(f"'{escaped_pattern}'")
99
- cmd_parts.append(path)
100
-
101
- return " ".join(cmd_parts), "rg"
102
- else:
103
- # Build find + grep command for cross-platform compatibility
104
- find_parts = ["find", path, "-type", "f", "("]
105
-
106
- for i, ft in enumerate(file_types):
107
- if i > 0:
108
- find_parts.append("-o")
109
- find_parts.extend(["-name", f"'{ft}'"])
110
-
111
- find_parts.append(")")
112
-
113
- # Add grep with proper flags
114
- grep_flags = "-n" # Line numbers
115
- if not case_sensitive:
116
- grep_flags += "i"
117
-
118
- # Escape pattern for shell
119
- escaped_pattern = pattern.replace("'", "'\\''")
120
-
121
- # Combine with xargs for efficiency
122
- cmd = f"{' '.join(find_parts)} 2>/dev/null | xargs grep -{grep_flags} '{escaped_pattern}' 2>/dev/null | head -n {max_results}"
123
-
124
- return cmd, "grep"
125
-
126
-
127
41
  def _build_notebook_search_command(
128
42
  pattern: str,
129
43
  notebook_path: Optional[str],
@@ -139,74 +53,6 @@ def _build_notebook_search_command(
139
53
  )
140
54
 
141
55
 
142
- @tool(args_schema=SearchWorkspaceInput)
143
- def search_workspace_tool(
144
- pattern: str,
145
- file_types: List[str] = None,
146
- path: str = ".",
147
- max_results: int = 50,
148
- case_sensitive: bool = False,
149
- execution_result: Optional[Dict[str, Any]] = None,
150
- workspace_root: str = ".",
151
- ) -> Dict[str, Any]:
152
- """
153
- Search for a pattern across files in the workspace.
154
-
155
- This tool is executed on the client side using subprocess (grep/ripgrep).
156
- Searches both regular files and Jupyter notebooks.
157
-
158
- Args:
159
- pattern: Search pattern (regex or text)
160
- file_types: File patterns to search (default: ['*.py', '*.ipynb'])
161
- path: Directory to search in (relative to workspace)
162
- max_results: Maximum number of results to return
163
- case_sensitive: Whether search is case-sensitive
164
-
165
- Returns:
166
- Dict with search results or pending_execution status
167
- """
168
- if file_types is None:
169
- file_types = ["*.py", "*.ipynb"]
170
-
171
- # Build the search command
172
- command, tool_used = _build_grep_command(
173
- pattern=pattern,
174
- file_types=file_types,
175
- path=path,
176
- case_sensitive=case_sensitive,
177
- max_results=max_results,
178
- )
179
-
180
- response: Dict[str, Any] = {
181
- "tool": "search_workspace_tool",
182
- "parameters": {
183
- "pattern": pattern,
184
- "file_types": file_types,
185
- "path": path,
186
- "max_results": max_results,
187
- "case_sensitive": case_sensitive,
188
- },
189
- "command": command,
190
- "tool_used": tool_used,
191
- "status": "pending_execution",
192
- "message": "Search queued for execution by client",
193
- }
194
-
195
- if execution_result is not None:
196
- response["execution_result"] = execution_result
197
- response["status"] = "complete"
198
- response["message"] = "Search executed with client-reported results"
199
- # Parse the execution result to extract search results
200
- if isinstance(execution_result, dict):
201
- response["success"] = execution_result.get("success", False)
202
- response["results"] = execution_result.get("results", [])
203
- response["total_results"] = execution_result.get("total_results", 0)
204
- if "error" in execution_result:
205
- response["error"] = execution_result["error"]
206
-
207
- return response
208
-
209
-
210
56
  @tool(args_schema=SearchNotebookCellsInput)
211
57
  def search_notebook_cells_tool(
212
58
  pattern: str,
@@ -281,11 +127,10 @@ def create_search_tools(workspace_root: str = ".") -> List:
281
127
  Note: workspace_root is not used since tools return pending_execution
282
128
  and actual execution happens on the client side.
283
129
  """
284
- return [search_workspace_tool, search_notebook_cells_tool]
130
+ return [search_notebook_cells_tool]
285
131
 
286
132
 
287
133
  # Export all tools
288
134
  SEARCH_TOOLS = [
289
- search_workspace_tool,
290
135
  search_notebook_cells_tool,
291
136
  ]
@@ -20,9 +20,9 @@ def format_file_fix_prompt(
20
20
  for rf in related_files:
21
21
  if rf.get("content"):
22
22
  related_context += f"""
23
- ### {rf['path']}
23
+ ### {rf["path"]}
24
24
  ```python
25
- {rf['content']}
25
+ {rf["content"]}
26
26
  ```
27
27
  """
28
28
 
@@ -33,9 +33,9 @@ def format_file_fix_prompt(
33
33
  {error_output}
34
34
  ```
35
35
 
36
- ## 메인 파일: {main_file['path']}
36
+ ## 메인 파일: {main_file["path"]}
37
37
  ```python
38
- {main_file['content']}
38
+ {main_file["content"]}
39
39
  ```
40
40
  {related_context}
41
41
 
@@ -97,17 +97,17 @@ def format_file_custom_prompt(
97
97
  for rf in related_files:
98
98
  if rf.get("content"):
99
99
  related_context += f"""
100
- ### {rf['path']}
100
+ ### {rf["path"]}
101
101
  ```python
102
- {rf['content']}
102
+ {rf["content"]}
103
103
  ```
104
104
  """
105
105
 
106
106
  return f"""{custom_prompt}
107
107
 
108
- ## 메인 파일: {main_file['path']}
108
+ ## 메인 파일: {main_file["path"]}
109
109
  ```python
110
- {main_file['content']}
110
+ {main_file["content"]}
111
111
  ```
112
112
  {related_context}
113
113
  """