hdsp-jupyter-extension 2.0.26__py3-none-any.whl → 2.0.28__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/context_providers/__init__.py +4 -2
- agent_server/context_providers/actions.py +73 -7
- agent_server/context_providers/file.py +23 -23
- agent_server/langchain/__init__.py +2 -2
- agent_server/langchain/agent.py +18 -251
- agent_server/langchain/agent_factory.py +26 -4
- agent_server/langchain/agent_prompts/planner_prompt.py +22 -35
- agent_server/langchain/custom_middleware.py +278 -43
- agent_server/langchain/llm_factory.py +102 -54
- agent_server/langchain/logging_utils.py +1 -1
- agent_server/langchain/middleware/__init__.py +5 -0
- agent_server/langchain/middleware/code_history_middleware.py +126 -37
- agent_server/langchain/middleware/content_injection_middleware.py +110 -0
- agent_server/langchain/middleware/subagent_events.py +88 -9
- agent_server/langchain/middleware/subagent_middleware.py +518 -240
- agent_server/langchain/prompts.py +5 -22
- agent_server/langchain/state_schema.py +44 -0
- agent_server/langchain/tools/jupyter_tools.py +4 -5
- agent_server/langchain/tools/tool_registry.py +6 -0
- agent_server/routers/chat.py +305 -2
- agent_server/routers/config.py +193 -8
- agent_server/routers/config_schema.py +254 -0
- agent_server/routers/context.py +31 -8
- agent_server/routers/langchain_agent.py +310 -153
- hdsp_agent_core/managers/config_manager.py +100 -1
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.data}/data/share/jupyter/labextensions/hdsp-agent/build_log.json +1 -1
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.data}/data/share/jupyter/labextensions/hdsp-agent/package.json +2 -2
- hdsp_jupyter_extension-2.0.26.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.b5e4416b4e07ec087aad.js → hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.55727265b00191e68d9a.js +479 -15
- hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.55727265b00191e68d9a.js.map +1 -0
- jupyter_ext/labextension/static/lib_index_js.67505497667f9c0a763d.js → hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.df05d90f366bfd5fa023.js +1287 -190
- hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.df05d90f366bfd5fa023.js.map +1 -0
- hdsp_jupyter_extension-2.0.26.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.0fe2dcbbd176ee0efceb.js → hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.08fce819ee32e9d25175.js +3 -3
- jupyter_ext/labextension/static/remoteEntry.0fe2dcbbd176ee0efceb.js.map → hdsp_jupyter_extension-2.0.28.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.08fce819ee32e9d25175.js.map +1 -1
- {hdsp_jupyter_extension-2.0.26.dist-info → hdsp_jupyter_extension-2.0.28.dist-info}/METADATA +1 -1
- {hdsp_jupyter_extension-2.0.26.dist-info → hdsp_jupyter_extension-2.0.28.dist-info}/RECORD +66 -64
- jupyter_ext/_version.py +1 -1
- jupyter_ext/handlers.py +41 -0
- jupyter_ext/labextension/build_log.json +1 -1
- jupyter_ext/labextension/package.json +2 -2
- jupyter_ext/labextension/static/{frontend_styles_index_js.b5e4416b4e07ec087aad.js → frontend_styles_index_js.55727265b00191e68d9a.js} +479 -15
- jupyter_ext/labextension/static/frontend_styles_index_js.55727265b00191e68d9a.js.map +1 -0
- hdsp_jupyter_extension-2.0.26.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.67505497667f9c0a763d.js → jupyter_ext/labextension/static/lib_index_js.df05d90f366bfd5fa023.js +1287 -190
- jupyter_ext/labextension/static/lib_index_js.df05d90f366bfd5fa023.js.map +1 -0
- jupyter_ext/labextension/static/{remoteEntry.0fe2dcbbd176ee0efceb.js → remoteEntry.08fce819ee32e9d25175.js} +3 -3
- hdsp_jupyter_extension-2.0.26.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.0fe2dcbbd176ee0efceb.js.map → jupyter_ext/labextension/static/remoteEntry.08fce819ee32e9d25175.js.map +1 -1
- agent_server/langchain/middleware/description_injector.py +0 -150
- hdsp_jupyter_extension-2.0.26.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.b5e4416b4e07ec087aad.js.map +0 -1
- hdsp_jupyter_extension-2.0.26.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.67505497667f9c0a763d.js.map +0 -1
- jupyter_ext/labextension/static/frontend_styles_index_js.b5e4416b4e07ec087aad.js.map +0 -1
- jupyter_ext/labextension/static/lib_index_js.67505497667f9c0a763d.js.map +0 -1
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.data}/data/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +0 -0
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.data}/data/share/jupyter/labextensions/hdsp-agent/install.json +0 -0
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.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.26.data → hdsp_jupyter_extension-2.0.28.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.26.data → hdsp_jupyter_extension-2.0.28.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.26.data → hdsp_jupyter_extension-2.0.28.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.26.data → hdsp_jupyter_extension-2.0.28.data}/data/share/jupyter/labextensions/hdsp-agent/static/style.js +0 -0
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.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.26.data → hdsp_jupyter_extension-2.0.28.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.26.data → hdsp_jupyter_extension-2.0.28.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js.24edcc52a1c014a8a5f0.js +0 -0
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js.24edcc52a1c014a8a5f0.js.map +0 -0
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.19ecf6babe00caff6b8a.js +0 -0
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.19ecf6babe00caff6b8a.js.map +0 -0
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.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.26.data → hdsp_jupyter_extension-2.0.28.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.26.data → hdsp_jupyter_extension-2.0.28.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js +0 -0
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.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.26.data → hdsp_jupyter_extension-2.0.28.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.1f5038488cdfd8b3a85d.js +0 -0
- {hdsp_jupyter_extension-2.0.26.data → hdsp_jupyter_extension-2.0.28.data}/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.1f5038488cdfd8b3a85d.js.map +0 -0
- {hdsp_jupyter_extension-2.0.26.dist-info → hdsp_jupyter_extension-2.0.28.dist-info}/WHEEL +0 -0
- {hdsp_jupyter_extension-2.0.26.dist-info → hdsp_jupyter_extension-2.0.28.dist-info}/licenses/LICENSE +0 -0
agent_server/routers/config.py
CHANGED
|
@@ -1,19 +1,42 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Config Router - Configuration management endpoints
|
|
3
|
+
|
|
4
|
+
Provides:
|
|
5
|
+
- GET/POST /config - Legacy full config (backward compatible)
|
|
6
|
+
- GET/POST /config/admin - Admin-only configuration
|
|
7
|
+
- GET/POST /config/user - User-only configuration
|
|
8
|
+
- GET /config/is-admin - Check if running in admin mode
|
|
9
|
+
- GET /config/prompts - Default system prompts
|
|
3
10
|
"""
|
|
4
11
|
|
|
5
|
-
from typing import Any, Dict,
|
|
12
|
+
from typing import Any, Dict, Optional
|
|
6
13
|
|
|
7
14
|
from fastapi import APIRouter, HTTPException
|
|
8
15
|
from hdsp_agent_core.managers.config_manager import ConfigManager
|
|
9
16
|
from pydantic import BaseModel
|
|
10
17
|
|
|
18
|
+
from agent_server.langchain.agent_prompts.athena_query_prompt import (
|
|
19
|
+
ATHENA_QUERY_SYSTEM_PROMPT,
|
|
20
|
+
)
|
|
21
|
+
|
|
11
22
|
# Import prompts from centralized location
|
|
12
|
-
from agent_server.langchain.prompts import DEFAULT_SYSTEM_PROMPT
|
|
13
23
|
from agent_server.langchain.agent_prompts.planner_prompt import PLANNER_SYSTEM_PROMPT
|
|
14
|
-
from agent_server.langchain.agent_prompts.python_developer_prompt import
|
|
15
|
-
|
|
16
|
-
|
|
24
|
+
from agent_server.langchain.agent_prompts.python_developer_prompt import (
|
|
25
|
+
PYTHON_DEVELOPER_SYSTEM_PROMPT,
|
|
26
|
+
)
|
|
27
|
+
from agent_server.langchain.agent_prompts.researcher_prompt import (
|
|
28
|
+
RESEARCHER_SYSTEM_PROMPT,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Import new schema models
|
|
32
|
+
from agent_server.routers.config_schema import (
|
|
33
|
+
AdminConfigResponse,
|
|
34
|
+
AdminConfigUpdateRequest,
|
|
35
|
+
IsAdminResponse,
|
|
36
|
+
UserConfigResponse,
|
|
37
|
+
UserConfigUpdateRequest,
|
|
38
|
+
is_admin_mode,
|
|
39
|
+
)
|
|
17
40
|
|
|
18
41
|
router = APIRouter()
|
|
19
42
|
|
|
@@ -107,6 +130,170 @@ def _mask_api_keys(config: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
107
130
|
return masked
|
|
108
131
|
|
|
109
132
|
|
|
133
|
+
# =============================================================================
|
|
134
|
+
# Admin Mode Detection API
|
|
135
|
+
# =============================================================================
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@router.get("/is-admin", response_model=IsAdminResponse)
|
|
139
|
+
async def check_admin_mode() -> IsAdminResponse:
|
|
140
|
+
"""
|
|
141
|
+
Check if the current environment is in admin mode.
|
|
142
|
+
|
|
143
|
+
Admin mode is determined by environment variables:
|
|
144
|
+
- Neither SAGEMAKER_SPACE_NAME nor HDSP_PRJ_ID is set (development env)
|
|
145
|
+
- OR SAGEMAKER_SPACE_NAME contains 'pl2wadmprj'
|
|
146
|
+
- OR HDSP_PRJ_ID equals 'pl2wadmprj'
|
|
147
|
+
"""
|
|
148
|
+
is_admin, reason = is_admin_mode()
|
|
149
|
+
return IsAdminResponse(isAdmin=is_admin, reason=reason)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# =============================================================================
|
|
153
|
+
# Admin Config API
|
|
154
|
+
# =============================================================================
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@router.get("/admin", response_model=AdminConfigResponse)
|
|
158
|
+
async def get_admin_config() -> AdminConfigResponse:
|
|
159
|
+
"""
|
|
160
|
+
Get admin configuration (LLM settings, prompts, server URLs).
|
|
161
|
+
|
|
162
|
+
API keys are masked for security.
|
|
163
|
+
"""
|
|
164
|
+
try:
|
|
165
|
+
config_manager = ConfigManager.get_instance()
|
|
166
|
+
config = config_manager.get_admin_config()
|
|
167
|
+
|
|
168
|
+
# Mask API keys
|
|
169
|
+
masked_config = _mask_api_keys(config)
|
|
170
|
+
|
|
171
|
+
# Also mask embedding API key if present
|
|
172
|
+
if "embedding" in masked_config and isinstance(
|
|
173
|
+
masked_config["embedding"], dict
|
|
174
|
+
):
|
|
175
|
+
embedding_config = masked_config["embedding"].copy()
|
|
176
|
+
if "apiKey" in embedding_config and embedding_config["apiKey"]:
|
|
177
|
+
key = embedding_config["apiKey"]
|
|
178
|
+
if len(key) > 8:
|
|
179
|
+
embedding_config["apiKey"] = f"{key[:4]}...{key[-4:]}"
|
|
180
|
+
else:
|
|
181
|
+
embedding_config["apiKey"] = "***"
|
|
182
|
+
masked_config["embedding"] = embedding_config
|
|
183
|
+
|
|
184
|
+
return AdminConfigResponse(
|
|
185
|
+
provider=masked_config.get("provider", "gemini"),
|
|
186
|
+
gemini=masked_config.get("gemini", {}),
|
|
187
|
+
openai=masked_config.get("openai", {}),
|
|
188
|
+
vllm=masked_config.get("vllm", {}),
|
|
189
|
+
summarization=masked_config.get("summarization", {}),
|
|
190
|
+
embedding=masked_config.get("embedding", {}),
|
|
191
|
+
rag=masked_config.get("rag", {}),
|
|
192
|
+
agentServerUrl=masked_config.get("agentServerUrl", "http://localhost:8000"),
|
|
193
|
+
agentServerTimeout=masked_config.get("agentServerTimeout", 120.0),
|
|
194
|
+
prompts=masked_config.get("prompts", {}),
|
|
195
|
+
useResponsesApi=masked_config.get("useResponsesApi", False),
|
|
196
|
+
idleTimeout=masked_config.get("idleTimeout", 300),
|
|
197
|
+
)
|
|
198
|
+
except Exception as e:
|
|
199
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@router.post("/admin")
|
|
203
|
+
async def update_admin_config(request: AdminConfigUpdateRequest) -> Dict[str, Any]:
|
|
204
|
+
"""
|
|
205
|
+
Update admin configuration.
|
|
206
|
+
|
|
207
|
+
Only updates provided fields.
|
|
208
|
+
"""
|
|
209
|
+
try:
|
|
210
|
+
config_manager = ConfigManager.get_instance()
|
|
211
|
+
|
|
212
|
+
# Build update dict from request
|
|
213
|
+
updates = {}
|
|
214
|
+
if request.provider is not None:
|
|
215
|
+
updates["provider"] = request.provider
|
|
216
|
+
if request.gemini is not None:
|
|
217
|
+
updates["gemini"] = request.gemini
|
|
218
|
+
if request.openai is not None:
|
|
219
|
+
updates["openai"] = request.openai
|
|
220
|
+
if request.vllm is not None:
|
|
221
|
+
updates["vllm"] = request.vllm
|
|
222
|
+
if request.summarization is not None:
|
|
223
|
+
updates["summarization"] = request.summarization
|
|
224
|
+
if request.embedding is not None:
|
|
225
|
+
updates["embedding"] = request.embedding
|
|
226
|
+
if request.rag is not None:
|
|
227
|
+
updates["rag"] = request.rag
|
|
228
|
+
if request.agentServerUrl is not None:
|
|
229
|
+
updates["agentServerUrl"] = request.agentServerUrl
|
|
230
|
+
if request.agentServerTimeout is not None:
|
|
231
|
+
updates["agentServerTimeout"] = request.agentServerTimeout
|
|
232
|
+
if request.prompts is not None:
|
|
233
|
+
updates["prompts"] = request.prompts
|
|
234
|
+
if request.useResponsesApi is not None:
|
|
235
|
+
updates["useResponsesApi"] = request.useResponsesApi
|
|
236
|
+
if request.idleTimeout is not None:
|
|
237
|
+
updates["idleTimeout"] = request.idleTimeout
|
|
238
|
+
|
|
239
|
+
if updates:
|
|
240
|
+
config_manager.update_admin_config(updates)
|
|
241
|
+
|
|
242
|
+
return {"status": "success", "message": "Admin configuration updated"}
|
|
243
|
+
except Exception as e:
|
|
244
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
# =============================================================================
|
|
248
|
+
# User Config API
|
|
249
|
+
# =============================================================================
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@router.get("/user", response_model=UserConfigResponse)
|
|
253
|
+
async def get_user_config() -> UserConfigResponse:
|
|
254
|
+
"""
|
|
255
|
+
Get user configuration (preferences).
|
|
256
|
+
"""
|
|
257
|
+
try:
|
|
258
|
+
config_manager = ConfigManager.get_instance()
|
|
259
|
+
config = config_manager.get_user_config()
|
|
260
|
+
|
|
261
|
+
return UserConfigResponse(
|
|
262
|
+
workspaceRoot=config.get("workspaceRoot", ""),
|
|
263
|
+
temperature=config.get("temperature", 0.7),
|
|
264
|
+
autoApprove=config.get("autoApprove", False),
|
|
265
|
+
)
|
|
266
|
+
except Exception as e:
|
|
267
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
@router.post("/user")
|
|
271
|
+
async def update_user_config(request: UserConfigUpdateRequest) -> Dict[str, Any]:
|
|
272
|
+
"""
|
|
273
|
+
Update user configuration.
|
|
274
|
+
|
|
275
|
+
Only updates provided fields.
|
|
276
|
+
"""
|
|
277
|
+
try:
|
|
278
|
+
config_manager = ConfigManager.get_instance()
|
|
279
|
+
|
|
280
|
+
# Build update dict from request
|
|
281
|
+
updates = {}
|
|
282
|
+
if request.workspaceRoot is not None:
|
|
283
|
+
updates["workspaceRoot"] = request.workspaceRoot
|
|
284
|
+
if request.temperature is not None:
|
|
285
|
+
updates["temperature"] = request.temperature
|
|
286
|
+
if request.autoApprove is not None:
|
|
287
|
+
updates["autoApprove"] = request.autoApprove
|
|
288
|
+
|
|
289
|
+
if updates:
|
|
290
|
+
config_manager.update_user_config(updates)
|
|
291
|
+
|
|
292
|
+
return {"status": "success", "message": "User configuration updated"}
|
|
293
|
+
except Exception as e:
|
|
294
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
295
|
+
|
|
296
|
+
|
|
110
297
|
# =============================================================================
|
|
111
298
|
# Default Prompts API
|
|
112
299
|
# =============================================================================
|
|
@@ -115,7 +302,6 @@ def _mask_api_keys(config: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
115
302
|
class DefaultPromptsResponse(BaseModel):
|
|
116
303
|
"""Default prompts response model"""
|
|
117
304
|
|
|
118
|
-
single: str # Single-agent mode system prompt
|
|
119
305
|
planner: str # Multi-agent: Planner/Coordinator prompt
|
|
120
306
|
python_developer: str # Multi-agent: Python Developer prompt
|
|
121
307
|
researcher: str # Multi-agent: Researcher prompt
|
|
@@ -125,13 +311,12 @@ class DefaultPromptsResponse(BaseModel):
|
|
|
125
311
|
@router.get("/prompts", response_model=DefaultPromptsResponse)
|
|
126
312
|
async def get_default_prompts() -> DefaultPromptsResponse:
|
|
127
313
|
"""
|
|
128
|
-
Get default system prompts for
|
|
314
|
+
Get default system prompts for multi-agent mode.
|
|
129
315
|
|
|
130
316
|
Returns centralized prompts that frontend can use as defaults.
|
|
131
317
|
This ensures prompts are managed in one place (backend).
|
|
132
318
|
"""
|
|
133
319
|
return DefaultPromptsResponse(
|
|
134
|
-
single=DEFAULT_SYSTEM_PROMPT,
|
|
135
320
|
planner=PLANNER_SYSTEM_PROMPT,
|
|
136
321
|
python_developer=PYTHON_DEVELOPER_SYSTEM_PROMPT,
|
|
137
322
|
researcher=RESEARCHER_SYSTEM_PROMPT,
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Config Schema - Pydantic models for Admin/User configuration
|
|
3
|
+
|
|
4
|
+
Admin Config: LLM settings, prompts, server URLs (managed by administrators)
|
|
5
|
+
User Config: Workspace settings, temperature, auto-approve (user preferences)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
from enum import Enum
|
|
10
|
+
from typing import Any, Dict, Optional
|
|
11
|
+
|
|
12
|
+
from pydantic import BaseModel, Field
|
|
13
|
+
|
|
14
|
+
# =============================================================================
|
|
15
|
+
# Enums
|
|
16
|
+
# =============================================================================
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class LLMProvider(str, Enum):
|
|
20
|
+
"""Supported LLM providers"""
|
|
21
|
+
|
|
22
|
+
GEMINI = "gemini"
|
|
23
|
+
OPENAI = "openai"
|
|
24
|
+
VLLM = "vllm"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# =============================================================================
|
|
28
|
+
# Admin Config Models
|
|
29
|
+
# =============================================================================
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class GeminiConfig(BaseModel):
|
|
33
|
+
"""Gemini provider configuration"""
|
|
34
|
+
|
|
35
|
+
apiKey: str = ""
|
|
36
|
+
model: str = "gemini-2.5-pro"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class OpenAIConfig(BaseModel):
|
|
40
|
+
"""OpenAI provider configuration"""
|
|
41
|
+
|
|
42
|
+
apiKey: str = ""
|
|
43
|
+
model: str = "gpt-4o"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class VLLMConfig(BaseModel):
|
|
47
|
+
"""vLLM/OpenRouter provider configuration"""
|
|
48
|
+
|
|
49
|
+
endpoint: str = "http://localhost:8000"
|
|
50
|
+
apiKey: str = ""
|
|
51
|
+
model: str = "meta-llama/Llama-2-7b-chat-hf"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class SummarizationConfig(BaseModel):
|
|
55
|
+
"""Summarization LLM configuration (optional separate LLM)"""
|
|
56
|
+
|
|
57
|
+
enabled: bool = False
|
|
58
|
+
provider: LLMProvider = LLMProvider.GEMINI
|
|
59
|
+
model: Optional[str] = None # If None, use provider's default
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class EmbeddingConfig(BaseModel):
|
|
63
|
+
"""Embedding model configuration for RAG"""
|
|
64
|
+
|
|
65
|
+
provider: str = "openai"
|
|
66
|
+
model: str = "text-embedding-3-small"
|
|
67
|
+
apiKey: Optional[str] = None # If None, use main provider's key
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class RAGConfig(BaseModel):
|
|
71
|
+
"""RAG/Qdrant configuration"""
|
|
72
|
+
|
|
73
|
+
qdrantUrl: str = "http://localhost:6333"
|
|
74
|
+
collectionName: str = "hdsp_docs"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class AgentPromptsConfig(BaseModel):
|
|
78
|
+
"""Custom system prompts for agents"""
|
|
79
|
+
|
|
80
|
+
planner: Optional[str] = None
|
|
81
|
+
python_developer: Optional[str] = None
|
|
82
|
+
researcher: Optional[str] = None
|
|
83
|
+
athena_query: Optional[str] = None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class AdminConfig(BaseModel):
|
|
87
|
+
"""
|
|
88
|
+
Administrator-managed configuration.
|
|
89
|
+
|
|
90
|
+
Includes:
|
|
91
|
+
- LLM provider settings (API keys, models)
|
|
92
|
+
- Summarization LLM settings
|
|
93
|
+
- Embedding configuration
|
|
94
|
+
- RAG/Qdrant settings
|
|
95
|
+
- Agent server URL
|
|
96
|
+
- Agent prompts
|
|
97
|
+
- Idle timeout
|
|
98
|
+
- Use Responses API toggle
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
# LLM Provider Settings
|
|
102
|
+
provider: LLMProvider = LLMProvider.GEMINI
|
|
103
|
+
gemini: GeminiConfig = Field(default_factory=GeminiConfig)
|
|
104
|
+
openai: OpenAIConfig = Field(default_factory=OpenAIConfig)
|
|
105
|
+
vllm: VLLMConfig = Field(default_factory=VLLMConfig)
|
|
106
|
+
|
|
107
|
+
# Summarization LLM (optional separate LLM for context compression)
|
|
108
|
+
summarization: SummarizationConfig = Field(default_factory=SummarizationConfig)
|
|
109
|
+
|
|
110
|
+
# Embedding Configuration
|
|
111
|
+
embedding: EmbeddingConfig = Field(default_factory=EmbeddingConfig)
|
|
112
|
+
|
|
113
|
+
# RAG Configuration
|
|
114
|
+
rag: RAGConfig = Field(default_factory=RAGConfig)
|
|
115
|
+
|
|
116
|
+
# Agent Server Configuration
|
|
117
|
+
agentServerUrl: str = "http://localhost:8000"
|
|
118
|
+
agentServerTimeout: float = 120.0
|
|
119
|
+
|
|
120
|
+
# Agent Prompts (custom overrides)
|
|
121
|
+
prompts: AgentPromptsConfig = Field(default_factory=AgentPromptsConfig)
|
|
122
|
+
|
|
123
|
+
# Feature Toggles
|
|
124
|
+
useResponsesApi: bool = False
|
|
125
|
+
idleTimeout: int = 300 # seconds
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# =============================================================================
|
|
129
|
+
# User Config Models
|
|
130
|
+
# =============================================================================
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class UserConfig(BaseModel):
|
|
134
|
+
"""
|
|
135
|
+
User-managed configuration (preferences).
|
|
136
|
+
|
|
137
|
+
Includes:
|
|
138
|
+
- Workspace root path
|
|
139
|
+
- Temperature setting
|
|
140
|
+
- Auto-approve toggle
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
workspaceRoot: str = ""
|
|
144
|
+
temperature: float = Field(default=0.7, ge=0.0, le=2.0)
|
|
145
|
+
autoApprove: bool = False
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# =============================================================================
|
|
149
|
+
# Combined Config
|
|
150
|
+
# =============================================================================
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class FullConfig(BaseModel):
|
|
154
|
+
"""Full configuration combining admin and user settings"""
|
|
155
|
+
|
|
156
|
+
admin: AdminConfig = Field(default_factory=AdminConfig)
|
|
157
|
+
user: UserConfig = Field(default_factory=UserConfig)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# =============================================================================
|
|
161
|
+
# Admin Mode Detection
|
|
162
|
+
# =============================================================================
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def is_admin_mode() -> tuple[bool, str | None]:
|
|
166
|
+
"""
|
|
167
|
+
Detect if running in admin mode based on environment variables.
|
|
168
|
+
|
|
169
|
+
Admin mode conditions:
|
|
170
|
+
1. NEITHER SAGEMAKER_SPACE_NAME NOR HDSP_PRJ_ID is set (development environment)
|
|
171
|
+
2. OR SAGEMAKER_SPACE_NAME contains 'pl2wadmprj' as substring
|
|
172
|
+
3. OR HDSP_PRJ_ID equals 'pl2wadmprj'
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
tuple[bool, str | None]: (is_admin, reason)
|
|
176
|
+
"""
|
|
177
|
+
sagemaker_space = os.environ.get("SAGEMAKER_SPACE_NAME")
|
|
178
|
+
hdsp_prj_id = os.environ.get("HDSP_PRJ_ID")
|
|
179
|
+
|
|
180
|
+
# Development environment: neither env var is set
|
|
181
|
+
if sagemaker_space is None and hdsp_prj_id is None:
|
|
182
|
+
return True, "development_environment"
|
|
183
|
+
|
|
184
|
+
# Check SAGEMAKER_SPACE_NAME contains admin project ID
|
|
185
|
+
if sagemaker_space and "pl2wadmprj" in sagemaker_space:
|
|
186
|
+
return True, "sagemaker_admin_space"
|
|
187
|
+
|
|
188
|
+
# Check HDSP_PRJ_ID equals admin project ID
|
|
189
|
+
if hdsp_prj_id == "pl2wadmprj":
|
|
190
|
+
return True, "hdsp_admin_project"
|
|
191
|
+
|
|
192
|
+
return False, None
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
# =============================================================================
|
|
196
|
+
# API Request/Response Models
|
|
197
|
+
# =============================================================================
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class AdminConfigResponse(BaseModel):
|
|
201
|
+
"""Admin config response (with masked API keys)"""
|
|
202
|
+
|
|
203
|
+
provider: str
|
|
204
|
+
gemini: Dict[str, Any]
|
|
205
|
+
openai: Dict[str, Any]
|
|
206
|
+
vllm: Dict[str, Any]
|
|
207
|
+
summarization: Dict[str, Any]
|
|
208
|
+
embedding: Dict[str, Any]
|
|
209
|
+
rag: Dict[str, Any]
|
|
210
|
+
agentServerUrl: str
|
|
211
|
+
agentServerTimeout: float
|
|
212
|
+
prompts: Dict[str, Any]
|
|
213
|
+
useResponsesApi: bool
|
|
214
|
+
idleTimeout: int
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class AdminConfigUpdateRequest(BaseModel):
|
|
218
|
+
"""Admin config update request"""
|
|
219
|
+
|
|
220
|
+
provider: Optional[str] = None
|
|
221
|
+
gemini: Optional[Dict[str, Any]] = None
|
|
222
|
+
openai: Optional[Dict[str, Any]] = None
|
|
223
|
+
vllm: Optional[Dict[str, Any]] = None
|
|
224
|
+
summarization: Optional[Dict[str, Any]] = None
|
|
225
|
+
embedding: Optional[Dict[str, Any]] = None
|
|
226
|
+
rag: Optional[Dict[str, Any]] = None
|
|
227
|
+
agentServerUrl: Optional[str] = None
|
|
228
|
+
agentServerTimeout: Optional[float] = None
|
|
229
|
+
prompts: Optional[Dict[str, Any]] = None
|
|
230
|
+
useResponsesApi: Optional[bool] = None
|
|
231
|
+
idleTimeout: Optional[int] = None
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class UserConfigResponse(BaseModel):
|
|
235
|
+
"""User config response"""
|
|
236
|
+
|
|
237
|
+
workspaceRoot: str
|
|
238
|
+
temperature: float
|
|
239
|
+
autoApprove: bool
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class UserConfigUpdateRequest(BaseModel):
|
|
243
|
+
"""User config update request"""
|
|
244
|
+
|
|
245
|
+
workspaceRoot: Optional[str] = None
|
|
246
|
+
temperature: Optional[float] = None
|
|
247
|
+
autoApprove: Optional[bool] = None
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class IsAdminResponse(BaseModel):
|
|
251
|
+
"""Response for admin mode check"""
|
|
252
|
+
|
|
253
|
+
isAdmin: bool
|
|
254
|
+
reason: Optional[str] = None
|
agent_server/routers/context.py
CHANGED
|
@@ -12,7 +12,12 @@ from typing import Optional
|
|
|
12
12
|
from fastapi import APIRouter, Query
|
|
13
13
|
from pydantic import BaseModel
|
|
14
14
|
|
|
15
|
-
from agent_server.context_providers import
|
|
15
|
+
from agent_server.context_providers import (
|
|
16
|
+
CompactContextProvider,
|
|
17
|
+
FileContextProvider,
|
|
18
|
+
HelpContextProvider,
|
|
19
|
+
ResetContextProvider,
|
|
20
|
+
)
|
|
16
21
|
from agent_server.context_providers.base import ListOptionsResponse
|
|
17
22
|
|
|
18
23
|
router = APIRouter()
|
|
@@ -24,7 +29,9 @@ def _get_all_providers(base_dir: str):
|
|
|
24
29
|
"""Get all available context/action providers."""
|
|
25
30
|
return {
|
|
26
31
|
"@file": FileContextProvider(base_dir=base_dir),
|
|
27
|
-
"
|
|
32
|
+
"/reset": ResetContextProvider(base_dir=base_dir),
|
|
33
|
+
"/compact": CompactContextProvider(base_dir=base_dir),
|
|
34
|
+
"/help": HelpContextProvider(base_dir=base_dir),
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
|
|
@@ -93,7 +100,7 @@ async def get_autocomplete_options(
|
|
|
93
100
|
options = provider.get_arg_options(arg_prefix)
|
|
94
101
|
return ListOptionsResponse(options=options)
|
|
95
102
|
else:
|
|
96
|
-
# For commands without args (like
|
|
103
|
+
# For commands without args (like /reset), return the command itself
|
|
97
104
|
return ListOptionsResponse(options=[provider.get_provider_option()])
|
|
98
105
|
|
|
99
106
|
# No matching provider
|
|
@@ -145,7 +152,7 @@ async def list_context_providers():
|
|
|
145
152
|
providers = [
|
|
146
153
|
{
|
|
147
154
|
"id": "@file",
|
|
148
|
-
"description": "
|
|
155
|
+
"description": "파일 내용을 프롬프트에 포함",
|
|
149
156
|
"requires_arg": True,
|
|
150
157
|
"is_action": False,
|
|
151
158
|
"usage": "@file:path/to/file.py",
|
|
@@ -156,12 +163,28 @@ async def list_context_providers():
|
|
|
156
163
|
],
|
|
157
164
|
},
|
|
158
165
|
{
|
|
159
|
-
"id": "
|
|
160
|
-
"description": "
|
|
166
|
+
"id": "/reset",
|
|
167
|
+
"description": "세션 초기화 및 에이전트 리셋",
|
|
161
168
|
"requires_arg": False,
|
|
162
169
|
"is_action": True,
|
|
163
|
-
"usage": "
|
|
164
|
-
"examples": ["
|
|
170
|
+
"usage": "/reset",
|
|
171
|
+
"examples": ["/reset"],
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"id": "/compact",
|
|
175
|
+
"description": "대화 기록 압축 및 요약",
|
|
176
|
+
"requires_arg": False,
|
|
177
|
+
"is_action": True,
|
|
178
|
+
"usage": "/compact",
|
|
179
|
+
"examples": ["/compact"],
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"id": "/help",
|
|
183
|
+
"description": "도움말 및 사용 가이드",
|
|
184
|
+
"requires_arg": False,
|
|
185
|
+
"is_action": True,
|
|
186
|
+
"usage": "/help",
|
|
187
|
+
"examples": ["/help"],
|
|
165
188
|
},
|
|
166
189
|
]
|
|
167
190
|
|