Files
2026-07-10 16:10:40 +08:00

11 KiB
Raw Permalink Blame History

name, description, version, tags
name description version tags
a2a-gateway Interact with 9Webs A2A Gateway — agent registration, Hindsight long-term memory, and agent-to-agent communication. Token retrieval solved. 2.0
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

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 点号)
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.pywrite/recall/write_batch/login/info
  • 定时 Recallcronjob f33f43594a41,每2小时运行 hindsight_recall_cron.py 拉取共享记忆

集成脚本用法

cd /home/ubuntu/.hermes/a2a
python3 hindsight.py write "[HAgent201] 要记住的内容"
python3 hindsight.py recall "搜索关键词"
python3 hindsight.py login    # 刷新 token
python3 hindsight.py info     # 显示凭据状态

Agent 间通信

点对点路由

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}"
    }
)

广播

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.jsonGET /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)。当前仅剩 hermessessionhermes 两个 banktest_bank 和 hermes_session 已于 2026-05-14 清理)。
  13. Hindsight 写入超时POST /proxy/hindsight/.../memories 写入时嵌入计算可能很慢,经常 30s 超时。建议 timeout=60 或更长,超时后重试(数据可能已写入也可能没写入)。