@agentunion/fastaun 0.5.21 → 0.5.22

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 (71) hide show
  1. package/CHANGELOG.md +58 -1
  2. package/_packed_docs/CHANGELOG.md +58 -1
  3. package/_packed_docs/INDEX.md +465 -453
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +168 -164
  5. package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +307 -67
  6. package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +41 -15
  7. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +5 -5
  8. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +30 -8
  9. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +669 -666
  10. package/_packed_docs/sdk/0.5.22-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +212 -0
  11. package/_packed_docs/sdk/0.5.22-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +199 -0
  12. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +16 -0
  13. package/_packed_docs/sdk/09-group-rpc-manual.md +10 -0
  14. package/_packed_docs/sdk/09-storage-rpc-manual.md +64 -7
  15. package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +3 -1
  16. package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +2 -0
  17. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +138 -134
  18. package/_packed_docs/sdk/INDEX.md +255 -239
  19. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +939 -930
  20. package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +312 -363
  21. package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +322 -553
  22. package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +4 -4
  23. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +484 -480
  24. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +190 -97
  25. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +158 -127
  26. package/dist/agent-md.d.ts +1 -1
  27. package/dist/agent-md.js +11 -4
  28. package/dist/agent-md.js.map +1 -1
  29. package/dist/auth.d.ts +1 -0
  30. package/dist/auth.js +18 -2
  31. package/dist/auth.js.map +1 -1
  32. package/dist/client/delivery.d.ts +28 -0
  33. package/dist/client/delivery.js +399 -44
  34. package/dist/client/delivery.js.map +1 -1
  35. package/dist/client/group-state.js +3 -0
  36. package/dist/client/group-state.js.map +1 -1
  37. package/dist/client/rpc-pipeline.js +28 -2
  38. package/dist/client/rpc-pipeline.js.map +1 -1
  39. package/dist/client/v2-e2ee.js +109 -39
  40. package/dist/client/v2-e2ee.js.map +1 -1
  41. package/dist/client.js +38 -10
  42. package/dist/client.js.map +1 -1
  43. package/dist/group-fs.d.ts +1 -0
  44. package/dist/group-fs.js +37 -19
  45. package/dist/group-fs.js.map +1 -1
  46. package/dist/org-protocol.d.ts +1 -0
  47. package/dist/org-protocol.js +54 -7
  48. package/dist/org-protocol.js.map +1 -1
  49. package/dist/ownership-v21.d.ts +21 -3
  50. package/dist/ownership-v21.js +135 -37
  51. package/dist/ownership-v21.js.map +1 -1
  52. package/dist/ownership-workflow.d.ts +7 -2
  53. package/dist/ownership-workflow.js +173 -17
  54. package/dist/ownership-workflow.js.map +1 -1
  55. package/dist/storage/lowlevel.d.ts +6 -0
  56. package/dist/storage/lowlevel.js +24 -7
  57. package/dist/storage/lowlevel.js.map +1 -1
  58. package/dist/storage/read-cache.d.ts +70 -0
  59. package/dist/storage/read-cache.js +625 -0
  60. package/dist/storage/read-cache.js.map +1 -0
  61. package/dist/storage/vfs.d.ts +2 -0
  62. package/dist/storage/vfs.js +50 -15
  63. package/dist/storage/vfs.js.map +1 -1
  64. package/dist/tools/cross-sdk-agent.d.ts +21 -1
  65. package/dist/tools/cross-sdk-agent.js +301 -19
  66. package/dist/tools/cross-sdk-agent.js.map +1 -1
  67. package/dist/transport.js +6 -2
  68. package/dist/transport.js.map +1 -1
  69. package/dist/version.d.ts +1 -1
  70. package/dist/version.js +1 -1
  71. package/package.json +1 -1
@@ -21,8 +21,8 @@ D:\modelunion\kite\aun-sdk-core\docs\aun公网测试运行指南.md
21
21
 
22
22
  | 环境 | 服务端 Compose | 域名 | 持久化数据 | project / 网络 | 主要容器 |
23
23
  | --- | --- | --- | --- | --- | --- |
24
- | agentid.pub 本地单实例 | 根 `docker-compose.yml` + `agentid.pub/docker-compose.yml` + `agentid.pub/local.env` | `agentid.pub` | `docker-deploy/data` | `kite-single` / `kite-single_kite-net` | `kite-app`、`kite-mysql`、`kite-redis` |
25
- | agentid.cn 本地跨域对端 | 根 `docker-compose.yml` + `agentid.cn/docker-compose.yml` + `agentid.cn/local.env` | `agentid.cn` | `docker-deploy/data-agentid-cn` | `kite-agentid-cn-local` / `kite-agentid-cn-local_kite-net` | `kite-agentid-cn-local-*` |
24
+ | agentid.pub 本地单实例 | 根 `docker-compose.yml` + `agentid.pub/docker-compose.yml` + `agentid.pub/local.env` | `agentid.pub` | 应用 `docker-deploy/data`;MySQL 命名卷 `org-pub-mysql-logical14-20261023-015854-855e` | `kite-single` / `kite-single_kite-net` | `kite-app`、`kite-mysql`、`kite-redis` |
25
+ | agentid.cn 本地跨域对端 | 根 `docker-compose.yml` + `agentid.cn/docker-compose.yml` + `agentid.cn/local.env` | `agentid.cn` | 应用 `docker-deploy/data-agentid-cn`;MySQL 独立 bind `data-agentid-cn/mysql-repaired-20260903-v2` | `kite-agentid-cn-local` / `kite-agentid-cn-local_kite-net` | `kite-agentid-cn-local-*` |
26
26
  | 三节点分布式 | `D:\modelunion\kite\docker-deploy\docker-compose.distributed.yml` | `dist-agentid.pub` | `D:\modelunion\kite\docker-deploy\data-dist` | `kite-main-dist-worktree` / `kite-main-dist-worktree_kite-distributed-net` | `kite-main-dist-*` |
27
27
  | 本地真实域名双域 Docker | 两套上述单节点 Compose 均叠加 `docker-compose.agentid-federation.yml` | `agentid.pub`、`agentid.cn` | 两域各自固定数据根 | 两个独立 project,共享 `kite-agentid-federation-net` | `kite-app`、`kite-agentid-cn-local-app` 及各自 MySQL/Redis |
28
28
  | 隔离双域 federation | `D:\modelunion\kite\docker-deploy\federation-test\docker-compose.yml` | `dist-aid.com`、`dist-aid.net` | `D:\modelunion\kite\docker-deploy\federation-test\data-dist` | `kite-main-dist-federation` / `kite-main-dist-federation_federation-net` | `main-dist-federation-*`、`main-dist-client-*` |
@@ -47,7 +47,7 @@ Tester 和 cross-SDK 都不是服务端环境:
47
47
 
48
48
  | 路径 | 实际用途 | 本地测试约束 |
49
49
  | --- | --- | --- |
50
- | `docker-deploy/data-agentid-pub/docker-compose.yml` | 历史 `agentid.pub` 生产迁移清单 | 不得启动;当前固定数据真源是 `docker-deploy/data` |
50
+ | `docker-deploy/data-agentid-pub/docker-compose.yml` | 历史 `agentid.pub` 生产迁移清单 | 不得启动;当前应用材料在 `docker-deploy/data`,MySQL 使用下文指定的命名卷 |
51
51
  | `docker-deploy/data-aun-pub/docker-compose.yml` | `aun.pub` 独立服务器部署材料 | 不纳入默认 `agentid.pub` 测试 |
52
52
  | `docker-deploy/evolagent.cn/`、`docker-deploy/data-evolagent-cn/docker-compose.yml` | 历史域部署材料 | 只保留历史线索;当前本地跨域对端是 `agentid.cn`,不得启动这些旧入口 |
53
53
  | `docker-deploy/app/docker-compose.yml` | 生产包展开目录或本机临时副本 | 不作为源码 worktree 的测试真源 |
@@ -55,7 +55,7 @@ Tester 和 cross-SDK 都不是服务端环境:
55
55
 
56
56
  ### 默认单实例测试前强制核验
57
57
 
58
- 每次开始本地单实例测试前,先选择域并执行以下只读检查。材料清单固定了 Issuer CA 指纹、12 个服务 AID 和 MySQL `server-uuid`;Compose 解析结果必须把 MySQL 和应用四个数据挂载全部指向同一域:
58
+ 每次开始本地单实例测试前,先选择域并执行以下只读检查。材料清单核对 Issuer CA 指纹、12 个服务 AID 和原始数据库材料的 `server-uuid`;当前运行库还必须单独核对挂载类型与来源,不能把材料目录校验当作运行库校验:
59
59
 
60
60
  ```powershell
61
61
  $domain = 'agentid.pub' # 校验本地跨域对端时改为 agentid.cn
@@ -65,7 +65,7 @@ docker compose --env-file "$domain\local.env" --project-directory . `
65
65
  -f docker-compose.yml -f "$domain\docker-compose.yml" config --quiet
66
66
  ```
67
67
 
68
- 启动后再核对运行态。下面以 `agentid.pub` 为例;`agentid.cn` 对应前缀是 `kite-agentid-cn-local`,数据根是 `data-agentid-cn`:
68
+ 启动后再核对运行态,沿用上面选择的 `$domain`:
69
69
 
70
70
  ```powershell
71
71
  function Resolve-DockerBindSource([string]$source) {
@@ -74,20 +74,28 @@ function Resolve-DockerBindSource([string]$source) {
74
74
  }
75
75
  [IO.Path]::GetFullPath($source)
76
76
  }
77
- $containers = docker inspect kite-app kite-mysql kite-redis |
78
- ConvertFrom-Json
77
+ $names = if ($domain -eq 'agentid.pub') { @('kite-app','kite-mysql','kite-redis') } else { @('kite-agentid-cn-local-app','kite-agentid-cn-local-mysql','kite-agentid-cn-local-redis') }
78
+ $project = if ($domain -eq 'agentid.pub') { 'kite-single' } else { 'kite-agentid-cn-local' }
79
+ $containers = docker inspect $names | ConvertFrom-Json
79
80
  $badProject = $containers | Where-Object {
80
- $_.Config.Labels.'com.docker.compose.project' -ne 'kite-single'
81
+ $_.Config.Labels.'com.docker.compose.project' -ne $project
81
82
  }
82
83
  if ($badProject) { throw "混入错误 project: $($badProject.Name -join ', ')" }
83
- $mysqlSource = (($containers | Where-Object Name -eq '/kite-mysql').Mounts |
84
- Where-Object Destination -eq '/var/lib/mysql').Source
85
- $expected = (Resolve-Path .\data\mysql).Path
86
- if ((Resolve-DockerBindSource $mysqlSource) -ine $expected) { throw "MySQL 数据根错误: $mysqlSource" }
84
+ $mysqlMount = (($containers | Where-Object Name -eq "/$($names[1])").Mounts |
85
+ Where-Object Destination -eq '/var/lib/mysql')
86
+ if ($domain -eq 'agentid.pub') {
87
+ if ($mysqlMount.Type -ne 'volume' -or $mysqlMount.Name -ne 'org-pub-mysql-logical14-20261023-015854-855e') { throw 'PUB MySQL 命名卷错误' }
88
+ docker volume inspect $mysqlMount.Name --format '{{.Mountpoint}}'
89
+ } else {
90
+ $expected = (Resolve-Path .\data-agentid-cn\mysql-repaired-20260903-v2).Path
91
+ if ($mysqlMount.Type -ne 'bind' -or (Resolve-DockerBindSource $mysqlMount.Source) -ine $expected) { throw "CN MySQL 数据根错误: $($mysqlMount.Source)" }
92
+ }
87
93
  ```
88
94
 
89
95
  Docker Desktop 可能把 Windows bind source 返回为 `/run/desktop/mnt/host/<盘符>/...`;上面的归一化用于避免把当前 worktree 误判成外部目录。
90
96
 
97
+ PUB 当前命名卷的数据在 Docker Desktop 的 Linux 引擎内,`docker volume inspect org-pub-mysql-logical14-20261023-015854-855e` 显示的 Mountpoint 为 `/var/lib/docker/volumes/org-pub-mysql-logical14-20261023-015854-855e/_data`,不是 Windows 外部挂载目录。2026-10-23 从隔离恢复副本完整逻辑导出并导入该干净卷,28 个库、491 张表、2,291,976 行的结构、行数和 checksum、账户权限、消息库四个索引及冷启动核验通过,固定身份和新增业务记录一致。PUB 当前使用 MySQL 8.0.44,域 Compose 设置 `--innodb-purge-threads=1`,本轮合成 purge 负载及冷启动已通过;CN 也已按用户授权设置为 1,正常重启及参数读回通过。这是本地恢复配置,根因尚未确认。此前 25 个废弃故障及诊断卷已按用户授权删除,本轮旧故障卷仍保留,完整逻辑导出和日志保留在 `docker-deploy/test-artifacts/org-20261021/`。原 `docker-deploy/data/mysql` 不得再启动或覆盖;PUB 的域 Compose 命名卷覆盖才是运行真源,不得根据旧 `AUN_MYSQL_DATA_ROOT` 值改回目录挂载。
98
+
91
99
  如果机器上还残留旧 `kite-single` 混合容器,只执行一次 `docker compose --env-file NUL -f docker-compose.yml down` 清理旧容器,不能加 `-v`。不得删除 MySQL/AID 目录,也不得通过 `setup_aids.py` 或清库掩盖环境选错。
92
100
 
93
101
  ## 当前单实例验收基线
@@ -136,7 +144,7 @@ JS 的真实 E2E 统一使用 `js/tests/e2e-browser`,不要把浏览器 E2E
136
144
  - `docker-compose.yml` 是可直接上线的服务端清单,禁止把 SDK Tester、测试源码挂载或测试数据目录加回该文件;服务端与 `docker-compose.testers.yml` 必须分别启动,不能合并为同一个 Compose project。
137
145
  - 分布式与双域测试统一按分布式指南运行,主指南不维护第二套 federation 命令。
138
146
  - Windows Git Bash 运行 `docker exec` / `docker run` 且命令里包含容器内绝对路径(如 `/tests/...`、`/test/...`、`/workspace/...`)时,统一在命令前加 `MSYS_NO_PATHCONV=1`,避免 Git Bash 把容器路径错误改写成宿主机路径。
139
- - 默认单实例 Python Tester 使用 `AUN_TEST_AUN_PATH=/data/aun-fixed-agentid-pub`,对应宿主机 `docker-deploy/data/extended-acceptance/group-management`;这里的 Alice/Bobb/Charlie 证书与 `data/mysql` 中的活动记录配套。
147
+ - 默认单实例 Python Tester 使用 `AUN_TEST_AUN_PATH=/data/aun-fixed-agentid-pub`,对应宿主机 `docker-deploy/data/extended-acceptance/group-management`;这里的 Alice/Bobb/Charlie 证书与 PUB 当前命名卷中从原库逻辑导入的活动记录配套。
140
148
  - **所有语言 SDK 的集成/E2E 测试必须串行运行**。即使各 Tester 使用独立本地数据目录,测试仍会复用服务端固定 AID、群、游标和消息状态;并行运行会造成相互污染。推荐按 Python → TypeScript → Go → JavaScript 的顺序依次运行。
141
149
  - 如果改了 `extensions/services` 下的服务端代码,必须重新 build Docker 镜像并重启对应容器。
142
150
  - 如果只改了各语言 SDK 源码或测试脚本,测试容器/宿主机通常都是目录挂载或直接读取,通常不需要 rebuild 镜像,直接重跑即可。
@@ -324,7 +332,7 @@ docker exec kite-python-sdk-tester sh -lc '
324
332
  - 容器内:`/data/aun-fixed-agentid-pub`
325
333
  - 宿主机:`D:\modelunion\kite\docker-deploy\data\extended-acceptance\group-management`
326
334
 
327
- `docker-compose.testers.yml`、默认单实例固定 AID 测试脚本和本文档都必须以这条路径为唯一真源。`data/sdk-tester-aun/single-domain/persistent` 中的同名 Alice/Bobb/Charlie 是旧证书,不能与当前 `data/mysql` 组合使用;否则登录会返回 `certificate mismatch with server record`。
335
+ `docker-compose.testers.yml`、默认单实例固定 AID 测试脚本和本文档都必须以这条路径为唯一真源。`data/sdk-tester-aun/single-domain/persistent` 中的同名 Alice/Bobb/Charlie 是旧证书,不能与当前 PUB 命名卷中的活动记录组合使用;否则登录会返回 `certificate mismatch with server record`。
328
336
 
329
337
  如果历史目录中还残留 `single-domain/AIDs/...`,应视为旧格式脏数据,不再继续复用,也不要把其中的文件和 `persistent` 目录混拷。
330
338
 
@@ -547,6 +555,24 @@ docker logs cross-sdk-go
547
555
  docker logs cross-sdk-js
548
556
  ```
549
557
 
558
+ #### Storage / Group FS 读缓存专项
559
+
560
+ [缓存矩阵](../tests/cross-sdk/cases.storage-cache.json) 包含 16 场景 × 4 SDK;须用[独立缓存 runner](../tests/cross-sdk/runner/run_storage_cache_e2e.py),通用 runner 不负责这些缓存断言。保持上文的 AID、网络预检变量及四个 test-control 客户端在线,在 SDK 根目录执行;现有 Compose 只挂载通用 runner,下面额外挂载专项入口并选择缓存用例:
561
+
562
+ ```powershell
563
+ $env:CROSS_SDK_CASES_BASENAME = 'cases.storage-cache.json'
564
+ $env:CROSS_SDK_CLIENTS = 'python,ts,go,js'
565
+ $cacheRunnerPath = (Resolve-Path tests/cross-sdk/runner/run_storage_cache_e2e.py).Path
566
+ docker compose -f tests/cross-sdk/docker-compose.cross-sdk.yml run --rm --no-deps `
567
+ -v "${cacheRunnerPath}:/cross-sdk/runner/run_storage_cache_e2e.py:ro" `
568
+ -e ARTIFACT_DIR=/artifacts/storage-cache `
569
+ cross-sdk-runner python /cross-sdk/runner/run_storage_cache_e2e.py
570
+ ```
571
+
572
+ 在最后一行追加 `--list` 只列用例、不连接服务;追加 `--from 'ts/inline-hot'` 从指定 ID(包含该用例)续跑,也可向 runner 传入环境变量 `CROSS_SDK_CACHE_FROM`(Compose 使用 `-e CROSS_SDK_CACHE_FROM=ts/inline-hot`)。runner 首失败立即停止,每次结果独立写到 `tests/cross-sdk/artifacts/storage-cache/attempt-<时间>-<随机后缀>/`,保留失败 ID 和原产物再续跑;恢复通用矩阵时将 `CROSS_SDK_CASES_BASENAME` 改回目标清单。若在其他已具备 `aiohttp` 的环境直接运行,须配置可达的 `PY_CLIENT_URL`、`TS_CLIENT_URL`、`GO_CLIENT_URL`、`JS_CLIENT_URL`,并将 `CROSS_SDK_CASES` 指向缓存清单;未设置 `ARTIFACT_DIR` 时产物默认位于专项 runner 同级的 `artifacts/storage-cache/`。
573
+
574
+ 补充入口:[Python Storage 缓存 E2E](../python/tests/e2e_test_storage_cache.py)、[浏览器 Storage 测试中的读缓存组](../js/tests/e2e-browser/storage.spec.ts)。这些入口的存在不代表矩阵或浏览器全套已通过;本版静态待验差异见 [parity 块⑦](../python/CHANGES_FOR_PARITY.md#块⑦-storage--group-fs-默认读缓存)。
575
+
550
576
  清理测试容器:保持本轮 `CROSS_SDK_*_AID`、`AUN_DOCKER_NETWORK` 和
551
577
  `EXPECTED_GATEWAY_IP` 变量仍在当前 PowerShell 会话;若已换会话,先重新执行上面的 AID
552
578
  初始化与预检初始化块。Compose 必须先完成变量插值才能执行 `down`:
@@ -1203,7 +1229,7 @@ docker logs --since 30m kite-app 2>&1 | Select-String -Pattern "WAL 批量写入
1203
1229
 
1204
1230
  - **Python Tester 随机 `SIGSEGV` 或标准库对象损坏**:先运行“启动 SDK Tester”一节的 `pip check` 和 100 次导入探针,并记录镜像 ID、容器退出码和服务日志。该症状发生在 SDK/RPC 调用前,不能按服务端业务失败处理;确认镜像依赖和 Docker 运行态后,只 recreate Python Tester,固定身份和本地 SQLite 数据必须保留。SDK 0.5.6 不依赖 `sqlcipher3`;若 Tester 中仍安装该原生扩展,应重建镜像移除,而不是继续围绕它补系统依赖。
1205
1231
  - **`message.send does not accept delivery_mode`**:SDK 新版本要求 `delivery_mode` 在 `connect()` 时配置,不能在 `message.send` 参数中传入。测试脚本中的 `”delivery_mode”: {“mode”: “fanout”}` 应从 `message.send` 调用中移除,改到 `make_client()` 或 `connect()` 参数中。
1206
- - **固定证书有效但登录报未激活**:这不是证书格式错误。先核对 MySQL 容器的 Compose project 和 `/var/lib/mysql` mount;agentid.pub 必须指向 `docker-deploy/data/mysql`,agentid.cn 必须指向 `docker-deploy/data-agentid-cn/mysql`。
1232
+ - **固定证书有效但登录报未激活**:这不是证书格式错误。先核对 MySQL 容器的 Compose project 和 `/var/lib/mysql` mount;agentid.pub 必须为 `Type=volume`、`Name=org-pub-mysql-logical14-20261023-015854-855e`,agentid.cn 必须为 `Type=bind`、来源 `docker-deploy/data-agentid-cn/mysql-repaired-20260903-v2`。不要重新启动旧 `data/mysql` 或更换固定身份。
1207
1233
  - **SDK `key.json` 身份私钥解密失败**:先核对 AID、身份目录,以及构造 `AIDStore` 或 SDK 客户端时传入的 `encryption_seed` / `seed_password` 是否与生成 `key.json` 时一致。不要在身份目录中查找或补建 seed 文件。Docker 服务的只读 PEM 身份不使用 seed,应核对证书、私钥、AID 主体和挂载路径。即使确认是临时 AID,删除或重建身份材料也必须先取得用户明确同意,固定身份材料不得改动。
1208
1234
 
1209
1235
  ## 当前边界
@@ -422,7 +422,7 @@ proxy-server 处理 `https://proxy.{issuer}/{user_name}/{svc_name}/...` 或等
422
422
  | `cursor_scope` | ❌ | 旧请求缺省 `global`;新 SDK 使用 `peer`,须有连接能力声明 |
423
423
  | `sender_aid` | peer 必需 | 完整发送方 AID,只返回该对端消息;global 请求不得携带此字段 |
424
424
 
425
- peer Forward 响应另含 `cursor_scope`、`sender_aid`、`scan_after_seq`、`covered_through_seq`、`next_after_seq`、`head_seq`、`server_ack_seq`、`persistent_has_more`、`volatile_has_more`、`has_more`、可选 `next_pending_seq`、`page_need_render_count` 和 `page_non_render_count`。固定可靠 Head 后,扫描 `(scan_after_seq, covered_through_seq]`,下一页使用 `next_after_seq=covered_through_seq`;原 seq 在不同 sender 之间共享,peer 页可稀疏,不能由相邻数字或返回条数推断缺消息。三个 `has_more` 必须为布尔值,且 `has_more = persistent_has_more OR volatile_has_more`。`count` 与两类页内数量按最终返回消息在内存计算,包含本页 volatile,不扫描全部积压;计数不改变扫描范围,不优先过滤可渲染消息。
425
+ peer Forward 响应另含 `cursor_scope`、`sender_aid`、`scan_after_seq`、`covered_through_seq`、`next_after_seq`、`head_seq`、`server_ack_seq`、`persistent_has_more`、`volatile_has_more`、`has_more`、可选 `next_pending_seq`、`page_need_render_count` 和 `page_non_render_count`。固定可靠 Head 后,扫描 `(scan_after_seq, covered_through_seq]`,下一页使用 `next_after_seq=covered_through_seq`;原 seq 在不同 sender 之间共享,peer 页可稀疏,不能由相邻数字或返回条数推断缺消息。三个 `has_more` 必须为布尔值,且 `has_more = persistent_has_more OR volatile_has_more`。`count` 与两类页内数量按最终返回消息在内存计算,包含本页 volatile,不扫描全部积压;计数不改变扫描范围,不优先过滤可渲染消息。 SDK 仅在覆盖证明、可靠提交和游标满足当前需求、两类 more 均为 false 且无未完成确认或期间新通知等责任时结束;more=true 而持久覆盖与 volatile 游标均无进展时,保留需求并以正延迟退避,不能空忙循环。空正文但覆盖或 volatile 游标推进不属于无进展。
426
426
 
427
427
  `next_pending_seq` 是 peer Forward(含 force)的可选调度提示:`persistent_has_more=true` 时,返回本页最终边界之后首条未返回持久投递的原 seq,满足 `covered_through_seq < seq <= head_seq`;无持久更多时省略,only-volatile 仍按 `volatile_has_more` 继续。它直接复用原 `limit+1` 查询和去重合并结果:200 条页取第 201 条,字节截断取第一条未返回持久消息,volatile 混排挤掉持久消息时修正为最终第一条未返回持久 seq,不新增 SQL。Tail/History/旧 global 不增加此字段。正常 Forward 在消息页可靠 commit 后即可将页提示用于排序,不等待 ACK;仅收到响应或 commit 失败不能采用,ACK 未完成或失败保留独立确认责任,拒绝旧/迟到页回退;Tail/force/History 不更新正常调度。非法或缺失的可选提示不使合法消息页失败,不能用 `covered_through_seq+1` 推导,也不参与覆盖、ACK 或完成判断。
428
428
 
@@ -459,7 +459,7 @@ peer Forward 响应另含 `cursor_scope`、`sender_aid`、`scan_after_seq`、`co
459
459
  | `count` | integer | 本次返回的消息条数 |
460
460
  | `latest_seq` | integer | 本次返回的最大 `seq` |
461
461
  | `latest_volatile_cursor` | string\|null | 本页最后一个 volatile 游标;不改变 `latest_seq` |
462
- | `volatile_has_more` | boolean | 是否仍有未返回的 volatile 消息;SDK 在 volatile 游标前进时据此继续分页 |
462
+ | `volatile_has_more` | boolean | Forward 表示是否仍有未返回的 volatile 消息;Tail 为只读继续提示,缺失时按未知处理,不能视为 false |
463
463
  | `volatile_earliest_cursor` | string\|null | 当前 boot epoch 内仍可读取的最早 volatile 游标 |
464
464
  | `volatile_dropped_count` | integer | 当前 boot epoch 内因过期或容量淘汰而不可读的累计数 |
465
465
  | `ephemeral_earliest_available_seq` | integer\|null | 当前临时缓冲中最早可用的 `seq`,`null` 表示无临时消息 |
@@ -469,16 +469,16 @@ peer Forward 响应另含 `cursor_scope`、`sender_aid`、`scan_after_seq`、`co
469
469
 
470
470
  **说明**:持久游标与 volatile 游标独立推进。SDK 只把含正 `seq` 的消息送入持久 tracker;volatile push/pull 按发送方和 `message_id` 去重,交付成功后自动 ACK。SDK 在传输层注入内部 slot,应用不得传入或读取,任何消息、响应和事件都不得包含该字段。epoch 不匹配时 SDK 清空 volatile 游标并重试一次。`message.history` 不返回 volatile 消息。
471
471
 
472
- **Tail 模式**:`window_mode="tail"` 时,服务端固定安全 `head_seq`;global 返回跨度不超过 `limit` 的最新 seq band,peer 按该 sender 最新消息条数取页,seq 跨度可大于 `limit`。额外返回:
472
+ **Tail 模式**:`window_mode="tail"` 时,服务端固定安全 `head_seq`;global 返回跨度不超过 `limit` 的最新 seq band,peer 按该 sender 最新消息条数取页,seq 跨度可大于 `limit`。另返回布尔 `volatile_has_more`:只读探测本次 AID、device、slot、peer 范围内 `after_volatile_cursor` 之后是否仍有可读 volatile 投递,不取回或返回非持久正文,不产生 lease、ACK 或游标变更,不新增 SQL;旧响应缺失该字段时为未知,不能当作 false。额外返回窗口字段:
473
473
 
474
474
  | 字段 | 说明 |
475
475
  |------|------|
476
476
  | `window_mode` | 固定为 `tail` |
477
- | `window_start_seq` | 已扫描窗口的包含式左边界 |
477
+ | `window_start_seq` | 已扫描窗口的包含式左边界;`head_seq<=after_seq` 时为合法追平空窗,`window_start_seq=covered_through_seq=head_seq` 且无持久正文;否则须满足 `after_seq<window_start_seq<=head_seq` |
478
478
  | `head_seq` | 本次请求固定的安全 Head |
479
479
  | `covered_through_seq` | 覆盖终点,正常等于 `head_seq` |
480
480
 
481
- Tail 不推进 ACK、retention/visibility floor、Pull activity 或 catch-up 状态,不接受 `ack_up_to_seq` 或 `force=true`。Tail 使用窗口证明,不要求 Forward 的三个 `has_more` 字段。global seq band 内未返回的序号视为服务端永久空号;peer 仅按服务端覆盖证明合并窗口,不能套用 dense seq 校验。新 SDK 仅在已验证自身 `agent.md.type=human` 时自动优先 Tail 再 Forward;其他或未知类型直接 Forward。无 `window_mode` 的旧 global 请求保持原副作用语义。
481
+ Tail 不推进 ACK、retention/visibility floor、Pull activity 或 catch-up 状态,不接受 `ack_up_to_seq` 或 `force=true`。Tail 使用窗口证明及上述 volatile 提示,不要求 Forward 的 `persistent_has_more/has_more`。global seq band 内未返回的序号视为服务端永久空号;peer 仅按服务端覆盖证明合并窗口,不能套用 dense seq 校验。新 SDK 仅在已验证自身 `agent.md.type=human`、适合实时预览且已知持久 Head 与可靠持久 A 的差值大于本次有效页容量(`limit`)时启用自动 Tail;差值小于等于页容量、纯 volatile 或持久上界未知时直接 Forward。该序号差仅作选路阈值,不表示稀疏 peer 的实际消息数量;已有待补窗口缺口或未完成 Forward 责任时延续 Forward,不重复 Tail;其他或未知类型直接 Forward。自动 Tail 占原总页预算一页,`volatile_has_more=true` 或缺失、durable gap/ACK 未完成或期间有新通知时,使用剩余预算继续 Forward;只有明确 false、可靠 A 覆盖本次 Head 及已知上界、ACK 已确认且期间无新通知时才可结束。预算不足保留未完成责任,不扩大原预算。显式 Tail 不受自动阈值限制,只取单窗,单窗请求返回不代表完整同步。无 `window_mode` 的旧 global 请求保持原副作用语义。
482
482
 
483
483
  #### `message.history`
484
484
 
@@ -31,14 +31,22 @@ Storage 服务是 AUN 协议的应用层扩展,提供对象存储能力。负
31
31
 
32
32
  ## 11.3 控制面方法
33
33
 
34
- **权威对象读取**:`storage.head_object`、`storage.get_object` 和 `storage.fs.stat` 可传 `consistency: authoritative`,绕过正负缓存并确认恢复可用性。结果包含 `consistency`、`exists`、`owner_aid`、`bucket`、规范 `path` 和 Unix 秒 `observed_at`;存在时附摘要及现有对象元数据,get 返回完整严格 Base64 `content`。故障、权限错误和恢复未完成不得返回 `exists=false`;下载或网关 404 不能证明权威不存在。
34
+ **权威对象读取**:`storage.head_object`、`storage.get_object` 和 `storage.fs.stat` 可传 `consistency: authoritative`,绕过正负缓存并确认恢复可用性。结果包含 `consistency`、`exists`、`owner_aid`、`bucket`、规范 `path` 和 Unix 秒 `observed_at`;存在时附摘要及现有对象元数据,get 返回完整严格 Base64 `content`。故障、权限错误和恢复未完成不得返回 `exists=false`;下载或网关 404 不能证明权威不存在。
35
35
 
36
36
 
37
37
 
38
- 规范 `default/agent.md` 与 `default/sub_aids/{sub_aid}/owner.md` 的上传会话使用独立临时对象,`create_upload_session` 返回 `session_id`;新客户端完成这些规范文件时必须携带同一 `session_id`。服务端核对会话的认证申请者、目标及有效期,验证完整内容后原子发布,失败保留旧完整文件。普通对象保持既有上传流程,不保证返回 `session_id`;该临时会话不记录 Ownership 关系事实或路径历史。
39
-
38
+ 规范 `default/agent.md` 与 `default/sub_aids/{sub_aid}/owner.md` 的上传会话使用独立临时对象,`create_upload_session` 返回 `session_id`;新客户端完成这些规范文件时必须携带同一 `session_id`。服务端核对会话的认证申请者、目标及有效期,验证完整内容后原子发布,失败保留旧完整文件。普通对象保持既有上传流程,不保证返回 `session_id`;该临时会话不记录 Ownership 关系事实或路径历史。
39
+
40
40
  Ownership 2.1 的 `default/sub_aids/{sub_aid}/owner.md` 必须公开可读,只有命名空间所属 owner 可修改、删除;该限制覆盖 ACL、token、父目录、移动、重命名、软链、挂载及自动清理,不能由通用权限顺序放宽。关系释放仍以 NS 验收为准;完整规则见 [Ownership 协议定义 2.1](Ownership协议定义2.1.md)。
41
41
 
42
+ ### 读取条件与缓存策略
43
+
44
+ 普通 `storage.get_object`、`storage.get_by_share` 和 `storage.create_download_ticket` 可接受 `if_sha256`(完整对象的 64 位十六进制 SHA-256)。服务端仍执行本次访问授权;摘要匹配时可返回对象元数据、`not_modified: true` 并省略正文或下载票据。该响应仅表示正文未变化,不等于 HTTP 304。SDK 只有在同一缓存键下持有摘要匹配且已验证的完整正文时,才能复用正文;无可用正文时必须重新请求完整内容。
45
+
46
+ 读取响应可返回 `read_cache`:`reusable` 表示响应可否复用,`inline` 表示是否允许缓存完整正文,`max_age_ms` 是有效期上限,`max_inline_bytes` 是服务端 inline 正文大小上限。显式允许策略须 `reusable: true`,正文还须 `inline: true`;省略 `max_age_ms` 时默认 60 秒,有限正数最多使用 60 秒;显式禁止、null/非正数/非法 TTL 均不得复用。`read_cache` 缺省或为 `null` 时,SDK 默认缓存元数据及不超过 65,536 字节、摘要已验证的完整正文 60 秒。服务端返回的 TTL 不得超过对象有效期或本次访问授权有效期,并须扣除本次授权/对象解析所用元数据的已缓存年龄及解析耗时,使元数据可能陈旧时间与 SDK 可复用时间之和不超过 60 秒;服务端正缓存内部同样封顶 60 秒。
47
+
48
+ 有限次 token、ACL 或分享授权的 inline 读取只有返回正文才计次;inline 和大对象匹配 `if_sha256`、仅返回无正文 `not_modified` 均不计次,额度耗尽后仍允许该条件验证。SDK 本地正文缓存命中不请求 Storage,因此不计次;HEAD 等纯元数据查询不计次。联网条件验证仍检查撤销、过期、身份和权限,不能借 SHA 绕过这些检查。限次授权可按 `read_cache` 缓存,TTL 受授权和对象有效期限制。大对象按下载授权计次:非 `not_modified` 请求签发下载 URL 或授权 302 时计一次,直接复用已签发的正文下载 URL 属于同次授权;再次向 Storage 申请 URL/授权跳转按新授权计次;Storage 不代理外部 OSS 正文,因此该计数不是 OSS 实际 GET 次数。范围参数错误、正文读取失败、下载 URL/票据准备失败不扣次;`storage.get_object_url` 仅返回稳定地址,不计次,权限和额度预检保持。响应准备成功后发生网络中断,不承诺退回次数。
49
+
42
50
  ### `storage.put_object`
43
51
 
44
52
  内联写入小对象(≤ 内联上限)。
@@ -75,12 +83,15 @@ Ownership 2.1 的 `default/sub_aids/{sub_aid}/owner.md` 必须公开可读,只
75
83
  | `owner_aid` | string | ❌ | 默认调用者 AID |
76
84
  | `bucket` | string | ❌ | 默认 `"default"` |
77
85
  | `object_key` | string | ✅ | 对象路径 |
86
+ | `if_sha256` | string | ❌ | 完整对象摘要条件;匹配时可返回 `not_modified: true` 并省略正文 |
78
87
  | `consistency` | string | ❌ | 传 `authoritative` 时绕过缓存并返回完整权威对象 |
79
88
 
80
- **响应**:`{ owner_aid, bucket, object_key, content (base64), content_type, size_bytes, sha256, version, updated_at }`
89
+ **响应**:`{ owner_aid, bucket, object_key, content (base64, 可省略), content_type, size_bytes, sha256, version, updated_at, read_cache, not_modified }`
81
90
 
82
91
  可选 `consistency: authoritative` 返回本节定义的权威对象结果;权威 get 要求完整对象,不接受范围读取。
83
92
 
93
+ `not_modified: true` 仅在带有匹配 `if_sha256` 时返回;响应仍须包含当前对象摘要及可用缓存策略。
94
+
84
95
  **权限**:私有对象仅所有者可读;公开对象(`is_private=false`)任何 AID 可读。
85
96
 
86
97
  ### `storage.head_object`
@@ -89,20 +100,28 @@ Ownership 2.1 的 `default/sub_aids/{sub_aid}/owner.md` 必须公开可读,只
89
100
 
90
101
  **参数**:同 `get_object`。
91
102
 
92
- **响应**:`{ owner_aid, bucket, object_key, content_type, size_bytes, sha256, version, etag, is_private, expire_at, created_at, updated_at }`
103
+ **响应**:`{ owner_aid, bucket, object_key, content_type, size_bytes, sha256, version, etag, is_private, expire_at, created_at, updated_at, read_cache }`
93
104
 
94
105
  可选 `consistency: authoritative` 返回本节定义的权威对象结果,包括明确当前不存在。
95
106
 
107
+ HEAD 不返回正文,也不消耗 token、ACL 或分享的读取次数。
108
+
96
109
  **权限**:同 `get_object`。
97
110
 
98
111
  ### `storage.delete_object`
99
112
 
100
113
  删除单个对象。
101
114
 
102
- **参数**:对象寻址同 `get_object`。
115
+ **参数**:对象寻址同 `get_object`,另有:
116
+
117
+ | 参数 | 类型 | 必需 | 说明 |
118
+ |------|------|:----:|------|
119
+ | `expected_version` | integer | ❌ | 非负 JSON 整数版本 CAS;缺省保持无条件删除 |
103
120
 
104
121
  **响应**:`{ deleted (bool), owner_aid, object_key }`。
105
122
 
123
+ 提供 `expected_version` 时,`0` 仅匹配对象不存在并返回 `deleted: false`;正整数仅匹配当前对象版本并删除。对象存在性或版本与条件不符、检查后对象被替换导致 CAS 失败时返回 `-32009`(Version conflict);不提供时保持既有无条件删除语义。字符串、浮点数、布尔值及负数不是合法版本条件。收到 `-32009` 后,先权威读取当前对象及原件摘要;目标已不是本任务原件时停止删除,不得改用新版本号自动重试。请求结果未知时,先核对目标是否已删除,再决定是否重放原条件请求。
124
+
106
125
  **权限**:仅所有者可删。
107
126
 
108
127
  **副作用**:成功后发布 `event/storage.object_changed`(`action: "delete"`)。
@@ -204,7 +223,7 @@ Ownership 2.1 的 `default/sub_aids/{sub_aid}/owner.md` 必须公开可读,只
204
223
  | `size_bytes` | integer | ❌ | 期望大小,服务端校验 |
205
224
  | `expire_in_seconds` | integer | ❌ | 过期时间,默认永不过期 |
206
225
  | `metadata` | object | ❌ | 用户自定义元数据 |
207
- | `expected_version` | integer | ❌ | CAS 并发控制 |
226
+ | `expected_version` | integer | ❌ | CAS 并发控制 |
208
227
  | `session_id` | string | ❌ | 规范 agent.md/owner.md 新上传必须沿用 create_upload_session 返回的同一会话 |
209
228
 
210
229
  **响应**:`{ owner_aid, bucket, object_key, size_bytes, content_type, sha256, version, etag, updated_at }`
@@ -222,9 +241,12 @@ Ownership 2.1 的 `default/sub_aids/{sub_aid}/owner.md` 必须公开可读,只
222
241
  | `owner_aid` | string | ❌ | 默认调用者 AID |
223
242
  | `bucket` | string | ❌ | 默认 `"default"` |
224
243
  | `object_key` | string | ✅ | 对象路径 |
244
+ | `if_sha256` | string | ❌ | 完整对象摘要条件;匹配时可返回 `not_modified: true` 并省略下载票据 |
225
245
  | `expire_in_seconds` | integer | ❌ | URL 有效期,默认 3600 秒 |
226
246
 
227
- **响应**:`{ download_url, expire_at, file_name, size_bytes, content_type, sha256, version, etag }`
247
+ **响应**:`{ download_url, expire_at, file_name, size_bytes, content_type, sha256, version, etag, read_cache, not_modified }`
248
+
249
+ 下载票据路径由 `create_download_ticket` 和 HTTP GET 组成。SDK 可在该路径与 `get_object` 入口间复用尚有效且摘要已验证的 inline 大小完整正文;没有可用正文时,必须获取新的下载票据并完成 HTTP 下载。票据 URL、token 和响应头不作为可长期复用的对象正文缓存。
228
250
 
229
251
  **权限**:私有对象仅所有者;公开对象任何 AID 可申请。
230
252