process-gpt-agent-sdk 0.2.11__tar.gz → 0.3.10__tar.gz

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.

Files changed (31) hide show
  1. process_gpt_agent_sdk-0.3.10/PKG-INFO +336 -0
  2. process_gpt_agent_sdk-0.3.10/README.md +312 -0
  3. process_gpt_agent_sdk-0.3.10/process_gpt_agent_sdk.egg-info/PKG-INFO +336 -0
  4. process_gpt_agent_sdk-0.3.10/process_gpt_agent_sdk.egg-info/SOURCES.txt +8 -0
  5. {process_gpt_agent_sdk-0.2.11 → process_gpt_agent_sdk-0.3.10}/process_gpt_agent_sdk.egg-info/requires.txt +1 -9
  6. process_gpt_agent_sdk-0.3.10/processgpt_agent_sdk/processgpt_agent_framework.py +402 -0
  7. {process_gpt_agent_sdk-0.2.11 → process_gpt_agent_sdk-0.3.10}/pyproject.toml +3 -14
  8. process_gpt_agent_sdk-0.2.11/MANIFEST.in +0 -3
  9. process_gpt_agent_sdk-0.2.11/PKG-INFO +0 -1026
  10. process_gpt_agent_sdk-0.2.11/README.md +0 -994
  11. process_gpt_agent_sdk-0.2.11/function.sql +0 -269
  12. process_gpt_agent_sdk-0.2.11/process_gpt_agent_sdk.egg-info/PKG-INFO +0 -1026
  13. process_gpt_agent_sdk-0.2.11/process_gpt_agent_sdk.egg-info/SOURCES.txt +0 -24
  14. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/__init__.py +0 -11
  15. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/core/__init__.py +0 -0
  16. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/core/database.py +0 -464
  17. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/server.py +0 -313
  18. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/simulator.py +0 -231
  19. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/tools/__init__.py +0 -0
  20. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/tools/human_query_tool.py +0 -211
  21. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/tools/knowledge_tools.py +0 -206
  22. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/tools/safe_tool_loader.py +0 -209
  23. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/utils/__init__.py +0 -0
  24. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/utils/context_manager.py +0 -45
  25. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/utils/crewai_event_listener.py +0 -205
  26. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/utils/event_handler.py +0 -72
  27. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/utils/logger.py +0 -97
  28. process_gpt_agent_sdk-0.2.11/processgpt_agent_sdk/utils/summarizer.py +0 -146
  29. {process_gpt_agent_sdk-0.2.11 → process_gpt_agent_sdk-0.3.10}/process_gpt_agent_sdk.egg-info/dependency_links.txt +0 -0
  30. {process_gpt_agent_sdk-0.2.11 → process_gpt_agent_sdk-0.3.10}/process_gpt_agent_sdk.egg-info/top_level.txt +0 -0
  31. {process_gpt_agent_sdk-0.2.11 → process_gpt_agent_sdk-0.3.10}/setup.cfg +0 -0
@@ -0,0 +1,336 @@
1
+ Metadata-Version: 2.4
2
+ Name: process-gpt-agent-sdk
3
+ Version: 0.3.10
4
+ Summary: Supabase 기반 이벤트/작업 폴링으로 A2A AgentExecutor를 실행하는 SDK
5
+ License: MIT
6
+ Project-URL: Homepage, https://github.com/your-org/process-gpt-agent-sdk
7
+ Project-URL: Issues, https://github.com/your-org/process-gpt-agent-sdk/issues
8
+ Keywords: agent,a2a,supabase,workflow,sdk,processgpt
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3 :: Only
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.9
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: supabase>=2.0.0
16
+ Requires-Dist: python-dotenv>=1.0.0
17
+ Requires-Dist: click>=8.0.0
18
+ Requires-Dist: asyncio-mqtt>=0.13.0
19
+ Requires-Dist: jsonschema>=4.0.0
20
+ Requires-Dist: structlog>=23.0.0
21
+ Requires-Dist: typing-extensions>=4.0.0
22
+ Requires-Dist: python-dateutil>=2.8.0
23
+ Requires-Dist: a2a-sdk==0.3.0
24
+
25
+ # ProcessGPT Agent Framework (A2A SDK 연동 가이드)
26
+
27
+ 이 저장소는 Supabase 기반의 프로세스 작업(Todolist)을 폴링하고, A2A 규격 이벤트를 통해 작업 상태/결과를 기록하는 **경량 에이전트 서버 프레임워크**입니다. 최소 구현으로 빠르게 통합하고, 필요하면 커스터마이즈할 수 있습니다.
28
+
29
+ - 런타임: Python 3.10+
30
+ - 저장소 의존: Supabase(Postgres) + 제공된 RPC/테이블
31
+ - 이벤트 규격: A2A `TaskStatusUpdateEvent` / `TaskArtifactUpdateEvent`
32
+
33
+
34
+ ## 아키텍처 한눈에 보기
35
+ ```mermaid
36
+ flowchart LR
37
+ subgraph Supabase
38
+ A[Todolist] --- B[Events]
39
+ A -.RPC.-> C[(save_task_result)]
40
+ D[(fetch_pending_task)] --> A
41
+ end
42
+
43
+ subgraph Agent Server
44
+ E[ProcessGPTAgentServer] -->|polls| D
45
+ E --> F[ProcessGPTRequestContext]
46
+ E --> G[ProcessGPTEventQueue]
47
+ H[Your AgentExecutor]
48
+ F --> H
49
+ H -->|A2A Events| G
50
+ end
51
+
52
+ G -->|TaskStatusUpdateEvent| B
53
+ G -->|TaskArtifactUpdateEvent| A
54
+ ```
55
+
56
+ - 서버는 주기적으로 Todolist를 폴링하여 새 작업을 가져옵니다.
57
+ - 사용자 구현 `AgentExecutor`가 요청을 처리하고, A2A 이벤트를 큐에 전달합니다.
58
+ - 이벤트 큐는 상태 이벤트를 `events` 테이블에, 아티팩트 이벤트를 `todolist.output`에 저장합니다.
59
+
60
+
61
+ ## 엔드-투-엔드 시퀀스(정상 흐름)
62
+ ```mermaid
63
+ sequenceDiagram
64
+ participant SB as Supabase
65
+ participant SRV as ProcessGPTAgentServer
66
+ participant CTX as RequestContext
67
+ participant EXE as Your AgentExecutor
68
+ participant EQ as ProcessGPTEventQueue
69
+
70
+ SRV->>SB: RPC fetch_pending_task
71
+ SB-->>SRV: todolist row
72
+ SRV->>CTX: prepare_context()
73
+ SRV->>EXE: execute(context, event_queue)
74
+ EXE->>EQ: TaskStatusUpdateEvent (state=working)
75
+ EQ->>SB: INSERT events (data=payload)
76
+ EXE->>EQ: TaskArtifactUpdateEvent (lastChunk=true, artifact)
77
+ EQ->>SB: RPC save_task_result (output=payload, p_final=true)
78
+ SRV->>EQ: task_done()
79
+ EQ->>SB: INSERT events (crew_completed)
80
+ ```
81
+
82
+
83
+ ## Human-in-the-loop(HITL) 시퀀스
84
+ ```mermaid
85
+ sequenceDiagram
86
+ participant EXE as Your AgentExecutor
87
+ participant EQ as ProcessGPTEventQueue
88
+ participant SB as Supabase
89
+ participant UI as Operator UI
90
+
91
+ EXE->>EQ: TaskStatusUpdateEvent (state=input_required)
92
+ Note right of EXE: event_type 전송 생략 가능
93
+ EQ->>SB: INSERT events (event_type=human_asked, data=질문 payload)
94
+ UI->>SB: INSERT events (event_type=human_response, data=사용자 응답)
95
+ EXE-->>SB: 선택: fetch_human_response_sync(job_id)
96
+ ```
97
+
98
+
99
+ ## 친절한 시작 가이드(5분 컷)
100
+ 1) 가상환경 + 설치
101
+ ```bash
102
+ uv venv --python 3.11.9
103
+ uv pip install -r requirements.txt
104
+ source .venv/Scripts/activate
105
+ ```
106
+
107
+ 2) .env 준비
108
+ - SUPABASE_URL, SUPABASE_KEY 필수
109
+ - ENV=dev (개발 환경에서 권장)
110
+
111
+ 3) 샘플 서버 실행
112
+ ```bash
113
+ python sample_server/minimal_server.py | cat
114
+ ```
115
+
116
+ 4) 이벤트 전송 패턴 이해
117
+ - 진행 상태: `TaskStatusUpdateEvent(state=working)` + `new_agent_text_message(text, contextId, taskId)`
118
+ - 사용자 입력 요청(HITL): `TaskState.input_required`만 보내면 event_type은 자동 `human_asked`
119
+ - 결과물: `TaskArtifactUpdateEvent(lastChunk=True)` + `new_text_artifact(name, desc, text)`
120
+
121
+ 5) 저장물 확인 포인트
122
+ - `events` 테이블: data에는 래퍼 제거된 순수 payload 저장
123
+ - `todolist.output`: 순수 payload 저장, 최종 청크면 `p_final=true`
124
+
125
+
126
+ ## 샘플 서버 실행 코드 (친절 버전)
127
+ ### A. 가장 간단한 서버(minimal)
128
+ ```python
129
+ # sample_server/minimal_server.py
130
+ import os
131
+ import sys
132
+ import asyncio
133
+ from dotenv import load_dotenv
134
+
135
+ # 패키지 루트 경로 추가 (샘플에서만)
136
+ sys.path.append(os.path.dirname(os.path.dirname(__file__)))
137
+
138
+ from processgpt_agent_sdk.processgpt_agent_framework import ProcessGPTAgentServer
139
+ from sample_server.minimal_executor import MinimalExecutor
140
+
141
+ async def main():
142
+ load_dotenv()
143
+ # agent_type은 Supabase의 todolist.agent_orch와 매칭되어야 함
144
+ server = ProcessGPTAgentServer(agent_executor=MinimalExecutor(), agent_type="crewai-action")
145
+ server.polling_interval = 3 # 초
146
+ await server.run()
147
+
148
+ if __name__ == "__main__":
149
+ try:
150
+ asyncio.run(main())
151
+ except KeyboardInterrupt:
152
+ pass
153
+ ```
154
+
155
+ - Windows
156
+ ```bash
157
+ python sample_server/minimal_server.py
158
+ ```
159
+ - macOS/Linux
160
+ ```bash
161
+ python3 sample_server/minimal_server.py
162
+ ```
163
+
164
+ ### B. CLI 옵션이 있는 서버 예시
165
+ ```python
166
+ # sample_server/crew_ai_dr_agent_server.py
167
+ import os
168
+ import sys
169
+ import asyncio
170
+ import click
171
+ from dotenv import load_dotenv
172
+
173
+ # 패키지 루트 경로 추가 (샘플에서만)
174
+ sys.path.append(os.path.dirname(os.path.dirname(__file__)))
175
+
176
+ from processgpt_agent_sdk.processgpt_agent_framework import ProcessGPTAgentServer
177
+ from sample_server.crew_ai_dr_agent_executor import CrewAIDeepResearchAgentExecutor
178
+
179
+ load_dotenv()
180
+
181
+ @click.command()
182
+ @click.option('--agent-type', default='crew-ai-dr', help='Agent type identifier')
183
+ @click.option('--polling-interval', default=5, help='Polling interval in seconds')
184
+ def cli_main(agent_type: str, polling_interval: int):
185
+ """ProcessGPT Agent Server for CrewAI Deep Research Agent"""
186
+
187
+ agent_executor = CrewAIDeepResearchAgentExecutor()
188
+ server = ProcessGPTAgentServer(agent_executor=agent_executor, agent_type=agent_type)
189
+ server.polling_interval = polling_interval
190
+
191
+ print(f"Starting ProcessGPT Agent Server...")
192
+ print(f"Agent Type: {agent_type}")
193
+ print(f"Polling Interval: {polling_interval} seconds")
194
+ print("Press Ctrl+C to stop")
195
+
196
+ try:
197
+ asyncio.run(server.run())
198
+ except KeyboardInterrupt:
199
+ print("\nShutting down server...")
200
+ server.stop()
201
+ except Exception as e:
202
+ print(f"Server error: {e}")
203
+ sys.exit(1)
204
+
205
+ if __name__ == "__main__":
206
+ cli_main()
207
+ ```
208
+
209
+ - 실행
210
+ - Windows
211
+ ```bash
212
+ python sample_server/crew_ai_dr_agent_server.py --agent-type crew-ai-dr --polling-interval 3
213
+ ```
214
+ - macOS/Linux
215
+ ```bash
216
+ python3 sample_server/crew_ai_dr_agent_server.py --agent-type crew-ai-dr --polling-interval 3
217
+ ```
218
+
219
+
220
+ ## 최소 예시(익스큐터)
221
+ ```python
222
+ # sample_server/minimal_executor.py (요약)
223
+ import asyncio
224
+ import json
225
+ from typing_extensions import override
226
+ from a2a.server.agent_execution import AgentExecutor, RequestContext
227
+ from a2a.server.events import EventQueue
228
+ from a2a.types import TaskStatusUpdateEvent, TaskState, TaskArtifactUpdateEvent
229
+ from a2a.utils import new_agent_text_message, new_text_artifact
230
+
231
+ class MinimalExecutor(AgentExecutor):
232
+ @override
233
+ async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
234
+ row = context.get_context_data()["row"]
235
+ context_id = row.get("root_proc_inst_id") or row.get("proc_inst_id")
236
+ task_id = row.get("id")
237
+
238
+ payload = {"order_process_activity_order_request_form": {"orderer_name": "안치윤","product_name": "금형세트","order_quantity": "50"}}
239
+
240
+ # 1) 진행 상태 이벤트
241
+ event_queue.enqueue_event(
242
+ TaskStatusUpdateEvent(
243
+ status={
244
+ "state": TaskState.working,
245
+ "message": new_agent_text_message(
246
+ json.dumps(payload, ensure_ascii=False),
247
+ context_id,
248
+ task_id,
249
+ ),
250
+ },
251
+ final=False,
252
+ contextId=context_id,
253
+ taskId=task_id,
254
+ metadata={"crew_type": "action", "event_type": "task_started", "job_id": "job-demo-0001"},
255
+ )
256
+ )
257
+
258
+ await asyncio.sleep(0.1)
259
+
260
+ # 2) HITL: 사용자 입력 요청 (event_type 생략해도 자동 human_asked)
261
+ event_queue.enqueue_event(
262
+ TaskStatusUpdateEvent(
263
+ status={
264
+ "state": TaskState.input_required,
265
+ "message": new_agent_text_message(
266
+ json.dumps(payload, ensure_ascii=False),
267
+ context_id,
268
+ task_id,
269
+ ),
270
+ },
271
+ final=True,
272
+ contextId=context_id,
273
+ taskId=task_id,
274
+ metadata={"crew_type": "action", "job_id": "job-demo-0001"},
275
+ )
276
+ )
277
+
278
+ await asyncio.sleep(0.1)
279
+
280
+ # 3) 최종 아티팩트
281
+ artifact = new_text_artifact(
282
+ name="current_result",
283
+ description="Result of request to agent.",
284
+ text=json.dumps(payload, ensure_ascii=False),
285
+ )
286
+ event_queue.enqueue_event(
287
+ TaskArtifactUpdateEvent(
288
+ artifact=artifact,
289
+ lastChunk=True,
290
+ contextId=context_id,
291
+ taskId=task_id,
292
+ )
293
+ )
294
+ ```
295
+
296
+
297
+ ## 서버가 해주는 일(정확한 규칙)
298
+ - 메시지/아티팩트 래퍼 제거 → `parts[0].text|content|data` → `root.*` → `top-level` 순서로 텍스트만 추출 후 JSON 파싱하여 저장
299
+ - `TaskStatusUpdateEvent` 수신 시
300
+ - `status.state == input_required`면 `event_type=human_asked`로 저장(명시값보다 우선)
301
+ - 그 외 상태는 `metadata.event_type` 저장(없으면 NULL)
302
+ - `TaskArtifactUpdateEvent` 수신 시
303
+ - `final` 또는 `lastChunk`가 참이면 최종 저장(`p_final=true`)
304
+
305
+
306
+ ## 체크리스트(실패 없는 통합을 위한)
307
+ - [ ] .env에 `SUPABASE_URL`, `SUPABASE_KEY` 설정했는가?
308
+ - [ ] `requirements.txt` 설치 완료했는가?
309
+ - [ ] Supabase에서 제공 SQL(`database_schema.sql`, `function.sql`) 적용했는가?
310
+ - [ ] 익스큐터에서 `contextId`, `taskId`를 todolist의 `proc_inst_id`, `id`로 매핑했는가?
311
+ - [ ] 상태 이벤트는 `new_agent_text_message`로 만들고 있는가?
312
+ - [ ] 최종 아티팩트는 `new_text_artifact` + `lastChunk=True`로 보내고 있는가?
313
+ - [ ] HITL 요청은 `TaskState.input_required`만 보내고 있는가?(event_type 생략 가능)
314
+
315
+
316
+ ## 트러블슈팅
317
+ - 이벤트 미기록
318
+ - Supabase URL/Key 재확인, 테이블/권한 확인
319
+ - 최종 아티팩트가 최종으로 저장되지 않음
320
+ - 익스큐터에서 `lastChunk=True` 또는 `final=True`로 보냈는지 확인
321
+ - payload가 래퍼와 같이 저장됨
322
+ - 메시지에 `parts[0].text` 또는 `parts[0].root.text`에 JSON 문자열이 들어있는지 확인
323
+ - 휴먼인더루프 이벤트 타입 미지정
324
+ - `input_required` 상태면 자동 `human_asked`로 저장됨
325
+
326
+
327
+ ## 레퍼런스
328
+ - 이벤트 유틸: `new_agent_text_message`, `new_text_artifact`
329
+ - 서버 진입점: `ProcessGPTAgentServer.run()`
330
+ - 컨텍스트 확장: `ProcessGPTRequestContext.prepare_context()`
331
+ - 이벤트 저장: `ProcessGPTEventQueue.enqueue_event(event)` → `database.record_event`/`save_task_result`
332
+ - 휴먼 응답 조회: `database.fetch_human_response_sync(job_id)`
333
+
334
+
335
+ ## 라이선스
336
+ 해당 저장소의 라이선스 정책을 따릅니다.
@@ -0,0 +1,312 @@
1
+ # ProcessGPT Agent Framework (A2A SDK 연동 가이드)
2
+
3
+ 이 저장소는 Supabase 기반의 프로세스 작업(Todolist)을 폴링하고, A2A 규격 이벤트를 통해 작업 상태/결과를 기록하는 **경량 에이전트 서버 프레임워크**입니다. 최소 구현으로 빠르게 통합하고, 필요하면 커스터마이즈할 수 있습니다.
4
+
5
+ - 런타임: Python 3.10+
6
+ - 저장소 의존: Supabase(Postgres) + 제공된 RPC/테이블
7
+ - 이벤트 규격: A2A `TaskStatusUpdateEvent` / `TaskArtifactUpdateEvent`
8
+
9
+
10
+ ## 아키텍처 한눈에 보기
11
+ ```mermaid
12
+ flowchart LR
13
+ subgraph Supabase
14
+ A[Todolist] --- B[Events]
15
+ A -.RPC.-> C[(save_task_result)]
16
+ D[(fetch_pending_task)] --> A
17
+ end
18
+
19
+ subgraph Agent Server
20
+ E[ProcessGPTAgentServer] -->|polls| D
21
+ E --> F[ProcessGPTRequestContext]
22
+ E --> G[ProcessGPTEventQueue]
23
+ H[Your AgentExecutor]
24
+ F --> H
25
+ H -->|A2A Events| G
26
+ end
27
+
28
+ G -->|TaskStatusUpdateEvent| B
29
+ G -->|TaskArtifactUpdateEvent| A
30
+ ```
31
+
32
+ - 서버는 주기적으로 Todolist를 폴링하여 새 작업을 가져옵니다.
33
+ - 사용자 구현 `AgentExecutor`가 요청을 처리하고, A2A 이벤트를 큐에 전달합니다.
34
+ - 이벤트 큐는 상태 이벤트를 `events` 테이블에, 아티팩트 이벤트를 `todolist.output`에 저장합니다.
35
+
36
+
37
+ ## 엔드-투-엔드 시퀀스(정상 흐름)
38
+ ```mermaid
39
+ sequenceDiagram
40
+ participant SB as Supabase
41
+ participant SRV as ProcessGPTAgentServer
42
+ participant CTX as RequestContext
43
+ participant EXE as Your AgentExecutor
44
+ participant EQ as ProcessGPTEventQueue
45
+
46
+ SRV->>SB: RPC fetch_pending_task
47
+ SB-->>SRV: todolist row
48
+ SRV->>CTX: prepare_context()
49
+ SRV->>EXE: execute(context, event_queue)
50
+ EXE->>EQ: TaskStatusUpdateEvent (state=working)
51
+ EQ->>SB: INSERT events (data=payload)
52
+ EXE->>EQ: TaskArtifactUpdateEvent (lastChunk=true, artifact)
53
+ EQ->>SB: RPC save_task_result (output=payload, p_final=true)
54
+ SRV->>EQ: task_done()
55
+ EQ->>SB: INSERT events (crew_completed)
56
+ ```
57
+
58
+
59
+ ## Human-in-the-loop(HITL) 시퀀스
60
+ ```mermaid
61
+ sequenceDiagram
62
+ participant EXE as Your AgentExecutor
63
+ participant EQ as ProcessGPTEventQueue
64
+ participant SB as Supabase
65
+ participant UI as Operator UI
66
+
67
+ EXE->>EQ: TaskStatusUpdateEvent (state=input_required)
68
+ Note right of EXE: event_type 전송 생략 가능
69
+ EQ->>SB: INSERT events (event_type=human_asked, data=질문 payload)
70
+ UI->>SB: INSERT events (event_type=human_response, data=사용자 응답)
71
+ EXE-->>SB: 선택: fetch_human_response_sync(job_id)
72
+ ```
73
+
74
+
75
+ ## 친절한 시작 가이드(5분 컷)
76
+ 1) 가상환경 + 설치
77
+ ```bash
78
+ uv venv --python 3.11.9
79
+ uv pip install -r requirements.txt
80
+ source .venv/Scripts/activate
81
+ ```
82
+
83
+ 2) .env 준비
84
+ - SUPABASE_URL, SUPABASE_KEY 필수
85
+ - ENV=dev (개발 환경에서 권장)
86
+
87
+ 3) 샘플 서버 실행
88
+ ```bash
89
+ python sample_server/minimal_server.py | cat
90
+ ```
91
+
92
+ 4) 이벤트 전송 패턴 이해
93
+ - 진행 상태: `TaskStatusUpdateEvent(state=working)` + `new_agent_text_message(text, contextId, taskId)`
94
+ - 사용자 입력 요청(HITL): `TaskState.input_required`만 보내면 event_type은 자동 `human_asked`
95
+ - 결과물: `TaskArtifactUpdateEvent(lastChunk=True)` + `new_text_artifact(name, desc, text)`
96
+
97
+ 5) 저장물 확인 포인트
98
+ - `events` 테이블: data에는 래퍼 제거된 순수 payload 저장
99
+ - `todolist.output`: 순수 payload 저장, 최종 청크면 `p_final=true`
100
+
101
+
102
+ ## 샘플 서버 실행 코드 (친절 버전)
103
+ ### A. 가장 간단한 서버(minimal)
104
+ ```python
105
+ # sample_server/minimal_server.py
106
+ import os
107
+ import sys
108
+ import asyncio
109
+ from dotenv import load_dotenv
110
+
111
+ # 패키지 루트 경로 추가 (샘플에서만)
112
+ sys.path.append(os.path.dirname(os.path.dirname(__file__)))
113
+
114
+ from processgpt_agent_sdk.processgpt_agent_framework import ProcessGPTAgentServer
115
+ from sample_server.minimal_executor import MinimalExecutor
116
+
117
+ async def main():
118
+ load_dotenv()
119
+ # agent_type은 Supabase의 todolist.agent_orch와 매칭되어야 함
120
+ server = ProcessGPTAgentServer(agent_executor=MinimalExecutor(), agent_type="crewai-action")
121
+ server.polling_interval = 3 # 초
122
+ await server.run()
123
+
124
+ if __name__ == "__main__":
125
+ try:
126
+ asyncio.run(main())
127
+ except KeyboardInterrupt:
128
+ pass
129
+ ```
130
+
131
+ - Windows
132
+ ```bash
133
+ python sample_server/minimal_server.py
134
+ ```
135
+ - macOS/Linux
136
+ ```bash
137
+ python3 sample_server/minimal_server.py
138
+ ```
139
+
140
+ ### B. CLI 옵션이 있는 서버 예시
141
+ ```python
142
+ # sample_server/crew_ai_dr_agent_server.py
143
+ import os
144
+ import sys
145
+ import asyncio
146
+ import click
147
+ from dotenv import load_dotenv
148
+
149
+ # 패키지 루트 경로 추가 (샘플에서만)
150
+ sys.path.append(os.path.dirname(os.path.dirname(__file__)))
151
+
152
+ from processgpt_agent_sdk.processgpt_agent_framework import ProcessGPTAgentServer
153
+ from sample_server.crew_ai_dr_agent_executor import CrewAIDeepResearchAgentExecutor
154
+
155
+ load_dotenv()
156
+
157
+ @click.command()
158
+ @click.option('--agent-type', default='crew-ai-dr', help='Agent type identifier')
159
+ @click.option('--polling-interval', default=5, help='Polling interval in seconds')
160
+ def cli_main(agent_type: str, polling_interval: int):
161
+ """ProcessGPT Agent Server for CrewAI Deep Research Agent"""
162
+
163
+ agent_executor = CrewAIDeepResearchAgentExecutor()
164
+ server = ProcessGPTAgentServer(agent_executor=agent_executor, agent_type=agent_type)
165
+ server.polling_interval = polling_interval
166
+
167
+ print(f"Starting ProcessGPT Agent Server...")
168
+ print(f"Agent Type: {agent_type}")
169
+ print(f"Polling Interval: {polling_interval} seconds")
170
+ print("Press Ctrl+C to stop")
171
+
172
+ try:
173
+ asyncio.run(server.run())
174
+ except KeyboardInterrupt:
175
+ print("\nShutting down server...")
176
+ server.stop()
177
+ except Exception as e:
178
+ print(f"Server error: {e}")
179
+ sys.exit(1)
180
+
181
+ if __name__ == "__main__":
182
+ cli_main()
183
+ ```
184
+
185
+ - 실행
186
+ - Windows
187
+ ```bash
188
+ python sample_server/crew_ai_dr_agent_server.py --agent-type crew-ai-dr --polling-interval 3
189
+ ```
190
+ - macOS/Linux
191
+ ```bash
192
+ python3 sample_server/crew_ai_dr_agent_server.py --agent-type crew-ai-dr --polling-interval 3
193
+ ```
194
+
195
+
196
+ ## 최소 예시(익스큐터)
197
+ ```python
198
+ # sample_server/minimal_executor.py (요약)
199
+ import asyncio
200
+ import json
201
+ from typing_extensions import override
202
+ from a2a.server.agent_execution import AgentExecutor, RequestContext
203
+ from a2a.server.events import EventQueue
204
+ from a2a.types import TaskStatusUpdateEvent, TaskState, TaskArtifactUpdateEvent
205
+ from a2a.utils import new_agent_text_message, new_text_artifact
206
+
207
+ class MinimalExecutor(AgentExecutor):
208
+ @override
209
+ async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
210
+ row = context.get_context_data()["row"]
211
+ context_id = row.get("root_proc_inst_id") or row.get("proc_inst_id")
212
+ task_id = row.get("id")
213
+
214
+ payload = {"order_process_activity_order_request_form": {"orderer_name": "안치윤","product_name": "금형세트","order_quantity": "50"}}
215
+
216
+ # 1) 진행 상태 이벤트
217
+ event_queue.enqueue_event(
218
+ TaskStatusUpdateEvent(
219
+ status={
220
+ "state": TaskState.working,
221
+ "message": new_agent_text_message(
222
+ json.dumps(payload, ensure_ascii=False),
223
+ context_id,
224
+ task_id,
225
+ ),
226
+ },
227
+ final=False,
228
+ contextId=context_id,
229
+ taskId=task_id,
230
+ metadata={"crew_type": "action", "event_type": "task_started", "job_id": "job-demo-0001"},
231
+ )
232
+ )
233
+
234
+ await asyncio.sleep(0.1)
235
+
236
+ # 2) HITL: 사용자 입력 요청 (event_type 생략해도 자동 human_asked)
237
+ event_queue.enqueue_event(
238
+ TaskStatusUpdateEvent(
239
+ status={
240
+ "state": TaskState.input_required,
241
+ "message": new_agent_text_message(
242
+ json.dumps(payload, ensure_ascii=False),
243
+ context_id,
244
+ task_id,
245
+ ),
246
+ },
247
+ final=True,
248
+ contextId=context_id,
249
+ taskId=task_id,
250
+ metadata={"crew_type": "action", "job_id": "job-demo-0001"},
251
+ )
252
+ )
253
+
254
+ await asyncio.sleep(0.1)
255
+
256
+ # 3) 최종 아티팩트
257
+ artifact = new_text_artifact(
258
+ name="current_result",
259
+ description="Result of request to agent.",
260
+ text=json.dumps(payload, ensure_ascii=False),
261
+ )
262
+ event_queue.enqueue_event(
263
+ TaskArtifactUpdateEvent(
264
+ artifact=artifact,
265
+ lastChunk=True,
266
+ contextId=context_id,
267
+ taskId=task_id,
268
+ )
269
+ )
270
+ ```
271
+
272
+
273
+ ## 서버가 해주는 일(정확한 규칙)
274
+ - 메시지/아티팩트 래퍼 제거 → `parts[0].text|content|data` → `root.*` → `top-level` 순서로 텍스트만 추출 후 JSON 파싱하여 저장
275
+ - `TaskStatusUpdateEvent` 수신 시
276
+ - `status.state == input_required`면 `event_type=human_asked`로 저장(명시값보다 우선)
277
+ - 그 외 상태는 `metadata.event_type` 저장(없으면 NULL)
278
+ - `TaskArtifactUpdateEvent` 수신 시
279
+ - `final` 또는 `lastChunk`가 참이면 최종 저장(`p_final=true`)
280
+
281
+
282
+ ## 체크리스트(실패 없는 통합을 위한)
283
+ - [ ] .env에 `SUPABASE_URL`, `SUPABASE_KEY` 설정했는가?
284
+ - [ ] `requirements.txt` 설치 완료했는가?
285
+ - [ ] Supabase에서 제공 SQL(`database_schema.sql`, `function.sql`) 적용했는가?
286
+ - [ ] 익스큐터에서 `contextId`, `taskId`를 todolist의 `proc_inst_id`, `id`로 매핑했는가?
287
+ - [ ] 상태 이벤트는 `new_agent_text_message`로 만들고 있는가?
288
+ - [ ] 최종 아티팩트는 `new_text_artifact` + `lastChunk=True`로 보내고 있는가?
289
+ - [ ] HITL 요청은 `TaskState.input_required`만 보내고 있는가?(event_type 생략 가능)
290
+
291
+
292
+ ## 트러블슈팅
293
+ - 이벤트 미기록
294
+ - Supabase URL/Key 재확인, 테이블/권한 확인
295
+ - 최종 아티팩트가 최종으로 저장되지 않음
296
+ - 익스큐터에서 `lastChunk=True` 또는 `final=True`로 보냈는지 확인
297
+ - payload가 래퍼와 같이 저장됨
298
+ - 메시지에 `parts[0].text` 또는 `parts[0].root.text`에 JSON 문자열이 들어있는지 확인
299
+ - 휴먼인더루프 이벤트 타입 미지정
300
+ - `input_required` 상태면 자동 `human_asked`로 저장됨
301
+
302
+
303
+ ## 레퍼런스
304
+ - 이벤트 유틸: `new_agent_text_message`, `new_text_artifact`
305
+ - 서버 진입점: `ProcessGPTAgentServer.run()`
306
+ - 컨텍스트 확장: `ProcessGPTRequestContext.prepare_context()`
307
+ - 이벤트 저장: `ProcessGPTEventQueue.enqueue_event(event)` → `database.record_event`/`save_task_result`
308
+ - 휴먼 응답 조회: `database.fetch_human_response_sync(job_id)`
309
+
310
+
311
+ ## 라이선스
312
+ 해당 저장소의 라이선스 정책을 따릅니다.