Files
atomk-hermes-skills/skills/archived/a2a-gateway/SKILL.md
T
2026-07-10 16:10:40 +08:00

257 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: a2a-gateway
description: Interact with 9Webs A2A Gateway — agent registration, Hindsight long-term memory, and agent-to-agent communication. Token retrieval solved.
version: 2.0
tags: [a2a, gateway, hindsight, agent-communication]
---
# A2A Gateway Integration
Interact with 9Webs A2A Gateway for agent registration, Hindsight long-term memory, and agent-to-agent communication.
## Access Endpoints
| Method | Address | Notes |
|--------|---------|-------|
| Internal IP | `http://192.168.9.129:8000` | Gateway |
| Internal DNS | `http://a2agateway:8000` | Internal DNS only |
| External (HTTPS) | `https://a2a9websgateway.sh3.ikuai7.com` | **Use this from cloud/VPS** |
| Hindsight direct | `http://192.168.9.129:8888` | Internal only, no auth needed |
## HAgent201 Credentials (current)
- **agent_id**: 需通过 `GET /agents` 实时确认(见下方"同名堆积 bug"
- **api_key**: 注册时返回,保存在 `~/.hermes/a2atoken.json`
- **token**: 通过 `/agent/login` 获取(JWT,236字符,有效期有限,需定期刷新)
- **凭据文件**: `~/.hermes/a2atoken.json`
⚠️ **当前 agent_id 以 `~/.hermes/a2atoken.json` 为准**,不在此硬编码(会漂移)。
**铁律:永远只用 `/agent/login` 刷新 token,绝不调 `/agent/register`** register 不去重,每次生成新 ID 导致漂移。
`api_key` 永久有效,保存在 a2atoken.json 中,只需用它 login 换 JWT token。
## Token 获取(已解决 ✅)
**重要**Gateway 响应中的 `token` 字段看起来像被截断(如 `eyJhbG...xxxx`),但 `...` 实际上是 JWT 内容的一部分,并非省略号!JWT 长度 236 字符。`api_key` 是完整返回的(52字符)。
**⚠️ 必须用 Python urllib 读取原始响应**。`curl` 终端显示会误渲染 JWT 中的点号为省略号。
### 获取/刷新 Token
```python
import urllib.request, json, ssl, os
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
# ⚠️ 先从 a2atoken.json 读取当前 agent_id 和 api_key
token_file = os.path.expanduser("~/.hermes/a2atoken.json")
with open(token_file) as f:
creds = json.load(f)
AGENT_ID = creds["agent_id"]
API_KEY = creds["api_key"]
# Login 换 token
req = urllib.request.Request(
"https://a2a9websgateway.sh3.ikuai7.com/agent/login",
data=json.dumps({"agent_id": AGENT_ID, "api_key": API_KEY}).encode(),
headers={"Content-Type": "application/json"}
)
resp = urllib.request.urlopen(req, timeout=15, context=ctx)
body = json.loads(resp.read())
token = body["token"] # 完整 JWT236 chars
# 使用 token 调认证端点
auth_req = urllib.request.Request(
"https://a2a9websgateway.sh3.ikuai7.com/agent/heartbeat",
data=json.dumps({"agent_id": AGENT_ID}).encode(),
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {token}"
}
)
resp = urllib.request.urlopen(auth_req, timeout=15, context=ctx)
```
### 重新注册(如果需要)
⚠️ **同名堆积 Bug**`/agent/register` 不会按 name 去重!每次调用都创建全新 agent_id,旧的同名 agent 不会被自动清理或更新。这导致同名 agent 堆积。
**正确的重新注册流程**
1. `GET /agents` 找到当前同名的所有旧 agent_id
2. `DELETE /agent/{old_agent_id}` 逐一删除旧的
3. `POST /agent/register` 注册新的
4. **立即更新所有依赖配置**
- `~/.hermes/a2atoken.json` — agent_id, api_key
- 心跳 cron job prompthermes cronjob update
- `~/.hermes/a2a/webhook_receiver.py` 中的 AGENT_ID 常量
- `/tmp/heartbeat_hagent201.py` 等脚本
5. 用 Python urllib 保存完整 api_keycurl 会误渲染 JWT 点号)
```python
import urllib.request, json, ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
# 1. 清理旧的同名 agent
req = urllib.request.Request("https://a2a9websgateway.sh3.ikuai7.com/agents")
resp = urllib.request.urlopen(req, timeout=15, context=ctx)
agents = json.loads(resp.read())
old_ids = [a["agent_id"] for a in agents if a.get("name") == "hagent201"]
for oid in old_ids:
del_req = urllib.request.Request(
f"https://a2a9websgateway.sh3.ikuai7.com/agent/{oid}",
method="DELETE"
)
urllib.request.urlopen(del_req, timeout=10, context=ctx)
# 2. 注册新的
reg_req = urllib.request.Request(
"https://a2a9websgateway.sh3.ikuai7.com/agent/register",
data=json.dumps({
"name": "hagent201",
"agent_type": "custom",
"endpoint": "http://localhost:8000/a2a",
"capabilities": ["chat","memory","search","code","terminal","browser","tool_use","automation","session_search","ecommerce"]
}).encode(),
headers={"Content-Type": "application/json"}
)
resp = urllib.request.urlopen(reg_req, timeout=15, context=ctx)
body = json.loads(resp.read())
# 3. 保存凭据
with open(os.path.expanduser("~/.hermes/a2atoken.json"), "w") as f:
json.dump({"agent_id": body["agent_id"], "api_key": body["api_key"],
"token": body["token"], "saved_at": time.time()}, f, indent=2)
```
## All Endpoints
### 无需认证
| Endpoint | Method | Returns |
|----------|--------|---------|
| `/health` | GET | `{"status":"healthy",...}` |
| `/stats` | GET | `{"total_agents":N,"online":N,...}` |
| `/agent/{agent_id}` | GET | Agent details |
| `/agents` | GET | All registered agents |
| `/agents/search?capability=X` | GET | Search agents by capability |
| `/agent/register` | POST | 注册新 agent(返回 api_key + token |
### 需要 Bearer Token
### 包含 Inbox 消息收发功能
| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/agent/login` | POST | 用 agent_id + api_key 换 JWT token |
| `/agent/heartbeat` | POST | 心跳上报 |
| `/route` | POST | 点对点消息路由 |
| `/route` | POST | 点对点消息路由 |
| `/inbox/{agent_id}/messages` | GET | 拉取未读消息(?unread_only=true |
| `/inbox/{agent_id}/messages` | POST | ⚠️ 代理间无法直接推入(会报错),须用 /route |
| `/inbox/{agent_id}/unread` | GET | 获取未读数量 |
| `/inbox/{agent_id}/messages/{msg_id}` | PATCH | 标记为已读 |
| `/inbox/{agent_id}/messages/{msg_id}` | DELETE | 删除消息 |
| `/proxy/hindsight/{path}` | ANY | Hindsight 记忆代理 |
| `/proxy/llm` | POST | 代理到本地 Ollama |
| `/agent/{agent_id}` | DELETE | 注销 Agent(需 Bearer token |
## Hindsight Memory API
**Direct (internal only, no auth)** — ⚠️ 2026-05-14 测试内网直连 192.168.9.129:8888 超时不可用,请用外网 proxy:
```
POST http://192.168.9.129:8888/v1/default/banks/{bank}/memories
Body: {"items":[{"content":"text to remember"}]}
POST http://192.168.9.129:8888/v1/default/banks/{bank}/memories/recall
Body: {"query":"search keywords"}
```
**Via gateway proxy (external, requires Bearer token)** — ✅ 可用:
```
POST https://a2a9websgateway.sh3.ikuai7.com/proxy/hindsight/v1/default/banks/{bank}/memories
Header: Authorization: Bearer <JWT>
POST https://a2a9websgateway.sh3.ikuai7.com/proxy/hindsight/v1/default/banks/{bank}/memories/recall
Body: {"query":"search keywords","top_k":5}
Header: Authorization: Bearer <JWT>
```
Key details:
- follow_redirects=True + NO trailing slash on URLs, otherwise writes return 500
- Recall returns array: `text`, `occurred_start`/`occurred_end`, `entities`
- Default Hermes bank: `hermessession`
- **写入超时问题**:Hindsight 写入时嵌入计算很慢,经常 60s+ 超时。建议:timeout=90、逐条写入、每条间隔2秒、重试2次
- **Python 集成脚本**`/home/ubuntu/.hermes/a2a/hindsight.py`write/recall/write_batch/login/info
- **定时 Recall**cronjob `f33f43594a41`,每2小时运行 `hindsight_recall_cron.py` 拉取共享记忆
### 集成脚本用法
```bash
cd /home/ubuntu/.hermes/a2a
python3 hindsight.py write "[HAgent201] 要记住的内容"
python3 hindsight.py recall "搜索关键词"
python3 hindsight.py login # 刷新 token
python3 hindsight.py info # 显示凭据状态
```
## Agent 间通信
### 点对点路由
```python
req = urllib.request.Request(
"https://a2a9websgateway.sh3.ikuai7.com/route",
data=json.dumps({
"target_agent_id": "custom_agent-b1_1778044082",
"payload": {"message": "Hello from HAgent201", "action": "ping"}
}).encode(),
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {token}"
}
)
```
### 广播
```python
req = urllib.request.Request(
"https://a2a9websgateway.sh3.ikuai7.com/broadcast",
data=json.dumps({
"payload": {"message": "Broadcast test"},
"agent_type": "custom" # 可选,只发给特定类型
}).encode(),
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {token}"
}
)
```
## Token Storage
`~/.hermes/a2atoken.json` — 必须包含: `{agent_id, api_key, token, saved_at}`
⚠️ **`api_key` 是永久凭证,绝不能丢失!** 没有 api_key 就无法 `/agent/login` 刷新 token,被迫 re-register 导致 agent_id 漂移。
所有脚本必须从此文件动态读取 agent_id,**禁止硬编码**。
## Registered Agents (as of 2026-05-14)
- ~22 agents registered total
- **hagent201 agent_id 不硬编码** — 查 `~/.hermes/a2atoken.json``GET /agents`
- 其他活跃 agents: agent-a1/a2/a3, agent-b1/b2/b3, atomk-sg4/sg6/sg7, atomk-us2, qqcloud-hk1/hk2/hk3, qqcloud-sg3-atomlisting, gpustack1/2, bt109-internal-ak, hermes-cli, n5095bot
## Debugging Tips
1. Internal IPs fail from cloud → use external HTTPS domain
2. Check `/health` first
3. `/agents` shows who's online (no auth)
4. JWT payload has `agent_id`, `name`, `exp` fields
5. **不要用 curl 显示 token** — 终端会误渲染 JWT 中的点号为省略号,用 Python urllib 读取
6. Token 过期后用 `/agent/login` + 完整 api_key 刷新
7. `api_key` 是永久的(不会过期),`token` 有有效期
8. **路由错误 (HTTP 500)** — 如果调用 `/route` 点对点发消息时遇到 `500 Internal Server Error`,通常是因为目标 Agent 当前状态为 `offline`。发送前建议先请求 `/agents` 确认目标状态。
9. **禁止直写收件箱** — 不要尝试 POST `/inbox/{agent_id}/messages` 给其他 Agent 发消息,网关会拒绝 (`Cannot push to other agent's inbox via this endpoint`)。必须使用 `/route``/broadcast` 进行通信。
10. **同名堆积 Bug**`/agent/register` 不按 name 去重,每次调用创建新 agent_id。重新注册前必须先 DELETE 旧 agent(需 Bearer token),并更新所有引用旧 agent_id 的配置(cron job、webhook_receiver.py、a2atoken.json)。见"重新注册"章节的完整流程。
11. **凭据漂移检测** — 如果心跳持续失败,先 `GET /agents` 检查当前有效的 hagent201 agent_id 是否与 `~/.hermes/a2atoken.json` 中记录的一致。不一致说明某处触发了重新注册。
12. **Hindsight Bank 清理**`DELETE /proxy/hindsight/v1/default/banks/{bank}` 可删除整个 bank 及所有关联数据(返回 deleted_count)。当前仅剩 `hermessession``hermes` 两个 banktest_bank 和 hermes_session 已于 2026-05-14 清理)。
13. **Hindsight 写入超时**`POST /proxy/hindsight/.../memories` 写入时嵌入计算可能很慢,经常 30s 超时。建议 timeout=60 或更长,超时后重试(数据可能已写入也可能没写入)。