process-gpt-agent-sdk 0.2.8__py3-none-any.whl → 0.2.10__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.
Potentially problematic release.
This version of process-gpt-agent-sdk might be problematic. Click here for more details.
- process_gpt_agent_sdk-0.2.10.dist-info/METADATA +1026 -0
- process_gpt_agent_sdk-0.2.10.dist-info/RECORD +19 -0
- processgpt_agent_sdk/__init__.py +11 -7
- processgpt_agent_sdk/core/database.py +464 -463
- processgpt_agent_sdk/server.py +313 -292
- processgpt_agent_sdk/simulator.py +231 -0
- processgpt_agent_sdk/tools/human_query_tool.py +211 -211
- processgpt_agent_sdk/tools/knowledge_tools.py +206 -206
- processgpt_agent_sdk/tools/safe_tool_loader.py +209 -209
- processgpt_agent_sdk/utils/context_manager.py +45 -45
- processgpt_agent_sdk/utils/crewai_event_listener.py +205 -205
- processgpt_agent_sdk/utils/event_handler.py +72 -72
- processgpt_agent_sdk/utils/logger.py +97 -39
- processgpt_agent_sdk/utils/summarizer.py +146 -146
- process_gpt_agent_sdk-0.2.8.dist-info/METADATA +0 -378
- process_gpt_agent_sdk-0.2.8.dist-info/RECORD +0 -18
- {process_gpt_agent_sdk-0.2.8.dist-info → process_gpt_agent_sdk-0.2.10.dist-info}/WHEEL +0 -0
- {process_gpt_agent_sdk-0.2.8.dist-info → process_gpt_agent_sdk-0.2.10.dist-info}/top_level.txt +0 -0
|
@@ -1,209 +1,209 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import subprocess
|
|
3
|
-
import time
|
|
4
|
-
from typing import List, Dict, Optional
|
|
5
|
-
import anyio
|
|
6
|
-
from mcp.client.stdio import StdioServerParameters
|
|
7
|
-
from crewai_tools import MCPServerAdapter
|
|
8
|
-
from .knowledge_tools import Mem0Tool, MementoTool
|
|
9
|
-
from ..utils.logger import write_log_message, handle_application_error
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# =============================================================================
|
|
13
|
-
# SafeToolLoader
|
|
14
|
-
# 설명: 로컬/외부 MCP 도구들을 안전하게 초기화·로드·종료 관리
|
|
15
|
-
# =============================================================================
|
|
16
|
-
class SafeToolLoader:
|
|
17
|
-
"""도구 로더 클래스"""
|
|
18
|
-
adapters = []
|
|
19
|
-
|
|
20
|
-
ANYIO_PATCHED: bool = False
|
|
21
|
-
|
|
22
|
-
def __init__(self, tenant_id: Optional[str] = None, user_id: Optional[str] = None, agent_name: Optional[str] = None, mcp_config: Optional[Dict] = None):
|
|
23
|
-
"""실행 컨텍스트(tenant/user/agent)와 MCP 설정을 보관한다."""
|
|
24
|
-
self.tenant_id = tenant_id
|
|
25
|
-
self.user_id = user_id
|
|
26
|
-
self.agent_name = agent_name
|
|
27
|
-
self._mcp_servers = (mcp_config or {}).get('mcpServers', {})
|
|
28
|
-
self.local_tools = ["mem0", "memento", "human_asked"]
|
|
29
|
-
write_log_message(f"SafeToolLoader 초기화 완료 (tenant_id: {tenant_id}, user_id: {user_id})")
|
|
30
|
-
|
|
31
|
-
# =============================================================================
|
|
32
|
-
# Warmup (npx 서버 사전 준비)
|
|
33
|
-
# =============================================================================
|
|
34
|
-
def warmup_server(self, server_key: str, mcp_config: Optional[Dict] = None):
|
|
35
|
-
"""npx 서버 패키지를 미리 캐싱해 최초 실행 지연을 줄인다."""
|
|
36
|
-
servers = (mcp_config or {}).get('mcpServers') or self._mcp_servers or {}
|
|
37
|
-
server_config = servers.get(server_key, {}) if isinstance(servers, dict) else {}
|
|
38
|
-
if not server_config or server_config.get("command") != "npx":
|
|
39
|
-
return
|
|
40
|
-
|
|
41
|
-
npx_command_path = self._find_npx_command()
|
|
42
|
-
if not npx_command_path:
|
|
43
|
-
return
|
|
44
|
-
|
|
45
|
-
arguments_list = server_config.get("args", [])
|
|
46
|
-
if not (arguments_list and arguments_list[0] == "-y"):
|
|
47
|
-
return
|
|
48
|
-
|
|
49
|
-
package_name = arguments_list[1]
|
|
50
|
-
|
|
51
|
-
try:
|
|
52
|
-
subprocess.run([npx_command_path, "-y", package_name, "--help"], capture_output=True, timeout=10, shell=True)
|
|
53
|
-
return
|
|
54
|
-
except subprocess.TimeoutExpired:
|
|
55
|
-
pass
|
|
56
|
-
except Exception:
|
|
57
|
-
pass
|
|
58
|
-
|
|
59
|
-
try:
|
|
60
|
-
subprocess.run([npx_command_path, "-y", package_name, "--help"], capture_output=True, timeout=60, shell=True)
|
|
61
|
-
except Exception:
|
|
62
|
-
pass
|
|
63
|
-
|
|
64
|
-
# =============================================================================
|
|
65
|
-
# 유틸: npx 경로 탐색
|
|
66
|
-
# =============================================================================
|
|
67
|
-
def _find_npx_command(self) -> str:
|
|
68
|
-
"""npx 실행 파일 경로를 탐색해 반환한다."""
|
|
69
|
-
try:
|
|
70
|
-
import shutil
|
|
71
|
-
npx_path = shutil.which("npx") or shutil.which("npx.cmd")
|
|
72
|
-
if npx_path:
|
|
73
|
-
return npx_path
|
|
74
|
-
except Exception:
|
|
75
|
-
pass
|
|
76
|
-
return "npx"
|
|
77
|
-
|
|
78
|
-
# =============================================================================
|
|
79
|
-
# 로컬 도구 생성
|
|
80
|
-
# =============================================================================
|
|
81
|
-
def create_tools_from_names(self, tool_names: List[str], mcp_config: Optional[Dict] = None) -> List:
|
|
82
|
-
"""tool_names 리스트에서 실제 Tool 객체들 생성"""
|
|
83
|
-
if isinstance(tool_names, str):
|
|
84
|
-
tool_names = [tool_names]
|
|
85
|
-
write_log_message(f"도구 생성 요청: {tool_names}")
|
|
86
|
-
|
|
87
|
-
tools = []
|
|
88
|
-
|
|
89
|
-
tools.extend(self._load_mem0())
|
|
90
|
-
tools.extend(self._load_memento())
|
|
91
|
-
tools.extend(self._load_human_asked())
|
|
92
|
-
|
|
93
|
-
for name in tool_names:
|
|
94
|
-
key = name.strip().lower()
|
|
95
|
-
if key in self.local_tools:
|
|
96
|
-
continue
|
|
97
|
-
else:
|
|
98
|
-
self.warmup_server(key, mcp_config)
|
|
99
|
-
tools.extend(self._load_mcp_tool(key, mcp_config))
|
|
100
|
-
|
|
101
|
-
write_log_message(f"총 {len(tools)}개 도구 생성 완료")
|
|
102
|
-
return tools
|
|
103
|
-
|
|
104
|
-
# =============================================================================
|
|
105
|
-
# 로컬 도구 로더들
|
|
106
|
-
# =============================================================================
|
|
107
|
-
def _load_mem0(self) -> List:
|
|
108
|
-
"""mem0 도구 로드 - 에이전트별 메모리"""
|
|
109
|
-
try:
|
|
110
|
-
if not self.user_id:
|
|
111
|
-
write_log_message("mem0 도구 로드 생략: user_id 없음")
|
|
112
|
-
return []
|
|
113
|
-
return [Mem0Tool(tenant_id=self.tenant_id, user_id=self.user_id)]
|
|
114
|
-
except Exception as error:
|
|
115
|
-
handle_application_error("툴mem0오류", error, raise_error=False)
|
|
116
|
-
return []
|
|
117
|
-
|
|
118
|
-
def _load_memento(self) -> List:
|
|
119
|
-
"""memento 도구 로드"""
|
|
120
|
-
try:
|
|
121
|
-
return [MementoTool(tenant_id=self.tenant_id)]
|
|
122
|
-
except Exception as error:
|
|
123
|
-
handle_application_error("툴memento오류", error, raise_error=False)
|
|
124
|
-
return []
|
|
125
|
-
|
|
126
|
-
def _load_human_asked(self) -> List:
|
|
127
|
-
"""human_asked 도구 로드 (선택사항: 사용 시 외부에서 주입)"""
|
|
128
|
-
try:
|
|
129
|
-
return []
|
|
130
|
-
except Exception as error:
|
|
131
|
-
handle_application_error("툴human오류", error, raise_error=False)
|
|
132
|
-
return []
|
|
133
|
-
|
|
134
|
-
# =============================================================================
|
|
135
|
-
# 외부 MCP 도구 로더
|
|
136
|
-
# =============================================================================
|
|
137
|
-
def _load_mcp_tool(self, tool_name: str, mcp_config: Optional[Dict] = None) -> List:
|
|
138
|
-
"""MCP 도구 로드 (timeout & retry 지원)"""
|
|
139
|
-
self._apply_anyio_patch()
|
|
140
|
-
|
|
141
|
-
servers = (mcp_config or {}).get('mcpServers') or self._mcp_servers or {}
|
|
142
|
-
server_config = servers.get(tool_name, {}) if isinstance(servers, dict) else {}
|
|
143
|
-
if not server_config:
|
|
144
|
-
return []
|
|
145
|
-
|
|
146
|
-
environment_variables = os.environ.copy()
|
|
147
|
-
environment_variables.update(server_config.get("env", {}))
|
|
148
|
-
timeout_seconds = server_config.get("timeout", 40)
|
|
149
|
-
|
|
150
|
-
max_retries = 2
|
|
151
|
-
retry_delay = 5
|
|
152
|
-
|
|
153
|
-
for attempt in range(1, max_retries + 1):
|
|
154
|
-
try:
|
|
155
|
-
cmd = server_config["command"]
|
|
156
|
-
if cmd == "npx":
|
|
157
|
-
cmd = self._find_npx_command() or cmd
|
|
158
|
-
|
|
159
|
-
params = StdioServerParameters(
|
|
160
|
-
command=cmd,
|
|
161
|
-
args=server_config.get("args", []),
|
|
162
|
-
env=environment_variables,
|
|
163
|
-
timeout=timeout_seconds
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
adapter = MCPServerAdapter(params)
|
|
167
|
-
SafeToolLoader.adapters.append(adapter)
|
|
168
|
-
write_log_message(f"{tool_name} MCP 로드 성공 (툴 {len(adapter.tools)}개): {[tool.name for tool in adapter.tools]}")
|
|
169
|
-
return adapter.tools
|
|
170
|
-
|
|
171
|
-
except Exception as e:
|
|
172
|
-
if attempt < max_retries:
|
|
173
|
-
time.sleep(retry_delay)
|
|
174
|
-
else:
|
|
175
|
-
handle_application_error(f"툴{tool_name}오류", e, raise_error=False)
|
|
176
|
-
return []
|
|
177
|
-
|
|
178
|
-
# =============================================================================
|
|
179
|
-
# anyio 서브프로세스 stderr 패치
|
|
180
|
-
# =============================================================================
|
|
181
|
-
def _apply_anyio_patch(self):
|
|
182
|
-
"""stderr에 fileno 없음 대비: PIPE로 보정해 예외를 방지한다."""
|
|
183
|
-
if SafeToolLoader.ANYIO_PATCHED:
|
|
184
|
-
return
|
|
185
|
-
from anyio._core._subprocesses import open_process as _orig
|
|
186
|
-
|
|
187
|
-
async def patched_open_process(*args, **kwargs):
|
|
188
|
-
stderr = kwargs.get('stderr')
|
|
189
|
-
if not (hasattr(stderr, 'fileno') and stderr.fileno()):
|
|
190
|
-
kwargs['stderr'] = subprocess.PIPE
|
|
191
|
-
return await _orig(*args, **kwargs)
|
|
192
|
-
|
|
193
|
-
anyio.open_process = patched_open_process
|
|
194
|
-
anyio._core._subprocesses.open_process = patched_open_process
|
|
195
|
-
SafeToolLoader.ANYIO_PATCHED = True
|
|
196
|
-
|
|
197
|
-
# =============================================================================
|
|
198
|
-
# 종료 처리
|
|
199
|
-
# =============================================================================
|
|
200
|
-
@classmethod
|
|
201
|
-
def shutdown_all_adapters(cls):
|
|
202
|
-
"""모든 MCPServerAdapter 연결을 안전하게 종료한다."""
|
|
203
|
-
for adapter in cls.adapters:
|
|
204
|
-
try:
|
|
205
|
-
adapter.stop()
|
|
206
|
-
except Exception as error:
|
|
207
|
-
handle_application_error("툴종료오류", error, raise_error=False)
|
|
208
|
-
write_log_message("모든 MCPServerAdapter 연결 종료 완료")
|
|
209
|
-
cls.adapters.clear()
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
import time
|
|
4
|
+
from typing import List, Dict, Optional
|
|
5
|
+
import anyio
|
|
6
|
+
from mcp.client.stdio import StdioServerParameters
|
|
7
|
+
from crewai_tools import MCPServerAdapter
|
|
8
|
+
from .knowledge_tools import Mem0Tool, MementoTool
|
|
9
|
+
from ..utils.logger import write_log_message, handle_application_error
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# =============================================================================
|
|
13
|
+
# SafeToolLoader
|
|
14
|
+
# 설명: 로컬/외부 MCP 도구들을 안전하게 초기화·로드·종료 관리
|
|
15
|
+
# =============================================================================
|
|
16
|
+
class SafeToolLoader:
|
|
17
|
+
"""도구 로더 클래스"""
|
|
18
|
+
adapters = []
|
|
19
|
+
|
|
20
|
+
ANYIO_PATCHED: bool = False
|
|
21
|
+
|
|
22
|
+
def __init__(self, tenant_id: Optional[str] = None, user_id: Optional[str] = None, agent_name: Optional[str] = None, mcp_config: Optional[Dict] = None):
|
|
23
|
+
"""실행 컨텍스트(tenant/user/agent)와 MCP 설정을 보관한다."""
|
|
24
|
+
self.tenant_id = tenant_id
|
|
25
|
+
self.user_id = user_id
|
|
26
|
+
self.agent_name = agent_name
|
|
27
|
+
self._mcp_servers = (mcp_config or {}).get('mcpServers', {})
|
|
28
|
+
self.local_tools = ["mem0", "memento", "human_asked"]
|
|
29
|
+
write_log_message(f"SafeToolLoader 초기화 완료 (tenant_id: {tenant_id}, user_id: {user_id})")
|
|
30
|
+
|
|
31
|
+
# =============================================================================
|
|
32
|
+
# Warmup (npx 서버 사전 준비)
|
|
33
|
+
# =============================================================================
|
|
34
|
+
def warmup_server(self, server_key: str, mcp_config: Optional[Dict] = None):
|
|
35
|
+
"""npx 서버 패키지를 미리 캐싱해 최초 실행 지연을 줄인다."""
|
|
36
|
+
servers = (mcp_config or {}).get('mcpServers') or self._mcp_servers or {}
|
|
37
|
+
server_config = servers.get(server_key, {}) if isinstance(servers, dict) else {}
|
|
38
|
+
if not server_config or server_config.get("command") != "npx":
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
npx_command_path = self._find_npx_command()
|
|
42
|
+
if not npx_command_path:
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
arguments_list = server_config.get("args", [])
|
|
46
|
+
if not (arguments_list and arguments_list[0] == "-y"):
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
package_name = arguments_list[1]
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
subprocess.run([npx_command_path, "-y", package_name, "--help"], capture_output=True, timeout=10, shell=True)
|
|
53
|
+
return
|
|
54
|
+
except subprocess.TimeoutExpired:
|
|
55
|
+
pass
|
|
56
|
+
except Exception:
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
subprocess.run([npx_command_path, "-y", package_name, "--help"], capture_output=True, timeout=60, shell=True)
|
|
61
|
+
except Exception:
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
# =============================================================================
|
|
65
|
+
# 유틸: npx 경로 탐색
|
|
66
|
+
# =============================================================================
|
|
67
|
+
def _find_npx_command(self) -> str:
|
|
68
|
+
"""npx 실행 파일 경로를 탐색해 반환한다."""
|
|
69
|
+
try:
|
|
70
|
+
import shutil
|
|
71
|
+
npx_path = shutil.which("npx") or shutil.which("npx.cmd")
|
|
72
|
+
if npx_path:
|
|
73
|
+
return npx_path
|
|
74
|
+
except Exception:
|
|
75
|
+
pass
|
|
76
|
+
return "npx"
|
|
77
|
+
|
|
78
|
+
# =============================================================================
|
|
79
|
+
# 로컬 도구 생성
|
|
80
|
+
# =============================================================================
|
|
81
|
+
def create_tools_from_names(self, tool_names: List[str], mcp_config: Optional[Dict] = None) -> List:
|
|
82
|
+
"""tool_names 리스트에서 실제 Tool 객체들 생성"""
|
|
83
|
+
if isinstance(tool_names, str):
|
|
84
|
+
tool_names = [tool_names]
|
|
85
|
+
write_log_message(f"도구 생성 요청: {tool_names}")
|
|
86
|
+
|
|
87
|
+
tools = []
|
|
88
|
+
|
|
89
|
+
tools.extend(self._load_mem0())
|
|
90
|
+
tools.extend(self._load_memento())
|
|
91
|
+
tools.extend(self._load_human_asked())
|
|
92
|
+
|
|
93
|
+
for name in tool_names:
|
|
94
|
+
key = name.strip().lower()
|
|
95
|
+
if key in self.local_tools:
|
|
96
|
+
continue
|
|
97
|
+
else:
|
|
98
|
+
self.warmup_server(key, mcp_config)
|
|
99
|
+
tools.extend(self._load_mcp_tool(key, mcp_config))
|
|
100
|
+
|
|
101
|
+
write_log_message(f"총 {len(tools)}개 도구 생성 완료")
|
|
102
|
+
return tools
|
|
103
|
+
|
|
104
|
+
# =============================================================================
|
|
105
|
+
# 로컬 도구 로더들
|
|
106
|
+
# =============================================================================
|
|
107
|
+
def _load_mem0(self) -> List:
|
|
108
|
+
"""mem0 도구 로드 - 에이전트별 메모리"""
|
|
109
|
+
try:
|
|
110
|
+
if not self.user_id:
|
|
111
|
+
write_log_message("mem0 도구 로드 생략: user_id 없음")
|
|
112
|
+
return []
|
|
113
|
+
return [Mem0Tool(tenant_id=self.tenant_id, user_id=self.user_id)]
|
|
114
|
+
except Exception as error:
|
|
115
|
+
handle_application_error("툴mem0오류", error, raise_error=False)
|
|
116
|
+
return []
|
|
117
|
+
|
|
118
|
+
def _load_memento(self) -> List:
|
|
119
|
+
"""memento 도구 로드"""
|
|
120
|
+
try:
|
|
121
|
+
return [MementoTool(tenant_id=self.tenant_id)]
|
|
122
|
+
except Exception as error:
|
|
123
|
+
handle_application_error("툴memento오류", error, raise_error=False)
|
|
124
|
+
return []
|
|
125
|
+
|
|
126
|
+
def _load_human_asked(self) -> List:
|
|
127
|
+
"""human_asked 도구 로드 (선택사항: 사용 시 외부에서 주입)"""
|
|
128
|
+
try:
|
|
129
|
+
return []
|
|
130
|
+
except Exception as error:
|
|
131
|
+
handle_application_error("툴human오류", error, raise_error=False)
|
|
132
|
+
return []
|
|
133
|
+
|
|
134
|
+
# =============================================================================
|
|
135
|
+
# 외부 MCP 도구 로더
|
|
136
|
+
# =============================================================================
|
|
137
|
+
def _load_mcp_tool(self, tool_name: str, mcp_config: Optional[Dict] = None) -> List:
|
|
138
|
+
"""MCP 도구 로드 (timeout & retry 지원)"""
|
|
139
|
+
self._apply_anyio_patch()
|
|
140
|
+
|
|
141
|
+
servers = (mcp_config or {}).get('mcpServers') or self._mcp_servers or {}
|
|
142
|
+
server_config = servers.get(tool_name, {}) if isinstance(servers, dict) else {}
|
|
143
|
+
if not server_config:
|
|
144
|
+
return []
|
|
145
|
+
|
|
146
|
+
environment_variables = os.environ.copy()
|
|
147
|
+
environment_variables.update(server_config.get("env", {}))
|
|
148
|
+
timeout_seconds = server_config.get("timeout", 40)
|
|
149
|
+
|
|
150
|
+
max_retries = 2
|
|
151
|
+
retry_delay = 5
|
|
152
|
+
|
|
153
|
+
for attempt in range(1, max_retries + 1):
|
|
154
|
+
try:
|
|
155
|
+
cmd = server_config["command"]
|
|
156
|
+
if cmd == "npx":
|
|
157
|
+
cmd = self._find_npx_command() or cmd
|
|
158
|
+
|
|
159
|
+
params = StdioServerParameters(
|
|
160
|
+
command=cmd,
|
|
161
|
+
args=server_config.get("args", []),
|
|
162
|
+
env=environment_variables,
|
|
163
|
+
timeout=timeout_seconds
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
adapter = MCPServerAdapter(params)
|
|
167
|
+
SafeToolLoader.adapters.append(adapter)
|
|
168
|
+
write_log_message(f"{tool_name} MCP 로드 성공 (툴 {len(adapter.tools)}개): {[tool.name for tool in adapter.tools]}")
|
|
169
|
+
return adapter.tools
|
|
170
|
+
|
|
171
|
+
except Exception as e:
|
|
172
|
+
if attempt < max_retries:
|
|
173
|
+
time.sleep(retry_delay)
|
|
174
|
+
else:
|
|
175
|
+
handle_application_error(f"툴{tool_name}오류", e, raise_error=False)
|
|
176
|
+
return []
|
|
177
|
+
|
|
178
|
+
# =============================================================================
|
|
179
|
+
# anyio 서브프로세스 stderr 패치
|
|
180
|
+
# =============================================================================
|
|
181
|
+
def _apply_anyio_patch(self):
|
|
182
|
+
"""stderr에 fileno 없음 대비: PIPE로 보정해 예외를 방지한다."""
|
|
183
|
+
if SafeToolLoader.ANYIO_PATCHED:
|
|
184
|
+
return
|
|
185
|
+
from anyio._core._subprocesses import open_process as _orig
|
|
186
|
+
|
|
187
|
+
async def patched_open_process(*args, **kwargs):
|
|
188
|
+
stderr = kwargs.get('stderr')
|
|
189
|
+
if not (hasattr(stderr, 'fileno') and stderr.fileno()):
|
|
190
|
+
kwargs['stderr'] = subprocess.PIPE
|
|
191
|
+
return await _orig(*args, **kwargs)
|
|
192
|
+
|
|
193
|
+
anyio.open_process = patched_open_process
|
|
194
|
+
anyio._core._subprocesses.open_process = patched_open_process
|
|
195
|
+
SafeToolLoader.ANYIO_PATCHED = True
|
|
196
|
+
|
|
197
|
+
# =============================================================================
|
|
198
|
+
# 종료 처리
|
|
199
|
+
# =============================================================================
|
|
200
|
+
@classmethod
|
|
201
|
+
def shutdown_all_adapters(cls):
|
|
202
|
+
"""모든 MCPServerAdapter 연결을 안전하게 종료한다."""
|
|
203
|
+
for adapter in cls.adapters:
|
|
204
|
+
try:
|
|
205
|
+
adapter.stop()
|
|
206
|
+
except Exception as error:
|
|
207
|
+
handle_application_error("툴종료오류", error, raise_error=False)
|
|
208
|
+
write_log_message("모든 MCPServerAdapter 연결 종료 완료")
|
|
209
|
+
cls.adapters.clear()
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
# =============================================================================
|
|
4
|
-
# Context Manager
|
|
5
|
-
# 설명: 요청/프로세스 범위의 컨텍스트 값을 ContextVar로 관리
|
|
6
|
-
# =============================================================================
|
|
7
|
-
|
|
8
|
-
from contextvars import ContextVar
|
|
9
|
-
from typing import Optional
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# 컨텍스트 변수 정의
|
|
13
|
-
todo_id_var: ContextVar[Optional[str]] = ContextVar("todo_id", default=None)
|
|
14
|
-
proc_id_var: ContextVar[Optional[str]] = ContextVar("proc_id", default=None)
|
|
15
|
-
crew_type_var: ContextVar[Optional[str]] = ContextVar("crew_type", default=None)
|
|
16
|
-
form_key_var: ContextVar[Optional[str]] = ContextVar("form_key", default=None)
|
|
17
|
-
form_id_var: ContextVar[Optional[str]] = ContextVar("form_id", default=None)
|
|
18
|
-
all_users_var: ContextVar[Optional[str]] = ContextVar("all_users", default=None)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def set_context(*, todo_id: Optional[str] = None, proc_inst_id: Optional[str] = None, crew_type: Optional[str] = None, form_key: Optional[str] = None, form_id: Optional[str] = None, all_users: Optional[str] = None) -> None:
|
|
22
|
-
"""전달된 값들만 ContextVar에 설정한다."""
|
|
23
|
-
if todo_id is not None:
|
|
24
|
-
todo_id_var.set(todo_id)
|
|
25
|
-
if proc_inst_id is not None:
|
|
26
|
-
proc_id_var.set(proc_inst_id)
|
|
27
|
-
if crew_type is not None:
|
|
28
|
-
crew_type_var.set(crew_type)
|
|
29
|
-
if form_key is not None:
|
|
30
|
-
form_key_var.set(form_key)
|
|
31
|
-
if form_id is not None:
|
|
32
|
-
form_id_var.set(form_id)
|
|
33
|
-
if all_users is not None:
|
|
34
|
-
all_users_var.set(all_users)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def reset_context() -> None:
|
|
38
|
-
"""모든 컨텍스트 값을 초기 상태(None)로 되돌린다."""
|
|
39
|
-
todo_id_var.set(None)
|
|
40
|
-
proc_id_var.set(None)
|
|
41
|
-
crew_type_var.set(None)
|
|
42
|
-
form_key_var.set(None)
|
|
43
|
-
form_id_var.set(None)
|
|
44
|
-
all_users_var.set(None)
|
|
45
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# Context Manager
|
|
5
|
+
# 설명: 요청/프로세스 범위의 컨텍스트 값을 ContextVar로 관리
|
|
6
|
+
# =============================================================================
|
|
7
|
+
|
|
8
|
+
from contextvars import ContextVar
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# 컨텍스트 변수 정의
|
|
13
|
+
todo_id_var: ContextVar[Optional[str]] = ContextVar("todo_id", default=None)
|
|
14
|
+
proc_id_var: ContextVar[Optional[str]] = ContextVar("proc_id", default=None)
|
|
15
|
+
crew_type_var: ContextVar[Optional[str]] = ContextVar("crew_type", default=None)
|
|
16
|
+
form_key_var: ContextVar[Optional[str]] = ContextVar("form_key", default=None)
|
|
17
|
+
form_id_var: ContextVar[Optional[str]] = ContextVar("form_id", default=None)
|
|
18
|
+
all_users_var: ContextVar[Optional[str]] = ContextVar("all_users", default=None)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def set_context(*, todo_id: Optional[str] = None, proc_inst_id: Optional[str] = None, crew_type: Optional[str] = None, form_key: Optional[str] = None, form_id: Optional[str] = None, all_users: Optional[str] = None) -> None:
|
|
22
|
+
"""전달된 값들만 ContextVar에 설정한다."""
|
|
23
|
+
if todo_id is not None:
|
|
24
|
+
todo_id_var.set(todo_id)
|
|
25
|
+
if proc_inst_id is not None:
|
|
26
|
+
proc_id_var.set(proc_inst_id)
|
|
27
|
+
if crew_type is not None:
|
|
28
|
+
crew_type_var.set(crew_type)
|
|
29
|
+
if form_key is not None:
|
|
30
|
+
form_key_var.set(form_key)
|
|
31
|
+
if form_id is not None:
|
|
32
|
+
form_id_var.set(form_id)
|
|
33
|
+
if all_users is not None:
|
|
34
|
+
all_users_var.set(all_users)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def reset_context() -> None:
|
|
38
|
+
"""모든 컨텍스트 값을 초기 상태(None)로 되돌린다."""
|
|
39
|
+
todo_id_var.set(None)
|
|
40
|
+
proc_id_var.set(None)
|
|
41
|
+
crew_type_var.set(None)
|
|
42
|
+
form_key_var.set(None)
|
|
43
|
+
form_id_var.set(None)
|
|
44
|
+
all_users_var.set(None)
|
|
45
|
+
|