hdsp-jupyter-extension 2.0.6__py3-none-any.whl → 2.0.7__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/reflection_engine.py +0 -1
- agent_server/knowledge/watchdog_service.py +1 -1
- agent_server/langchain/ARCHITECTURE.md +1193 -0
- agent_server/langchain/agent.py +74 -588
- agent_server/langchain/custom_middleware.py +636 -0
- agent_server/langchain/executors/__init__.py +2 -7
- agent_server/langchain/executors/notebook_searcher.py +46 -38
- agent_server/langchain/hitl_config.py +66 -0
- agent_server/langchain/llm_factory.py +166 -0
- agent_server/langchain/logging_utils.py +184 -0
- agent_server/langchain/prompts.py +119 -0
- agent_server/langchain/state.py +16 -6
- agent_server/langchain/tools/__init__.py +6 -0
- agent_server/langchain/tools/file_tools.py +91 -129
- agent_server/langchain/tools/jupyter_tools.py +18 -18
- agent_server/langchain/tools/resource_tools.py +161 -0
- agent_server/langchain/tools/search_tools.py +198 -216
- agent_server/langchain/tools/shell_tools.py +54 -0
- agent_server/main.py +4 -1
- agent_server/routers/health.py +1 -1
- agent_server/routers/langchain_agent.py +940 -285
- hdsp_agent_core/prompts/auto_agent_prompts.py +3 -3
- {hdsp_jupyter_extension-2.0.6.data → hdsp_jupyter_extension-2.0.7.data}/data/share/jupyter/labextensions/hdsp-agent/build_log.json +1 -1
- {hdsp_jupyter_extension-2.0.6.data → hdsp_jupyter_extension-2.0.7.data}/data/share/jupyter/labextensions/hdsp-agent/package.json +2 -2
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.02d346171474a0fb2dc1.js → hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.4770ec0fb2d173b6deb4.js +312 -6
- hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.4770ec0fb2d173b6deb4.js.map +1 -0
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.a223ea20056954479ae9.js → hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.29cf4312af19e86f82af.js +1547 -330
- hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.29cf4312af19e86f82af.js.map +1 -0
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.addf2fa038fa60304aa2.js → hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.61343eb4cf0577e74b50.js +8 -8
- hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.61343eb4cf0577e74b50.js.map +1 -0
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js.24edcc52a1c014a8a5f0.js → hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js-node_modules-782ee5.d9ed8645ef1d311657d8.js +209 -2
- hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js-node_modules-782ee5.d9ed8645ef1d311657d8.js.map +1 -0
- jupyter_ext/labextension/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.19ecf6babe00caff6b8a.js → hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.36b49c71871f98d4f549.js +2 -209
- hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.36b49c71871f98d4f549.js.map +1 -0
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.1f5038488cdfd8b3a85d.js → hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js +3 -212
- hdsp_jupyter_extension-2.0.7.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js.map +1 -0
- {hdsp_jupyter_extension-2.0.6.dist-info → hdsp_jupyter_extension-2.0.7.dist-info}/METADATA +2 -1
- {hdsp_jupyter_extension-2.0.6.dist-info → hdsp_jupyter_extension-2.0.7.dist-info}/RECORD +71 -68
- jupyter_ext/_version.py +1 -1
- jupyter_ext/handlers.py +1176 -58
- jupyter_ext/labextension/build_log.json +1 -1
- jupyter_ext/labextension/package.json +2 -2
- jupyter_ext/labextension/static/{frontend_styles_index_js.02d346171474a0fb2dc1.js → frontend_styles_index_js.4770ec0fb2d173b6deb4.js} +312 -6
- jupyter_ext/labextension/static/frontend_styles_index_js.4770ec0fb2d173b6deb4.js.map +1 -0
- jupyter_ext/labextension/static/{lib_index_js.a223ea20056954479ae9.js → lib_index_js.29cf4312af19e86f82af.js} +1547 -330
- jupyter_ext/labextension/static/lib_index_js.29cf4312af19e86f82af.js.map +1 -0
- jupyter_ext/labextension/static/{remoteEntry.addf2fa038fa60304aa2.js → remoteEntry.61343eb4cf0577e74b50.js} +8 -8
- jupyter_ext/labextension/static/remoteEntry.61343eb4cf0577e74b50.js.map +1 -0
- jupyter_ext/labextension/static/{vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js.24edcc52a1c014a8a5f0.js → vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js-node_modules-782ee5.d9ed8645ef1d311657d8.js} +209 -2
- jupyter_ext/labextension/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js-node_modules-782ee5.d9ed8645ef1d311657d8.js.map +1 -0
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.19ecf6babe00caff6b8a.js → jupyter_ext/labextension/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.36b49c71871f98d4f549.js +2 -209
- jupyter_ext/labextension/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.36b49c71871f98d4f549.js.map +1 -0
- jupyter_ext/labextension/static/{vendors-node_modules_mui_material_utils_createSvgIcon_js.1f5038488cdfd8b3a85d.js → vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js} +3 -212
- jupyter_ext/labextension/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js.map +1 -0
- jupyter_ext/resource_usage.py +180 -0
- jupyter_ext/tests/test_handlers.py +58 -0
- agent_server/langchain/executors/jupyter_executor.py +0 -429
- agent_server/langchain/middleware/__init__.py +0 -36
- agent_server/langchain/middleware/code_search_middleware.py +0 -278
- agent_server/langchain/middleware/error_handling_middleware.py +0 -338
- agent_server/langchain/middleware/jupyter_execution_middleware.py +0 -301
- agent_server/langchain/middleware/rag_middleware.py +0 -227
- agent_server/langchain/middleware/validation_middleware.py +0 -240
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.02d346171474a0fb2dc1.js.map +0 -1
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.a223ea20056954479ae9.js.map +0 -1
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.addf2fa038fa60304aa2.js.map +0 -1
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js.24edcc52a1c014a8a5f0.js.map +0 -1
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.19ecf6babe00caff6b8a.js.map +0 -1
- hdsp_jupyter_extension-2.0.6.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.1f5038488cdfd8b3a85d.js.map +0 -1
- jupyter_ext/labextension/static/frontend_styles_index_js.02d346171474a0fb2dc1.js.map +0 -1
- jupyter_ext/labextension/static/lib_index_js.a223ea20056954479ae9.js.map +0 -1
- jupyter_ext/labextension/static/remoteEntry.addf2fa038fa60304aa2.js.map +0 -1
- jupyter_ext/labextension/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js.24edcc52a1c014a8a5f0.js.map +0 -1
- jupyter_ext/labextension/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.19ecf6babe00caff6b8a.js.map +0 -1
- jupyter_ext/labextension/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.1f5038488cdfd8b3a85d.js.map +0 -1
- {hdsp_jupyter_extension-2.0.6.data → hdsp_jupyter_extension-2.0.7.data}/data/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +0 -0
- {hdsp_jupyter_extension-2.0.6.data → hdsp_jupyter_extension-2.0.7.data}/data/share/jupyter/labextensions/hdsp-agent/install.json +0 -0
- {hdsp_jupyter_extension-2.0.6.data → hdsp_jupyter_extension-2.0.7.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.6.data → hdsp_jupyter_extension-2.0.7.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.6.data → hdsp_jupyter_extension-2.0.7.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.6.data → hdsp_jupyter_extension-2.0.7.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.6.data → hdsp_jupyter_extension-2.0.7.data}/data/share/jupyter/labextensions/hdsp-agent/static/style.js +0 -0
- {hdsp_jupyter_extension-2.0.6.data → hdsp_jupyter_extension-2.0.7.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.6.data → hdsp_jupyter_extension-2.0.7.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.6.data → hdsp_jupyter_extension-2.0.7.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.6.data → hdsp_jupyter_extension-2.0.7.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.6.data → hdsp_jupyter_extension-2.0.7.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js +0 -0
- {hdsp_jupyter_extension-2.0.6.data → hdsp_jupyter_extension-2.0.7.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.6.dist-info → hdsp_jupyter_extension-2.0.7.dist-info}/WHEEL +0 -0
- {hdsp_jupyter_extension-2.0.6.dist-info → hdsp_jupyter_extension-2.0.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Jupyter Execution Middleware
|
|
3
|
-
|
|
4
|
-
Handles actual execution of code in Jupyter kernel.
|
|
5
|
-
Wraps jupyter_cell tool calls to execute code and return results.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import asyncio
|
|
9
|
-
import logging
|
|
10
|
-
from typing import Any, Callable, Dict, Optional
|
|
11
|
-
|
|
12
|
-
from agent_server.langchain.executors.jupyter_executor import (
|
|
13
|
-
JupyterExecutor,
|
|
14
|
-
get_jupyter_executor,
|
|
15
|
-
)
|
|
16
|
-
from agent_server.langchain.state import AgentRuntime, AgentState
|
|
17
|
-
|
|
18
|
-
logger = logging.getLogger(__name__)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class JupyterExecutionMiddleware:
|
|
22
|
-
"""
|
|
23
|
-
Middleware that executes code in Jupyter kernel.
|
|
24
|
-
|
|
25
|
-
This middleware:
|
|
26
|
-
1. Wraps jupyter_cell and markdown tool calls
|
|
27
|
-
2. Executes code using JupyterExecutor
|
|
28
|
-
3. Returns execution results to the agent
|
|
29
|
-
4. Handles execution errors and timeouts
|
|
30
|
-
|
|
31
|
-
Uses @wrap_tool_call hook pattern from LangChain middleware.
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
def __init__(
|
|
35
|
-
self,
|
|
36
|
-
executor: Optional[JupyterExecutor] = None,
|
|
37
|
-
timeout: float = 60.0,
|
|
38
|
-
add_to_notebook: bool = True,
|
|
39
|
-
enabled: bool = True,
|
|
40
|
-
):
|
|
41
|
-
"""
|
|
42
|
-
Initialize Jupyter execution middleware.
|
|
43
|
-
|
|
44
|
-
Args:
|
|
45
|
-
executor: JupyterExecutor instance
|
|
46
|
-
timeout: Execution timeout in seconds
|
|
47
|
-
add_to_notebook: Whether to add cells to notebook
|
|
48
|
-
enabled: Whether execution is enabled
|
|
49
|
-
"""
|
|
50
|
-
self._executor = executor
|
|
51
|
-
self._timeout = timeout
|
|
52
|
-
self._add_to_notebook = add_to_notebook
|
|
53
|
-
self._enabled = enabled
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def name(self) -> str:
|
|
57
|
-
return "JupyterExecutionMiddleware"
|
|
58
|
-
|
|
59
|
-
def _get_executor(self, runtime: AgentRuntime) -> JupyterExecutor:
|
|
60
|
-
"""Get executor from runtime or create default"""
|
|
61
|
-
if runtime and runtime.jupyter_executor:
|
|
62
|
-
return runtime.jupyter_executor
|
|
63
|
-
if self._executor:
|
|
64
|
-
return self._executor
|
|
65
|
-
return get_jupyter_executor()
|
|
66
|
-
|
|
67
|
-
async def wrap_tool_call(
|
|
68
|
-
self,
|
|
69
|
-
tool_name: str,
|
|
70
|
-
tool_input: Dict[str, Any],
|
|
71
|
-
next_call: Callable,
|
|
72
|
-
state: AgentState,
|
|
73
|
-
runtime: AgentRuntime,
|
|
74
|
-
) -> Dict[str, Any]:
|
|
75
|
-
"""
|
|
76
|
-
Wrap tool calls to handle Jupyter execution.
|
|
77
|
-
|
|
78
|
-
For jupyter_cell tools, executes code in kernel.
|
|
79
|
-
For other tools, passes through to next handler.
|
|
80
|
-
|
|
81
|
-
Args:
|
|
82
|
-
tool_name: Name of the tool
|
|
83
|
-
tool_input: Tool input parameters
|
|
84
|
-
next_call: Next handler in chain
|
|
85
|
-
state: Current agent state
|
|
86
|
-
runtime: Agent runtime context
|
|
87
|
-
|
|
88
|
-
Returns:
|
|
89
|
-
Tool execution result
|
|
90
|
-
"""
|
|
91
|
-
if not self._enabled:
|
|
92
|
-
return await next_call(tool_name, tool_input)
|
|
93
|
-
|
|
94
|
-
# Handle jupyter_cell execution
|
|
95
|
-
if tool_name == "jupyter_cell_tool":
|
|
96
|
-
return await self._execute_jupyter_cell(
|
|
97
|
-
tool_input, state, runtime
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
# Handle markdown cell
|
|
101
|
-
if tool_name == "markdown_tool":
|
|
102
|
-
return await self._add_markdown_cell(
|
|
103
|
-
tool_input, state, runtime
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
# Handle final_answer
|
|
107
|
-
if tool_name == "final_answer_tool":
|
|
108
|
-
return await self._handle_final_answer(
|
|
109
|
-
tool_input, state, runtime
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
# Pass through for other tools
|
|
113
|
-
return await next_call(tool_name, tool_input)
|
|
114
|
-
|
|
115
|
-
async def _execute_jupyter_cell(
|
|
116
|
-
self,
|
|
117
|
-
tool_input: Dict[str, Any],
|
|
118
|
-
state: AgentState,
|
|
119
|
-
runtime: AgentRuntime,
|
|
120
|
-
) -> Dict[str, Any]:
|
|
121
|
-
"""Execute code in Jupyter cell"""
|
|
122
|
-
code = tool_input.get("code", "")
|
|
123
|
-
if not code:
|
|
124
|
-
return {
|
|
125
|
-
"success": False,
|
|
126
|
-
"error": "No code provided",
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
# Check for validation failure
|
|
130
|
-
if tool_input.get("validation_failed"):
|
|
131
|
-
errors = tool_input.get("validation_errors", [])
|
|
132
|
-
return {
|
|
133
|
-
"success": False,
|
|
134
|
-
"error_type": "ValidationError",
|
|
135
|
-
"error": "Code validation failed",
|
|
136
|
-
"validation_errors": errors,
|
|
137
|
-
"message": "Please fix validation errors and try again",
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
executor = self._get_executor(runtime)
|
|
141
|
-
|
|
142
|
-
# Initialize executor if needed
|
|
143
|
-
if not executor.is_initialized:
|
|
144
|
-
notebook_context = state.get("notebook_context", {})
|
|
145
|
-
kernel_id = notebook_context.get("kernel_id")
|
|
146
|
-
notebook_path = notebook_context.get("notebook_path")
|
|
147
|
-
|
|
148
|
-
if kernel_id and notebook_path:
|
|
149
|
-
await executor.initialize(kernel_id, notebook_path)
|
|
150
|
-
else:
|
|
151
|
-
logger.warning("Kernel/notebook not available, using mock execution")
|
|
152
|
-
|
|
153
|
-
try:
|
|
154
|
-
result = await asyncio.wait_for(
|
|
155
|
-
executor.execute_code(
|
|
156
|
-
code,
|
|
157
|
-
timeout=self._timeout,
|
|
158
|
-
add_to_notebook=self._add_to_notebook,
|
|
159
|
-
),
|
|
160
|
-
timeout=self._timeout + 5,
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
# Update execution history in state
|
|
164
|
-
execution_history = state.get("execution_history", [])
|
|
165
|
-
execution_history.append(result.to_dict())
|
|
166
|
-
state["execution_history"] = execution_history
|
|
167
|
-
|
|
168
|
-
if result.success:
|
|
169
|
-
return {
|
|
170
|
-
"success": True,
|
|
171
|
-
"output": result.output,
|
|
172
|
-
"execution_count": result.execution_count,
|
|
173
|
-
"cell_index": result.cell_index,
|
|
174
|
-
"display_data": result.display_data,
|
|
175
|
-
}
|
|
176
|
-
else:
|
|
177
|
-
# Update error state
|
|
178
|
-
state["error_count"] = state.get("error_count", 0) + 1
|
|
179
|
-
state["last_error"] = {
|
|
180
|
-
"error_type": result.error_type,
|
|
181
|
-
"error_message": result.error_message,
|
|
182
|
-
"traceback": result.traceback,
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return {
|
|
186
|
-
"success": False,
|
|
187
|
-
"error_type": result.error_type,
|
|
188
|
-
"error": result.error_message,
|
|
189
|
-
"traceback": result.traceback,
|
|
190
|
-
"output": result.output,
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
except asyncio.TimeoutError:
|
|
194
|
-
logger.error(f"Execution timeout after {self._timeout}s")
|
|
195
|
-
state["error_count"] = state.get("error_count", 0) + 1
|
|
196
|
-
state["last_error"] = {
|
|
197
|
-
"error_type": "TimeoutError",
|
|
198
|
-
"error_message": f"Execution timed out after {self._timeout} seconds",
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return {
|
|
202
|
-
"success": False,
|
|
203
|
-
"error_type": "TimeoutError",
|
|
204
|
-
"error": f"Execution timed out after {self._timeout} seconds",
|
|
205
|
-
}
|
|
206
|
-
except Exception as e:
|
|
207
|
-
logger.error(f"Execution failed: {e}")
|
|
208
|
-
state["error_count"] = state.get("error_count", 0) + 1
|
|
209
|
-
state["last_error"] = {
|
|
210
|
-
"error_type": type(e).__name__,
|
|
211
|
-
"error_message": str(e),
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return {
|
|
215
|
-
"success": False,
|
|
216
|
-
"error_type": type(e).__name__,
|
|
217
|
-
"error": str(e),
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
async def _add_markdown_cell(
|
|
221
|
-
self,
|
|
222
|
-
tool_input: Dict[str, Any],
|
|
223
|
-
state: AgentState,
|
|
224
|
-
runtime: AgentRuntime,
|
|
225
|
-
) -> Dict[str, Any]:
|
|
226
|
-
"""Add markdown cell to notebook"""
|
|
227
|
-
content = tool_input.get("content", "")
|
|
228
|
-
if not content:
|
|
229
|
-
return {
|
|
230
|
-
"success": False,
|
|
231
|
-
"error": "No content provided",
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
executor = self._get_executor(runtime)
|
|
235
|
-
|
|
236
|
-
if not executor.is_initialized:
|
|
237
|
-
return {
|
|
238
|
-
"success": True,
|
|
239
|
-
"message": "[Mock] Markdown cell would be added",
|
|
240
|
-
"content": content[:100],
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
try:
|
|
244
|
-
cell_index = await executor.add_markdown_cell(content)
|
|
245
|
-
|
|
246
|
-
return {
|
|
247
|
-
"success": True,
|
|
248
|
-
"cell_index": cell_index,
|
|
249
|
-
"message": "Markdown cell added successfully",
|
|
250
|
-
}
|
|
251
|
-
except Exception as e:
|
|
252
|
-
logger.error(f"Failed to add markdown cell: {e}")
|
|
253
|
-
return {
|
|
254
|
-
"success": False,
|
|
255
|
-
"error": str(e),
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
async def _handle_final_answer(
|
|
259
|
-
self,
|
|
260
|
-
tool_input: Dict[str, Any],
|
|
261
|
-
state: AgentState,
|
|
262
|
-
runtime: AgentRuntime,
|
|
263
|
-
) -> Dict[str, Any]:
|
|
264
|
-
"""Handle final answer tool"""
|
|
265
|
-
answer = tool_input.get("answer", "")
|
|
266
|
-
summary = tool_input.get("summary", "")
|
|
267
|
-
|
|
268
|
-
# Update state
|
|
269
|
-
state["final_answer"] = answer
|
|
270
|
-
state["is_complete"] = True
|
|
271
|
-
|
|
272
|
-
return {
|
|
273
|
-
"success": True,
|
|
274
|
-
"answer": answer,
|
|
275
|
-
"summary": summary,
|
|
276
|
-
"message": "Task completed",
|
|
277
|
-
"is_complete": True,
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
def create_jupyter_execution_middleware(
|
|
282
|
-
timeout: float = 60.0,
|
|
283
|
-
add_to_notebook: bool = True,
|
|
284
|
-
enabled: bool = True,
|
|
285
|
-
) -> JupyterExecutionMiddleware:
|
|
286
|
-
"""
|
|
287
|
-
Factory function to create Jupyter execution middleware.
|
|
288
|
-
|
|
289
|
-
Args:
|
|
290
|
-
timeout: Execution timeout in seconds
|
|
291
|
-
add_to_notebook: Add cells to notebook
|
|
292
|
-
enabled: Whether to enable execution
|
|
293
|
-
|
|
294
|
-
Returns:
|
|
295
|
-
Configured JupyterExecutionMiddleware instance
|
|
296
|
-
"""
|
|
297
|
-
return JupyterExecutionMiddleware(
|
|
298
|
-
timeout=timeout,
|
|
299
|
-
add_to_notebook=add_to_notebook,
|
|
300
|
-
enabled=enabled,
|
|
301
|
-
)
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
RAG Middleware
|
|
3
|
-
|
|
4
|
-
Injects relevant context from the RAG system before model calls.
|
|
5
|
-
Uses the existing RAG manager to retrieve relevant documentation
|
|
6
|
-
and code examples based on the user's request.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import logging
|
|
10
|
-
from typing import Any, Dict, List, Optional
|
|
11
|
-
|
|
12
|
-
from agent_server.langchain.state import AgentRuntime, AgentState
|
|
13
|
-
|
|
14
|
-
logger = logging.getLogger(__name__)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class RAGMiddleware:
|
|
18
|
-
"""
|
|
19
|
-
Middleware that injects RAG context before model calls.
|
|
20
|
-
|
|
21
|
-
This middleware:
|
|
22
|
-
1. Detects required libraries from the user request
|
|
23
|
-
2. Queries the RAG system for relevant documentation
|
|
24
|
-
3. Injects the context into the agent state
|
|
25
|
-
|
|
26
|
-
Uses @before_model hook pattern from LangChain middleware.
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
def __init__(
|
|
30
|
-
self,
|
|
31
|
-
rag_manager: Any = None,
|
|
32
|
-
library_detector: Any = None,
|
|
33
|
-
max_context_length: int = 4000,
|
|
34
|
-
enabled: bool = True,
|
|
35
|
-
):
|
|
36
|
-
"""
|
|
37
|
-
Initialize RAG middleware.
|
|
38
|
-
|
|
39
|
-
Args:
|
|
40
|
-
rag_manager: RAGManager instance for context retrieval
|
|
41
|
-
library_detector: LibraryDetector for detecting required libraries
|
|
42
|
-
max_context_length: Maximum context length to inject
|
|
43
|
-
enabled: Whether RAG injection is enabled
|
|
44
|
-
"""
|
|
45
|
-
self._rag_manager = rag_manager
|
|
46
|
-
self._library_detector = library_detector
|
|
47
|
-
self._max_context_length = max_context_length
|
|
48
|
-
self._enabled = enabled
|
|
49
|
-
|
|
50
|
-
@property
|
|
51
|
-
def name(self) -> str:
|
|
52
|
-
return "RAGMiddleware"
|
|
53
|
-
|
|
54
|
-
def _get_rag_manager(self):
|
|
55
|
-
"""Lazy load RAG manager if not provided"""
|
|
56
|
-
if self._rag_manager is None:
|
|
57
|
-
try:
|
|
58
|
-
from agent_server.core.rag_manager import get_rag_manager
|
|
59
|
-
self._rag_manager = get_rag_manager()
|
|
60
|
-
except ImportError:
|
|
61
|
-
logger.warning("RAG manager not available")
|
|
62
|
-
return None
|
|
63
|
-
return self._rag_manager
|
|
64
|
-
|
|
65
|
-
def _get_library_detector(self):
|
|
66
|
-
"""Lazy load library detector if not provided"""
|
|
67
|
-
if self._library_detector is None:
|
|
68
|
-
try:
|
|
69
|
-
from hdsp_agent_core.knowledge.loader import get_library_detector
|
|
70
|
-
self._library_detector = get_library_detector()
|
|
71
|
-
except ImportError:
|
|
72
|
-
logger.warning("Library detector not available")
|
|
73
|
-
return None
|
|
74
|
-
return self._library_detector
|
|
75
|
-
|
|
76
|
-
def _detect_libraries(
|
|
77
|
-
self,
|
|
78
|
-
request: str,
|
|
79
|
-
imported_libraries: List[str],
|
|
80
|
-
) -> List[str]:
|
|
81
|
-
"""Detect required libraries from the request"""
|
|
82
|
-
detector = self._get_library_detector()
|
|
83
|
-
if detector is None:
|
|
84
|
-
return []
|
|
85
|
-
|
|
86
|
-
try:
|
|
87
|
-
from hdsp_agent_core.knowledge.loader import get_knowledge_base
|
|
88
|
-
knowledge_base = get_knowledge_base()
|
|
89
|
-
available = knowledge_base.list_available_libraries()
|
|
90
|
-
|
|
91
|
-
if not available:
|
|
92
|
-
return []
|
|
93
|
-
|
|
94
|
-
detected = detector.detect(
|
|
95
|
-
request=request,
|
|
96
|
-
available_libraries=available,
|
|
97
|
-
imported_libraries=imported_libraries,
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
return detected
|
|
101
|
-
except Exception as e:
|
|
102
|
-
logger.warning(f"Library detection failed: {e}")
|
|
103
|
-
return []
|
|
104
|
-
|
|
105
|
-
async def _get_rag_context(
|
|
106
|
-
self,
|
|
107
|
-
query: str,
|
|
108
|
-
detected_libraries: List[str],
|
|
109
|
-
) -> Optional[str]:
|
|
110
|
-
"""Get RAG context for the query"""
|
|
111
|
-
rag_manager = self._get_rag_manager()
|
|
112
|
-
if rag_manager is None or not rag_manager.is_ready:
|
|
113
|
-
return None
|
|
114
|
-
|
|
115
|
-
try:
|
|
116
|
-
context = await rag_manager.get_context_for_query(
|
|
117
|
-
query=query,
|
|
118
|
-
detected_libraries=detected_libraries,
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
if context and len(context) > self._max_context_length:
|
|
122
|
-
context = context[:self._max_context_length] + "\n... (truncated)"
|
|
123
|
-
|
|
124
|
-
return context
|
|
125
|
-
except Exception as e:
|
|
126
|
-
logger.warning(f"RAG context retrieval failed: {e}")
|
|
127
|
-
return None
|
|
128
|
-
|
|
129
|
-
async def before_model(
|
|
130
|
-
self,
|
|
131
|
-
state: AgentState,
|
|
132
|
-
runtime: AgentRuntime,
|
|
133
|
-
) -> Optional[Dict[str, Any]]:
|
|
134
|
-
"""
|
|
135
|
-
Hook called before each model invocation.
|
|
136
|
-
|
|
137
|
-
Injects RAG context into the state if available.
|
|
138
|
-
|
|
139
|
-
Args:
|
|
140
|
-
state: Current agent state
|
|
141
|
-
runtime: Agent runtime context
|
|
142
|
-
|
|
143
|
-
Returns:
|
|
144
|
-
Updated state fields or None
|
|
145
|
-
"""
|
|
146
|
-
if not self._enabled:
|
|
147
|
-
return None
|
|
148
|
-
|
|
149
|
-
# Skip if context already injected
|
|
150
|
-
if state.get("rag_context"):
|
|
151
|
-
return None
|
|
152
|
-
|
|
153
|
-
user_request = state.get("user_request", "")
|
|
154
|
-
if not user_request:
|
|
155
|
-
return None
|
|
156
|
-
|
|
157
|
-
# Detect libraries
|
|
158
|
-
notebook_context = state.get("notebook_context", {})
|
|
159
|
-
imported_libs = notebook_context.get("imported_libraries", [])
|
|
160
|
-
|
|
161
|
-
detected_libraries = self._detect_libraries(user_request, imported_libs)
|
|
162
|
-
|
|
163
|
-
if detected_libraries:
|
|
164
|
-
logger.info(f"Detected libraries: {detected_libraries}")
|
|
165
|
-
|
|
166
|
-
# Get RAG context
|
|
167
|
-
rag_context = await self._get_rag_context(user_request, detected_libraries)
|
|
168
|
-
|
|
169
|
-
if rag_context:
|
|
170
|
-
logger.info(f"RAG context injected: {len(rag_context)} chars")
|
|
171
|
-
return {
|
|
172
|
-
"rag_context": rag_context,
|
|
173
|
-
"detected_libraries": detected_libraries,
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return {"detected_libraries": detected_libraries}
|
|
177
|
-
|
|
178
|
-
def format_context_for_prompt(
|
|
179
|
-
self,
|
|
180
|
-
rag_context: Optional[str],
|
|
181
|
-
detected_libraries: List[str],
|
|
182
|
-
) -> str:
|
|
183
|
-
"""
|
|
184
|
-
Format RAG context for inclusion in the prompt.
|
|
185
|
-
|
|
186
|
-
Args:
|
|
187
|
-
rag_context: Retrieved RAG context
|
|
188
|
-
detected_libraries: List of detected libraries
|
|
189
|
-
|
|
190
|
-
Returns:
|
|
191
|
-
Formatted context string
|
|
192
|
-
"""
|
|
193
|
-
if not rag_context:
|
|
194
|
-
return ""
|
|
195
|
-
|
|
196
|
-
parts = []
|
|
197
|
-
|
|
198
|
-
if detected_libraries:
|
|
199
|
-
parts.append(f"## Detected Libraries: {', '.join(detected_libraries)}")
|
|
200
|
-
|
|
201
|
-
parts.append("## Relevant Documentation")
|
|
202
|
-
parts.append(rag_context)
|
|
203
|
-
|
|
204
|
-
return "\n\n".join(parts)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def create_rag_middleware(
|
|
208
|
-
rag_manager: Any = None,
|
|
209
|
-
max_context_length: int = 4000,
|
|
210
|
-
enabled: bool = True,
|
|
211
|
-
) -> RAGMiddleware:
|
|
212
|
-
"""
|
|
213
|
-
Factory function to create RAG middleware.
|
|
214
|
-
|
|
215
|
-
Args:
|
|
216
|
-
rag_manager: Optional RAGManager instance
|
|
217
|
-
max_context_length: Maximum context length
|
|
218
|
-
enabled: Whether to enable RAG
|
|
219
|
-
|
|
220
|
-
Returns:
|
|
221
|
-
Configured RAGMiddleware instance
|
|
222
|
-
"""
|
|
223
|
-
return RAGMiddleware(
|
|
224
|
-
rag_manager=rag_manager,
|
|
225
|
-
max_context_length=max_context_length,
|
|
226
|
-
enabled=enabled,
|
|
227
|
-
)
|