# 📘 ProcessGPT Agent SDK – README
## 1. 이게 뭐하는 건가요?
이 SDK는 **ProcessGPT 에이전트 서버**를 만들 때 필요한 **공통 기능**을 제공합니다.
- DB에서 **작업(todo) 폴링** → 처리할 일감 가져오기
- **컨텍스트 준비** (사용자 정보, 폼 정의, MCP 설정 등 자동으로 조회)
- 다양한 **에이전트 오케스트레이션(A2A)** 과 호환
- **이벤트(Event) 전송 규격 통일화** → 결과를 DB에 안전하게 저장
👉 쉽게 말하면: **여러 종류의 AI 에이전트를 같은 규칙으로 실행/저장/호출할 수 있게 해주는 통합 SDK** 입니다.
---
## 2. 아키텍처 다이어그램
```mermaid
flowchart TD
subgraph DB[Postgres/Supabase]
T[todolist]:::db
E[events]:::db
end
subgraph SDK
P[Polling\n(fetch_pending_task)] --> C[Context 준비\n(fetch_context_bundle 등)]
C --> X[Executor\n(MinimalExecutor)]
X -->|TaskStatusUpdateEvent| E
X -->|TaskArtifactUpdateEvent| T
end
classDef db fill=#f2f2f2,stroke=#333,stroke-width=1px;
```
- **todolist**: 각 작업(Task)의 진행 상태, 결과물 저장
- **events**: 실행 중간에 발생한 이벤트 로그 저장
- SDK는 두 테이블을 자동으로 연결해 줍니다.
---
## 3. A2A 타입과 이벤트 종류
### A2A 타입 (2가지)
| A2A 타입 | 설명 | 매칭 테이블 |
|----------|------|-------------|
| **TaskStatusUpdateEvent** | 작업 상태 업데이트 | `events` 테이블 |
| **TaskArtifactUpdateEvent** | 작업 결과물 업데이트 | `todolist` 테이블 |
### Event Type (4가지)
| Event Type | Python 클래스 | 저장 테이블 | 설명 |
|------------|---------------|-------------|------|
| **task_started** | `TaskStatusUpdateEvent` | `events` | 작업 시작 상태 |
| **task_working** | `TaskStatusUpdateEvent` | `events` | 작업 진행 중 상태 |
| **task_completed** | `TaskArtifactUpdateEvent` | `todolist` | 작업 완료 및 결과물 저장 |
| **task_error** | `TaskStatusUpdateEvent` | `events` | 작업 오류 발생 |
👉 **A2A 타입 2가지**가 핵심이며, 각각 `events`와 `todolist` 테이블에 매칭됩니다. **Event Type 4가지**로 세부 상태를 구분합니다.
---
## 4. 미니멀 예제 (기본 사용법)
### minimal_executor.py
```python
class MinimalExecutor(AgentExecutor):
async def execute(self, context: RequestContext, event_queue: EventQueue):
# 1) 입력 가져오기
query = context.get_user_input()
print("User Query:", query)
# 2) 상태 이벤트 (events 테이블 저장)
payload = {"demo": "hello world"}
event_queue.enqueue_event(
TaskStatusUpdateEvent(
status={
"state": TaskState.working,
"message": new_agent_text_message(
json.dumps(payload, ensure_ascii=False), # ⚠️ str() 쓰지말고 반드시 json.dumps!
context.get_context_data()["row"]["proc_inst_id"],
context.get_context_data()["row"]["id"],
),
},
contextId=context.get_context_data()["row"]["proc_inst_id"],
taskId=context.get_context_data()["row"]["id"],
metadata={"crew_type": "action", "event_type": "task_started"},
)
)
# 3) 최종 아티팩트 이벤트 (todolist 테이블 저장)
artifact = new_text_artifact(
name="result",
description="Demo Result",
text=json.dumps(payload, ensure_ascii=False), # ⚠️ 여기서도 str() 금지!
)
event_queue.enqueue_event(
TaskArtifactUpdateEvent(
artifact=artifact,
lastChunk=True,
contextId=context.get_context_data()["row"]["proc_inst_id"],
taskId=context.get_context_data()["row"]["id"],
)
)
```
### minimal_server.py
```python
async def main():
load_dotenv()
server = ProcessGPTAgentServer(
agent_executor=MinimalExecutor(),
agent_type="crewai-action" # 오케스트레이터 타입
)
await server.run()
```
👉 실행하면 SDK가 자동으로:
1. DB에서 작업 하나 가져오기 (`fetch_pending_task`)
2. 컨텍스트 준비 (폼/유저/MCP 조회)
3. Executor 실행 → 이벤트/결과 DB에 저장
---
## 5. ⚠️ JSON 직렬화 주의 (str() 절대 금지)
반드시 `json.dumps()`로 직렬화해야 합니다.
- ❌ 이렇게 하면 안됨:
```python
text = str({"key": "value"}) # Python dict string → JSON 아님
```
DB에 `"'{key: value}'"` 꼴로 문자열 저장됨 → 파싱 실패
- ✅ 이렇게 해야 함:
```python
text = json.dumps({"key": "value"}, ensure_ascii=False)
```
DB에 `{"key": "value"}` JSON 저장됨 → 파싱 성공
👉 **SDK는 내부에서 `json.loads`로 재파싱**하기 때문에, 표준 JSON 문자열이 아니면 무조건 문자열로만 남습니다.
---
## 6. 요약
- 이 SDK는 **ProcessGPT Agent**를 표준 규격으로 실행/저장/호출하는 공통 레이어
- 작업 → 컨텍스트 준비 → Executor 실행 → 이벤트 저장 전체를 자동화
- **A2A 타입 2가지**: `TaskStatusUpdateEvent`, `TaskArtifactUpdateEvent`
- **Event Type 4가지**: `task_started`, `task_working`, `task_completed`, `task_error`
- **DB 매핑**:
- `TaskStatusUpdateEvent` → `events` 테이블
- `TaskArtifactUpdateEvent` → `todolist` 테이블
- ⚠️ **str() 대신 무조건 `json.dumps` 사용!**
## 7. 버전업
- ./release.sh 버전
- 오류 발생시 : python -m ensurepip --upgrade
Raw data
{
"_id": null,
"home_page": null,
"name": "process-gpt-agent-sdk",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "agent, a2a, supabase, workflow, sdk, processgpt",
"author": null,
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/b7/bd/2f63cfc742303ceb08cf9089ce04c4c4f5fc6f388747073c1dc52060adae/process_gpt_agent_sdk-0.4.9.tar.gz",
"platform": null,
"description": "# \ud83d\udcd8 ProcessGPT Agent SDK \u2013 README\r\n\r\n## 1. \uc774\uac8c \ubb50\ud558\ub294 \uac74\uac00\uc694?\r\n\uc774 SDK\ub294 **ProcessGPT \uc5d0\uc774\uc804\ud2b8 \uc11c\ubc84**\ub97c \ub9cc\ub4e4 \ub54c \ud544\uc694\ud55c **\uacf5\ud1b5 \uae30\ub2a5**\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4. \r\n\r\n- DB\uc5d0\uc11c **\uc791\uc5c5(todo) \ud3f4\ub9c1** \u2192 \ucc98\ub9ac\ud560 \uc77c\uac10 \uac00\uc838\uc624\uae30 \r\n- **\ucee8\ud14d\uc2a4\ud2b8 \uc900\ube44** (\uc0ac\uc6a9\uc790 \uc815\ubcf4, \ud3fc \uc815\uc758, MCP \uc124\uc815 \ub4f1 \uc790\ub3d9\uc73c\ub85c \uc870\ud68c) \r\n- \ub2e4\uc591\ud55c **\uc5d0\uc774\uc804\ud2b8 \uc624\ucf00\uc2a4\ud2b8\ub808\uc774\uc158(A2A)** \uacfc \ud638\ud658 \r\n- **\uc774\ubca4\ud2b8(Event) \uc804\uc1a1 \uaddc\uaca9 \ud1b5\uc77c\ud654** \u2192 \uacb0\uacfc\ub97c DB\uc5d0 \uc548\uc804\ud558\uac8c \uc800\uc7a5 \r\n\r\n\ud83d\udc49 \uc27d\uac8c \ub9d0\ud558\uba74: **\uc5ec\ub7ec \uc885\ub958\uc758 AI \uc5d0\uc774\uc804\ud2b8\ub97c \uac19\uc740 \uaddc\uce59\uc73c\ub85c \uc2e4\ud589/\uc800\uc7a5/\ud638\ucd9c\ud560 \uc218 \uc788\uac8c \ud574\uc8fc\ub294 \ud1b5\ud569 SDK** \uc785\ub2c8\ub2e4. \r\n\r\n---\r\n\r\n## 2. \uc544\ud0a4\ud14d\ucc98 \ub2e4\uc774\uc5b4\uadf8\ub7a8\r\n```mermaid\r\nflowchart TD\r\n subgraph DB[Postgres/Supabase]\r\n T[todolist]:::db\r\n E[events]:::db\r\n end\r\n\r\n subgraph SDK\r\n P[Polling\\n(fetch_pending_task)] --> C[Context \uc900\ube44\\n(fetch_context_bundle \ub4f1)]\r\n C --> X[Executor\\n(MinimalExecutor)]\r\n X -->|TaskStatusUpdateEvent| E\r\n X -->|TaskArtifactUpdateEvent| T\r\n end\r\n\r\n classDef db fill=#f2f2f2,stroke=#333,stroke-width=1px;\r\n```\r\n\r\n- **todolist**: \uac01 \uc791\uc5c5(Task)\uc758 \uc9c4\ud589 \uc0c1\ud0dc, \uacb0\uacfc\ubb3c \uc800\uc7a5 \r\n- **events**: \uc2e4\ud589 \uc911\uac04\uc5d0 \ubc1c\uc0dd\ud55c \uc774\ubca4\ud2b8 \ub85c\uadf8 \uc800\uc7a5 \r\n- SDK\ub294 \ub450 \ud14c\uc774\ube14\uc744 \uc790\ub3d9\uc73c\ub85c \uc5f0\uacb0\ud574 \uc90d\ub2c8\ub2e4. \r\n\r\n---\r\n\r\n## 3. A2A \ud0c0\uc785\uacfc \uc774\ubca4\ud2b8 \uc885\ub958\r\n\r\n### A2A \ud0c0\uc785 (2\uac00\uc9c0)\r\n| A2A \ud0c0\uc785 | \uc124\uba85 | \ub9e4\uce6d \ud14c\uc774\ube14 |\r\n|----------|------|-------------|\r\n| **TaskStatusUpdateEvent** | \uc791\uc5c5 \uc0c1\ud0dc \uc5c5\ub370\uc774\ud2b8 | `events` \ud14c\uc774\ube14 |\r\n| **TaskArtifactUpdateEvent** | \uc791\uc5c5 \uacb0\uacfc\ubb3c \uc5c5\ub370\uc774\ud2b8 | `todolist` \ud14c\uc774\ube14 |\r\n\r\n### Event Type (4\uac00\uc9c0)\r\n| Event Type | Python \ud074\ub798\uc2a4 | \uc800\uc7a5 \ud14c\uc774\ube14 | \uc124\uba85 |\r\n|------------|---------------|-------------|------|\r\n| **task_started** | `TaskStatusUpdateEvent` | `events` | \uc791\uc5c5 \uc2dc\uc791 \uc0c1\ud0dc |\r\n| **task_working** | `TaskStatusUpdateEvent` | `events` | \uc791\uc5c5 \uc9c4\ud589 \uc911 \uc0c1\ud0dc |\r\n| **task_completed** | `TaskArtifactUpdateEvent` | `todolist` | \uc791\uc5c5 \uc644\ub8cc \ubc0f \uacb0\uacfc\ubb3c \uc800\uc7a5 |\r\n| **task_error** | `TaskStatusUpdateEvent` | `events` | \uc791\uc5c5 \uc624\ub958 \ubc1c\uc0dd |\r\n\r\n\ud83d\udc49 **A2A \ud0c0\uc785 2\uac00\uc9c0**\uac00 \ud575\uc2ec\uc774\uba70, \uac01\uac01 `events`\uc640 `todolist` \ud14c\uc774\ube14\uc5d0 \ub9e4\uce6d\ub429\ub2c8\ub2e4. **Event Type 4\uac00\uc9c0**\ub85c \uc138\ubd80 \uc0c1\ud0dc\ub97c \uad6c\ubd84\ud569\ub2c8\ub2e4.\r\n\r\n---\r\n\r\n## 4. \ubbf8\ub2c8\uba40 \uc608\uc81c (\uae30\ubcf8 \uc0ac\uc6a9\ubc95)\r\n\r\n### minimal_executor.py\r\n```python\r\nclass MinimalExecutor(AgentExecutor):\r\n async def execute(self, context: RequestContext, event_queue: EventQueue):\r\n # 1) \uc785\ub825 \uac00\uc838\uc624\uae30\r\n query = context.get_user_input()\r\n print(\"User Query:\", query)\r\n\r\n # 2) \uc0c1\ud0dc \uc774\ubca4\ud2b8 (events \ud14c\uc774\ube14 \uc800\uc7a5)\r\n payload = {\"demo\": \"hello world\"}\r\n event_queue.enqueue_event(\r\n TaskStatusUpdateEvent(\r\n status={\r\n \"state\": TaskState.working,\r\n \"message\": new_agent_text_message(\r\n json.dumps(payload, ensure_ascii=False), # \u26a0\ufe0f str() \uc4f0\uc9c0\ub9d0\uace0 \ubc18\ub4dc\uc2dc json.dumps!\r\n context.get_context_data()[\"row\"][\"proc_inst_id\"],\r\n context.get_context_data()[\"row\"][\"id\"],\r\n ),\r\n },\r\n contextId=context.get_context_data()[\"row\"][\"proc_inst_id\"],\r\n taskId=context.get_context_data()[\"row\"][\"id\"],\r\n metadata={\"crew_type\": \"action\", \"event_type\": \"task_started\"},\r\n )\r\n )\r\n\r\n # 3) \ucd5c\uc885 \uc544\ud2f0\ud329\ud2b8 \uc774\ubca4\ud2b8 (todolist \ud14c\uc774\ube14 \uc800\uc7a5)\r\n artifact = new_text_artifact(\r\n name=\"result\",\r\n description=\"Demo Result\",\r\n text=json.dumps(payload, ensure_ascii=False), # \u26a0\ufe0f \uc5ec\uae30\uc11c\ub3c4 str() \uae08\uc9c0!\r\n )\r\n event_queue.enqueue_event(\r\n TaskArtifactUpdateEvent(\r\n artifact=artifact,\r\n lastChunk=True,\r\n contextId=context.get_context_data()[\"row\"][\"proc_inst_id\"],\r\n taskId=context.get_context_data()[\"row\"][\"id\"],\r\n )\r\n )\r\n```\r\n\r\n### minimal_server.py\r\n```python\r\nasync def main():\r\n load_dotenv()\r\n server = ProcessGPTAgentServer(\r\n agent_executor=MinimalExecutor(),\r\n agent_type=\"crewai-action\" # \uc624\ucf00\uc2a4\ud2b8\ub808\uc774\ud130 \ud0c0\uc785\r\n )\r\n await server.run()\r\n```\r\n\r\n\ud83d\udc49 \uc2e4\ud589\ud558\uba74 SDK\uac00 \uc790\ub3d9\uc73c\ub85c:\r\n1. DB\uc5d0\uc11c \uc791\uc5c5 \ud558\ub098 \uac00\uc838\uc624\uae30 (`fetch_pending_task`) \r\n2. \ucee8\ud14d\uc2a4\ud2b8 \uc900\ube44 (\ud3fc/\uc720\uc800/MCP \uc870\ud68c) \r\n3. Executor \uc2e4\ud589 \u2192 \uc774\ubca4\ud2b8/\uacb0\uacfc DB\uc5d0 \uc800\uc7a5 \r\n\r\n---\r\n\r\n## 5. \u26a0\ufe0f JSON \uc9c1\ub82c\ud654 \uc8fc\uc758 (str() \uc808\ub300 \uae08\uc9c0)\r\n\r\n\ubc18\ub4dc\uc2dc `json.dumps()`\ub85c \uc9c1\ub82c\ud654\ud574\uc57c \ud569\ub2c8\ub2e4. \r\n\r\n- \u274c \uc774\ub807\uac8c \ud558\uba74 \uc548\ub428:\r\n ```python\r\n text = str({\"key\": \"value\"}) # Python dict string \u2192 JSON \uc544\ub2d8\r\n ```\r\n DB\uc5d0 `\"'{key: value}'\"` \uaf34\ub85c \ubb38\uc790\uc5f4 \uc800\uc7a5\ub428 \u2192 \ud30c\uc2f1 \uc2e4\ud328\r\n\r\n- \u2705 \uc774\ub807\uac8c \ud574\uc57c \ud568:\r\n ```python\r\n text = json.dumps({\"key\": \"value\"}, ensure_ascii=False)\r\n ```\r\n DB\uc5d0 `{\"key\": \"value\"}` JSON \uc800\uc7a5\ub428 \u2192 \ud30c\uc2f1 \uc131\uacf5\r\n\r\n\ud83d\udc49 **SDK\ub294 \ub0b4\ubd80\uc5d0\uc11c `json.loads`\ub85c \uc7ac\ud30c\uc2f1**\ud558\uae30 \ub54c\ubb38\uc5d0, \ud45c\uc900 JSON \ubb38\uc790\uc5f4\uc774 \uc544\ub2c8\uba74 \ubb34\uc870\uac74 \ubb38\uc790\uc5f4\ub85c\ub9cc \ub0a8\uc2b5\ub2c8\ub2e4. \r\n\r\n---\r\n\r\n## 6. \uc694\uc57d\r\n- \uc774 SDK\ub294 **ProcessGPT Agent**\ub97c \ud45c\uc900 \uaddc\uaca9\uc73c\ub85c \uc2e4\ud589/\uc800\uc7a5/\ud638\ucd9c\ud558\ub294 \uacf5\ud1b5 \ub808\uc774\uc5b4 \r\n- \uc791\uc5c5 \u2192 \ucee8\ud14d\uc2a4\ud2b8 \uc900\ube44 \u2192 Executor \uc2e4\ud589 \u2192 \uc774\ubca4\ud2b8 \uc800\uc7a5 \uc804\uccb4\ub97c \uc790\ub3d9\ud654 \r\n- **A2A \ud0c0\uc785 2\uac00\uc9c0**: `TaskStatusUpdateEvent`, `TaskArtifactUpdateEvent` \r\n- **Event Type 4\uac00\uc9c0**: `task_started`, `task_working`, `task_completed`, `task_error` \r\n- **DB \ub9e4\ud551**: \r\n - `TaskStatusUpdateEvent` \u2192 `events` \ud14c\uc774\ube14 \r\n - `TaskArtifactUpdateEvent` \u2192 `todolist` \ud14c\uc774\ube14 \r\n- \u26a0\ufe0f **str() \ub300\uc2e0 \ubb34\uc870\uac74 `json.dumps` \uc0ac\uc6a9!**\r\n\r\n\r\n\r\n## 7. \ubc84\uc804\uc5c5\r\n- ./release.sh \ubc84\uc804\r\n- \uc624\ub958 \ubc1c\uc0dd\uc2dc : python -m ensurepip --upgrade\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Supabase \uae30\ubc18 \uc774\ubca4\ud2b8/\uc791\uc5c5 \ud3f4\ub9c1\uc73c\ub85c A2A AgentExecutor\ub97c \uc2e4\ud589\ud558\ub294 SDK",
"version": "0.4.9",
"project_urls": {
"Homepage": "https://github.com/your-org/process-gpt-agent-sdk",
"Issues": "https://github.com/your-org/process-gpt-agent-sdk/issues"
},
"split_keywords": [
"agent",
" a2a",
" supabase",
" workflow",
" sdk",
" processgpt"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "60e8a06ce8a57a718a967fc253e916302f5f438a6f82bba8905636eb81ce0a92",
"md5": "15bc3995753fd57197dd94033f459272",
"sha256": "34f69b71107455c11fb46bbe9a198344655590428f97f4f61812bbb28cf92849"
},
"downloads": -1,
"filename": "process_gpt_agent_sdk-0.4.9-py3-none-any.whl",
"has_sig": false,
"md5_digest": "15bc3995753fd57197dd94033f459272",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 19986,
"upload_time": "2025-10-15T09:30:52",
"upload_time_iso_8601": "2025-10-15T09:30:52.013272Z",
"url": "https://files.pythonhosted.org/packages/60/e8/a06ce8a57a718a967fc253e916302f5f438a6f82bba8905636eb81ce0a92/process_gpt_agent_sdk-0.4.9-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "b7bd2f63cfc742303ceb08cf9089ce04c4c4f5fc6f388747073c1dc52060adae",
"md5": "75ff970220359c499e2fdec65f2b6bd4",
"sha256": "d7e23206cb5ade9d708cc91b724b4822218c6dca5dffe6b36cea2331753d38ae"
},
"downloads": -1,
"filename": "process_gpt_agent_sdk-0.4.9.tar.gz",
"has_sig": false,
"md5_digest": "75ff970220359c499e2fdec65f2b6bd4",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 17843,
"upload_time": "2025-10-15T09:30:53",
"upload_time_iso_8601": "2025-10-15T09:30:53.021476Z",
"url": "https://files.pythonhosted.org/packages/b7/bd/2f63cfc742303ceb08cf9089ce04c4c4f5fc6f388747073c1dc52060adae/process_gpt_agent_sdk-0.4.9.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-15 09:30:53",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "your-org",
"github_project": "process-gpt-agent-sdk",
"github_not_found": true,
"lcname": "process-gpt-agent-sdk"
}