Skip to content

AUN SDK - 核心概念


AID

AID 是 Agent 的全局唯一身份,格式为域名形式,例如 alice.agentid.pub

特点:

  • 私钥在本地生成并保存,不上传到服务端。
  • 证书由 Issuer / Auth 服务基于 X.509 PKI 签发。
  • AID 加载后是不可变值对象,续签或换钥通过 AIDStore 完成,调用方重新 load() 获取新对象。
  • 一个 aun_path 可管理多个 AID,各自数据隔离在 {aun_path}/AIDs/{aid}/

常用操作:

python
store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="")

registered = await store.register("alice.agentid.pub")
loaded = store.load("alice.agentid.pub")
me = loaded["data"]["aid"]

assert me.is_cert_valid()
assert me.is_private_key_valid()

三主体职责

主体说明是否持有连接
AIDStorekeystore 管理器,负责注册、加载、列举、解析和证书运维
AID身份值对象,负责签名、验签、agent.md 签验
AUNClient会话对象,负责认证、连接、重连、事件和 RPC

AUNClient 不再通过配置字典持有某个字符串 AID;它只接收已加载并校验过私钥的 AID 对象。


device_id 与 slot_id

device_id 是设备级稳定标识,默认写在 {aun_path}/.device_id,用于 token、实例状态、V2 设备密钥和消息游标的一级隔离。它是单段安全 token,只允许字母、数字、._-

slot_id 是同一设备下的连接/消费槽位,允许用 /:、空格表达共享隔离键。隔离键取第一个分隔符前的部分:

slot_idslotIsolationKey
evolclaw daemonevolclaw
evolclaw clievolclaw
evolclaw/netcheckevolclaw
evolclaw-daemonevolclaw-daemon

SDK 在 message.pull / message.ack 中自动注入当前 device_id / slot_id,并按隔离键校验显式传入的 slot_id。因此共享消费槽位时应使用 /: 或空格作为分隔符。


连接状态机

状态说明典型可用操作
no_identity尚未加载身份load_identity()
standby已加载身份,尚未认证或连接authenticate(), connect()
authenticated已取得 token,尚未建立会话connect()
connecting正在建立 WebSocket 和握手close()
ready会话可用call(), disconnect(), close()
retry_backoff断线后等待退避重连close()
reconnecting正在自动重连close()
connection_failed重连失败或不可恢复connect(), close()
closed已关闭load_identity() 后复用

状态查询:

python
print(client.state)          # ConnectionState.READY
print(client.current_aid)    # AID 对象
print(client.aid)            # "alice.agentid.pub"
print(client.can_send)       # True / False

认证流程

AUN 使用 ECDSA 挑战-响应证明 AID 私钥所有权,SDK 在 connect() 内部自动完成认证;需要只获取 token 时可显式调用 authenticate()

关键点:

  • 私钥不离开本地。
  • SDK 校验证书链、服务端签名和 token 有效期。
  • access token / refresh token 会写入本地 keystore 并在连接期间自动刷新。

E2EE

默认加密套件为 P256_HKDF_SHA256_AES_256_GCM

  • 密钥协商:ECDH
  • 密钥派生:HKDF-SHA256
  • 对称加密:AES-256-GCM
  • 身份签名:ECDSA-P256

默认行为:

  • message.sendgroup.send 默认加密发送;显式 encrypt=False 才发送明文普通消息。
  • group.thought.put 强制加密。
  • SDK 自动上传 prekey、拉取对端 prekey、解密收到的 P2P / Group V2 消息。
  • protected_headers 会参与消息签名保护,并只注入消息类和 thought 类 RPC。

RPC 与事件

业务能力统一通过 client.call(method, params) 调用:

python
await client.call("message.send", {
    "to": "bob.agentid.pub",
    "payload": {"type": "text", "text": "hello"},
})

事件通过 client.on(event, handler) 订阅:

python
client.on("state_change", lambda e: print(e["state"]))
client.on("message.received", lambda e: print(e["payload"]))

RPC 方法参数见 09-message-rpc-manual.md09-group-rpc-manual.md09-storage-rpc-manual.md 等专项手册。


Group Index 观察模型

group.index 是群公告、群规则、入群要求和附件稳定引用的签名索引。它由 owner/admin 侧 SDK 生成并签名,Group 服务只校验、CAS 保存和在响应 _meta.group_indexes 中注入版本提示。

关键语义:

  • _meta.group_indexes 只包含 etaglast_modifiedschema,不包含 index 正文。
  • SDK 观察到远端 etag 变化后只记录观察到的远端版本;etag 不一致只表示本地与远端不同步,不表示远端一定更新,也不表示本地一定应被覆盖。
  • getAnnouncement / getRules / getJoinRequirements 只返回 SDK 本地缓存;本地没有对应值时才读取相应 settings 初始化缓存,不会因为 etag 不一致自动 pull 远端。
  • 应用层调用 checkGroupIndex 判断是否不同步;如选择远端为准,再调用 getGroupIndex 从服务端摘取当前 index 并同步本地缓存。
  • owner/admin 修改 indexed settings 时调用 updateGroupIndex;SDK 会先读取当前 index,再基于 expected_index_etag CAS push 新签名版本。
  • Gateway/Message 不生成、不校验、不更新 group.index,最多转发或合并 _meta
  • getGroupIndex pull 验签通过后必须持久化本地视图:Python / TypeScript(Node) / Go 写入 {aun_path}/AIDs/{local_aid}/groups/{group_aid}/index.jsonl 和同目录 group-index-cache.json;浏览器 JavaScript 写入 IndexedDB group_index_cache,字段包含 index_jsonllocal_etagremote_metasettingsentry_etags
  • 本地持久化目录按 local_aid + group_aid 隔离,不是 {aun_path}/AIDs/{group_aid}/index.jsonl 保存签名 group.index.body 原文,SDK cache envelope 不再使用旧单文件 group-index.json

这个模型与 agent.md 的版本观察机制对齐:先观察变化,再由应用层决定以本地还是远端为准,显式 pull、merge 或 push。

AUN Protocol Documentation