# a2a-agent

`a2a-agent`는 MQTT 위에서 커맨더와 워커가 A2A 형식 메시지를 주고받기 위한 작은 명령줄 도구입니다.

현재 버전은 MQTT 브로커(기본값은 환경변수 `A2A_BROKER_HOST`, 미설정 시 `localhost:1883`), 기본 방 `team`, 6자리 페어링 코드, 역할별 `run` 루프, 커맨더 `send`, 워커 `echo`/`opencode`/`cursor` 실행기를 지원합니다.

0.1.7부터 워커 `run`은 실행 중에도 PyPI 최신 버전을 주기적으로 확인합니다. 배포 설치본에서 새 버전이 발견되면 업데이트 후 같은 명령으로 재시작합니다. 개발용 editable 설치는 자동 업데이트를 건너뜁니다.

## 설치

PyPI 배포 후에는 다음처럼 설치할 수 있습니다.

```bash
python -m pip install a2a-agent
```

개발 환경에서 소스 코드로 설치하려면 저장소 루트에서 실행합니다.

```bash
python -m venv .venv
source .venv/bin/activate
python -m pip install -e .
```

## 기본 사용

커맨더 설정을 만듭니다.

```bash
a2a-agent init --room team --device-name commander --broker-host <BROKER_HOST> --broker-port 1883 --no-tls
```

커맨더 실행 루프를 켭니다. 이 루프가 켜져 있어야 워커의 페어링 요청에 답할 수 있습니다.

```bash
a2a-agent run
```

다른 터미널에서 워커 6자리 페어링 코드를 발급합니다.

```bash
a2a-agent invite macbook-air
```

워커 기기에서는 코드만 입력해 참여합니다.

```bash
a2a-agent join ABC234
```

워커 실행 루프를 켭니다. 기본 실행기는 `echo`입니다.

```bash
A2A_EXECUTOR=echo a2a-agent run
```

자동 업데이트를 임시로 끄려면 `A2A_AUTO_UPDATE=0`을 붙입니다.

```bash
A2A_AUTO_UPDATE=0 A2A_EXECUTOR=echo a2a-agent run
```

워커의 실행 중 업데이트 확인 주기는 기본 3600초입니다. 필요하면 `A2A_UPDATE_INTERVAL_SECONDS`로 조정하고, `0`으로 두면 실행 중 감시만 끕니다.

```bash
A2A_UPDATE_INTERVAL_SECONDS=1800 A2A_EXECUTOR=echo a2a-agent run
```

커맨더에서 워커에게 작업을 보냅니다.

```bash
a2a-agent send macbook-air "ping-테스트"
```

커맨더는 사람용 별칭도 저장할 수 있습니다. 별칭은 커맨더 config에만 저장되고, 워커의 실제 기기명은 바꾸지 않습니다.

```bash
a2a-agent set-alias "회사 PC" windows-cursor
a2a-agent send "회사 PC" "ping-테스트"
```

## 원격 제어 태스크

0.2.6부터 커맨더는 워커의 AI 실행기를 거치지 않는 내장 제어 태스크를 보낼 수 있습니다. 기기 별칭도 그대로 사용할 수 있습니다.

```bash
a2a-agent control "데스크탑 PC" install-autostart
a2a-agent control "데스크탑 PC" uninstall-autostart
```

워커 코드는 위 두 이름만 고정 함수로 처리합니다. 다른 값은 `unsupported control` 실패 응답이 되며, 임의 셸 명령은 실행하지 않습니다. 등록 활성화나 제거가 끝나지 않아 수동 명령이 필요한 결과도 실패로 응답합니다. 응답 대기 시간은 일반 `send`와 같은 `A2A_SEND_TIMEOUT`을 사용합니다. 제어 명령을 보내기 전에 대상 워커도 0.2.6 이상인지 확인해야 합니다.

## 파일 첨부

커맨더는 작업에 파일을 첨부할 수 있습니다. 파일은 공유 저장소(Synology FileStation)에 업로드되고, MQTT 메시지에는 참조만 실립니다. 저장소 접속 정보는 `A2A_SHARE_*` 환경변수로 커맨더에 주입하고, 워커는 페어링 때 자동으로 전달받습니다.

```bash
a2a-agent send macbook-air "이 이미지 분석해줘" --file chart.png
```

워커는 첨부 파일을 내려받아 실행기에 전달하고, 결과 파일은 지정된 out 폴더에 저장하면 응답에 함께 첨부됩니다. 커맨더는 응답 파일을 자동으로 내려받습니다. `A2A_SHARE_*`가 없으면 파일 첨부만 비활성화되고 텍스트 통신은 그대로 동작합니다.

## 워커 실행기

- `echo`: 받은 텍스트를 그대로 회신합니다. 연결 확인용 기본값입니다.
- `opencode`: `opencode run -m opencode/big-pickle "<프롬프트>"`를 호출하고 표준출력을 회신합니다. 실패하거나 설치되어 있지 않으면 에러 메시지를 결과로 돌려보냅니다.
- `cursor`: `cursor-agent -p --yolo --trust "<프롬프트>"`를 호출하고 표준출력을 회신합니다. 느릴 수 있으므로 커맨더 송신 시 `A2A_SEND_TIMEOUT`을 늘릴 수 있습니다.
- `grok`: `grok --always-approve -p "<프롬프트>"`(일회용, `-c` 없음)를 호출하고 표준출력을 회신합니다.

실행기는 설정 파일의 `executor` 또는 환경변수 `A2A_EXECUTOR`로 선택합니다. 환경변수가 우선합니다.

## 토픽

페어링 토픽은 방과 무관한 전역 토픽입니다.

```text
a2a/_pairing/request
a2a/_pairing/reply/{code}
```

작업 토픽은 방과 워커 이름을 기준으로 나뉩니다.

```text
a2a/{room}/agents/{device}/card
a2a/{room}/agents/{device}/status
a2a/{room}/cmd/{device}/request
a2a/{room}/cmd/{device}/response
a2a/{room}/cmd/{device}/task-status
```

## 구조

```text
a2a-agent/
├── pyproject.toml
├── README.md
├── LICENSE
├── install/install.sh
├── scripts/live_broker_roundtrip.py
├── src/a2a_agent/
│   ├── cli.py
│   ├── client.py
│   ├── config.py
│   ├── executor.py
│   ├── invite.py
│   ├── pairing.py
│   ├── protocol.py
│   ├── runtime.py
│   ├── updater.py
│   └── topics.py
└── tests/
```

## 라이선스

MIT 라이선스를 따릅니다.
