hdsp-jupyter-extension 2.0.0__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/__init__.py +8 -0
- agent_server/core/__init__.py +92 -0
- agent_server/core/api_key_manager.py +427 -0
- agent_server/core/code_validator.py +1238 -0
- agent_server/core/context_condenser.py +308 -0
- agent_server/core/embedding_service.py +254 -0
- agent_server/core/error_classifier.py +577 -0
- agent_server/core/llm_client.py +95 -0
- agent_server/core/llm_service.py +649 -0
- agent_server/core/notebook_generator.py +274 -0
- agent_server/core/prompt_builder.py +35 -0
- agent_server/core/rag_manager.py +742 -0
- agent_server/core/reflection_engine.py +489 -0
- agent_server/core/retriever.py +248 -0
- agent_server/core/state_verifier.py +452 -0
- agent_server/core/summary_generator.py +484 -0
- agent_server/core/task_manager.py +198 -0
- agent_server/knowledge/__init__.py +9 -0
- agent_server/knowledge/watchdog_service.py +352 -0
- agent_server/main.py +160 -0
- agent_server/prompts/__init__.py +60 -0
- agent_server/prompts/file_action_prompts.py +113 -0
- agent_server/routers/__init__.py +9 -0
- agent_server/routers/agent.py +591 -0
- agent_server/routers/chat.py +188 -0
- agent_server/routers/config.py +100 -0
- agent_server/routers/file_resolver.py +293 -0
- agent_server/routers/health.py +42 -0
- agent_server/routers/rag.py +163 -0
- agent_server/schemas/__init__.py +60 -0
- hdsp_agent_core/__init__.py +158 -0
- hdsp_agent_core/factory.py +252 -0
- hdsp_agent_core/interfaces.py +203 -0
- hdsp_agent_core/knowledge/__init__.py +31 -0
- hdsp_agent_core/knowledge/chunking.py +356 -0
- hdsp_agent_core/knowledge/libraries/dask.md +188 -0
- hdsp_agent_core/knowledge/libraries/matplotlib.md +164 -0
- hdsp_agent_core/knowledge/libraries/polars.md +68 -0
- hdsp_agent_core/knowledge/loader.py +337 -0
- hdsp_agent_core/llm/__init__.py +13 -0
- hdsp_agent_core/llm/service.py +556 -0
- hdsp_agent_core/managers/__init__.py +22 -0
- hdsp_agent_core/managers/config_manager.py +133 -0
- hdsp_agent_core/managers/session_manager.py +251 -0
- hdsp_agent_core/models/__init__.py +115 -0
- hdsp_agent_core/models/agent.py +316 -0
- hdsp_agent_core/models/chat.py +41 -0
- hdsp_agent_core/models/common.py +95 -0
- hdsp_agent_core/models/rag.py +368 -0
- hdsp_agent_core/prompts/__init__.py +63 -0
- hdsp_agent_core/prompts/auto_agent_prompts.py +1260 -0
- hdsp_agent_core/prompts/cell_action_prompts.py +98 -0
- hdsp_agent_core/services/__init__.py +18 -0
- hdsp_agent_core/services/agent_service.py +438 -0
- hdsp_agent_core/services/chat_service.py +205 -0
- hdsp_agent_core/services/rag_service.py +262 -0
- hdsp_agent_core/tests/__init__.py +1 -0
- hdsp_agent_core/tests/conftest.py +102 -0
- hdsp_agent_core/tests/test_factory.py +251 -0
- hdsp_agent_core/tests/test_services.py +326 -0
- hdsp_jupyter_extension-2.0.0.data/data/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +7 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/build_log.json +738 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/install.json +5 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/package.json +134 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2607ff74c74acfa83158.js +4369 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2607ff74c74acfa83158.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.622c1a5918b3aafb2315.js +12496 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.622c1a5918b3aafb2315.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.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 +94 -0
- hdsp_jupyter_extension-2.0.0.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 +1 -0
- hdsp_jupyter_extension-2.0.0.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 +94 -0
- hdsp_jupyter_extension-2.0.0.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 +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.dae97cde171e13b8c834.js +623 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.dae97cde171e13b8c834.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/style.js +4 -0
- hdsp_jupyter_extension-2.0.0.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 +507 -0
- hdsp_jupyter_extension-2.0.0.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 +1 -0
- hdsp_jupyter_extension-2.0.0.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 +2071 -0
- hdsp_jupyter_extension-2.0.0.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
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.36b49c71871f98d4f549.js +1059 -0
- hdsp_jupyter_extension-2.0.0.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.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js +376 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js +60336 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js.map +1 -0
- hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js +7132 -0
- hdsp_jupyter_extension-2.0.0.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.0.dist-info/METADATA +152 -0
- hdsp_jupyter_extension-2.0.0.dist-info/RECORD +121 -0
- hdsp_jupyter_extension-2.0.0.dist-info/WHEEL +4 -0
- hdsp_jupyter_extension-2.0.0.dist-info/licenses/LICENSE +21 -0
- jupyter_ext/__init__.py +233 -0
- jupyter_ext/_version.py +4 -0
- jupyter_ext/config.py +111 -0
- jupyter_ext/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +7 -0
- jupyter_ext/handlers.py +632 -0
- jupyter_ext/labextension/build_log.json +738 -0
- jupyter_ext/labextension/package.json +134 -0
- jupyter_ext/labextension/static/frontend_styles_index_js.2607ff74c74acfa83158.js +4369 -0
- jupyter_ext/labextension/static/frontend_styles_index_js.2607ff74c74acfa83158.js.map +1 -0
- jupyter_ext/labextension/static/lib_index_js.622c1a5918b3aafb2315.js +12496 -0
- jupyter_ext/labextension/static/lib_index_js.622c1a5918b3aafb2315.js.map +1 -0
- jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b80.c095373419d05e6f141a.js +94 -0
- jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b80.c095373419d05e6f141a.js.map +1 -0
- jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b81.61e75fb98ecff46cf836.js +94 -0
- jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b81.61e75fb98ecff46cf836.js.map +1 -0
- jupyter_ext/labextension/static/remoteEntry.dae97cde171e13b8c834.js +623 -0
- jupyter_ext/labextension/static/remoteEntry.dae97cde171e13b8c834.js.map +1 -0
- jupyter_ext/labextension/static/style.js +4 -0
- jupyter_ext/labextension/static/vendors-node_modules_babel_runtime_helpers_esm_extends_js-node_modules_emotion_serialize_dist-051195.e2553aab0c3963b83dd7.js +507 -0
- jupyter_ext/labextension/static/vendors-node_modules_babel_runtime_helpers_esm_extends_js-node_modules_emotion_serialize_dist-051195.e2553aab0c3963b83dd7.js.map +1 -0
- jupyter_ext/labextension/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js-node_modules-782ee5.d9ed8645ef1d311657d8.js +2071 -0
- jupyter_ext/labextension/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.36b49c71871f98d4f549.js +1059 -0
- 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_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js +376 -0
- jupyter_ext/labextension/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js.map +1 -0
- jupyter_ext/labextension/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js +60336 -0
- jupyter_ext/labextension/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js.map +1 -0
- jupyter_ext/labextension/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js +7132 -0
- jupyter_ext/labextension/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js.map +1 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RAG Router - Endpoints for RAG search and status.
|
|
3
|
+
|
|
4
|
+
Provides:
|
|
5
|
+
- POST /rag/search - Explicit RAG search
|
|
6
|
+
- GET /rag/status - RAG system status
|
|
7
|
+
- POST /rag/reindex - Manual re-indexing trigger
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
from fastapi import APIRouter, HTTPException
|
|
13
|
+
from hdsp_agent_core.models.rag import (
|
|
14
|
+
ChunkDebugInfo,
|
|
15
|
+
DebugSearchRequest,
|
|
16
|
+
DebugSearchResponse,
|
|
17
|
+
IndexStatusResponse,
|
|
18
|
+
LibraryDetectionDebug,
|
|
19
|
+
ReindexRequest,
|
|
20
|
+
ReindexResponse,
|
|
21
|
+
SearchConfigDebug,
|
|
22
|
+
SearchRequest,
|
|
23
|
+
SearchResponse,
|
|
24
|
+
SearchResult,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
from agent_server.core.rag_manager import get_rag_manager
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
router = APIRouter()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@router.post("/search", response_model=SearchResponse)
|
|
35
|
+
async def search(request: SearchRequest) -> SearchResponse:
|
|
36
|
+
"""
|
|
37
|
+
Perform explicit RAG search.
|
|
38
|
+
|
|
39
|
+
Use this endpoint for direct knowledge base queries.
|
|
40
|
+
For automatic RAG context in plan generation, use /agent/plan instead.
|
|
41
|
+
"""
|
|
42
|
+
rag_manager = get_rag_manager()
|
|
43
|
+
|
|
44
|
+
if not rag_manager.is_ready:
|
|
45
|
+
raise HTTPException(
|
|
46
|
+
status_code=503,
|
|
47
|
+
detail="RAG system not ready. Check /rag/status for details.",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
results = await rag_manager.search(
|
|
52
|
+
query=request.query, top_k=request.top_k, filters=request.filters
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
search_results = [
|
|
56
|
+
SearchResult(
|
|
57
|
+
content=r["content"],
|
|
58
|
+
score=r["score"] if request.include_score else 0.0,
|
|
59
|
+
metadata=r["metadata"],
|
|
60
|
+
)
|
|
61
|
+
for r in results
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
return SearchResponse(
|
|
65
|
+
results=search_results,
|
|
66
|
+
query=request.query,
|
|
67
|
+
total_results=len(search_results),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
except Exception as e:
|
|
71
|
+
logger.error(f"Search failed: {e}")
|
|
72
|
+
raise HTTPException(status_code=500, detail=f"Search failed: {str(e)}")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@router.get("/status", response_model=IndexStatusResponse)
|
|
76
|
+
async def get_status() -> IndexStatusResponse:
|
|
77
|
+
"""
|
|
78
|
+
Get RAG system status.
|
|
79
|
+
|
|
80
|
+
Returns information about:
|
|
81
|
+
- System readiness
|
|
82
|
+
- Document/chunk counts
|
|
83
|
+
- Last update time
|
|
84
|
+
- Knowledge base path
|
|
85
|
+
"""
|
|
86
|
+
rag_manager = get_rag_manager()
|
|
87
|
+
return rag_manager.get_status()
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@router.post("/reindex", response_model=ReindexResponse)
|
|
91
|
+
async def reindex(request: ReindexRequest) -> ReindexResponse:
|
|
92
|
+
"""
|
|
93
|
+
Manually trigger re-indexing.
|
|
94
|
+
|
|
95
|
+
Use this to:
|
|
96
|
+
- Force full reindex after knowledge base changes
|
|
97
|
+
- Index a specific file or directory
|
|
98
|
+
"""
|
|
99
|
+
rag_manager = get_rag_manager()
|
|
100
|
+
|
|
101
|
+
if not rag_manager.is_ready:
|
|
102
|
+
raise HTTPException(
|
|
103
|
+
status_code=503,
|
|
104
|
+
detail="RAG system not ready. Check /rag/status for details.",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
# For now, return a simple success response
|
|
109
|
+
# Full reindex implementation would go here
|
|
110
|
+
return ReindexResponse(success=True, indexed=0, skipped=0, errors=[])
|
|
111
|
+
|
|
112
|
+
except Exception as e:
|
|
113
|
+
logger.error(f"Reindex failed: {e}")
|
|
114
|
+
raise HTTPException(status_code=500, detail=f"Reindex failed: {str(e)}")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@router.post("/debug", response_model=DebugSearchResponse)
|
|
118
|
+
async def debug_search(request: DebugSearchRequest) -> DebugSearchResponse:
|
|
119
|
+
"""
|
|
120
|
+
RAG 검색 디버깅 - 전체 파이프라인 리니지 추적.
|
|
121
|
+
|
|
122
|
+
사용 사례:
|
|
123
|
+
- 특정 청크가 왜 검색되었는지 확인
|
|
124
|
+
- 점수 계산이 최종 RAG 컨텍스트에 어떻게 영향을 미치는지 분석
|
|
125
|
+
|
|
126
|
+
반환 정보:
|
|
127
|
+
- 라이브러리 감지 결과
|
|
128
|
+
- 청크별 벡터 유사도 점수
|
|
129
|
+
- 최종 포맷된 컨텍스트
|
|
130
|
+
"""
|
|
131
|
+
rag_manager = get_rag_manager()
|
|
132
|
+
|
|
133
|
+
if not rag_manager.is_ready:
|
|
134
|
+
raise HTTPException(
|
|
135
|
+
status_code=503,
|
|
136
|
+
detail="RAG system not ready. Check /rag/status for details.",
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
result = await rag_manager.debug_search(
|
|
141
|
+
query=request.query,
|
|
142
|
+
imported_libraries=request.imported_libraries,
|
|
143
|
+
top_k=request.top_k,
|
|
144
|
+
include_full_content=request.include_full_content,
|
|
145
|
+
simulate_plan_context=request.simulate_plan_context,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Convert dict to response model
|
|
149
|
+
return DebugSearchResponse(
|
|
150
|
+
library_detection=LibraryDetectionDebug(**result["library_detection"]),
|
|
151
|
+
config=SearchConfigDebug(**result["config"]),
|
|
152
|
+
chunks=[ChunkDebugInfo(**c) for c in result["chunks"]],
|
|
153
|
+
total_candidates=result["total_candidates"],
|
|
154
|
+
total_passed_threshold=result["total_passed_threshold"],
|
|
155
|
+
search_ms=result["search_ms"],
|
|
156
|
+
formatted_context=result["formatted_context"],
|
|
157
|
+
context_char_count=result["context_char_count"],
|
|
158
|
+
estimated_context_tokens=result["estimated_context_tokens"],
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
except Exception as e:
|
|
162
|
+
logger.error(f"Debug search failed: {e}", exc_info=True)
|
|
163
|
+
raise HTTPException(status_code=500, detail=f"Debug search failed: {str(e)}")
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Server API Schemas
|
|
3
|
+
|
|
4
|
+
Re-export from hdsp_agent_core.models for backward compatibility.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from hdsp_agent_core.models.agent import (
|
|
8
|
+
ExecutionPlan,
|
|
9
|
+
PlanRequest,
|
|
10
|
+
PlanResponse,
|
|
11
|
+
PlanStep,
|
|
12
|
+
RefineRequest,
|
|
13
|
+
RefineResponse,
|
|
14
|
+
ReflectRequest,
|
|
15
|
+
ReflectResponse,
|
|
16
|
+
ReplanRequest,
|
|
17
|
+
ReplanResponse,
|
|
18
|
+
ReportExecutionRequest,
|
|
19
|
+
ReportExecutionResponse,
|
|
20
|
+
VerifyStateRequest,
|
|
21
|
+
VerifyStateResponse,
|
|
22
|
+
)
|
|
23
|
+
from hdsp_agent_core.models.chat import (
|
|
24
|
+
ChatRequest,
|
|
25
|
+
ChatResponse,
|
|
26
|
+
StreamChunk,
|
|
27
|
+
)
|
|
28
|
+
from hdsp_agent_core.models.common import (
|
|
29
|
+
APIResponse,
|
|
30
|
+
ErrorInfo,
|
|
31
|
+
NotebookContext,
|
|
32
|
+
ToolCall,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
# Common
|
|
37
|
+
"APIResponse",
|
|
38
|
+
"ErrorInfo",
|
|
39
|
+
"NotebookContext",
|
|
40
|
+
"ToolCall",
|
|
41
|
+
# Agent
|
|
42
|
+
"ExecutionPlan",
|
|
43
|
+
"PlanRequest",
|
|
44
|
+
"PlanResponse",
|
|
45
|
+
"PlanStep",
|
|
46
|
+
"RefineRequest",
|
|
47
|
+
"RefineResponse",
|
|
48
|
+
"ReflectRequest",
|
|
49
|
+
"ReflectResponse",
|
|
50
|
+
"ReplanRequest",
|
|
51
|
+
"ReplanResponse",
|
|
52
|
+
"ReportExecutionRequest",
|
|
53
|
+
"ReportExecutionResponse",
|
|
54
|
+
"VerifyStateRequest",
|
|
55
|
+
"VerifyStateResponse",
|
|
56
|
+
# Chat
|
|
57
|
+
"ChatRequest",
|
|
58
|
+
"ChatResponse",
|
|
59
|
+
"StreamChunk",
|
|
60
|
+
]
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HDSP Agent Core - Shared Core Library
|
|
3
|
+
|
|
4
|
+
Embedded Agent Server Architecture를 위한 공유 코어 라이브러리.
|
|
5
|
+
Development(embedded)와 Production(proxy) 모드 모두에서 사용되는 공통 컴포넌트.
|
|
6
|
+
|
|
7
|
+
Modules:
|
|
8
|
+
- models: Pydantic data models (agent, chat, common, rag)
|
|
9
|
+
- managers: Singleton managers (config, session, rag)
|
|
10
|
+
- llm: LLM service abstraction (multi-provider support)
|
|
11
|
+
- knowledge: Knowledge base and document chunking
|
|
12
|
+
- prompts: Prompt templates for Auto-Agent
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__version__ = "1.0.0"
|
|
16
|
+
|
|
17
|
+
# Models
|
|
18
|
+
from hdsp_agent_core.models import (
|
|
19
|
+
# Common
|
|
20
|
+
APIResponse,
|
|
21
|
+
ErrorInfo,
|
|
22
|
+
GeminiConfig,
|
|
23
|
+
LLMConfig,
|
|
24
|
+
NotebookContext,
|
|
25
|
+
OpenAIConfig,
|
|
26
|
+
ToolCall,
|
|
27
|
+
VLLMConfig,
|
|
28
|
+
# Agent
|
|
29
|
+
ExecutionPlan,
|
|
30
|
+
PlanRequest,
|
|
31
|
+
PlanResponse,
|
|
32
|
+
PlanStep,
|
|
33
|
+
RefineRequest,
|
|
34
|
+
RefineResponse,
|
|
35
|
+
ReplanRequest,
|
|
36
|
+
ReplanResponse,
|
|
37
|
+
ValidationIssue,
|
|
38
|
+
# Chat
|
|
39
|
+
ChatRequest,
|
|
40
|
+
ChatResponse,
|
|
41
|
+
StreamChunk,
|
|
42
|
+
# RAG
|
|
43
|
+
ChunkingConfig,
|
|
44
|
+
EmbeddingConfig,
|
|
45
|
+
IndexStatusResponse,
|
|
46
|
+
QdrantConfig,
|
|
47
|
+
RAGConfig,
|
|
48
|
+
ReindexRequest,
|
|
49
|
+
ReindexResponse,
|
|
50
|
+
SearchRequest,
|
|
51
|
+
SearchResponse,
|
|
52
|
+
WatchdogConfig,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Managers
|
|
56
|
+
from hdsp_agent_core.managers import (
|
|
57
|
+
ConfigManager,
|
|
58
|
+
SessionManager,
|
|
59
|
+
get_config_manager,
|
|
60
|
+
get_session_manager,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# LLM
|
|
64
|
+
from hdsp_agent_core.llm import (
|
|
65
|
+
LLMService,
|
|
66
|
+
call_llm,
|
|
67
|
+
call_llm_stream,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# Knowledge
|
|
71
|
+
from hdsp_agent_core.knowledge import (
|
|
72
|
+
DocumentChunker,
|
|
73
|
+
KnowledgeBase,
|
|
74
|
+
KnowledgeLoader,
|
|
75
|
+
LibraryDetector,
|
|
76
|
+
chunk_file,
|
|
77
|
+
get_knowledge_base,
|
|
78
|
+
get_knowledge_loader,
|
|
79
|
+
get_library_detector,
|
|
80
|
+
LIBRARY_DESCRIPTIONS,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Prompts
|
|
84
|
+
from hdsp_agent_core.prompts import (
|
|
85
|
+
PLAN_GENERATION_PROMPT,
|
|
86
|
+
CODE_GENERATION_PROMPT,
|
|
87
|
+
ERROR_REFINEMENT_PROMPT,
|
|
88
|
+
ADAPTIVE_REPLAN_PROMPT,
|
|
89
|
+
format_plan_prompt,
|
|
90
|
+
format_refine_prompt,
|
|
91
|
+
format_replan_prompt,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
__all__ = [
|
|
95
|
+
# Version
|
|
96
|
+
"__version__",
|
|
97
|
+
# Models - Common
|
|
98
|
+
"APIResponse",
|
|
99
|
+
"ErrorInfo",
|
|
100
|
+
"GeminiConfig",
|
|
101
|
+
"LLMConfig",
|
|
102
|
+
"NotebookContext",
|
|
103
|
+
"OpenAIConfig",
|
|
104
|
+
"ToolCall",
|
|
105
|
+
"VLLMConfig",
|
|
106
|
+
# Models - Agent
|
|
107
|
+
"ExecutionPlan",
|
|
108
|
+
"PlanRequest",
|
|
109
|
+
"PlanResponse",
|
|
110
|
+
"PlanStep",
|
|
111
|
+
"RefineRequest",
|
|
112
|
+
"RefineResponse",
|
|
113
|
+
"ReplanRequest",
|
|
114
|
+
"ReplanResponse",
|
|
115
|
+
"ValidationIssue",
|
|
116
|
+
# Models - Chat
|
|
117
|
+
"ChatRequest",
|
|
118
|
+
"ChatResponse",
|
|
119
|
+
"StreamChunk",
|
|
120
|
+
# Models - RAG
|
|
121
|
+
"ChunkingConfig",
|
|
122
|
+
"EmbeddingConfig",
|
|
123
|
+
"IndexStatusResponse",
|
|
124
|
+
"QdrantConfig",
|
|
125
|
+
"RAGConfig",
|
|
126
|
+
"ReindexRequest",
|
|
127
|
+
"ReindexResponse",
|
|
128
|
+
"SearchRequest",
|
|
129
|
+
"SearchResponse",
|
|
130
|
+
"WatchdogConfig",
|
|
131
|
+
# Managers
|
|
132
|
+
"ConfigManager",
|
|
133
|
+
"SessionManager",
|
|
134
|
+
"get_config_manager",
|
|
135
|
+
"get_session_manager",
|
|
136
|
+
# LLM
|
|
137
|
+
"LLMService",
|
|
138
|
+
"call_llm",
|
|
139
|
+
"call_llm_stream",
|
|
140
|
+
# Knowledge
|
|
141
|
+
"DocumentChunker",
|
|
142
|
+
"KnowledgeBase",
|
|
143
|
+
"KnowledgeLoader",
|
|
144
|
+
"LibraryDetector",
|
|
145
|
+
"chunk_file",
|
|
146
|
+
"get_knowledge_base",
|
|
147
|
+
"get_knowledge_loader",
|
|
148
|
+
"get_library_detector",
|
|
149
|
+
"LIBRARY_DESCRIPTIONS",
|
|
150
|
+
# Prompts
|
|
151
|
+
"PLAN_GENERATION_PROMPT",
|
|
152
|
+
"CODE_GENERATION_PROMPT",
|
|
153
|
+
"ERROR_REFINEMENT_PROMPT",
|
|
154
|
+
"ADAPTIVE_REPLAN_PROMPT",
|
|
155
|
+
"format_plan_prompt",
|
|
156
|
+
"format_refine_prompt",
|
|
157
|
+
"format_replan_prompt",
|
|
158
|
+
]
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HDSP Agent Core - Service Factory
|
|
3
|
+
|
|
4
|
+
ServiceFactory for creating Embedded or Proxy service implementations
|
|
5
|
+
based on the HDSP_AGENT_MODE environment variable.
|
|
6
|
+
|
|
7
|
+
Modes:
|
|
8
|
+
- embedded: Services run directly in-process (development mode)
|
|
9
|
+
- proxy: Services proxy to external agent server via HTTP (production mode)
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import logging
|
|
13
|
+
import os
|
|
14
|
+
from enum import Enum
|
|
15
|
+
from typing import Optional
|
|
16
|
+
|
|
17
|
+
from hdsp_agent_core.interfaces import IAgentService, IChatService, IRAGService
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AgentMode(Enum):
|
|
23
|
+
"""Agent execution mode"""
|
|
24
|
+
EMBEDDED = "embedded" # Direct in-process execution
|
|
25
|
+
PROXY = "proxy" # HTTP proxy to external server
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ServiceFactory:
|
|
29
|
+
"""
|
|
30
|
+
Factory for creating service instances based on execution mode.
|
|
31
|
+
|
|
32
|
+
Singleton pattern ensures consistent service instances across the application.
|
|
33
|
+
|
|
34
|
+
Usage:
|
|
35
|
+
factory = ServiceFactory.get_instance()
|
|
36
|
+
await factory.initialize()
|
|
37
|
+
|
|
38
|
+
agent_service = factory.get_agent_service()
|
|
39
|
+
chat_service = factory.get_chat_service()
|
|
40
|
+
rag_service = factory.get_rag_service()
|
|
41
|
+
|
|
42
|
+
Environment Variables:
|
|
43
|
+
HDSP_AGENT_MODE: "embedded" or "proxy" (default: "proxy")
|
|
44
|
+
AGENT_SERVER_URL: URL for proxy mode (default: "http://localhost:8000")
|
|
45
|
+
AGENT_SERVER_TIMEOUT: HTTP timeout in seconds (default: 120.0)
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
_instance: Optional["ServiceFactory"] = None
|
|
49
|
+
|
|
50
|
+
def __init__(self):
|
|
51
|
+
"""Initialize factory (use get_instance() instead)"""
|
|
52
|
+
self._mode = self._detect_mode()
|
|
53
|
+
self._initialized = False
|
|
54
|
+
|
|
55
|
+
# Service instances (lazy loaded)
|
|
56
|
+
self._agent_service: Optional[IAgentService] = None
|
|
57
|
+
self._chat_service: Optional[IChatService] = None
|
|
58
|
+
self._rag_service: Optional[IRAGService] = None
|
|
59
|
+
|
|
60
|
+
# Proxy configuration
|
|
61
|
+
self._server_url = os.environ.get("AGENT_SERVER_URL", "http://localhost:8000")
|
|
62
|
+
self._timeout = float(os.environ.get("AGENT_SERVER_TIMEOUT", "120.0"))
|
|
63
|
+
|
|
64
|
+
logger.info(f"ServiceFactory created with mode: {self._mode.value}")
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def get_instance(cls) -> "ServiceFactory":
|
|
68
|
+
"""Get singleton factory instance"""
|
|
69
|
+
if cls._instance is None:
|
|
70
|
+
cls._instance = ServiceFactory()
|
|
71
|
+
return cls._instance
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def reset_instance(cls) -> None:
|
|
75
|
+
"""Reset singleton instance (for testing)"""
|
|
76
|
+
cls._instance = None
|
|
77
|
+
|
|
78
|
+
def _detect_mode(self) -> AgentMode:
|
|
79
|
+
"""Detect execution mode from environment variable"""
|
|
80
|
+
mode_str = os.environ.get("HDSP_AGENT_MODE", "proxy").lower()
|
|
81
|
+
|
|
82
|
+
if mode_str == "embedded":
|
|
83
|
+
return AgentMode.EMBEDDED
|
|
84
|
+
elif mode_str == "proxy":
|
|
85
|
+
return AgentMode.PROXY
|
|
86
|
+
else:
|
|
87
|
+
logger.warning(
|
|
88
|
+
f"Unknown HDSP_AGENT_MODE '{mode_str}', defaulting to proxy"
|
|
89
|
+
)
|
|
90
|
+
return AgentMode.PROXY
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def mode(self) -> AgentMode:
|
|
94
|
+
"""Get current execution mode"""
|
|
95
|
+
return self._mode
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def is_embedded(self) -> bool:
|
|
99
|
+
"""Check if running in embedded mode"""
|
|
100
|
+
return self._mode == AgentMode.EMBEDDED
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def is_proxy(self) -> bool:
|
|
104
|
+
"""Check if running in proxy mode"""
|
|
105
|
+
return self._mode == AgentMode.PROXY
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def is_initialized(self) -> bool:
|
|
109
|
+
"""Check if factory has been initialized"""
|
|
110
|
+
return self._initialized
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def server_url(self) -> str:
|
|
114
|
+
"""Get agent server URL (for proxy mode)"""
|
|
115
|
+
return self._server_url
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def timeout(self) -> float:
|
|
119
|
+
"""Get HTTP timeout (for proxy mode)"""
|
|
120
|
+
return self._timeout
|
|
121
|
+
|
|
122
|
+
async def initialize(self) -> None:
|
|
123
|
+
"""
|
|
124
|
+
Initialize all services based on current mode.
|
|
125
|
+
|
|
126
|
+
For embedded mode: Initializes RAG manager, loads knowledge base
|
|
127
|
+
For proxy mode: Validates server connectivity
|
|
128
|
+
"""
|
|
129
|
+
if self._initialized:
|
|
130
|
+
logger.debug("ServiceFactory already initialized")
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
logger.info(f"Initializing ServiceFactory in {self._mode.value} mode")
|
|
134
|
+
|
|
135
|
+
if self.is_embedded:
|
|
136
|
+
await self._initialize_embedded_services()
|
|
137
|
+
else:
|
|
138
|
+
await self._initialize_proxy_services()
|
|
139
|
+
|
|
140
|
+
self._initialized = True
|
|
141
|
+
logger.info(f"ServiceFactory initialization complete ({self._mode.value} mode)")
|
|
142
|
+
|
|
143
|
+
async def _initialize_embedded_services(self) -> None:
|
|
144
|
+
"""Initialize services for embedded mode"""
|
|
145
|
+
from hdsp_agent_core.services.agent_service import EmbeddedAgentService
|
|
146
|
+
from hdsp_agent_core.services.chat_service import EmbeddedChatService
|
|
147
|
+
from hdsp_agent_core.services.rag_service import EmbeddedRAGService
|
|
148
|
+
|
|
149
|
+
# Create service instances
|
|
150
|
+
self._agent_service = EmbeddedAgentService()
|
|
151
|
+
self._chat_service = EmbeddedChatService()
|
|
152
|
+
self._rag_service = EmbeddedRAGService()
|
|
153
|
+
|
|
154
|
+
# Initialize RAG service (may need async initialization)
|
|
155
|
+
await self._rag_service.initialize()
|
|
156
|
+
|
|
157
|
+
logger.info("Embedded services initialized")
|
|
158
|
+
|
|
159
|
+
async def _initialize_proxy_services(self) -> None:
|
|
160
|
+
"""Initialize services for proxy mode"""
|
|
161
|
+
from hdsp_agent_core.services.agent_service import ProxyAgentService
|
|
162
|
+
from hdsp_agent_core.services.chat_service import ProxyChatService
|
|
163
|
+
from hdsp_agent_core.services.rag_service import ProxyRAGService
|
|
164
|
+
|
|
165
|
+
# Create proxy service instances
|
|
166
|
+
self._agent_service = ProxyAgentService(
|
|
167
|
+
base_url=self._server_url,
|
|
168
|
+
timeout=self._timeout
|
|
169
|
+
)
|
|
170
|
+
self._chat_service = ProxyChatService(
|
|
171
|
+
base_url=self._server_url,
|
|
172
|
+
timeout=self._timeout
|
|
173
|
+
)
|
|
174
|
+
self._rag_service = ProxyRAGService(
|
|
175
|
+
base_url=self._server_url,
|
|
176
|
+
timeout=self._timeout
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Optionally validate connectivity
|
|
180
|
+
# await self._validate_server_connectivity()
|
|
181
|
+
|
|
182
|
+
logger.info(f"Proxy services initialized (server: {self._server_url})")
|
|
183
|
+
|
|
184
|
+
async def shutdown(self) -> None:
|
|
185
|
+
"""Shutdown all services and cleanup resources"""
|
|
186
|
+
logger.info("Shutting down ServiceFactory")
|
|
187
|
+
|
|
188
|
+
# Cleanup RAG service
|
|
189
|
+
if self._rag_service and hasattr(self._rag_service, "shutdown"):
|
|
190
|
+
await self._rag_service.shutdown()
|
|
191
|
+
|
|
192
|
+
# Reset service instances
|
|
193
|
+
self._agent_service = None
|
|
194
|
+
self._chat_service = None
|
|
195
|
+
self._rag_service = None
|
|
196
|
+
self._initialized = False
|
|
197
|
+
|
|
198
|
+
logger.info("ServiceFactory shutdown complete")
|
|
199
|
+
|
|
200
|
+
def get_agent_service(self) -> IAgentService:
|
|
201
|
+
"""
|
|
202
|
+
Get the Agent service instance.
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
IAgentService implementation based on current mode
|
|
206
|
+
|
|
207
|
+
Raises:
|
|
208
|
+
RuntimeError: If factory not initialized
|
|
209
|
+
"""
|
|
210
|
+
if not self._initialized:
|
|
211
|
+
raise RuntimeError(
|
|
212
|
+
"ServiceFactory not initialized. Call await factory.initialize() first."
|
|
213
|
+
)
|
|
214
|
+
return self._agent_service
|
|
215
|
+
|
|
216
|
+
def get_chat_service(self) -> IChatService:
|
|
217
|
+
"""
|
|
218
|
+
Get the Chat service instance.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
IChatService implementation based on current mode
|
|
222
|
+
|
|
223
|
+
Raises:
|
|
224
|
+
RuntimeError: If factory not initialized
|
|
225
|
+
"""
|
|
226
|
+
if not self._initialized:
|
|
227
|
+
raise RuntimeError(
|
|
228
|
+
"ServiceFactory not initialized. Call await factory.initialize() first."
|
|
229
|
+
)
|
|
230
|
+
return self._chat_service
|
|
231
|
+
|
|
232
|
+
def get_rag_service(self) -> IRAGService:
|
|
233
|
+
"""
|
|
234
|
+
Get the RAG service instance.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
IRAGService implementation based on current mode
|
|
238
|
+
|
|
239
|
+
Raises:
|
|
240
|
+
RuntimeError: If factory not initialized
|
|
241
|
+
"""
|
|
242
|
+
if not self._initialized:
|
|
243
|
+
raise RuntimeError(
|
|
244
|
+
"ServiceFactory not initialized. Call await factory.initialize() first."
|
|
245
|
+
)
|
|
246
|
+
return self._rag_service
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# Convenience function for getting the singleton factory
|
|
250
|
+
def get_service_factory() -> ServiceFactory:
|
|
251
|
+
"""Get the singleton ServiceFactory instance"""
|
|
252
|
+
return ServiceFactory.get_instance()
|