# AWOS v0.2：Shared System 对外 API 与数据结构定义

状态：外部 API 规格 / 对接基线  
适用范围：Node local callers、`shared_client / SDK`、Shared Service 服务端实现、联调测试  
关联文档：

- `docs/shared-system/01-architecture-v0.2.md`
- `docs/shared-system/02-shared-db-schema.md`
- `docs/shared-system/03-shared-service-contracts.md`
- `docs/shared-system/04-shared-implementation-plan.md`
- `docs/shared-system/05-db9-mem9-adoption-notes.md`

---

## 1. 文档目标

本文档是 Shared System 的“对外接口定义稿”，目标不是解释内部实现，而是给下面几类角色一个统一 contract：

- Node Local Team
- Shared Team
- SDK / client 实现方
- 集成测试与联调同学

本文档回答：

1. Shared Service 对外到底暴露哪些 API
2. 每个 API 的请求头、请求体、响应体怎么定义
3. 对外暴露的数据结构长什么样
4. 幂等、分页、错误码、时间格式、枚举值怎么统一
5. 哪些字段属于稳定对外 contract，哪些只是内部实现细节

注意：

- 本文档只定义 Shared Service facade 的外部 API
- 不定义 Shared Service 内部 `mem9_client` 的具体调用实现
- 不直接暴露 mem9 hosted API 原始 contract
- 不覆盖 storage schema，storage schema 以 `02-shared-db-schema.md` 为准

---

## 2. API 总体约定

## 2.1 Base URL 与版本

第一阶段统一使用：

- Base URL：`/api/v1`

推荐对外路由分组：

- `/api/v1/identity/*`
- `/api/v1/memory/*`
- `/api/v1/capabilities/*`
- `/api/v1/promotion/*`
- `/api/v1/system/*`

## 2.2 认证与请求头

除 health/system 自检类接口外，所有业务接口建议带：

```http
Authorization: Bearer <shared-service-token>
X-Shared-Org-Id: <org_id>
X-Shared-Node-Id: <node_id>
X-Shared-Person-Id: <person_id>
X-Request-Id: <request_id>
Idempotency-Key: <idempotency_key>   # 仅写接口要求
Content-Type: application/json
```

字段说明：

- `Authorization`
  - Shared Service 的统一服务认证
- `X-Shared-Org-Id`
  - 组织隔离边界
- `X-Shared-Node-Id`
  - 节点身份标识
- `X-Shared-Person-Id`
  - 节点所属人员标识
- `X-Request-Id`
  - 用于链路追踪与审计
- `Idempotency-Key`
  - 用于写接口去重与重复投递保护

## 2.3 时间格式

统一使用 RFC3339 / ISO-8601 UTC 字符串，例如：

```text
2026-04-21T09:30:45Z
```

## 2.4 ID 命名约定

第一阶段不强制所有 ID 的底层实现方式，但建议对外保持可读前缀：

- `node_...`
- `person_...`
- `mem_...`
- `cap_...`
- `space_...`
- `req_...`
- `promo_...`

## 2.5 分页约定

对 list/search 类接口建议统一：

```yaml
pagination:
  limit: integer
  cursor: string|null
  has_more: boolean
  next_cursor: string|null
```

第一阶段如果实现上暂时用 offset，也建议不要把 offset 暴露成最终长期 contract，优先对外暴露 cursor 风格。

## 2.6 统一响应 envelope

所有 facade API 建议返回统一 envelope：

```yaml
service_result:
  ok: boolean
  operation: string
  changed: boolean
  result: object|null
  error: error_object|null
  meta:
    request_id: string
    downstream: string|null
    cursor: string|null
    next_cursor: string|null
    has_more: boolean|null
```

### `error_object`

```yaml
error_object:
  code: string
  message: string
  retryable: boolean
  details: object|null
```

## 2.7 错误码集合

第一阶段建议统一错误码：

- `validation_error`
- `not_found`
- `conflict`
- `permission_error`
- `idempotency_conflict`
- `storage_error`
- `embedding_error`
- `downstream_unavailable`
- `rate_limited`
- `not_supported`

---

## 3. 对外核心数据结构

## 3.1 `node_identity`

```yaml
node_identity:
  node_id: string
  person_id: string
  display_name: string
  role_label: string
  team_label: string
  status: active | disabled | archived
  metadata: object|null
  created_at: string
  updated_at: string
```

## 3.2 `shared_memory_space_summary`

这是 Shared Memory 的外部配置摘要对象，用于表达“当前 org 对接哪种 memory backend”。

注意：

- 它只表达 backend routing 配置
- 它不表达 memory ownership
- memory entry 的业务 ownership 以 `person` 为主

```yaml
shared_memory_space_summary:
  space_id: string
  org_id: string
  provider: mem9_hosted
  api_base_url: string
  mode: managed | self_hosted
  status: active | disabled | archived
  default_agent_id: string|null
  created_at: string
  updated_at: string
```

注意：

- 不对外返回 API key
- 不对外返回 secret ref

## 3.3 `shared_memory_entry`

```yaml
shared_memory_entry:
  entry_id: string
  owner_person_id: string
  owner_team_label: string|null
  content: string
  summary: string|null
  content_type: summary | decision | risk | question | handoff_note | status_snapshot | insight
  tags:
    - string
  source_node_id: string
  source_role_label: string|null
  source_team_label: string|null
  source_task_id: string|null
  source_container_id: string|null
  write_reason: string|null
  revision: integer
  state: active | archived | deleted | superseded
  score: number|null
  confidence: integer|null
  relative_age: string|null
  created_at: string
  updated_at: string
```

说明：

- `entry_id` 是 Shared Service 对外的稳定 memory id
- `owner_person_id` 表达 memory 的业务 owner；node 迁移后记忆仍归同一个人
- `owner_team_label` 用于 team 维度查询
- 底层可以映射到 mem9 hosted memory object
- AWOS-specific 字段由 Shared Service facade 统一补齐和回填
- visibility 先不外露，第一阶段默认都是 org 内公开可查

## 3.4 `shared_memory_entry_summary`

用于列表和候选场景：

```yaml
shared_memory_entry_summary:
  entry_id: string
  owner_person_id: string
  owner_team_label: string|null
  summary: string|null
  content_type: string|null
  source_node_id: string
  source_task_id: string|null
  revision: integer
  state: string
  score: number|null
  updated_at: string
```

## 3.5 `shared_capability_package_summary`

```yaml
shared_capability_package_summary:
  package_id: string
  title: string
  slug: string
  summary: string
  revision: integer
  status: active | superseded | archived
  source_node_id: string
  creator_person_id: string
  score: number|null
  updated_at: string
```

## 3.6 `shared_capability_package_detail`

```yaml
shared_capability_package_detail:
  package_id: string
  title: string
  slug: string
  summary: string
  revision: integer
  status: active | superseded | archived
  source_node_id: string
  creator_person_id: string
  source_local_package_id: string
  package_hash: string
  frontmatter: object
  body_markdown: string
  skill_refs:
    - shared_skill_ref
  input_contract: object|null
  output_contract: object|null
  onboarding_template: string|null
  created_at: string
  updated_at: string
  archived_at: string|null
```

其中：

- `frontmatter` 面向机器，用于 discover / filter / routing / contract 判断
- `body_markdown` 面向人和 Agent，用于 mount 后实际消费
- `skill_refs` 只描述依赖关系，真正的高级 skill 内容由 `shared_skill_assets` 承接



## 3.7 `shared_skill_ref`

```yaml
shared_skill_ref:
  ref_id: string
  skill_id: string
  source_type: builtin | shared_asset | external
  version: string
  required: boolean
  mount_mode: reference | snapshot
```

说明：

- `skill_refs` 不再只是 skill 名字列表
- 它表达 package 对 skill 的结构化依赖关系
- 如果 skill 是 agent 动态构建的共享资产，`source_type` 应为 `shared_asset`

## 3.8 `shared_skill_asset`

```yaml
shared_skill_asset:
  asset_id: string
  org_id: string
  title: string
  slug: string
  source_type: builtin_ref | uploaded | agent_generated | imported
  format: hermes_skill_md | markdown | yaml | json | python | bundle
  content_text: string|null
  content_json: object|null
  content_hash: string
  version: integer
  author_node_id: string
  author_person_id: string|null
  status: active | archived
  created_at: string
  updated_at: string
```

用途：

- 存真正可共享的 skill 内容或快照
- 支持 agent 动态构建 skill 的版本化与复用

## 3.9 `promotion_result`

```yaml
promotion_result:
  promotion_id: string
  action: ignore | create_shared | update_shared
  reason: string
  shared_package_id: string|null
  revision: integer|null
  created_at: string
```

---

## 4. 系统级接口

## 4.1 `GET /api/v1/system/health`

用途：

- 健康检查
- 负载均衡探活

使用场景：

- k8s / SLB / ingress 探活
- 联调时快速确认 Shared Service 是否存活

响应：

```json
{
  "ok": true,
  "operation": "health_check",
  "changed": false,
  "result": {
    "status": "ok",
    "service": "shared_service",
    "version": "v0.2",
    "time": "2026-04-21T09:30:45Z"
  },
  "error": null,
  "meta": {
    "request_id": "req_health_001",
    "downstream": null,
    "cursor": null,
    "next_cursor": null,
    "has_more": null
  }
}
```

## 4.2 `GET /api/v1/system/capabilities`

认证：

- 与 health 一样，作为 system 自检/feature detection 接口，对外公开可访问
- 不要求业务 bearer token，也不要求 org/node/person 头

用途：

- 返回当前 Shared Service 对外启用的能力摘要
- 方便 SDK 或联调脚本做 feature detection

使用场景：

- SDK 初始化时判断 imports / session 等可选能力是否启用
- staging / prod 环境能力不一致时做兼容
- 管理或调试脚本快速检查当前实例支持哪些 API

结果建议：

```yaml
system_capabilities_result:
  memory_backend: mem9_hosted
  memory_modes:
    - managed
  apis:
    - identity
    - memory
    - capabilities
    - promotion
  features:
    memory_write: true
    memory_recall: true
    memory_imports: true|false
    memory_sessions: true|false
    capability_discover: true
    promotion: true
```

---

## 5. Identity API

## 5.1 `POST /api/v1/identity/nodes`

用途：

- 注册或幂等更新 node identity

使用场景：

- 新 node 首次接入 Shared Service
- 同一人的 node 迁移后，新的 node 重新完成 identity 绑定
- node 的角色/team 变更后做幂等更新

请求：

```yaml
register_node_request:
  node_id: string
  person_id: string
  display_name: string
  role_label: string
  team_label: string
  metadata: object|null
```

结果：

```yaml
register_node_result:
  node: node_identity
  created: boolean
```

语义：

- 不存在：create
- 已存在且内容相同：`changed=false`
- 已存在且内容不同：update + `changed=true`

## 5.2 `GET /api/v1/identity/nodes/{node_id}`

用途：

- 获取指定 node 的完整 identity

使用场景：

- Node local 初始化时做自检
- 管理后台或联调用于排查某个 node 的归属关系

结果：

```yaml
get_node_result:
  node: node_identity
```

## 5.3 `PATCH /api/v1/identity/nodes/{node_id}/status`

使用场景：

- 某个 node 退役、禁用或被替换时更新状态
- 管理后台做节点治理

请求：

```yaml
update_node_status_request:
  status: active | disabled | archived
```

结果：

```yaml
update_node_status_result:
  node_id: string
  status: string
  updated_at: string
```

## 5.4 `GET /api/v1/identity/memory-space`

用途：

- 获取当前 org 对应的 Shared Memory backend 配置摘要

使用场景：

- 管理后台查看当前 org 路由到哪套 memory backend
- 联调或排障时确认当前 org 是否有 active mem9 space

说明：

- 这不是业务主链接口
- 正常 memory 写入/查询时，调用方不需要先手动调用它

结果：

```yaml
get_shared_memory_space_result:
  space: shared_memory_space_summary
```

---

## 6. Shared Memory API

## 6.1 `POST /api/v1/memory/write-context`

用途：

- 给写入决策提供规范化上下文与候选项
- 常用于 Agent 决定 create / update / ignore 之前

使用场景：

- `task_completed` 后 deciding 是否沉淀一条 shared memory
- `session_end` / reflection job 在正式写入前先查重和取候选

说明：

- 这是高级辅助接口
- 不是所有集成方都必须使用

请求：

```yaml
prepare_write_context_request:
  trigger: string
  node_identity:
    node_id: string
    person_id: string
    role_label: string
    team_label: string
  runtime_context:
    task_id: string|null
    container_id: string|null
    current_summary: string|null
    source_messages:
      - role: string
        content: string
  policy:
    allow_content_types:
      - string
    deny_content_types:
      - string
    visibility_default: org_internal
```

结果：

```yaml
prepare_write_context_result:
  normalized_context: object
  existing_candidates:
    - shared_memory_entry_summary
  recommended_action: create | update | ignore
```

## 6.2 `POST /api/v1/memory/entries`

用途：

- 创建一条 Shared Memory

使用场景：

- 某项任务完成后，把稳定结论沉淀成共享记忆
- 用户 node 迁移后，新的 node 仍然可以继续为同一个 person 写入记忆

请求：

```yaml
create_shared_memory_request:
  content: string
  content_type: summary | decision | risk | question | handoff_note | status_snapshot | insight
  summary: string|null
  tags:
    - string
  source_node_id: string
  owner_person_id: string
  source_role_label: string|null
  source_team_label: string|null
  source_task_id: string|null
  source_container_id: string|null
  write_reason: string|null
  source_kind: string|null
```

结果：

```yaml
create_shared_memory_result:
  entry: shared_memory_entry
  stored_in: mem9_hosted
```

## 6.3 `GET /api/v1/memory/entries/{entry_id}`

用途：

- 获取指定 Shared Memory 详情

使用场景：

- recall 命中后再拉完整正文
- 审计/调试某一条 memory 的详情

结果：

```yaml
get_shared_memory_result:
  entry: shared_memory_entry
```

## 6.4 `POST /api/v1/memory/entries/search`

用途：

- 搜索 / recall Shared Memory

使用场景：

- person 查询自己历史共享记忆（跨 node 延续）
- team 成员按 team 维度互查共享记忆
- mount / planning / reflection 阶段检索可复用上下文

请求：

```yaml
recall_shared_memory_request:
  query: string
  limit: integer
  cursor: string|null
  recall_mode: hybrid | text_only | vector_only
  content_types:
    - string
  source_node_ids:
    - string
  owner_person_ids:
    - string
  team_labels:
    - string
  include_archived: boolean
```

结果：

```yaml
recall_shared_memory_result:
  entries:
    - shared_memory_entry
  recall_meta:
    downstream: mem9_hosted
    mode_used: hybrid | text_only | vector_only
    degraded: boolean
```

分页字段通过 envelope `meta` 返回。

## 6.5 `POST /api/v1/memory/entries/{entry_id}/update`

用途：

- 更新一条 Shared Memory
- 语义上推荐新 revision / supersede previous

使用场景：

- 原有 shared memory 被新的稳定结论修正
- postmortem / reflection 后补充更完整的版本

请求：

```yaml
update_shared_memory_request:
  new_content: string
  new_summary: string|null
  new_tags:
    - string
  supersede_previous: boolean
  update_reason: string|null
```

结果：

```yaml
update_shared_memory_result:
  entry: shared_memory_entry
  previous_entry_id: string|null
  archived_previous: boolean
```

## 6.6 `POST /api/v1/memory/entries/{entry_id}/archive`

用途：

- 归档一条 Shared Memory

使用场景：

- 旧结论失效
- 被新 revision 替代
- 管理或治理流程需要下线某条共享记忆

请求：

```yaml
archive_shared_memory_request:
  reason: string
```

结果：

```yaml
archive_shared_memory_result:
  entry_id: string
  state: archived
  archived_at: string
```

## 6.7 `POST /api/v1/memory/imports`

用途：

- 对外暴露 memory import 能力
- 是否启用以系统能力开关和 hosted API 实际支持为准

使用场景：

- 批量导入复盘文档、playbook、外部文章等共享知识
- 把已有知识材料导入 Shared Memory 以供后续 recall

请求：

```yaml
create_memory_import_request:
  source_type: file | url | text_bundle
  source_ref: string
  tags:
    - string
  metadata: object|null
```

结果：

```yaml
create_memory_import_result:
  import_id: string
  status: pending | running | completed | failed
  downstream: mem9_hosted
```

## 6.8 `GET /api/v1/memory/session-messages`

用途：

- 对外暴露 session-related retrieval
- 一期建议作为 capability-gated 接口，不保证默认启用

使用场景：

- 调试某个 session 的原始消息上下文
- import / memory 生成链的排障

说明：

- 不是 Shared Memory 主业务接口
- 以 hosted mem9 API 的实际可用能力为准

查询参数建议：

- `session_id`
- `limit`
- `cursor`

结果：

```yaml
list_session_messages_result:
  messages:
    - id: string
      session_id: string
      role: string
      content: string
      content_type: string
      tags:
        - string
      created_at: string
```

如果当前系统未启用或 hosted API 不支持，应返回：

```yaml
error:
  code: not_supported
  retryable: false
```

---

## 7. Shared Capability API

## 7.1 `POST /api/v1/capabilities`

用途：

- 直接创建一条 Shared Capability Package

使用场景：

- 管理后台手工创建共享能力包
- 批量导入、迁移、运营维护
- 内部服务在已经完成“共享化重写”后直接落库

说明：

- 这不是常规主业务入口
- 对多数业务主链，更推荐走 `promote_local_package`

请求：

```yaml
create_shared_capability_request:
  title: string
  slug: string
  summary: string
  frontmatter: object
  body_markdown: string
  skill_refs:
    - shared_skill_ref
  input_contract: object|null
  output_contract: object|null
  onboarding_template: string|null
  creator_person_id: string
  source_node_id: string
  source_local_package_id: string
```

结果：

```yaml
create_shared_capability_result:
  package: shared_capability_package_detail
```

## 7.2 `GET /api/v1/capabilities/{package_id}`

用途：

- 获取 Shared Capability Package 详情

使用场景：

- discover 命中后读取完整内容
- mount 前获取 `frontmatter`、`body_markdown`、`skill_refs`、contract 信息

结果：

```yaml
get_shared_capability_result:
  package: shared_capability_package_detail
```

## 7.3 `POST /api/v1/capabilities/{package_id}/update`

用途：

- 直接更新一条 Shared Capability Package

使用场景：

- 管理台修订 package
- 内部迁移/运营任务手工更新共享包

请求：

```yaml
update_shared_capability_request:
  title: string|null
  summary: string|null
  frontmatter: object|null
  body_markdown: string|null
  skill_refs:
    - shared_skill_ref
  input_contract: object|null
  output_contract: object|null
  onboarding_template: string|null
  update_reason: string|null
```

结果：

```yaml
update_shared_capability_result:
  package: shared_capability_package_detail
  previous_package_id: string|null
```

## 7.4 `POST /api/v1/capabilities/{package_id}/archive`

用途：

- 下线一条 Shared Capability Package

使用场景：

- package 被新版替代
- package 不再适合继续复用

请求：

```yaml
archive_shared_capability_request:
  reason: string
```

结果：

```yaml
archive_shared_capability_result:
  package_id: string
  status: archived
  archived_at: string
```

## 7.5 `POST /api/v1/capabilities/search`

用途：

- discover Shared Capability Package

使用场景：

- Node local 在匹配可复用 package 时查询
- 管理后台搜索已有共享包

请求：

```yaml
discover_shared_capability_request:
  query: string
  limit: integer
  cursor: string|null
  include_archived: boolean
  tags:
    - string
  task_type: string|null
```

结果：

```yaml
discover_shared_capability_result:
  candidates:
    - shared_capability_package_summary
```


## 7.6 `GET /api/v1/capabilities/skill-assets/{asset_id}`

用途：

- 获取一个共享 skill 资产的详情或快照

使用场景：

- mount package 时需要拉取 agent 动态生成的 skill 正文
- 管理后台查看某个 shared skill asset 的版本内容

结果：

```yaml
get_shared_skill_asset_result:
  asset:
    asset_id: string
    org_id: string
    title: string
    slug: string
    source_type: builtin_ref | uploaded | agent_generated | imported
    format: hermes_skill_md | markdown | yaml | json | python | bundle
    content_text: string|null
    content_json: object|null
    content_hash: string
    version: integer
    author_node_id: string
    author_person_id: string|null
    status: active | archived
    created_at: string
    updated_at: string
```

---

## 8. Promotion API

## 8.1 `POST /api/v1/promotion/local-packages`

用途：

- 把 `Local Capability Package` 升格为 `Shared Capability Package`

使用场景：

- package agent 在任务完成后判断某个 local package 是否值得共享
- 业务主链把“本地沉淀”提升为“共享复用资产”

说明：

- 这是 `Shared Capability Package` 的主业务入口
- 与 `create_shared_capability` 不是同一层：promotion 负责决策，create 负责直接落库

请求：

```yaml
promote_local_package_request:
  local_package:
    package_id: string
    title: string
    summary: string
    frontmatter: object
    body_markdown: string
    source_node_id: string
    creator_person_id: string
    package_hash: string
  task_capability_summary: object|null
  strategy:
    allow_create: boolean
    allow_update: boolean
```

结果：

```yaml
promote_local_package_result:
  promotion: promotion_result
```

---

## 9. 幂等与重试建议

## 9.1 必须支持 `Idempotency-Key` 的接口

- `POST /api/v1/identity/nodes`
- `POST /api/v1/memory/entries`
- `POST /api/v1/memory/entries/{entry_id}/update`
- `POST /api/v1/memory/entries/{entry_id}/archive`
- `POST /api/v1/capabilities`
- `POST /api/v1/capabilities/{package_id}/update`
- `POST /api/v1/capabilities/{package_id}/archive`
- `POST /api/v1/promotion/local-packages`

## 9.2 客户端重试建议

Node local SDK 建议：

- 对 `downstream_unavailable`、`rate_limited` 做有限重试
- 对 `validation_error`、`permission_error`、`not_supported` 不重试
- 对写接口重试时必须复用同一个 `Idempotency-Key`

---

## 10. 对外 contract 与内部实现的边界

下面这些属于稳定对外 contract：

- 路由
- 请求头要求
- envelope 结构
- 核心数据模型字段名
- 错误码
- 幂等语义

下面这些不属于稳定对外 contract：

- mem9 hosted API 的底层 path
- mem9 的原始字段名与 query 细节
- Shared Service 内部如何做 metadata 映射
- 底层 storage schema 与 index 细节
- 是否使用 db9/SQLite/mock adapter 做本地实现

---

## 11. 最终结论

1. Shared System 的外部 API 统一由 Shared Service facade 暴露
2. Node local 只认 `/api/v1/*` 的 shared contract，不直接接第三方 memory backend
3. Shared Memory 的业务 ownership 以 `person` 为主，默认在 org 内公开可查
4. `shared_memory_spaces` 只是 backend routing 配置，不是 memory ownership 模型
5. `skill_refs` 已升级为高级结构，agent 生成的 skill 通过 `shared_skill_assets` 承接
6. 后续如果实现细节变化，只要不破坏本文定义的请求头、路由、envelope 和核心对象字段，就不视为外部 contract 破坏
