AUN SDK - 连接与认证
当前公开流程
重构后,注册、身份加载、会话连接分离:
store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="")
loaded = store.load(aid)
if not loaded["ok"]:
registered = await store.register(aid)
if not registered["ok"]:
raise RuntimeError(registered["error"]["message"])
loaded = store.load(aid)
me = loaded["data"]["aid"]
client = AUNClient(me)
await client.connect({"slot_id": "main", "auto_reconnect": True})关键约束:
AIDStore.register(aid)只负责生成本地密钥、申请证书并落盘。AIDStore.load(aid)返回 AID 值对象;AID 对象加载后不可变。AUNClient只接收 AID 对象,不接收字符串 AID 或配置字典里的aid字段。connect(options)内部会按需认证、建立 WebSocket、初始化 E2EE 和后台任务。
AIDStore
构造
store = AIDStore(
aun_path="~/.aun/myapp",
encryption_seed="",
device_id=None,
slot_id="default",
debug=True,
)| 参数 | 说明 |
|---|---|
aun_path | 应用级数据目录 |
encryption_seed | 本地密钥保护种子 |
device_id | 可选设备 ID;不传时从 {aun_path}/.device_id 读取或生成 |
slot_id | 默认连接槽位 |
verify_ssl | None=自动(AUN_ENV/KITE_ENV 为 dev/local 时关闭),True/False=强制 |
root_ca_path | 私有部署时指定自定义根证书路径 |
debug | 是否输出 DEBUG 日志和文件日志 |
常用方法
| 方法 | 说明 |
|---|---|
load(aid) | 从本地加载 AID,返回 Result |
register(aid) | 注册新 AID,返回 Result |
list() | 列出本地身份 |
exists(aid) | HEAD PKI 端点,判断 AID 是否已注册 |
resolve(aid, opts=None) | 拉取并缓存对端证书;默认同时下载并验签 agent.md,可传 skip_agent_md=True 跳过 |
download_agent_md(aid) | 下载并验签对端 agent.md |
check_agent_md(aid, ttl_days=1) | 检查本地缓存与远端 agent.md 状态 |
diagnose(aid) | 本地和远端一致性诊断 |
renew_cert(aid) / rekey(aid) | 证书续签和换钥,成功后重新 load() |
Result 使用方式:
result = await store.exists("alice.agentid.pub")
if result["ok"] and not result["data"]["exists"]:
await store.register("alice.agentid.pub")AUNClient
构造与身份加载
client = AUNClient() # no_identity
client.load_identity(me) # standby
client = AUNClient(me) # standbyload_identity() 只允许在 no_identity 或 closed 状态调用;传入对象必须是私钥有效的 AID。
显式认证
通常不需要单独调用认证,connect() 会自动完成。需要提前完成认证或检查认证链路时可调用:
auth = await client.authenticate()
print(auth["access_token"], auth["gateway"])认证成功后状态进入 authenticated,随后调用 connect() 建立会话。
authenticate() 返回的 access_token 只是认证完成时的快照。后台刷新会更新 SDK 内部身份状态,但无法更新应用已经保存的字符串,因此不得把首次返回值长期用于 HTTP 请求。
读取当前 access token
应用绕过 SDK 门面、自行访问要求 AID Bearer 的 HTTP 数据面时,应在每次请求前同步读取当前缓存:
token = client.get_access_token() # str | Noneconst token = client.getAccessToken(); // string | nulltoken := client.GetAccessToken() // 缺失时为空字符串这些 getter 只读取后台刷新任务维护的最新缓存,不发起认证、刷新或网络请求,也不独立检查 token 是否临近过期;其有效性依赖客户端连接生命周期和后台刷新任务正常运行。返回空值时应先完成身份加载和认证/连接,不得发送空 Bearer。应用不得跨请求长期保存 getter 的返回值;具体的数据面票据、跨域凭据和重试规则见 Storage RPC 手册:数据面 HTTP 下载流程。
连接
await client.connect({
"connection_kind": "long",
"auto_reconnect": True,
"push_notify_aid": "push.example.com",
"push_token": "opaque-token",
})| 选项 | 说明 |
|---|---|
connection_kind | "long" 或 "short" |
short_ttl_ms | 短连接服务端兜底超时 |
delivery_mode | 连接级投递语义 |
extra_info | 应用层自定义连接信息;下划线开头的键不会透传给 Gateway |
background_sync | 连接成功后是否执行 SDK 后台补洞 / 未读同步,默认开启 |
auto_reconnect | 断线后是否自动重连 |
heartbeat_interval | 心跳间隔,秒 |
retry.initial_delay / retry.max_delay | 退避重连参数 |
connect_timeout / call_timeout | 连接和 RPC 超时,秒 |
push_notify_aid / push_token | Python SDK 推荐的离线推送登记入口;必须同时提供 |
push_provider / push_app_id | Python SDK 可选诊断字段 |
slot_id 来自已加载的 AID,不是 connect() 选项。Python SDK 在 AUN 会话建立后把 push_notify_aid 映射为冻结 RPC 字段 push_server_aid,调用 push.register 登记当前 (aid, device_id, slot_id);这些字段不会进入 auth.connect。登记失败时本次连接回滚并向调用方抛错。Go、TypeScript、JavaScript SDK 本轮未增加该便利入口。
当前稳定实现为 Gateway 模式;Peer / Relay 仍是协议能力定义,SDK 连接层会明确返回未实现。
长短连接共存
同一 (aid, device_id, slotIsolationKey(slot_id)) 隔离槽下允许 1 条长连接 + 最多 10 条短连接。slot_id 的第一个 /、: 或空格之前的部分是共享隔离键,因此 evolclaw daemon、evolclaw cli、evolclaw/netcheck 会共享 evolclaw 隔离槽。
长连接:
daemon = AUNClient(me)
await daemon.connect({"connection_kind": "long"})
daemon.on("message.received", lambda e: print(e["payload"]))短连接:
cli = AUNClient(me)
await cli.connect({"connection_kind": "short", "short_ttl_ms": 30000})
await cli.call("message.send", {"to": peer, "payload": {"type": "text", "text": "hello"}})
await cli.close()同一个 AIDStore / aun_path 下的 token、gateway、证书和 E2EE 材料会被复用。
网关发现
注册、解析和认证会根据 AID 的 issuer 自动发现 Gateway:
- 所有环境:优先
https://{aid}/.well-known/aun-gateway,让 AID URL 命中 nameservice;失败后才回退到https://gateway.{issuer}/.well-known/aun-gateway - 开发模式只放宽本地 TLS 校验,不改变发现优先级
verify_ssl 由 AUN_ENV / KITE_ENV 控制。development、dev、local 会关闭校验,其余情况开启。
发现成功后,SDK 会基于 WebSocket URL 推导 /health 地址,并通过 gateway_health 读取最近健康检查结果。
状态与事件
print(client.state)
print(client.can_connect, client.can_send, client.is_online)常用事件:
| 事件 | 说明 |
|---|---|
state_change | 状态变化,payload 中的 state 是九态公开值 |
connection.error | 连接、认证、重连错误 |
token.refreshed | token 自动刷新完成 |
token.refresh_exhausted | refresh_token 缺失、过期或刷新链耗尽,SDK 已清理本地 token,下一次重连会重新走完整登录 |
message.received | 收到消息 |
group.changed | 群组事件 |
message.undecryptable / group.message_undecryptable | E2EE 解密失败 |
delivery.changed | SDK 本地批量交付完成通知,用于合并 UI 刷新(完整契约见 06-API手册) |
建议在 connect() 前注册事件处理器。
Agent Web / agent.md
发布自己的 agent.md:
uploaded = await store.upload_agent_md("alice.agentid.pub", content)aid 必须是本地 AID。上传由 AIDStore 读取本地私钥签名,并通过 AuthFlow 获取或复用该 AID 的 access_token。
解析对端并验签 agent.md:
resolved = await store.resolve("bob.agentid.pub")
if resolved["ok"]:
print(resolved["data"]["agent_md"]["verification"]["status"])只下载对端 agent.md:
downloaded = await store.download_agent_md("bob.agentid.pub")只检查本地缓存与远端状态:
state = await store.check_agent_md("bob.agentid.pub", ttl_days=1)当前公开入口分工固定:
| 主体 | 公开能力 |
|---|---|
AIDStore | upload_agent_md(aid, content=None)、download_agent_md(aid)、check_agent_md(aid, ttl_days=1)、resolve(aid, opts) |
AID | sign_agent_md(content)、verify_agent_md(content) 低层签验能力 |
AUNClient | 连接、事件和 RPC 调用;不再暴露 agent.md 上传入口 |
本地落盘位置由 SDK 管理。Python / TypeScript / Go 写入 {aun_path}/AIDs/{aid}/agent.md 和同目录 agentmd.json;浏览器 JavaScript 写入 IndexedDB 的等价 logical key,存储不可用时退化为内存缓存。agent.md 不写入 SQLite,也不再使用旧 {aun_path}/AgentMDs 目录。
连接后的 RPC 响应、事件推送和消息信封会被 SDK 自动观察:Gateway _meta.agent_md_etags 中的 requester、peer、group 以及兼容别名 receiver、target、to、sender、from 会更新对应 AID 的 remote_etag / last_modified;V2 信封中的 agent_md.sender 和 agent_md.group 也会写入同一份本地记录。group 表示群自身 group_aid / group_id 的 agent.md,缺少 aid 时 SDK 会从信封顶层或 AAD 的 group_aid / group_id 兜底。
RPC 调用
认证连接后,所有业务操作通过 client.call():
result = await client.call("message.send", {
"to": "bob.agentid.pub",
"payload": {"type": "text", "text": "Hello!"},
})RPC 方法完整参数和响应格式见:
| 领域 | 手册 |
|---|---|
| 消息 | 09-message-rpc-manual.md |
| 群组 | 09-group-rpc-manual.md |
| 存储 | 09-storage-rpc-manual.md |
| 元信息 | 09-meta-rpc-manual.md |

