docs: add new agent integration guide (5-step checklist and architecture blueprint)

This commit is contained in:
2026-08-26 10:19:25 +09:00
parent 76151c76b2
commit 926ca5452b
+288
View File
@@ -0,0 +1,288 @@
# 🔌 Multi-Agent Mux (MAM): 신규 에이전트 타입 추가 가이드 (New Agent Integration Guide)
본 문서는 Multi-Agent Mux (MAM) 프레임워크에 새로운 AI 에이전트 CLI/TUI 백엔드(예: `grok`, `codex`, `opencode`, `kimi`, `cursor` 등)를 추가하기 위한 아키텍처 구조와 **5단계 필수 작업 절차**를 안내합니다.
---
## 1. 아키텍처 개요 (Architecture Overview)
MAM은 에이전트별 동작 특성(TUI 프롬프트 패턴, 세션 복원 인자, 아티팩트 저장소 등)을 Python 기반의 **어댑터 패턴(`BaseAgentAdapter`)**으로 격리하여 관리합니다. 코어 런타임(Shell, Herdr Daemon, MQTT 브로커)을 수정할 필요 없이 어댑터를 플러그인 형태로 추가할 수 있습니다.
```
┌──────────────────────────────────────────────────────────┐
│ Herdr Runtime │
│ (herdr agent start <name> --kind <kind> -- <cmd>) │
└────────────────────────────┬─────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ lib.sh (Shell Runtime) │
│ • resolve_agent_type_from_registry() │
│ • wait_for_tui_ready() (via MAM_READY_TOKENS) │
│ • send_keys_safe() / stop_session.sh │
└────────────────────────────┬─────────────────────────────┘
eval $(python -m lib_py.agents facts <agent>)
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ lib_py.agents Framework │
│ │
│ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │
│ │ BaseAgentAdapter │ │
│ │ • name, own_key, ready_tokens, exit_key, delegate_agent_key, identity_cache_fields │ │
│ │ • input_prompt, input_placeholder, input_rule_pattern │ │
│ │ • artifact_path(), verify_artifact(), purge_artifacts() │ │
│ │ • spawn_spec(), resume_spec(), auth_ok(), discover() │ │
│ └────────────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌────────────────────┬───────────────────────────────┼───────────────────────────────┬─────────────────────┐ │
│ ▼ ▼ ▼ ▼ ▼ │
│ ClaudeAgentAdapter AgyAgentAdapter ClineAgentAdapter HermesAgentAdapter [NewAgentAdapter] │
│ (Claude Code) (Antigravity) (Cline) (Hermes) (Grok / Codex / ...) │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
```
---
## 2. 5단계 필수 구현 가이드 (Step-by-Step Implementation)
신규 에이전트 `<agent>`(예: `grok`)를 연동하기 위해서는 다음 5개 파일/영역의 수정이 필요합니다.
```
📁 .agents/skills/lib_py/agents/adapters/<agent>.py # Step 1: 어댑터 클래스 구현
📁 .agents/skills/lib_py/agents/registry.py # Step 2: 어댑터 레지스트리 등록
📁 .agents/skills/lib.sh # Step 3: 쉘 디스패치 및 kind 매핑
📁 Herdr Runtime Configuration # Step 4: Herdr CLI 데몬 kind 호환성 확인
📁 tests/test_a4_adapter_contract.py # Step 5: 어댑터 계약 단위 테스트 작성
```
---
### Step 1: Python 어댑터 구현 (`.agents/skills/lib_py/agents/adapters/<agent>.py`)
`BaseAgentAdapter`를 상속하는 `<Agent>AgentAdapter` 클래스를 생성합니다.
```python
"""
<agent>.py — <Agent> agent adapter for Multi-Agent Mux (MAM)
"""
import os
from typing import Any, List, Optional
from ..base import BaseAgentAdapter, DiscoveryContext
class GrokAgentAdapter(BaseAgentAdapter):
@property
def name(self) -> str:
"""에이전트 고유 식별자 (소문자 영문)"""
return 'grok'
@property
def own_key(self) -> str:
"""YAML (.mam/agent-sessions.yaml) 세션 상태에 저장될 키 이름"""
return 'grok_session_id_own'
@property
def ready_tokens(self) -> str:
"""TUI 부팅 완료 및 사용자 입력 대기 상태를 감지하는 정규식 패턴"""
return r'Grok|xAI|Assistant||>>>'
@property
def exit_key(self) -> str:
"""정상 종료(Graceful exit) 시 TUI에 입력할 키/명령어"""
return '/exit' # 또는 'Exit', 'quit', ':q'
@property
def delegate_agent_key(self) -> str:
"""delegate-job MQTT 이벤트 채널에서 사용할 수신자 식별자"""
return 'grok-cli'
@property
def identity_cache_fields(self) -> tuple:
"""세션 복원 시 캐시할 식별자 필드 튜플"""
return ('session_id',)
# =========================================================================
# TUI 프롬프트 영역 비주얼 파싱 (선택적 커스터마이징)
# =========================================================================
@property
def input_prompt(self) -> str:
return ''
@property
def input_placeholder(self) -> str:
return ''
@property
def input_rule_pattern(self) -> str:
return r'{10,}'
# =========================================================================
# 아티팩트 및 대화 히스토리 수명 주기 관리
# =========================================================================
def artifact_path(self, uuid: str, ctx: DiscoveryContext) -> str:
"""해당 세션 UUID의 대화 로그/아티팩트가 저장되는 절대 경로 반환"""
return f"{ctx.home_dir}/.grok/sessions/{uuid}.json"
def verify_artifact(self, uuid: str, ctx: DiscoveryContext) -> bool:
"""디스크 상의 아티팩트 유효성 및 타임스탬프 검증"""
path = self.artifact_path(uuid, ctx)
if not os.path.exists(path):
return False
if ctx.epoch and os.path.getmtime(path) < ctx.epoch:
return False
return True
def purge_artifacts(self, uuid: str, ctx: DiscoveryContext) -> List[str]:
"""--purge-conversation 옵션 호출 시 디스크의 대화 파일 삭제"""
path = self.artifact_path(uuid, ctx)
if os.path.exists(path):
os.remove(path)
return [path]
return []
# =========================================================================
# CLI 실행 및 세션 복원 인자 생성
# =========================================================================
def spawn_spec(self, binary: str, session_uuid: str = "", use_wrapper: bool = False) -> str:
"""신규 세션 기동 시 실행할 커맨드라인 문자열 생성"""
if session_uuid:
return f"{binary} --session {session_uuid}"
return binary
def resume_spec(self, binary: str, session_uuid: str, materialized: bool = False) -> str:
"""기존 세션 복원(Resume) 시 실행할 커맨드라인 문자열 생성"""
if materialized and session_uuid:
return f"{binary} --resume {session_uuid}"
return f"{binary} --session {session_uuid}" if session_uuid else binary
# =========================================================================
# 인증 상태 검사 및 세션 디스커버리
# =========================================================================
def auth_ok(self, run_cmd: Optional[Any] = None) -> bool:
"""에이전트 실행에 필요한 API 키/토큰/설정 파일 존재 여부 확인"""
token_file = os.path.expanduser('~/.grok/token.json')
return os.path.exists(token_file) or bool(os.environ.get('GROK_API_KEY') or os.environ.get('XAI_API_KEY'))
def discover(self, ctx: DiscoveryContext) -> List[str]:
"""디스크의 세션 저장소에서 워크스페이스와 일치하는 세션 UUID 목록 탐색"""
return []
```
---
### Step 2: 어댑터 레지스트리 등록 (`.agents/skills/lib_py/agents/registry.py`)
`registry.py``_ADAPTERS` 딕셔너리에 새 어댑터 인스턴스를 등록합니다.
```python
# 1. 어댑터 임포트
from .adapters.grok import GrokAgentAdapter
# 2. 레지스트리 맵에 등록
_ADAPTERS: Dict[str, BaseAgentAdapter] = {
'claude': ClaudeAgentAdapter(),
'agy': AgyAgentAdapter(),
'hermes': HermesAgentAdapter(),
'cline': ClineAgentAdapter(),
'grok': GrokAgentAdapter(), # 👈 추가
}
```
> **등록 후 즉시 사용 가능한 CLI 명령**:
> - `python -m lib_py.agents facts grok` ➔ 쉘 환경변수(`MAM_READY_TOKENS`, `MAM_EXIT_KEY` 등) 자동 출력
> - `python -m lib_py.agents spawn-spec grok grok` ➔ 기동 커맨드 생성
> - `python -m lib_py.agents resume-spec grok grok <uuid>` ➔ 복원 커맨드 생성
> - `python -m lib_py.agents resolve <session_name>` ➔ 세션 이름 기반 에이전트 자동 식별
---
### Step 3: 쉘 런타임 디스패치 연동 (`.agents/skills/lib.sh`)
`lib.sh`에서 Herdr 세션 기동 시 올바른 `kind`가 전달되도록 패턴 매칭을 추가합니다.
#### 1) Herdr Session Kind 매핑 (`lib.sh:357-371`)
```bash
case "$name" in
*-creator-claude|*-planner-claude|*-reviewer-claude) kind="claude" ;;
*-creator-agy|*-planner-agy|*-reviewer-agy) kind="agy" ;;
*-creator-hermes|*-planner-hermes|*-reviewer-hermes) kind="hermes" ;;
*-creator-cline|*-planner-cline|*-reviewer-cline) kind="cline" ;;
*-creator-grok|*-planner-grok|*-reviewer-grok) kind="grok" ;; # 👈 추가
*)
if echo "$name" | grep -qi "claude"; then kind="claude"
elif echo "$name" | grep -qi "agy"; then kind="agy"
elif echo "$name" | grep -qi "hermes"; then kind="hermes"
elif echo "$name" | grep -qi "cline"; then kind="cline"
elif echo "$name" | grep -qi "grok"; then kind="grok" # 👈 추가
else kind="generic"; fi
;;
esac
```
#### 2) 바이너리 이름 중복 제거 튜플 (`lib.sh:385`)
`herdr agent start` 호출 시 첫 번째 인자로 전달되는 바이너리 중복을 방지하기 위해 등록합니다:
```bash
if [[ " claude agy hermes cline grok " =~ " ${cmd_binary} " ]]; then
```
---
### Step 4: Herdr CLI 데몬 호환성 확인
- **내장 kind 지원 여부 확인**:
- `herdr` 데몬이 해당 `--kind`를 자체적으로 파싱하는지 확인합니다.
- 별도 내장 파서가 없는 경우 `--kind generic`으로도 세션 기동 및 터미널 I/O 제어가 완전하게 지원됩니다.
---
### Step 5: 테스트 작성 및 계약 검증 (`tests/test_a4_adapter_contract.py`)
신규 어댑터가 MAM 계약 규격을 완벽하게 충족하는지 검증하는 단위 테스트를 등록합니다.
```python
# tests/test_a4_adapter_contract.py
def test_agent_adapter_registry():
"""모든 등록된 에이전트 어댑터 인스턴스 검증"""
adapters = get_all_adapters()
assert set(adapters.keys()) == {'claude', 'agy', 'hermes', 'cline', 'grok'}
def test_adapter_required_properties():
"""어댑터 필수 프로퍼티 무결성 검증"""
# ('grok', ('grok_session_id_own', r'Grok|xAI|Assistant||>>>', '/exit', 'grok-cli', ('session_id',)))
```
테스트 실행:
```bash
.venv/bin/python -m pytest tests/test_a4_adapter_contract.py -v
```
---
## 3. 에이전트 백엔드별 구현 난이도 매트릭스
| 에이전트 백엔드 | 세션 저장소 형식 | 인증 방식 | 프롬프트 감지 난이도 | 난이도 Tier | 예상 소요 공수 |
| :--- | :--- | :--- | :--- | :---: | :---: |
| **OpenCode** | `~/.opencode/sessions/*.json` | 로컬 토큰 / API Key | 쉬움 (`OpenCode\|Chat`) | **Tier 1 (낮음)** | **~0.5일** |
| **Codex CLI** | `~/.codex/projects/*.jsonl` | `OPENAI_API_KEY` | 쉬움 (`Codex\|`) | **Tier 1 (낮음)** | **~0.5일** |
| **Kimi CLI** | `~/.kimi/history.db` (SQLite) | `~/.kimi/config` | 쉬움 (`Moonshot\|Kimi`) | **Tier 1 (낮음)** | **~0.5일** |
| **Grok-Build** | `~/.grok/sessions/*.json` | 토큰 파일 / Env | 쉬움 (`Grok\|Building`) | **Tier 1 (낮음)** | **~0.5일** |
| **Cursor CLI** | `~/.cursor/` (Headless/RPC) | OAuth / 쿠키 | 보통 (RPC 포트/상태 파싱) | **Tier 2 (중간)** | **~1.5일** |
| **Local LLM** | `ollama` / `vllm` CLI stdout | 로컬 호스트 | 보통 (`>>>` ANSI 패턴 감지) | **Tier 2 (중간)** | **~1.0일** |
---
## 4. 완료 정의 (Definition of Done Checklist)
신규 에이전트 연동 PR 또는 커밋 전 다음 항목을 확인합니다:
- [ ] `.agents/skills/lib_py/agents/adapters/<agent>.py``BaseAgentAdapter` 모든 추상 메서드/프로퍼티 구현 완료
- [ ] `.agents/skills/lib_py/agents/registry.py`에 어댑터 등록 완료
- [ ] `.agents/skills/lib.sh``kind` 매핑 및 바이너리 패턴 등록 완료
- [ ] `tests/test_a4_adapter_contract.py` 테스트 케이스 추가 및 통과
- [ ] `tests/test_tier1_unit.py` 및 전체 테스트 스위트 통과 (`pytest tests/`)
- [ ] 세션 기동(`multi-agent-mux-create`), 정지(`multi-agent-mux-stop`), 복원(`multi-agent-mux-resume`) 동작 검증 완료