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.
Files changed (121) hide show
  1. agent_server/__init__.py +8 -0
  2. agent_server/core/__init__.py +92 -0
  3. agent_server/core/api_key_manager.py +427 -0
  4. agent_server/core/code_validator.py +1238 -0
  5. agent_server/core/context_condenser.py +308 -0
  6. agent_server/core/embedding_service.py +254 -0
  7. agent_server/core/error_classifier.py +577 -0
  8. agent_server/core/llm_client.py +95 -0
  9. agent_server/core/llm_service.py +649 -0
  10. agent_server/core/notebook_generator.py +274 -0
  11. agent_server/core/prompt_builder.py +35 -0
  12. agent_server/core/rag_manager.py +742 -0
  13. agent_server/core/reflection_engine.py +489 -0
  14. agent_server/core/retriever.py +248 -0
  15. agent_server/core/state_verifier.py +452 -0
  16. agent_server/core/summary_generator.py +484 -0
  17. agent_server/core/task_manager.py +198 -0
  18. agent_server/knowledge/__init__.py +9 -0
  19. agent_server/knowledge/watchdog_service.py +352 -0
  20. agent_server/main.py +160 -0
  21. agent_server/prompts/__init__.py +60 -0
  22. agent_server/prompts/file_action_prompts.py +113 -0
  23. agent_server/routers/__init__.py +9 -0
  24. agent_server/routers/agent.py +591 -0
  25. agent_server/routers/chat.py +188 -0
  26. agent_server/routers/config.py +100 -0
  27. agent_server/routers/file_resolver.py +293 -0
  28. agent_server/routers/health.py +42 -0
  29. agent_server/routers/rag.py +163 -0
  30. agent_server/schemas/__init__.py +60 -0
  31. hdsp_agent_core/__init__.py +158 -0
  32. hdsp_agent_core/factory.py +252 -0
  33. hdsp_agent_core/interfaces.py +203 -0
  34. hdsp_agent_core/knowledge/__init__.py +31 -0
  35. hdsp_agent_core/knowledge/chunking.py +356 -0
  36. hdsp_agent_core/knowledge/libraries/dask.md +188 -0
  37. hdsp_agent_core/knowledge/libraries/matplotlib.md +164 -0
  38. hdsp_agent_core/knowledge/libraries/polars.md +68 -0
  39. hdsp_agent_core/knowledge/loader.py +337 -0
  40. hdsp_agent_core/llm/__init__.py +13 -0
  41. hdsp_agent_core/llm/service.py +556 -0
  42. hdsp_agent_core/managers/__init__.py +22 -0
  43. hdsp_agent_core/managers/config_manager.py +133 -0
  44. hdsp_agent_core/managers/session_manager.py +251 -0
  45. hdsp_agent_core/models/__init__.py +115 -0
  46. hdsp_agent_core/models/agent.py +316 -0
  47. hdsp_agent_core/models/chat.py +41 -0
  48. hdsp_agent_core/models/common.py +95 -0
  49. hdsp_agent_core/models/rag.py +368 -0
  50. hdsp_agent_core/prompts/__init__.py +63 -0
  51. hdsp_agent_core/prompts/auto_agent_prompts.py +1260 -0
  52. hdsp_agent_core/prompts/cell_action_prompts.py +98 -0
  53. hdsp_agent_core/services/__init__.py +18 -0
  54. hdsp_agent_core/services/agent_service.py +438 -0
  55. hdsp_agent_core/services/chat_service.py +205 -0
  56. hdsp_agent_core/services/rag_service.py +262 -0
  57. hdsp_agent_core/tests/__init__.py +1 -0
  58. hdsp_agent_core/tests/conftest.py +102 -0
  59. hdsp_agent_core/tests/test_factory.py +251 -0
  60. hdsp_agent_core/tests/test_services.py +326 -0
  61. hdsp_jupyter_extension-2.0.0.data/data/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +7 -0
  62. hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/build_log.json +738 -0
  63. hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/install.json +5 -0
  64. hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/package.json +134 -0
  65. hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2607ff74c74acfa83158.js +4369 -0
  66. hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/frontend_styles_index_js.2607ff74c74acfa83158.js.map +1 -0
  67. hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.622c1a5918b3aafb2315.js +12496 -0
  68. hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/lib_index_js.622c1a5918b3aafb2315.js.map +1 -0
  69. 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
  70. 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
  71. 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
  72. 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
  73. hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.dae97cde171e13b8c834.js +623 -0
  74. hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/remoteEntry.dae97cde171e13b8c834.js.map +1 -0
  75. hdsp_jupyter_extension-2.0.0.data/data/share/jupyter/labextensions/hdsp-agent/static/style.js +4 -0
  76. 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
  77. 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
  78. 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
  79. 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
  80. 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
  81. 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
  82. 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
  83. 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
  84. 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
  85. 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
  86. 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
  87. 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
  88. hdsp_jupyter_extension-2.0.0.dist-info/METADATA +152 -0
  89. hdsp_jupyter_extension-2.0.0.dist-info/RECORD +121 -0
  90. hdsp_jupyter_extension-2.0.0.dist-info/WHEEL +4 -0
  91. hdsp_jupyter_extension-2.0.0.dist-info/licenses/LICENSE +21 -0
  92. jupyter_ext/__init__.py +233 -0
  93. jupyter_ext/_version.py +4 -0
  94. jupyter_ext/config.py +111 -0
  95. jupyter_ext/etc/jupyter/jupyter_server_config.d/hdsp_jupyter_extension.json +7 -0
  96. jupyter_ext/handlers.py +632 -0
  97. jupyter_ext/labextension/build_log.json +738 -0
  98. jupyter_ext/labextension/package.json +134 -0
  99. jupyter_ext/labextension/static/frontend_styles_index_js.2607ff74c74acfa83158.js +4369 -0
  100. jupyter_ext/labextension/static/frontend_styles_index_js.2607ff74c74acfa83158.js.map +1 -0
  101. jupyter_ext/labextension/static/lib_index_js.622c1a5918b3aafb2315.js +12496 -0
  102. jupyter_ext/labextension/static/lib_index_js.622c1a5918b3aafb2315.js.map +1 -0
  103. jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b80.c095373419d05e6f141a.js +94 -0
  104. jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b80.c095373419d05e6f141a.js.map +1 -0
  105. jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b81.61e75fb98ecff46cf836.js +94 -0
  106. jupyter_ext/labextension/static/node_modules_emotion_use-insertion-effect-with-fallbacks_dist_emotion-use-insertion-effect-wi-3ba6b81.61e75fb98ecff46cf836.js.map +1 -0
  107. jupyter_ext/labextension/static/remoteEntry.dae97cde171e13b8c834.js +623 -0
  108. jupyter_ext/labextension/static/remoteEntry.dae97cde171e13b8c834.js.map +1 -0
  109. jupyter_ext/labextension/static/style.js +4 -0
  110. jupyter_ext/labextension/static/vendors-node_modules_babel_runtime_helpers_esm_extends_js-node_modules_emotion_serialize_dist-051195.e2553aab0c3963b83dd7.js +507 -0
  111. jupyter_ext/labextension/static/vendors-node_modules_babel_runtime_helpers_esm_extends_js-node_modules_emotion_serialize_dist-051195.e2553aab0c3963b83dd7.js.map +1 -0
  112. jupyter_ext/labextension/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js-node_modules-782ee5.d9ed8645ef1d311657d8.js +2071 -0
  113. jupyter_ext/labextension/static/vendors-node_modules_emotion_cache_dist_emotion-cache_browser_development_esm_js-node_modules-782ee5.d9ed8645ef1d311657d8.js.map +1 -0
  114. jupyter_ext/labextension/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.36b49c71871f98d4f549.js +1059 -0
  115. jupyter_ext/labextension/static/vendors-node_modules_emotion_react_dist_emotion-react_browser_development_esm_js.36b49c71871f98d4f549.js.map +1 -0
  116. jupyter_ext/labextension/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js +376 -0
  117. jupyter_ext/labextension/static/vendors-node_modules_emotion_styled_dist_emotion-styled_browser_development_esm_js.661fb5836f4978a7c6e1.js.map +1 -0
  118. jupyter_ext/labextension/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js +60336 -0
  119. jupyter_ext/labextension/static/vendors-node_modules_mui_material_index_js.985697e0162d8d088ca2.js.map +1 -0
  120. jupyter_ext/labextension/static/vendors-node_modules_mui_material_utils_createSvgIcon_js.2e13df4ea61496e95d45.js +7132 -0
  121. 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()