@agentunion/fastaun 0.5.32 → 0.5.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +28 -26
  3. package/_packed_docs/CHANGELOG.md +58 -0
  4. package/_packed_docs/INDEX.md +17 -3
  5. package/_packed_docs/KITE_DOCS_GUIDE.md +10 -4
  6. package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +58 -8
  7. package/_packed_docs/sdk/0.5.33-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +464 -0
  8. package/_packed_docs/sdk/0.5.33-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +499 -0
  9. package/_packed_docs/sdk/0.5.34-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +133 -0
  10. package/_packed_docs/sdk/0.5.34-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +107 -0
  11. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +16 -13
  12. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +13 -1
  13. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +17 -7
  14. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +55 -14
  15. package/_packed_docs/sdk/09-collab-rpc-manual.md +48 -30
  16. package/_packed_docs/sdk/09-custody-api-manual.md +3 -3
  17. package/_packed_docs/sdk/09-group-rpc-manual.md +53 -6
  18. package/_packed_docs/sdk/09-message-rpc-manual.md +22 -0
  19. package/_packed_docs/sdk/09-meta-rpc-manual.md +2 -1
  20. package/_packed_docs/sdk/09-payload-reference.md +9 -8
  21. package/_packed_docs/sdk/09-proxy-rpc-manual.md +20 -14
  22. package/_packed_docs/sdk/09-storage-rpc-manual.md +1698 -1642
  23. package/_packed_docs/sdk/09-stream-rpc-manual.md +33 -20
  24. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +11 -9
  25. package/_packed_docs/sdk/AUN/344/272/213/344/273/266/345/217/221/345/270/203/350/256/242/351/230/205/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +53 -28
  26. package/_packed_docs/sdk/AUN/344/272/213/344/273/266/345/217/221/345/270/203/350/256/242/351/230/205/345/274/200/345/217/221/347/247/273/346/244/215/346/214/207/345/215/227.md +62 -28
  27. package/_packed_docs/sdk/INDEX.md +21 -9
  28. package/_packed_docs/sdk/README.md +11 -6
  29. package/dist/agent-md.d.ts +2 -1
  30. package/dist/agent-md.js +17 -0
  31. package/dist/agent-md.js.map +1 -1
  32. package/dist/auth.js +8 -2
  33. package/dist/auth.js.map +1 -1
  34. package/dist/client/control-messages.js +4 -4
  35. package/dist/client/control-messages.js.map +1 -1
  36. package/dist/client/delivery.d.ts +5 -0
  37. package/dist/client/delivery.js +146 -32
  38. package/dist/client/delivery.js.map +1 -1
  39. package/dist/client/lifecycle.js +3 -0
  40. package/dist/client/lifecycle.js.map +1 -1
  41. package/dist/client/rpc-budget.d.ts +21 -0
  42. package/dist/client/rpc-budget.js +82 -0
  43. package/dist/client/rpc-budget.js.map +1 -0
  44. package/dist/client/rpc-pipeline.d.ts +3 -0
  45. package/dist/client/rpc-pipeline.js +193 -65
  46. package/dist/client/rpc-pipeline.js.map +1 -1
  47. package/dist/client/sync-channels.d.ts +89 -0
  48. package/dist/client/sync-channels.js +489 -0
  49. package/dist/client/sync-channels.js.map +1 -0
  50. package/dist/client/v2-e2ee.d.ts +4 -1
  51. package/dist/client/v2-e2ee.js +401 -298
  52. package/dist/client/v2-e2ee.js.map +1 -1
  53. package/dist/client.d.ts +9 -4
  54. package/dist/client.js +125 -15
  55. package/dist/client.js.map +1 -1
  56. package/dist/index.d.ts +2 -2
  57. package/dist/index.js.map +1 -1
  58. package/dist/ownership-workflow.d.ts +23 -3
  59. package/dist/ownership-workflow.js +36 -13
  60. package/dist/ownership-workflow.js.map +1 -1
  61. package/dist/pubsub/binding.js +14 -1
  62. package/dist/pubsub/binding.js.map +1 -1
  63. package/dist/pubsub/channel.d.ts +4 -0
  64. package/dist/pubsub/channel.js +26 -0
  65. package/dist/pubsub/channel.js.map +1 -1
  66. package/dist/pubsub/client.d.ts +9 -0
  67. package/dist/pubsub/client.js +154 -31
  68. package/dist/pubsub/client.js.map +1 -1
  69. package/dist/pubsub/credentials.d.ts +3 -0
  70. package/dist/pubsub/credentials.js +57 -20
  71. package/dist/pubsub/credentials.js.map +1 -1
  72. package/dist/pubsub/index.d.ts +3 -0
  73. package/dist/pubsub/index.js +69 -53
  74. package/dist/pubsub/index.js.map +1 -1
  75. package/dist/pubsub/service.d.ts +3 -0
  76. package/dist/pubsub/service.js +167 -12
  77. package/dist/pubsub/service.js.map +1 -1
  78. package/dist/pubsub/types.d.ts +2 -0
  79. package/dist/storage/lowlevel.d.ts +7 -3
  80. package/dist/storage/lowlevel.js +15 -0
  81. package/dist/storage/lowlevel.js.map +1 -1
  82. package/dist/storage/read-cache.js +12 -0
  83. package/dist/storage/read-cache.js.map +1 -1
  84. package/dist/storage/types.d.ts +10 -0
  85. package/dist/storage/types.js.map +1 -1
  86. package/dist/storage/vfs.d.ts +7 -3
  87. package/dist/storage/vfs.js +2 -2
  88. package/dist/storage/vfs.js.map +1 -1
  89. package/dist/tools/cross-sdk-agent.d.ts +62 -6
  90. package/dist/tools/cross-sdk-agent.js +169 -37
  91. package/dist/tools/cross-sdk-agent.js.map +1 -1
  92. package/dist/transport.d.ts +12 -0
  93. package/dist/transport.js +91 -6
  94. package/dist/transport.js.map +1 -1
  95. package/dist/version.d.ts +1 -1
  96. package/dist/version.js +1 -1
  97. package/package.json +1 -1
@@ -0,0 +1,107 @@
1
+ # AUN SDK 0.5.34 开发与移植指南
2
+
3
+ 本文只定义相对已发布 `0.5.33` 的四端实现增量。控制消息、Ownership、基础 Storage/VFS、E2EE、消息游标和原有 EventService wire 请先阅读 [0.5.33 开发与移植指南](0.5.33-SDK开发与移植指南.md) 及 [RPC 手册](09-message-rpc-manual.md)。实现级差异见 [parity 0.5.34](../../python/CHANGES_FOR_PARITY.md#v0534),应用接线见 [0.5.34 应用集成指南](0.5.34-SDK应用集成指南.md)。
4
+
5
+ 本指南描述工作区源码和现有测试契约,不表示服务端部署、Ubuntu Docker、浏览器 live E2E 或跨域 E2E 已全部通过。
6
+
7
+ ## 1. 0.5.34 增量范围
8
+
9
+ | 范围 | SDK 共同责任 | 配套服务责任 |
10
+ | --- | --- | --- |
11
+ | EventService 多角色 | `(bus_aid, role)` 独立绑定、授权、恢复和查询 | Message 仅维护 Bus 实例租约和投递 |
12
+ | 本地持久化 | SQLite/IndexedDB 保存目录、订阅意图、授权材料和待发布 outbox | 服务端继续维护事件接收和历史边界 |
13
+ | Storage 条件 ACL | VFS、LowLevel、RPC 字段一致透传和定向失效 | Storage/NS 负责条件判权、名片回源和计次 |
14
+ | Group FS / Proxy | 门面参数、上传 headers、隧道请求头和错误映射一致 | Group、Storage、Gateway、proxy-server 提供对应 RPC |
15
+ | 弹性补拉 | 主辅生命周期、策略代际、持久/volatile 分流和消费背压 | Gateway 授权/回收;Message/Group 分页和游标 |
16
+ | Python 专项 | 限流等待和容量压测工具 | 保持现有服务接口 |
17
+
18
+ ## 2. EventService 多角色共同契约
19
+
20
+ 同一 SDK 身份在同一 Bus 按 `(bus_aid, role)` 保存 `bus`、`pub`、`sub` 三类状态。Bus 启动仍要求 `bus_aid == client.aid`;Pub/Sub 必须分别完成授权。移植实现不能再以单个 AID 已承担其它角色为冲突条件。
21
+
22
+ 公开查询入口为 `publications` 和 `subscriptions`:
23
+
24
+ | 查询 | 返回内容 |
25
+ | --- | --- |
26
+ | `publications` | `publisher_aid`、`event_name`、`published`、`first_published_at`、`last_published_at` 汇总 |
27
+ | `subscriptions` | 当前有效的 `subscriber_aid`、`event_name`、`device_id`、`slot_id`、`expires_at` |
28
+
29
+ 两者支持事件过滤、`limit`、`page_token`;分页 token 绑定运行实例、查询范围和操作,Bus 重启后失效。发布查询不保存消息正文或逐消息 `event_id`;订阅查询只返回当前生效的关系,不能把授权目录当作订阅。
30
+
31
+ ## 3. SQLite/IndexedDB 状态与 durable outbox
32
+
33
+ Python、Node.js TypeScript 和 Go 默认使用当前 AID 的 SQLite metadata;浏览器 JavaScript 使用 IndexedDB。实现必须按 AID、Bus、角色、device 和 slot 隔离状态,并支持显式状态路径或适配器覆盖。
34
+
35
+ 状态恢复顺序固定为:
36
+
37
+ 1. 打开本地数据库并加载旧目录、授权材料、订阅意图和待发布记录。
38
+ 2. 复核当前身份、凭证、租约和事件范围;复核失败时保留记录等待重新授权。
39
+ 3. 将新注册、授权和订阅按事件名增量合并;缺省条目不能清空旧状态。
40
+ 4. 恢复有效订阅和未完成发布到内存队列。
41
+
42
+ 发布队列必须遵守“持久化正文及原 `event_id`/`expires_at` → 确认入队 → 后台发送 → 达到所选 `reply_mode` 成功阶段 → 删除正文”。关闭、发送失败、结果未知或删除失败时保留正文;成功后只保留有界结果摘要。TTL 过期的记录写入 `EXPIRED`,不再发送、不延长 TTL、不生成新 ID。
43
+
44
+ | SDK | 默认后端 | 恢复入口 |
45
+ | --- | --- | --- |
46
+ | Python | 当前 AID SQLite metadata | `start`/`authorize` 后恢复目录、订阅和 pending publish |
47
+ | TypeScript | Node SQLite 状态适配器 | `start`/`authorize` 后恢复角色状态 |
48
+ | JavaScript | IndexedDB 状态适配器 | 重新连接并授权后恢复 |
49
+ | Go | 当前 AID SQLite instance state | `Start`/`Authorize` 后恢复,`StatePath` 可覆盖 |
50
+
51
+ Bus 已受理后的 fanout、Message 的 volatile 收件箱、目标投递和事件历史不属于 SDK durable outbox;实现不得把这些运行时状态写入发布队列恢复账本。
52
+
53
+ ## 4. Storage、Group FS 与 Service Proxy wire
54
+
55
+ ### 4.1 条件 ACL
56
+
57
+ 四端统一透传以下主体结构:
58
+
59
+ - `subject.ownership.owner_aid` 和可选 `scope`(`direct` 或 `descendants`)匹配当前 Ownership 关系。
60
+ - `subject.card.type` 和 `exttype` 匹配可信 `agent.md` 名片;跨属性 AND,同属性数组 OR。
61
+ - `grantee_aids` 支持多 AID,`grantee_aid` 保留兼容;VFS、LowLevel 和 RPC 不得改变字段语义。
62
+
63
+ 服务端负责当前 Owner 声明、名片 TTL、规则计次和最终判权。SDK 在 ACL 成功或异常(包括批量部分完成)后定向失效受影响路径缓存,保留无关路径缓存和原始错误。短期 ticket、URL 和 token 不进入长期本地索引。
64
+
65
+ ### 4.2 Group FS 和上传 Content-Type
66
+
67
+ 四端门面补齐 `group.fs.set_visibility`、`group.fs.namespace_ready`;`group.fs.ls` 使用 `page/size`,`limit` 为兼容别名;挂载路径限定为 `/memberdata/{member_ref}`,`readonly=true`、`require_approval=false` 为默认值。
68
+
69
+ 上传 session、HTTP PUT 和 complete 必须使用同一个实际 `Content-Type`,显式值优先;session 返回的 `session_id`/`headers` 必须原样保留。Browser JS 的 `cp(string, group)` 默认按 UTF-8 文本;本地路径要求 `sourceType: "path"`、`localPath: true` 或 `local:` 前缀,其他 SDK 保持既有字符串路径语义。
70
+
71
+ ### 4.3 Service Proxy
72
+
73
+ 四端统一服务名校验、Gateway 控制面注册、proxy-server 数据面隧道注册和 provider wakeup 错误映射。Browser provider 的 `webSocketFactory` 必须具备设置 `Authorization` 请求头的能力;隧道认证失败不能降级为无认证连接。
74
+
75
+ ## 5. 弹性补拉的本版共同契约
76
+
77
+ 0.5.33 已定义基础策略开关、`history_sync` 用途和连接回收;本版只补充下列实现边界:
78
+
79
+ - 辅助 Transport 复用主 Client 的 AID、device、slot、token、解密、游标和应用分发状态,不创建完整 Client,不刷新 refresh token。
80
+ - `storage_scope=persistent` 使用持久 cursor/ACK;`storage_scope=volatile` 使用独立 cursor,不提交持久水位、覆盖证明或服务端 ACK;`all` 保留旧请求行为。
81
+ - 同一 namespace 的 Pull 串行,不同 namespace 可按 Gateway 策略和共享预算并行。策略、连接和任务均绑定主会话代际,旧结果不能向新会话提交游标或 ACK。
82
+ - Gateway 回收或辅助连接断开时,释放页内存预留,将未完成任务退回主连接;同一策略版本内不自动冷重连。
83
+ - `max_page_bytes` 超限时返回 `OVERSIZED_MESSAGE`,停止该流自动续页并发布 `sync.error`;其它流继续。
84
+
85
+ 共享预算仍为总 16、background 8、event 4、pull 4;历史使用 pull 子额度。完整策略字段、回收通知和服务端限制见 [消息弹性补拉通道方案](../消息弹性补拉通道方案.md) 和 [0.5.33 开发与移植指南](0.5.33-SDK开发与移植指南.md)。
86
+
87
+ ## 6. Python 专项
88
+
89
+ Python 0.5.34 的 `_record_rate_limit` 优先使用正的 `retry_after_seconds`/`retry_after_ms`;明确为队列、背压或容量拥塞且没有有效提示时默认等待 1 秒,其它限流仍默认 60 秒。新增容量压测 CLI `aun bench run/report`,支持 16 种场景、套件、预算和断点续跑;该工具不新增网络协议。
90
+
91
+ ## 7. 四端移植验收
92
+
93
+ | 范围 | 必须覆盖 |
94
+ | --- | --- |
95
+ | 版本 | Python、TypeScript、JavaScript、Go 的运行时、配置、锁文件和测试引用均为 `0.5.34` |
96
+ | EventService | 三角色共存、状态重开、目录合并、写入失败不确认、成功删除正文、原 TTL 恢复、`EXPIRED` 结果和分页 token 失效 |
97
+ | Storage ACL | 条件主体、批量主体、ACL 错误后的定向缓存失效、四端 VFS/LowLevel/RPC 字段一致 |
98
+ | Group FS / Proxy | namespace、`ls` 分页、mount、session headers、Content-Type 三阶段和 Browser Authorization 隧道 |
99
+ | 弹性补拉 | 策略代际、持久/volatile 分流、断线退主、消费预留、超页和旧会话无 ACK |
100
+
101
+ 按 Python → Node TypeScript → Go → 浏览器 JavaScript 顺序执行受影响定向测试,再执行跨 SDK runner;首失败停止并从失败项续跑。真实 Gateway cap、服务端重启、Ubuntu Docker、浏览器 live E2E 和跨域 E2E 需单独记录,不能由静态检查替代。
102
+
103
+ ## 8. 历史基线索引
104
+
105
+ - [0.5.33 SDK 开发与移植指南](0.5.33-SDK开发与移植指南.md):控制消息、Ownership、基础 ACL、消息同步和弹性补拉原有契约。
106
+ - [0.5.32 SDK 开发与移植指南](0.5.32-SDK开发与移植指南.md):EventService 初始实现、租约、凭证、fanout、队列和 RPC 预算。
107
+ - [parity 0.5.34](../../python/CHANGES_FOR_PARITY.md#v0534):四端实现路径、测试入口和服务端依赖。
@@ -1,6 +1,6 @@
1
1
  # AUN SDK - 快速开始
2
2
 
3
- **版本**: 0.4.5+ | **Python**: >= 3.11
3
+ **版本**: 0.5.34 | **Python**: >= 3.11
4
4
 
5
5
  ---
6
6
 
@@ -54,7 +54,7 @@ async def load_or_register(store: AIDStore, aid: str):
54
54
  if loaded["ok"]:
55
55
  return loaded["data"]["aid"]
56
56
 
57
- registered = await store.register(aid)
57
+ registered = await store.register(aid, type="human")
58
58
  if not registered["ok"]:
59
59
  raise RuntimeError(registered["error"]["message"])
60
60
 
@@ -65,10 +65,10 @@ async def load_or_register(store: AIDStore, aid: str):
65
65
 
66
66
 
67
67
  async def create_client(aid: str) -> AUNClient:
68
- store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="")
68
+ store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="", slot_id="main")
69
69
  identity = await load_or_register(store, aid)
70
70
  client = AUNClient(identity)
71
- await client.connect({"slot_id": "main", "auto_reconnect": True})
71
+ await client.connect({"auto_reconnect": True})
72
72
  return client
73
73
 
74
74
 
@@ -122,7 +122,7 @@ store = AIDStore(
122
122
  identity = store.load("alice.agentid.pub")["data"]["aid"]
123
123
  client = AUNClient(identity)
124
124
  client.set_protected_headers({"sdk": "python"})
125
- await client.connect({"slot_id": "main", "connection_kind": "long"})
125
+ await client.connect({"connection_kind": "long"})
126
126
  ```
127
127
 
128
128
  `verify_ssl` 在 `AIDStore` 构造时配置,不在 `AUNClient` 中配置。自动模式下 SDK 根据环境变量决定:
@@ -137,7 +137,7 @@ await client.connect({"slot_id": "main", "connection_kind": "long"})
137
137
 
138
138
  ## 数据目录布局
139
139
 
140
- SDK 使用 `{aun_path}/AIDs/{aid}/` 存储每个 AID 的专属数据:
140
+ Python / TypeScript(Node.js)/ Go 使用 `{aun_path}/AIDs/{aid}/` 存储每个 AID 的专属数据:
141
141
 
142
142
  ```text
143
143
  {aun_path}/
@@ -146,16 +146,17 @@ SDK 使用 `{aun_path}/AIDs/{aid}/` 存储每个 AID 的专属数据:
146
146
  ├── alice.agentid.pub/
147
147
  │ ├── private/key.json
148
148
  │ ├── public/cert.pem
149
- │ └── tokens/meta.json
149
+ │ └── aun.db
150
150
  └── bob.agentid.pub/
151
151
  ├── private/key.json
152
152
  ├── public/cert.pem
153
- └── tokens/meta.json
153
+ └── aun.db
154
154
  ```
155
155
 
156
156
  要点:
157
157
 
158
158
  - `aun_path` 是应用级目录,一个目录可管理多个 AID。
159
+ - token、消息游标、实例状态及 EventService 状态保存在身份目录的 SQLite `aun.db`;浏览器 JavaScript 使用 IndexedDB,不使用上述文件布局。
159
160
  - 不要用 AID 名称作为 `aun_path`,避免出现 `~/.aun/{aid}/AIDs/{aid}/` 冗余嵌套。
160
161
  - 私钥、令牌、群密钥等敏感数据由 SDK 的本地保护机制保存,不应手工删除或迁移单个文件。
161
162
 
@@ -183,11 +184,11 @@ Go:
183
184
 
184
185
  ```go
185
186
  store := aun.NewAIDStore("~/.aun/myapp", "")
186
- aid, err := store.Load("alice.agentid.pub")
187
- if err != nil {
188
- return err
187
+ loaded := store.Load("alice.agentid.pub")
188
+ if !loaded.Ok {
189
+ panic(loaded.Error)
189
190
  }
190
- client := aun.NewAUNClient(aid.Data.AID)
191
+ client := aun.NewAUNClient(loaded.Data.AID)
191
192
  ```
192
193
 
193
194
  ---
@@ -195,12 +196,14 @@ client := aun.NewAUNClient(aid.Data.AID)
195
196
  ## 核心流程
196
197
 
197
198
  1. 创建 `AIDStore`。
198
- 2. `store.load(aid)` 加载本地 AID;本地不存在时调用 `store.register(aid)` 后再次加载。
199
+ 2. `store.load(aid)` 加载本地 AID;本地不存在时调用 `store.register(aid, type="human")`(非 human 类型还需提供 `owner`)后再次加载。
199
200
  3. 用 AID 对象构造 `AUNClient(aid)`,或先 `AUNClient()` 再 `load_identity(aid)`。
200
201
  4. 先注册事件处理器,再调用 `connect(options)`。
201
202
  5. 通过 `call(method, params)` 执行业务 RPC。
202
203
  6. 通过 `close()` 释放连接和后台任务。
203
204
 
205
+ 事件发布订阅使用 `client.EventService`(Go 为 `client.EventService()`):Bus 宿主先 `start`,Pub/Sub 分别 `authorize`,然后发布或订阅;同一 client 可在同一 Bus 上绑定多个角色。完整流程及 SQLite/IndexedDB 恢复规则见 [AUN事件发布订阅应用集成指南](AUN事件发布订阅应用集成指南.md)。
206
+
204
207
  详细 API 见 [06-API手册.md](06-API手册.md),RPC 参数见各领域的 `09-*-rpc-manual.md`。
205
208
 
206
209
 
@@ -18,7 +18,7 @@ AID 是 Agent 的全局唯一身份,格式为域名形式,例如 `alice.agen
18
18
  ```python
19
19
  store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="")
20
20
 
21
- registered = await store.register("alice.agentid.pub")
21
+ registered = await store.register("alice.agentid.pub", type="human")
22
22
  loaded = store.load("alice.agentid.pub")
23
23
  me = loaded["data"]["aid"]
24
24
 
@@ -191,6 +191,18 @@ RPC 方法参数见 `09-message-rpc-manual.md`、`09-group-rpc-manual.md`、`09-
191
191
 
192
192
  ---
193
193
 
194
+ ## EventService 发布订阅
195
+
196
+ EventService 运行在 Bus AID 的 SDK 内,以 `(bus_aid, event_name)` 标识事件;Pub 向 Bus 发布 JSON 对象,Bus 按有效订阅向设备实例定向分发。同一 client 在同一 Bus 上可以同时承担 `bus`、`pub`、`sub`,发布与订阅分别授权;Bus 身份也须取得相应发布或订阅权限。
197
+
198
+ 四端默认持久保存 Bus 目录、白名单、可复核的授权与订阅,以及客户端授权材料、目录、订阅意图和待发布记录。Python / TypeScript(Node.js)/ Go 使用 SQLite,浏览器 JavaScript 使用 IndexedDB。启动先加载已有状态,再合并本次配置;恢复待发布记录沿用原 `event_id` 与 TTL,过期后记录失败,不重新发送。应用仍须重新启动 Bus 或按角色接入目标 Bus,SDK 不自动枚举历史 Bus。
199
+
200
+ 发布遵循“本地持久化成功 → 入队 → 后台发送 → 按所选回复模式确认成功 → 删除本地正文”。默认 `none` 表示 AUN 已接受发送,`accepted` 表示 Bus 已受理;两者均不表示订阅方已完成业务处理。Bus fanout、服务端 volatile 收件箱和事件历史不在本地待发布队列的恢复范围内。
201
+
202
+ `catalog` 查询事件定义;`publications` 查询本次 Bus 运行的首次受理汇总,`subscriptions` 查询当前有效订阅,授权目录不等于实际订阅。完整 API、可见范围及分页规则见 [API 手册](06-API手册.md#eventservice-事件发布订阅)与[应用集成指南](AUN事件发布订阅应用集成指南.md)。
203
+
204
+ ---
205
+
194
206
  ## Group Index 观察模型
195
207
 
196
208
  `group.index` 是群公告、群规则、入群要求和附件稳定引用的签名索引。它由 owner/admin 侧 SDK 生成并签名,Group 服务只校验、CAS 保存和在响应 `_meta.group_indexes` 中注入版本提示。
@@ -7,23 +7,23 @@
7
7
  重构后,注册、身份加载、会话连接分离:
8
8
 
9
9
  ```python
10
- store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="")
10
+ store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="", slot_id="main")
11
11
 
12
12
  loaded = store.load(aid)
13
13
  if not loaded["ok"]:
14
- registered = await store.register(aid)
14
+ registered = await store.register(aid, type="human")
15
15
  if not registered["ok"]:
16
16
  raise RuntimeError(registered["error"]["message"])
17
17
  loaded = store.load(aid)
18
18
 
19
19
  me = loaded["data"]["aid"]
20
20
  client = AUNClient(me)
21
- await client.connect({"slot_id": "main", "auto_reconnect": True})
21
+ await client.connect({"auto_reconnect": True})
22
22
  ```
23
23
 
24
24
  关键约束:
25
25
 
26
- - `AIDStore.register(aid)` 只负责生成本地密钥、申请证书并落盘。
26
+ - `AIDStore.register(aid, *, type, owner=None, exttype=None)` 只负责生成本地密钥、申请证书并落盘;`type` 必填,非 `human` 类型还需按归属流程提供 `owner`。
27
27
  - `AIDStore.load(aid)` 返回 AID 值对象;AID 对象加载后不可变。
28
28
  - `AUNClient` 只接收 AID 对象,不接收字符串 AID 或配置字典里的 `aid` 字段。
29
29
  - `connect(options)` 内部会按需认证、建立 WebSocket、初始化 E2EE 和后台任务。
@@ -59,7 +59,7 @@ store = AIDStore(
59
59
  | 方法 | 说明 |
60
60
  |------|------|
61
61
  | `load(aid)` | 从本地加载 AID,返回 Result |
62
- | `register(aid)` | 注册新 AID,返回 Result |
62
+ | `register(aid, *, type, owner=None, exttype=None)` | 注册新 AID,返回 Result |
63
63
  | `list()` | 列出本地身份 |
64
64
  | `exists(aid)` | HEAD PKI 端点,判断 AID 是否已注册 |
65
65
  | `resolve(aid, opts=None)` | 解析身份与 agent.md,返回结构化 frontmatter;自有私钥身份优先本地草稿/缓存,可传 `{"skip_agent_md": True}` 跳过名片,或 `{"ownership": client}` 按需查询并缓存共识和 owner.md |
@@ -75,7 +75,7 @@ Result 使用方式:
75
75
  ```python
76
76
  result = await store.exists("alice.agentid.pub")
77
77
  if result["ok"] and not result["data"]["exists"]:
78
- await store.register("alice.agentid.pub")
78
+ await store.register("alice.agentid.pub", type="human")
79
79
  ```
80
80
 
81
81
  ---
@@ -143,7 +143,7 @@ await client.connect({
143
143
  | `extra_info` | 应用层自定义连接信息;下划线开头的键不会透传给 Gateway |
144
144
  | `background_sync` | 连接成功后是否执行消息后台补洞 / 未读同步,默认开启;不关闭已读状态查询补偿 |
145
145
  | `auto_reconnect` | 断线后是否自动重连 |
146
- | `heartbeat_interval` | 心跳间隔,秒 |
146
+ | `heartbeat_interval` | 保留的兼容选项;当前不启用 RPC 心跳,连接保活使用 WebSocket 控制帧 |
147
147
  | `retry.initial_delay` / `retry.max_delay` | 退避重连参数 |
148
148
  | `connect_timeout` / `call_timeout` | 连接和 RPC 超时,秒 |
149
149
  | `push_notify_aid` / `push_token` | Python SDK 推荐的离线推送登记入口;必须同时提供 |
@@ -151,6 +151,8 @@ await client.connect({
151
151
 
152
152
  `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 本轮未增加该便利入口。
153
153
 
154
+ 本表使用 Python 选项名;TS/JS 使用 `connectionKind`、`shortTtlMs`、`autoReconnect`、`backgroundSync` 等 camelCase 名称,Go 使用 `ConnectionOptions` 的 `ConnectionKind`、`ShortTTLMS`、`AutoReconnect`、`BackgroundSync` 等字段。
155
+
154
156
  当前稳定实现为 Gateway 模式;Peer / Relay 仍是协议能力定义,SDK 连接层会明确返回未实现。
155
157
 
156
158
  ---
@@ -180,6 +182,14 @@ await cli.close()
180
182
 
181
183
  ---
182
184
 
185
+ ## EventService 接入与恢复
186
+
187
+ EventService 使用已就绪的 AUNClient:Python / TS / JS 为 `client.EventService`,Go 为 `client.EventService()`。Bus 宿主调用 `start`,要求 Bus AID 等于当前身份;远端 Pub/Sub 直接 `authorize(bus_aid, role, ...)`,内部自动建立该角色客户端。多角色分别授权,使用独立的授权材料与租约。
188
+
189
+ 连接恢复时 SDK 会重新核验授权并恢复订阅和待发布队列;新进程仍需重新 `start` 本地 Bus,或对目标 Bus 的 Pub/Sub 角色调用 `authorize`。默认 SQLite/IndexedDB 保存待发布记录,恢复不延长 TTL,已过期记录转为可查询的失败结果。`close` 保留这些持久状态;停止接收新工作后可先 `drain` 再关闭。方法签名与目录查询见 [API 手册](06-API手册.md#eventservice-事件发布订阅),完整流程见 [应用集成指南](AUN事件发布订阅应用集成指南.md)。
190
+
191
+ ---
192
+
183
193
  ## 网关发现
184
194
 
185
195
  注册、解析和认证会根据 AID 的 issuer 自动发现 Gateway:
@@ -1,5 +1,7 @@
1
1
  # AUN SDK - API 手册
2
2
 
3
+ 本手册对照四 SDK 0.5.34 的公开接口;历史版本专题中的接口以其标注版本为准。
4
+
3
5
  ---
4
6
 
5
7
  ## 目录
@@ -8,6 +10,7 @@
8
10
  - [AID](#aid)
9
11
  - [AUNClient](#aunclient)
10
12
  - [业务门面](#业务门面)
13
+ - [EventService 事件发布订阅](#eventservice-事件发布订阅)
11
14
  - [事件](#事件)
12
15
  - [ServiceProxyClient](#serviceproxyclient)
13
16
  - [E2EE 高级 API](#e2ee-高级-api)
@@ -64,7 +67,7 @@ store := aun.NewAIDStore(aunPath, encryptionSeed, aun.AIDStoreOptions{
64
67
  | Python | TS/JS | Go | 说明 |
65
68
  |--------|-------|----|------|
66
69
  | `load(aid)` | `load(aid)` | `Load(aid)` | 从本地加载 AID |
67
- | `register(aid)` | `register(aid)` | `Register(ctx, aid[, opts])` | 注册并落盘证书和私钥;Go 两参数旧调用仍可用,显式选项使用 `AIDStoreRegisterOptions` |
70
+ | `register(aid, *, type, owner=None, exttype=None)` | `register(aid, {type, owner?, exttype?})` | `Register(ctx, aid[, opts])` | 注册并落盘证书和私钥;`type` 必填,非 human 类型还需 `owner`;Go 两参数旧调用仍可用,显式选项使用 `AIDStoreRegisterOptions` |
68
71
  | `list()` | `list()` | `List()` | 列出本地 AID |
69
72
  | `exists(aid)` | `exists(aid)` | `Exists(ctx, aid)` | 远端存在性检查 |
70
73
  | `resolve(aid, opts=None)` | `resolve(aid, opts?)` | `Resolve(ctx, aid, opts...)` | 解析身份及名片,返回结构化 `agent_md.frontmatter`;可按需复用 ownership 共识校验并缓存 owner.md,完整输入输出见下节 |
@@ -270,11 +273,11 @@ AID 由 `AIDStore.load()` 返回,应用层不直接构造。
270
273
 
271
274
  | Python | TS/JS | Go | 说明 |
272
275
  |--------|-------|----|------|
273
- | `aid` | `aid` | `AID()` | AID 字符串 |
274
- | `cert_pem` | `certPem` | `CertPEM()` | 证书 PEM |
275
- | `public_key` | `publicKey` | `PublicKey()` | 公钥 |
276
- | `cert_fingerprint` | `certFingerprint` | `CertFingerprint()` | 证书指纹 |
277
- | `aun_path` | `aunPath` | `AUNPath()` | 所属数据目录 |
276
+ | `aid` | `aid` | `Aid` 字段 | AID 字符串 |
277
+ | `cert_pem` | `certPem` | `CertPem` 字段 | 证书 PEM |
278
+ | `public_key` | `publicKey` | `PublicKey` 字段 | 公钥 |
279
+ | `cert_fingerprint` | `certFingerprint` | `CertFingerprint` 字段 | 证书指纹 |
280
+ | `aun_path` | `aunPath` | `AunPath` 字段 | 所属数据目录 |
278
281
  | `device_id` | `deviceId` | `DeviceID` | 设备 ID |
279
282
  | `slot_id` | `slotId` | `SlotID` | 实例槽位 ID;允许 `/`、`:`、空格作为共享隔离键分隔符 |
280
283
  | `verify_ssl` | `verifySsl` | `VerifySSL` | 是否校验 TLS 证书 |
@@ -471,6 +474,44 @@ headers = client.get_protected_headers()
471
474
 
472
475
  除 `client.call(method, params)` 外,四语言 SDK 提供高层门面(Facade),封装常用操作并简化参数。普通应用优先用门面,只有需要精确控制底层参数时再直调 RPC。
473
476
 
477
+ ### EventService 事件发布订阅
478
+
479
+ Python / TS / JS 使用 `client.EventService` 属性,Go 使用 `client.EventService()`。以下均为该门面的方法,不是 Gateway `pubsub.*` RPC;跨 AID 请求由 SDK 通过 E2EE P2P 消息承载。
480
+
481
+ | 操作 | Python | TypeScript / JavaScript | Go |
482
+ |------|--------|-------------------------|----|
483
+ | 启动本地 Bus | `await start(bus_aid, catalog=..., allowlist=...)` | `await start(busAid, {catalog, allowlist})` | `Start(ctx, busAid, EventServiceStartOptions{...})` |
484
+ | 按角色授权 | `await authorize(bus_aid, role, auth_mode, events, credential=None)` | `await authorize(busAid, role, authMode, events, credential?)` | `Authorize(ctx, busAid, role, authMode, events, grant)` |
485
+ | 发布对象 | `await publish(bus_aid, event_name, data, **options)` | `await publish(busAid, eventName, data, options?)` | `Publish(ctx, busAid, eventName, data, options...)` |
486
+ | 等待发布结果 | `await wait_published(bus_aid, event_id)` | `await waitPublished(busAid, eventId)` | `WaitPublished(ctx, busAid, eventID)` |
487
+ | 订阅/取消订阅 | `await subscribe(bus_aid, events)` / `unsubscribe(...)` | `await subscribe(busAid, events)` / `unsubscribe(...)` | `Subscribe(ctx, busAid, events)` / `Unsubscribe(...)` |
488
+ | 接收事件 | `on_event(bus_aid, handler)` / `await next_event(bus_aid, timeout=None)` | `onEvent(busAid, handler)` / `await nextEvent(busAid, timeout?)` | `OnEvent(busAid, handler)` / `NextEvent(ctx, busAid)` |
489
+ | 事件定义目录 | `await catalog(bus_aid, **params)` | `await catalog(busAid, params?)` | `Catalog(ctx, busAid, params)` |
490
+ | 发布/订阅目录 | `await publications(bus_aid, **params)` / `subscriptions(...)` | `await publications(busAid, params?)` / `subscriptions(...)` | `Publications(ctx, busAid, params)` / `Subscriptions(...)` |
491
+ | 宿主管理 | `update_config` / `stats` / `issue_grant` / `revoke_grant` | `updateConfig` / `stats` / `issueGrant` / `revokeGrant` | `UpdateConfig` / `Stats` / `IssueGrant` / `RevokeGrant` |
492
+ | 生命周期 | `renew` / `drain` / `close` | `renew` / `drain` / `close` | `Renew` / `Drain` / `Close` |
493
+
494
+ `start` 要求 `bus_aid == client.aid`;接入远端 Bus 直接按 `pub` / `sub` 分别 `authorize`,授权成功自动加载获准的事件定义目录。同一 client 可在同一 Bus 上同时绑定 `bus`、`pub`、`sub`,Bus 自发自订仍需相应权限。管理方法仅本地 Bus 宿主可用。`renew`、`drain`、`close` 覆盖该 Bus 相关角色;Go `Close(busAid)` 不接收 context,异步方法的具体参数及返回见[应用集成指南](AUN事件发布订阅应用集成指南.md)。
495
+
496
+ `publish` 的 `data` 必须是 JSON 对象,成功返回 `event_id` 字符串(Go 另返回 error),表示已持久化并入队。选项分别为 Python `schema_version` / `ttl_seconds` / `reply_mode` / `event_id`,TS/JS `schemaVersion` / `ttlSeconds` / `replyMode` / `eventId`,Go `PubSubPublishOptions`。`wait_published` / `waitPublished` / `WaitPublished` 返回所选阶段结果:默认 `none` 为 AUN 已接受发送,`accepted` 为 Bus 已受理,均不证明订阅方业务完成。后台完成通知分别使用 `on_publish` / `onPublish` / `OnPublish`;Go handler 接收 `(eventID, result, error)`,Python / TS / JS handler 接收含 `event_id` 与 `result` 或 `error` 的对象。
497
+
498
+ 默认持久化覆盖 Bus 事件目录、白名单、有效授权和订阅,以及客户端授权材料、目录、订阅意图、待发布记录和过期失败结果。Python / TS(Node.js)/ Go 复用身份目录的 SQLite `aun.db`,浏览器 JS 使用 IndexedDB;自定义 Bus 存储与 Python / Go 的 `state_path` / `StatePath` 边界见[持久化说明](AUN事件发布订阅应用集成指南.md#7-持久化统计与故障定位)。启动加载旧目录后按事件合并本次配置,未提交的事件保留,同名条目以本次配置为准;后续注册、订阅与配置修改写回持久层。
499
+
500
+ 待发布消息先落库再入队;达到所选回复模式的成功阶段后删除本地正文,关闭或未确认成功时保留。重启重新接入对应角色后按原 `event_id`、原 `expires_at` 恢复,过期后记录 `EXPIRED`,不延长 TTL。成功结果仅有界保留在运行期,过期失败结果也受容量限制。Bus 已受理后的 fanout、服务端 volatile 收件箱及历史事件不在此持久恢复范围内。
501
+
502
+ #### publications / subscriptions 查询
503
+
504
+ 查询的可选参数为 `event_name`、`limit`(默认 50,范围 1–200)、`page_token`;TS/JS 和 Go 的查询 map 也使用这些 snake_case 字段。`role` 只在本地选择查询端:`publications` 可选 `bus` / `pub`,`subscriptions` 可选 `bus` / `sub`;省略优先本地 Bus,否则使用对应客户端角色,不发送到网络。
505
+
506
+ Bus 宿主可查询全局;Pub 仅查看自身 AID、当前发布权限内的汇总,Sub 仅查看当前设备租约实际生效的订阅。`authorize` 成功本身不建立订阅。查询返回 `{service_aid, since, as_of, items, next_page_token}`,时间均为 Unix 毫秒,末页 token 为 null:
507
+
508
+ | 查询 | `items` 字段 |
509
+ |------|---------------|
510
+ | `publications` | `publisher_aid`、`event_name`、`published`、`first_published_at`、`last_published_at` |
511
+ | `subscriptions` | `subscriber_aid`、`event_name`、`device_id`、`slot_id`、`expires_at` |
512
+
513
+ 发布汇总只计 Bus 首次受理,不计拒绝与去重,TTL 到期不删除汇总,Bus 重启清零;订阅目录只返回当前有效关系,不包含凭证或租约令牌。每页是实时视图,不冻结快照;分页 token 有效 60 秒并绑定操作、查询范围及当前 Bus 运行实例,完整回包最多 64 KiB。事件定义仍通过 `catalog` 查询。完整流程和参数见[应用集成指南](AUN事件发布订阅应用集成指南.md),内部契约见[开发移植指南](AUN事件发布订阅开发移植指南.md)。
514
+
474
515
  ### Ownership、凭证与组织专题
475
516
 
476
517
  | 领域 | 当前入口 | 详细指南 |
@@ -860,7 +901,7 @@ await client.push.unregister()
860
901
 
861
902
  ## ServiceProxyClient
862
903
 
863
- Service Proxy 用于 provider 通过 AUN 身份暴露本地 HTTP / WebSocket 服务。当前公开封装在 Python SDK 的 `ServiceProxyClient` 中;其它语言可以按 [09-proxy-rpc-manual.md](09-proxy-rpc-manual.md) 直接实现同等控制面和隧道消息。
904
+ Service Proxy 用于 provider 通过 AUN 身份暴露本地 HTTP / WebSocket 服务。Python、TypeScript、JavaScript 和 Go 均提供 `ServiceProxyClient` 封装;浏览器 JavaScript 需通过可承载 Authorization Bearer 的自定义 WebSocket factory 建立隧道。公开入口与控制面字段见 [09-proxy-rpc-manual.md](09-proxy-rpc-manual.md)。
864
905
 
865
906
  ```python
866
907
  from aun_core.service_proxy import ServiceProxyClient
@@ -895,6 +936,8 @@ proxy-server 连接地址不能由应用外部传入或配置。`ServiceProxyCli
895
936
  | `serve_once()` | 处理有限数量的 proxy-server 转发请求 |
896
937
  | `serve_forever(connection_mode="persistent")` | 持续提供 Service Proxy 服务;支持 persistent / on_demand |
897
938
 
939
+ 四端构造与生命周期命名:Python `ServiceProxyClient(provider_aid=..., aun_client=client)`;TS/JS `new ServiceProxyClient({providerAid, aunClient})`;Go `NewServiceProxyClient(ServiceProxyClientOptions{ProviderAID: ..., AUNClient: client})`。对应方法分别使用 `register_service` / `registerService` / `RegisterService`、`connect_once` / `connectOnce` / `ConnectOnce`、`serve_once` / `serveOnce` / `ServeOnce`、`serve_forever` / `serveForever` / `ServeForever`。浏览器 JS 的 `webSocketFactory` 必须能发送隧道的 Authorization Bearer 请求头,原生浏览器 WebSocket 不满足该条件。
940
+
898
941
  自动注册顺序:
899
942
 
900
943
  - `connect_once()`、`serve_once()`、`serve_forever()` 在存在 `aun_client.call()` 时,会先向 Gateway 调用 `proxy.register_services`。
@@ -1046,13 +1089,11 @@ JavaScript 浏览器 SDK 的 Worker 是网络隔离增强:`new Worker()` 同
1046
1089
 
1047
1090
  | API | 说明 |
1048
1091
  |-----|------|
1049
- | `client.e2ee.encrypt_message(...)` | 裸 WebSocket 或特殊集成中的 P2P 加密 |
1050
- | `client.e2ee.decrypt_message(...)` | 裸消息解密 |
1051
- | `client.e2ee.generate_prekey()` | 生成 prekey |
1052
- | `client.e2ee.invalidate_prekey_cache(peer_aid)` | 清理对端 prekey 缓存 |
1053
- | `client.group_e2ee.encrypt(...)` | 群消息加密 |
1054
- | `client.group_e2ee.decrypt(...)` | 群消息解密 |
1055
- | `client.group_e2ee.current_epoch(group_id)` | 查询当前群 epoch |
1092
+ | Python | `aun_core.v2.e2ee.encrypt_p2p.encrypt_p2p_message`、`encrypt_group.encrypt_group_message`、`decrypt.decrypt_message` |
1093
+ | TypeScript / JavaScript | 根入口导出的 `encryptP2PMessage`、`encryptGroupMessage`、`decryptMessage` |
1094
+ | Go | `v2/e2ee.EncryptP2PMessage`、`EncryptGroupMessage`、`DecryptMessage` |
1095
+
1096
+ 这些是低层 E2EE 函数,需要调用方提供对应的密钥和目标上下文;普通 `message.send` / `group.send` 由 SDK 自动管理加密,不应改用低层函数替代。
1056
1097
 
1057
1098
  ---
1058
1099
 
@@ -6,7 +6,15 @@
6
6
  >
7
7
  > **授权 = 协作根写 ACL**:谁能 `commit` = 谁对 `collab_root` 有写权限。普通 AID storage 可继续用 `storage.set_acl/remove_acl` 管理写授权;群 `memberdata` 协作根必须用 `collab.set_acl/remove_acl` 按 `collab_root` 授权,SDK/CLI 不得拼接真实 `group_data` 路径。
8
8
  >
9
- > SDK 侧通过 `client.collab` 访问(`CollabClient`),每个命令 1:1 映射一条 `collab.*` RPC。
9
+ > Python / TypeScript / Browser SDK 通过 `client.collab` 访问(`CollabClient`);Go 使用 `client.Collab()`,标签入口为 `.Tag()`。每个命令映射一条 `collab.*` RPC。
10
+
11
+ ## SDK 返回差异
12
+
13
+ 下文定义服务端原始 RPC 字段。Python / TypeScript / Browser 保留原始结果;Go 0.5.34 的类型化返回尚有以下差异,需要完整字段时使用原始 `client.Call()`:
14
+
15
+ - GC 不保留 `reachable` / `freed_bytes`;Reflog 不保留 `seq` / `metadata`,且其 `RequesterAID` / `CreatedAt` 不能接收当前 `requester` / `timestamp` 字段。
16
+ - Tag Create 不保留 `bump` / `changed`;Revert 不保留 `no_change`;Tag Restore 不保留 `partial`,`new_snapshot_version: null` 解析为空字符串。
17
+ - Tag Diff 的 `added` / `removed` 实际为文档名字符串数组,Go 类型仍按对象数组解析,非空时会返回解码错误;Tag Rm 的 `removed: true` 转为整数 `1`,且不保留 `version`。
10
18
 
11
19
  ## 方法索引
12
20
 
@@ -74,11 +82,11 @@
74
82
 
75
83
  ### 乐观锁(commit)
76
84
 
77
- 1. `put_object`(写新版本文件,永不失败,数据先存下)。
85
+ 1. `put_object` 写入候选版本文件;上传失败直接返回错误。
78
86
  2. 同一事务:`atomic_repoint(<doc>@current, new_target, expected_version=onto)` + 台账追加。
79
- 3. CAS 成功 → version+1;CAS 失败 → 整事务回滚,返回 `{ok:false, current_version, hint}`。
87
+ 3. CAS 成功 → version+1;CAS 失败 → 返回 JSON-RPC `-32009`,`error.data` 包含 `current_version`、`current_target`、`hint`,并清理候选文件。
80
88
 
81
- `onto` 来源:`collab.show` 响应的 `version` 字段;merge 后用 commit 失败响应的 `current_version`。
89
+ `onto` 来源:`collab.show` 响应的 `version` 字段;冲突时由 SDK 的 `CollabConflictError` 取得当前版本,合并后再提交。失败请求不保证保留候选正文,调用方应保留自己的草稿。
82
90
 
83
91
  ### 数据不变量
84
92
 
@@ -126,7 +134,7 @@ docs = await client.collab.ls_files("alice.aid.pub:/projects/myapp")
126
134
  |------|------|------|------|
127
135
  | `collab_root` | string | 是 | 协作根 `<aid>:<path>` |
128
136
  | `doc` | string | 是 | 文档名 |
129
- | `source` | string | 是 | 初始内容:本地文件路径或 `<aid>:<path>` |
137
+ | `source` | string | 是 | Base64 编码的正文或可读的 `<aid>:<path>`;SDK 不读取本地文件路径 |
130
138
 
131
139
  ### 响应
132
140
 
@@ -153,11 +161,11 @@ docs = await client.collab.ls_files("alice.aid.pub:/projects/myapp")
153
161
 
154
162
  | 字段 | 类型 | 说明 |
155
163
  |------|------|------|
156
- | `content` | string | base64 编码的当前内容 |
164
+ | `content` | string | base64 编码的所读版本内容 |
157
165
  | `version` | integer | 当前或指定版本号(**commit 的 onto 来源**) |
158
- | `author` | string | 当前版本作者 AID |
159
- | `anchor` | string | 台账锚点(读取历史版本时返回) |
160
- | `current_target` | string | 当前版本文件绝对路径(读取当前版本时返回) |
166
+ | `author` | string | 所读版本作者 AID |
167
+ | `anchor` | string | 台账锚点,当前和历史版本均返回 |
168
+ | `current_target` | string | 所读版本文件绝对路径,当前和历史版本均返回 |
161
169
 
162
170
  ---
163
171
 
@@ -171,8 +179,9 @@ docs = await client.collab.ls_files("alice.aid.pub:/projects/myapp")
171
179
  |------|------|------|------|
172
180
  | `collab_root` | string | 是 | 协作根 `<aid>:<path>` |
173
181
  | `doc` | string | 是 | 文档名 |
174
- | `source` | string | 是 | 新内容:本地路径或 `<aid>:<path>` |
182
+ | `source` | string | 是 | Base64 编码的新正文或可读的 `<aid>:<path>`;不是本地文件路径 |
175
183
  | `onto` | integer | 是 | 基线版本号(来自 `collab.show` 的 `version`) |
184
+ | `message` | string | 否 | 台账说明,默认空字符串 |
176
185
 
177
186
  ### 响应
178
187
 
@@ -184,23 +193,27 @@ docs = await client.collab.ls_files("alice.aid.pub:/projects/myapp")
184
193
  | `version` | integer | 新版本号(onto+1) |
185
194
  | `current_target` | string | 新版本文件绝对路径 |
186
195
 
187
- **撞版本失败**(数据已安全保存,需 merge 后重提):
196
+ **撞版本失败**:JSON-RPC `-32009` 的 `error.data` 字段如下;四个 SDK 映射为 `CollabConflictError`,不是成功响应中的 `ok:false`。
188
197
 
189
198
  | 字段 | 类型 | 说明 |
190
199
  |------|------|------|
191
- | `ok` | boolean | `false` |
192
200
  | `current_version` | integer | 当前权威版本号(**merge 后 commit 用此作新 onto**) |
193
201
  | `current_target` | string | 当前权威版本文件绝对路径 |
194
- | `hint` | string | 后端格式化好的下一步命令行字符串 |
202
+ | `hint` | string | 合并并重新提交的提示语,不是可执行命令 |
195
203
 
196
204
  ### 示例
197
205
 
198
206
  ```python
207
+ from aun_core.collab.errors import CollabConflictError
208
+ import base64
209
+ source = base64.b64encode(draft_bytes).decode()
199
210
  cur = await client.collab.show(root, "design.md")
200
- res = await client.collab.commit(root, "design.md", "./design.md", cur["version"])
201
- if not res["ok"]:
202
- await client.collab.merge(root, "design.md", "./design.md", cur["version"])
203
- res = await client.collab.commit(root, "design.md", "./design.md", res["current_version"])
211
+ try:
212
+ res = await client.collab.commit(root, "design.md", source, cur["version"])
213
+ except CollabConflictError as conflict:
214
+ merged = await client.collab.merge(root, "design.md", source, cur["version"])
215
+ if not merged["conflicts"]:
216
+ res = await client.collab.commit(root, "design.md", merged["content"], conflict.current_version)
204
217
  ```
205
218
 
206
219
  ---
@@ -215,7 +228,7 @@ if not res["ok"]:
215
228
  |------|------|------|------|
216
229
  | `collab_root` | string | 是 | 协作根 `<aid>:<path>` |
217
230
  | `doc` | string | 是 | 文档名 |
218
- | `source` | string | 是 | 本地草稿内容(ours):本地路径或 `<aid>:<path>` |
231
+ | `source` | string | 是 | 草稿内容(ours):Base64 正文或可读的 `<aid>:<path>` |
219
232
  | `onto` | integer | 是 | 共同祖先版本号 |
220
233
 
221
234
  ### 响应
@@ -225,7 +238,7 @@ if not res["ok"]:
225
238
  | `content` | string | base64 编码的合并结果 |
226
239
  | `conflicts` | boolean | 是否含冲突标记(`<<<<<<<` / `=======` / `>>>>>>>`) |
227
240
 
228
- `conflicts=true` 时需人工编辑消解冲突后再 commit。
241
+ merge 只计算并返回正文,不修改草稿或当前版本。`conflicts=true` 时需编辑消解冲突;提交时将合并正文编码后传给 `commit`。
229
242
 
230
243
  ---
231
244
 
@@ -256,8 +269,8 @@ if not res["ok"]:
256
269
  |------|------|------|------|
257
270
  | `collab_root` | string | 是 | 协作根 `<aid>:<path>` |
258
271
  | `doc` | string | 是 | 文档名 |
259
- | `from` | integer | 是 | 起始版本号(SDK 形参 `v_from`) |
260
- | `to` | integer | 是 | 目标版本号(SDK 形参 `v_to`) |
272
+ | `from` | integer | 是 | 起始版本号;Python 形参 `v_from`,TS/Browser/Go 为 `fromVersion` |
273
+ | `to` | integer | 是 | 目标版本号;Python 形参 `v_to`,TS/Browser/Go 为 `toVersion` |
261
274
 
262
275
  ### 响应
263
276
 
@@ -342,7 +355,7 @@ if not res["ok"]:
342
355
 
343
356
  ### 响应
344
357
 
345
- 返回日志数组,每项包含 `seq`、`action`、`requester`、`doc`、`version`、`onto`、`target`、`status`、`error_code`、`error_msg`、`metadata`、`timestamp` 等字段。
358
+ 返回日志数组,每项包含 `seq`、`action`、`requester`、`doc`、`version`、`base_version`、`target`、`status`、`error_code`、`error_msg`、`metadata`、`timestamp` 等字段。
346
359
 
347
360
  ---
348
361
 
@@ -441,13 +454,13 @@ if not res["ok"]:
441
454
 
442
455
  ### 响应
443
456
 
444
- 返回新增/删除/版本变化的文档清单。
457
+ 返回 `added`、`removed`、`changed` 三个文档名字符串数组。
445
458
 
446
459
  ---
447
460
 
448
461
  ## collab.tag.restore
449
462
 
450
- 回滚到某标签。**forward-only**:不回退 version 计数器,而是对每个文档以标签中的旧内容写一个新版本(vN+1),最后以回滚后状态自动创建新标签。
463
+ 回滚到某标签。**forward-only**:不回退 version 计数器,而是对每个文档以标签中的旧内容写一个新版本(vN+1),完成后尝试创建新标签;部分失败或无变化时不保证产生新标签。
451
464
 
452
465
  ### 参数
453
466
 
@@ -462,14 +475,16 @@ if not res["ok"]:
462
475
  | 字段 | 类型 | 说明 |
463
476
  |------|------|------|
464
477
  | `restored_from` | string | 回滚来源标签版本 |
465
- | `new_snapshot_version` | string | 回滚后自动创建的新标签版本(历史字段名保留为 `new_snapshot_version`) |
478
+ | `new_snapshot_version` | string / null | 回滚后创建的新标签版本;部分失败或无变化时可为 `null`,历史字段名保留 |
466
479
  | `warnings` | array | 回滚过程中的告警(如某文档被他人并发提交而跳过) |
480
+ | `restored_docs` | array | 已恢复的文档 |
481
+ | `partial` | boolean | 可选;部分失败时为 `true`,RPC 本身仍可成功返回 |
467
482
 
468
483
  ---
469
484
 
470
485
  ## collab.tag.rm
471
486
 
472
- 删除单个标签。
487
+ 删除单个标签;当前活动标签不能删除。
473
488
 
474
489
  ### 参数
475
490
 
@@ -482,7 +497,8 @@ if not res["ok"]:
482
497
 
483
498
  | 字段 | 类型 | 说明 |
484
499
  |------|------|------|
485
- | `ok` | boolean | `true` |
500
+ | `removed` | boolean | 是否删除 |
501
+ | `version` | string | 标签版本 |
486
502
 
487
503
  ---
488
504
 
@@ -537,7 +553,7 @@ if not res["ok"]:
537
553
 
538
554
  | 字段 | 类型 | 说明 |
539
555
  |------|------|------|
540
- | `ok` | boolean | `true` |
556
+ | `removed` | integer | 删除的注册表条目数 |
541
557
 
542
558
  ---
543
559
 
@@ -577,5 +593,7 @@ if not res["ok"]:
577
593
  | -32002 | 服务暂不可用(数据库未连接) |
578
594
  | -32004 | 权限拒绝(requester 对 collab_root 无写权限) |
579
595
  | -32008 | 协作文档 / 版本 / 标签不存在 |
580
- | -32009 | 版本冲突(commit 撞版本,见 `ok:false` 响应;tag create 时标签头已移动) |
581
- | -32000 | 通用错误(参数校验失败、源内容读取失败、无变更可打标签等) |
596
+ | -32009 | 版本冲突;commit 的 `error.data` 包含当前版本与合并提示,tag create 时也可能表示标签头已移动 |
597
+ | -32010 | 无变化可创建标签 |
598
+ | -32602 | 参数校验失败 |
599
+ | -32000 | 其它服务错误,如源内容读取失败 |