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,489 @@
1
+ """
2
+ Reflection Engine Service
3
+ 실행 결과 분석 및 적응적 조정을 위한 서비스
4
+
5
+ Checkpoint 기반 실행 검증과 Reflection을 통한 계획 조정
6
+ """
7
+
8
+ from dataclasses import dataclass, field
9
+ from enum import Enum
10
+ from typing import Any, Dict, List, Optional
11
+
12
+
13
+ class ImpactSeverity(Enum):
14
+ """영향도 심각도"""
15
+
16
+ NONE = "none"
17
+ MINOR = "minor"
18
+ MAJOR = "major"
19
+ CRITICAL = "critical"
20
+
21
+
22
+ class ReflectionAction(Enum):
23
+ """Reflection 결과에 따른 액션"""
24
+
25
+ CONTINUE = "continue" # 계속 진행
26
+ ADJUST = "adjust" # 조정 후 진행
27
+ RETRY = "retry" # 현재 단계 재시도
28
+ REPLAN = "replan" # 전체 계획 재수립
29
+
30
+
31
+ class AdjustmentType(Enum):
32
+ """조정 유형"""
33
+
34
+ MODIFY_CODE = "modify_code"
35
+ ADD_STEP = "add_step"
36
+ REMOVE_STEP = "remove_step"
37
+ CHANGE_APPROACH = "change_approach"
38
+
39
+
40
+ @dataclass
41
+ class ReflectionEvaluation:
42
+ """Checkpoint 평가 결과"""
43
+
44
+ checkpoint_passed: bool
45
+ output_matches_expected: bool
46
+ confidence_score: float # 0.0 ~ 1.0
47
+
48
+ def to_dict(self) -> Dict[str, Any]:
49
+ return {
50
+ "checkpoint_passed": self.checkpoint_passed,
51
+ "output_matches_expected": self.output_matches_expected,
52
+ "confidence_score": self.confidence_score,
53
+ }
54
+
55
+
56
+ @dataclass
57
+ class ReflectionAnalysis:
58
+ """실행 분석 결과"""
59
+
60
+ success_factors: List[str] = field(default_factory=list)
61
+ failure_factors: List[str] = field(default_factory=list)
62
+ unexpected_outcomes: List[str] = field(default_factory=list)
63
+
64
+ def to_dict(self) -> Dict[str, Any]:
65
+ return {
66
+ "success_factors": self.success_factors,
67
+ "failure_factors": self.failure_factors,
68
+ "unexpected_outcomes": self.unexpected_outcomes,
69
+ }
70
+
71
+
72
+ @dataclass
73
+ class ReflectionImpact:
74
+ """남은 단계에 대한 영향"""
75
+
76
+ affected_steps: List[int] = field(default_factory=list)
77
+ severity: ImpactSeverity = ImpactSeverity.NONE
78
+ description: str = ""
79
+
80
+ def to_dict(self) -> Dict[str, Any]:
81
+ return {
82
+ "affected_steps": self.affected_steps,
83
+ "severity": self.severity.value,
84
+ "description": self.description,
85
+ }
86
+
87
+
88
+ @dataclass
89
+ class Adjustment:
90
+ """계획 조정 항목"""
91
+
92
+ step_number: int
93
+ change_type: AdjustmentType
94
+ description: str
95
+ new_content: Optional[str] = None
96
+
97
+ def to_dict(self) -> Dict[str, Any]:
98
+ result = {
99
+ "step_number": self.step_number,
100
+ "change_type": self.change_type.value,
101
+ "description": self.description,
102
+ }
103
+ if self.new_content:
104
+ result["new_content"] = self.new_content
105
+ return result
106
+
107
+
108
+ @dataclass
109
+ class ReflectionRecommendations:
110
+ """조정 권장사항"""
111
+
112
+ action: ReflectionAction
113
+ adjustments: List[Adjustment] = field(default_factory=list)
114
+ reasoning: str = ""
115
+
116
+ def to_dict(self) -> Dict[str, Any]:
117
+ return {
118
+ "action": self.action.value,
119
+ "adjustments": [adj.to_dict() for adj in self.adjustments],
120
+ "reasoning": self.reasoning,
121
+ }
122
+
123
+
124
+ @dataclass
125
+ class ReflectionResult:
126
+ """Reflection 전체 결과"""
127
+
128
+ evaluation: ReflectionEvaluation
129
+ analysis: ReflectionAnalysis
130
+ impact_on_remaining: ReflectionImpact
131
+ recommendations: ReflectionRecommendations
132
+
133
+ def to_dict(self) -> Dict[str, Any]:
134
+ return {
135
+ "evaluation": self.evaluation.to_dict(),
136
+ "analysis": self.analysis.to_dict(),
137
+ "impact_on_remaining": self.impact_on_remaining.to_dict(),
138
+ "recommendations": self.recommendations.to_dict(),
139
+ }
140
+
141
+
142
+ class ReflectionEngine:
143
+ """실행 결과 분석 및 Reflection 엔진"""
144
+
145
+ def __init__(self):
146
+ pass
147
+
148
+ def evaluate_checkpoint(
149
+ self,
150
+ execution_status: str,
151
+ execution_output: str,
152
+ expected_outcome: Optional[str],
153
+ validation_criteria: Optional[List[str]],
154
+ error_message: Optional[str] = None,
155
+ ) -> ReflectionEvaluation:
156
+ """
157
+ Checkpoint 평가
158
+
159
+ Args:
160
+ execution_status: 실행 상태 ('ok', 'error')
161
+ execution_output: 실행 출력
162
+ expected_outcome: 예상 결과
163
+ validation_criteria: 검증 기준 목록
164
+ error_message: 오류 메시지 (있는 경우)
165
+
166
+ Returns:
167
+ ReflectionEvaluation: 평가 결과
168
+ """
169
+ # 기본 평가
170
+ is_success = execution_status == "ok" and not error_message
171
+
172
+ # 출력 매칭 평가 (간단한 휴리스틱)
173
+ output_matches = True
174
+ if expected_outcome and execution_output:
175
+ # 예상 결과의 키워드가 출력에 포함되는지 확인
176
+ expected_keywords = expected_outcome.lower().split()
177
+ output_lower = execution_output.lower()
178
+ matches = sum(1 for kw in expected_keywords if kw in output_lower)
179
+ output_matches = matches >= len(expected_keywords) * 0.5
180
+
181
+ # 검증 기준 평가
182
+ criteria_passed = 0
183
+ total_criteria = len(validation_criteria) if validation_criteria else 0
184
+ if validation_criteria:
185
+ for criterion in validation_criteria:
186
+ # 간단한 키워드 매칭
187
+ if any(
188
+ word in execution_output.lower()
189
+ for word in criterion.lower().split()
190
+ ):
191
+ criteria_passed += 1
192
+
193
+ # 신뢰도 점수 계산
194
+ confidence = 0.0
195
+ if is_success:
196
+ confidence = 0.5
197
+ if output_matches:
198
+ confidence += 0.3
199
+ if total_criteria > 0:
200
+ confidence += 0.2 * (criteria_passed / total_criteria)
201
+ else:
202
+ confidence = 0.2 if execution_output else 0.0
203
+
204
+ return ReflectionEvaluation(
205
+ checkpoint_passed=is_success and output_matches,
206
+ output_matches_expected=output_matches,
207
+ confidence_score=min(confidence, 1.0),
208
+ )
209
+
210
+ def analyze_execution(
211
+ self,
212
+ execution_status: str,
213
+ execution_output: str,
214
+ error_message: Optional[str],
215
+ executed_code: str,
216
+ ) -> ReflectionAnalysis:
217
+ """
218
+ 실행 결과 분석
219
+
220
+ Args:
221
+ execution_status: 실행 상태
222
+ execution_output: 실행 출력
223
+ error_message: 오류 메시지
224
+ executed_code: 실행된 코드
225
+
226
+ Returns:
227
+ ReflectionAnalysis: 분석 결과
228
+ """
229
+ success_factors = []
230
+ failure_factors = []
231
+ unexpected_outcomes = []
232
+
233
+ if execution_status == "ok":
234
+ success_factors.append("코드가 오류 없이 실행됨")
235
+
236
+ # 출력 분석
237
+ if execution_output:
238
+ if (
239
+ "error" in execution_output.lower()
240
+ or "warning" in execution_output.lower()
241
+ ):
242
+ unexpected_outcomes.append("출력에 오류/경고 메시지 포함")
243
+ if len(execution_output) > 10000:
244
+ unexpected_outcomes.append("출력이 예상보다 큼")
245
+
246
+ # 코드 패턴 분석
247
+ if "try:" in executed_code and "except" in executed_code:
248
+ success_factors.append("예외 처리 포함")
249
+
250
+ else:
251
+ failure_factors.append(f"실행 실패: {error_message or '알 수 없는 오류'}")
252
+
253
+ # 일반적인 오류 패턴 분석
254
+ if error_message:
255
+ error_lower = error_message.lower()
256
+ if "nameerror" in error_lower:
257
+ failure_factors.append("정의되지 않은 변수 사용")
258
+ elif (
259
+ "importerror" in error_lower or "modulenotfounderror" in error_lower
260
+ ):
261
+ failure_factors.append("필요한 모듈 import 누락")
262
+ elif "syntaxerror" in error_lower:
263
+ failure_factors.append("문법 오류")
264
+ elif "typeerror" in error_lower:
265
+ failure_factors.append("타입 불일치")
266
+ elif "keyerror" in error_lower or "indexerror" in error_lower:
267
+ failure_factors.append("데이터 접근 오류")
268
+
269
+ return ReflectionAnalysis(
270
+ success_factors=success_factors,
271
+ failure_factors=failure_factors,
272
+ unexpected_outcomes=unexpected_outcomes,
273
+ )
274
+
275
+ def assess_impact(
276
+ self,
277
+ evaluation: ReflectionEvaluation,
278
+ analysis: ReflectionAnalysis,
279
+ remaining_steps: Optional[List[Dict[str, Any]]],
280
+ ) -> ReflectionImpact:
281
+ """
282
+ 남은 단계에 대한 영향 평가
283
+
284
+ Args:
285
+ evaluation: Checkpoint 평가 결과
286
+ analysis: 실행 분석 결과
287
+ remaining_steps: 남은 단계 목록
288
+
289
+ Returns:
290
+ ReflectionImpact: 영향 평가 결과
291
+ """
292
+ if not remaining_steps:
293
+ return ReflectionImpact(
294
+ affected_steps=[],
295
+ severity=ImpactSeverity.NONE,
296
+ description="남은 단계 없음",
297
+ )
298
+
299
+ affected_steps = []
300
+ severity = ImpactSeverity.NONE
301
+ description = ""
302
+
303
+ # Checkpoint 실패 시 영향 평가
304
+ if not evaluation.checkpoint_passed:
305
+ # 모든 후속 단계가 영향받을 가능성
306
+ affected_steps = [
307
+ step.get("stepNumber", i + 1) for i, step in enumerate(remaining_steps)
308
+ ]
309
+
310
+ if analysis.failure_factors:
311
+ # 심각한 오류 유형 확인
312
+ critical_errors = [
313
+ "정의되지 않은 변수",
314
+ "필요한 모듈 import 누락",
315
+ "문법 오류",
316
+ ]
317
+ if any(
318
+ err in factor
319
+ for factor in analysis.failure_factors
320
+ for err in critical_errors
321
+ ):
322
+ severity = ImpactSeverity.CRITICAL
323
+ description = "핵심 오류로 인해 후속 단계 실행 불가"
324
+ else:
325
+ severity = ImpactSeverity.MAJOR
326
+ description = "실행 오류로 인해 후속 단계에 영향"
327
+ else:
328
+ severity = ImpactSeverity.MINOR
329
+ description = "예상과 다른 결과로 후속 단계 조정 필요"
330
+
331
+ elif analysis.unexpected_outcomes:
332
+ # 예상치 못한 결과가 있는 경우
333
+ severity = ImpactSeverity.MINOR
334
+ affected_steps = (
335
+ [remaining_steps[0].get("stepNumber", 1)] if remaining_steps else []
336
+ )
337
+ description = "예상치 못한 출력으로 다음 단계 검토 필요"
338
+
339
+ return ReflectionImpact(
340
+ affected_steps=affected_steps, severity=severity, description=description
341
+ )
342
+
343
+ def generate_recommendations(
344
+ self,
345
+ evaluation: ReflectionEvaluation,
346
+ analysis: ReflectionAnalysis,
347
+ impact: ReflectionImpact,
348
+ ) -> ReflectionRecommendations:
349
+ """
350
+ 조정 권장사항 생성
351
+
352
+ Args:
353
+ evaluation: Checkpoint 평가 결과
354
+ analysis: 실행 분석 결과
355
+ impact: 영향 평가 결과
356
+
357
+ Returns:
358
+ ReflectionRecommendations: 권장사항
359
+ """
360
+ adjustments = []
361
+ reasoning = ""
362
+
363
+ # 성공적인 경우
364
+ if evaluation.checkpoint_passed and evaluation.confidence_score >= 0.7:
365
+ return ReflectionRecommendations(
366
+ action=ReflectionAction.CONTINUE,
367
+ adjustments=[],
368
+ reasoning="실행이 성공적이며 예상 결과와 일치함",
369
+ )
370
+
371
+ # 실패 유형에 따른 권장사항
372
+ if impact.severity == ImpactSeverity.CRITICAL:
373
+ # 심각한 오류 - 재계획 권장
374
+ return ReflectionRecommendations(
375
+ action=ReflectionAction.REPLAN,
376
+ adjustments=[],
377
+ reasoning="핵심 오류로 인해 전체 계획 재수립 필요",
378
+ )
379
+
380
+ if impact.severity == ImpactSeverity.MAJOR:
381
+ # 주요 오류 - 재시도 또는 조정
382
+ if "정의되지 않은 변수" in str(analysis.failure_factors):
383
+ adjustments.append(
384
+ Adjustment(
385
+ step_number=0, # 현재 단계
386
+ change_type=AdjustmentType.ADD_STEP,
387
+ description="필요한 변수 정의 단계 추가",
388
+ )
389
+ )
390
+ elif "import 누락" in str(analysis.failure_factors):
391
+ adjustments.append(
392
+ Adjustment(
393
+ step_number=0,
394
+ change_type=AdjustmentType.MODIFY_CODE,
395
+ description="필요한 import 문 추가",
396
+ )
397
+ )
398
+ else:
399
+ adjustments.append(
400
+ Adjustment(
401
+ step_number=0,
402
+ change_type=AdjustmentType.MODIFY_CODE,
403
+ description="오류 수정",
404
+ )
405
+ )
406
+
407
+ return ReflectionRecommendations(
408
+ action=ReflectionAction.RETRY,
409
+ adjustments=adjustments,
410
+ reasoning="오류 수정 후 재시도 필요",
411
+ )
412
+
413
+ if impact.severity == ImpactSeverity.MINOR:
414
+ # 경미한 조정 - 조정 후 계속
415
+ return ReflectionRecommendations(
416
+ action=ReflectionAction.ADJUST,
417
+ adjustments=adjustments,
418
+ reasoning="경미한 조정 후 계속 진행 가능",
419
+ )
420
+
421
+ # 기본: 계속 진행
422
+ return ReflectionRecommendations(
423
+ action=ReflectionAction.CONTINUE,
424
+ adjustments=[],
425
+ reasoning="특별한 조정 없이 진행 가능",
426
+ )
427
+
428
+ def reflect(
429
+ self,
430
+ step_number: int,
431
+ step_description: str,
432
+ executed_code: str,
433
+ execution_status: str,
434
+ execution_output: str,
435
+ error_message: Optional[str] = None,
436
+ expected_outcome: Optional[str] = None,
437
+ validation_criteria: Optional[List[str]] = None,
438
+ remaining_steps: Optional[List[Dict[str, Any]]] = None,
439
+ ) -> ReflectionResult:
440
+ """
441
+ 전체 Reflection 수행
442
+
443
+ Args:
444
+ step_number: 단계 번호
445
+ step_description: 단계 설명
446
+ executed_code: 실행된 코드
447
+ execution_status: 실행 상태 ('ok' 또는 'error')
448
+ execution_output: 실행 출력
449
+ error_message: 오류 메시지 (있는 경우)
450
+ expected_outcome: 예상 결과
451
+ validation_criteria: 검증 기준 목록
452
+ remaining_steps: 남은 단계 목록
453
+
454
+ Returns:
455
+ ReflectionResult: Reflection 결과
456
+ """
457
+ # 1. Checkpoint 평가
458
+ evaluation = self.evaluate_checkpoint(
459
+ execution_status=execution_status,
460
+ execution_output=execution_output,
461
+ expected_outcome=expected_outcome,
462
+ validation_criteria=validation_criteria,
463
+ error_message=error_message,
464
+ )
465
+
466
+ # 2. 실행 분석
467
+ analysis = self.analyze_execution(
468
+ execution_status=execution_status,
469
+ execution_output=execution_output,
470
+ error_message=error_message,
471
+ executed_code=executed_code,
472
+ )
473
+
474
+ # 3. 영향 평가
475
+ impact = self.assess_impact(
476
+ evaluation=evaluation, analysis=analysis, remaining_steps=remaining_steps
477
+ )
478
+
479
+ # 4. 권장사항 생성
480
+ recommendations = self.generate_recommendations(
481
+ evaluation=evaluation, analysis=analysis, impact=impact
482
+ )
483
+
484
+ return ReflectionResult(
485
+ evaluation=evaluation,
486
+ analysis=analysis,
487
+ impact_on_remaining=impact,
488
+ recommendations=recommendations,
489
+ )