Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ AgentHub lets you collaborate with human teammates and AI agents in the same gro

## Quick Start

Minimal local bootstrap (5 steps). Requires OpenSSL, Docker, Go 1.26+, Node 22+/corepack, pnpm 10+.
Minimal local bootstrap (5 steps). Requires OpenSSL, Docker, Go 1.26+, Node 24+/corepack, pnpm 10+.

```bash
cp .env.example .env && secret="$(openssl rand -hex 32)" && sed -i.bak "s/^AGENTHUB_JWT_SECRET=.*/AGENTHUB_JWT_SECRET=$secret/" .env && rm -f .env.bak && export AGENTHUB_JWT_SECRET="$secret" && unset secret # 1. Copy config and generate a random dev secret
Expand Down
3 changes: 2 additions & 1 deletion api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ api/
├── README.md # API 总入口
├── conventions.md # 命名、分页、错误、权限、版本
├── openapi.yaml # REST API 路径总表和基础契约
├── dispatch.md # Hub→Edge dispatch、admission、execution intent、callback ownership
└── events.md # WebSocket event envelope、源码 owner、事件族和验收边界
```

`openapi.yaml` 只描述 REST API。WebSocket 的 envelope、frame、事件族、源码 owner 和验收边界写在 `events.md`;完整事件常量由 `edge-server/internal/adapters/adapter.go`、`hub-server/internal/ws/frame.go` 和 shared transcript tests 守住。业务解释、权威边界和架构背景写进 `docs/`,不要塞进 OpenAPI。
`openapi.yaml` 只描述 REST API。跨 Hub→Edge 的 dispatch、admission、execution intent 与 callback ownership 语义见 `dispatch.md`。WebSocket 的 envelope、frame、事件族、源码 owner 和验收边界写在 `events.md`;完整事件常量由 `edge-server/internal/adapters/adapter.go`、`hub-server/internal/ws/frame.go` 和 shared transcript tests 守住。业务解释、权威边界和架构背景写进 `docs/`,不要塞进 OpenAPI。

## 产品术语

Expand Down
2 changes: 1 addition & 1 deletion api/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

最后更新:2026-08-09

本文定义 AgentHub REST API 和 WebSocket typed events 的通用规则。完整路径/schema 以 `api/openapi.yaml` 为准;事件合同入口见 `api/events.md`;错误码源头见 `pkg/errcode`、`edge-server/internal/errcode/` 和 `hub-server/internal/errcode/`。
本文定义 AgentHub REST API 和 WebSocket typed events 的通用规则。完整路径/schema 以 `api/openapi.yaml` 为准;跨 Hub→Edge 的 dispatch/admission/callback ownership 合同见 `api/dispatch.md`;事件合同入口见 `api/events.md`;错误码源头见 `pkg/errcode`、`edge-server/internal/errcode/` 和 `hub-server/internal/errcode/`。

## Principles

Expand Down
66 changes: 55 additions & 11 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1373,11 +1373,19 @@ paths:
operationId: decidePermission
summary: Approve or deny a pending permission request.
description: >
Resolves a pending tool-permission request of a run. Under Hub JWT /
multi-user mode the run must be owned by the caller; a run owned by
another Hub user and a nonexistent run are reported identically (404),
so this endpoint is not a runId existence oracle. A caller without a Hub
identity fails closed. Local single-tenant mode is unaffected.
Resolves a pending tool-permission request of a run. The legacy form
(both `controlId` and `hubTaskId` absent) keeps one-shot receiver
semantics. The modern form supplies both fields and is idempotent: an
identical retry returns the original applied receipt, a different
control for the same run/request or a changed payload for the same
control fails with 409, and a cold/evicted receipt is never invented as
success. The receipt cache is process-local, bounded, and non-durable;
capacity pressure returns 429 before applying the decision. Under Hub
JWT / multi-user mode the run must be owned by the caller and a modern
request must match the stored `hubTaskId`. A foreign run, nonexistent
run, wrong task, and missing pending request are reported identically
(404), so this endpoint is not an existence oracle. A caller without a
Hub identity fails closed. Local single-tenant mode is unaffected.
x-agenthub-status: implemented
x-agenthub-owner: Edge
requestBody:
Expand All @@ -1388,20 +1396,53 @@ paths:
type: object
required: [runId, requestId, decision]
properties:
controlId:
type: string
description: Modern idempotency identity; must be supplied with hubTaskId.
hubTaskId:
type: string
description: Exact Hub task bound to the Edge run; must be supplied with controlId.
runId: { type: string }
requestId: { type: string }
decision: { type: string, enum: [allow, deny] }
reason: { type: string }
responses:
"200":
description: Decision recorded.
description: >
Decision applied. Legacy requests return `{status: ok}`; modern
requests return the applied receipt and set `deduplicated` when the
request replayed an existing receipt.
content:
application/json:
schema:
type: object
required: [code, data]
properties:
code: { type: string }
data:
type: object
required: [status]
properties:
status: { type: string }
controlId: { type: string }
hubTaskId: { type: string }
runId: { type: string }
requestId: { type: string }
decision: { type: string, enum: [allow, deny] }
applied: { type: boolean }
deduplicated: { type: boolean }
"400":
description: Invalid decision payload.
description: Invalid decision payload or only one of controlId/hubTaskId supplied.
"404":
description: >
Pending permission request not found. The same response is returned
when the run belongs to another Hub user, so a foreign runId and a
nonexistent runId are indistinguishable.
when the run belongs to another Hub user or the modern hubTaskId
does not match, so a foreign/mismatched run and a nonexistent run
are indistinguishable.
"409":
description: The control identity or run/request already has a conflicting decision receipt.
"429":
description: The bounded permission decision receipt cache is full; no decision was applied.

/v1/plans/decide:
post:
Expand Down Expand Up @@ -8655,14 +8696,17 @@ components:
additionalProperties: true
capabilities:
type: object
required: [runCallbackOwnership, directHubCallbacks]
required: [runCallbackOwnership, directHubCallbacks, permissionDecisionReceipts]
properties:
runCallbackOwnership:
type: boolean
description: The Edge enforces and persists per-run callback ownership.
directHubCallbacks:
type: boolean
description: Direct callbacks have a configured destination and current credential; no token or live reachability is exposed.
permissionDecisionReceipts:
type: boolean
description: The Edge supports idempotent modern permission decision receipts.
DispatchContextMessage:
type: object
required: [role, content]
Expand Down Expand Up @@ -9690,7 +9734,7 @@ components:
description: True on an accepted replay of an already admitted delivery (same runId returned, no new run created).
deliveryId:
type: string
description: The delivery_id whose accepted receipt is being replayed; present on accepted replays.
description: On an accepted replay, echoes the current request's deliveryId; a cold replay with a different deliveryId may therefore differ from the original receipt.

HubAuditEvent:
type: object
Expand Down
10 changes: 6 additions & 4 deletions docs/api-reference.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AgentHub API Reference

最后更新:2026-08-16
最后更新:2026-09-09

本文件只做 API 契约入口。旧 2041 行静态 API 参考见 [history.md](history.md),避免它和 OpenAPI / WebSocket 契约漂移。

Expand All @@ -10,13 +10,15 @@
|---|---|---|
| REST 路径、schema、阶段标记 | `api/openapi.yaml` | OpenAPI YAML parse / endpoint tests |
| WebSocket envelope、frame、事件族和源码 owner | [../api/events.md](../api/events.md) | WS tests / event normalizer tests |
| Hub→Edge dispatch、admission、execution intent、callback ownership | [../api/dispatch.md](../api/dispatch.md) | dispatch/runcontrol tests |
| 命名、分页、错误、权限、版本 | [../api/conventions.md](../api/conventions.md) | API review / handler tests |
| 架构背景和边界 | [architecture.md](architecture.md) | 架构 review |

## 使用规则

1. 新 REST 接口先改 `api/openapi.yaml`。
2. 新 WebSocket 事件先改源码 owner,再同步 `api/events.md` 的事件族和验收边界。
3. 通用命名、错误、分页、权限规则先改 `api/conventions.md`。
4. 新增鉴权、session、TokenDance ID 或权限行为时,同步 [architecture/06-auth-identity.md](architecture/06-auth-identity.md) 和 `AGENTS.md` 中的边界规则。
5. 不再在 `docs/` 里维护第二份完整 API 表。
3. 跨 Hub→Edge 的 dispatch/admission/callback ownership 先改 `api/dispatch.md`。
4. 通用命名、错误、分页、权限规则先改 `api/conventions.md`。
5. 新增鉴权、session、TokenDance ID 或权限行为时,同步 [architecture/06-auth-identity.md](architecture/06-auth-identity.md) 和 `AGENTS.md` 中的边界规则。
6. 不再在 `docs/` 里维护第二份完整 API 表。
4 changes: 2 additions & 2 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AgentHub 架构概览

最后更新:2026-08-29
最后更新:2026-09-09

本文档是架构入口,只保留当前结构、边界和 owner 链接。旧长版架构说明见 [history.md](history.md)。

Expand Down Expand Up @@ -44,7 +44,7 @@ Mobile (fixture/boundary lane, independent RN rendering)
| Mobile | `app/mobile-rn/` | RN shell、Mobile adapter、Hub viewer surface(fixture/边界验证 lane,独立渲染,非 release candidate) |
| Edge | `edge-server/` | 本地项目、Thread、Run lifecycle、Runtime adapter、Artifact index |
| Hub | `hub-server/` | TokenDance ID relying party、Hub session、IM、AgentTeam、同步、中继、审计 |
| API | `api/` | REST APIWebSocket event 契约 |
| API | `api/` | REST APIWebSocket event 与 Hub→Edge dispatch 契约 |

## 核心数据流

Expand Down
3 changes: 2 additions & 1 deletion docs/architecture/01-hub-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> 子文档 | 主索引:[architecture.md](../architecture.md)
>
> 最后更新:2026-08-20
> 最后更新:2026-09-09

Hub Server(`hub-server/`)是 AgentHub 的云端控制面:TokenDance ID relying party、Hub session、IM、AgentTeam、同步、中继、审计和远程控制面。它不启动本机 Agent Runtime;执行仍由 Edge Server 和 adapter 负责。

Expand Down Expand Up @@ -54,6 +54,7 @@ Hub Server(`hub-server/`)是 AgentHub 的云端控制面:TokenDance ID rel
|---|---|
| REST path/schema | `api/openapi.yaml` |
| WS frame/event families | `api/events.md` |
| Hub→Edge dispatch/admission/callback ownership | `api/dispatch.md` |
| API conventions | `api/conventions.md` |
| Auth/identity | [06-auth-identity.md](06-auth-identity.md) |
| Deployment boundary | [05-deployment.md](05-deployment.md) |
Expand Down
8 changes: 4 additions & 4 deletions docs/architecture/02-edge-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> 子文档 | 主索引:[architecture.md](../architecture.md)
>
> 最后更新:2026-09-06
> 最后更新:2026-09-09

## 职责

Expand Down Expand Up @@ -68,7 +68,7 @@ ProcessExecutor 配置 `RunTimeout`(默认 30 分钟)、`ShutdownGracePeriod

`SQLiteStore`(`internal/store/sqlite_store.go`)在写入后同步持久化快照差分到 SQLite(WAL 模式,定期 checkpoint),支持崩溃恢复。SQL 连接初始化与持久化串行化独立于普通业务读面,不能用额外 SQL 读者的争用直接代替业务读取测量。

终端状态 runs(finished/failed/cancelled/completed_with_issues)按 `TerminalTTL` 超时或 `MaxTerminalRunsPerThread` 上限自动清理,级联删除关联 diffs/artifacts/previews/items/checkpoints。Checkpoint 在 run 完成时保留,在 run 清理或所属 thread 删除时随 run 移除;这不删除工作区文件。 SQLite 后台清理有删除时同步提交;失败通过 `LastPersistError` 和日志留痕,下一周期即使没有新删除也会重试。关闭时先停止并等待后台清理/checkpoint 任务,再做最终持久化与数据库关闭。
终端状态 runs(finished/failed/cancelled/completed_with_issues)按 `TerminalTTL` 超时或 `MaxTerminalRunsPerThread` 上限自动清理,级联删除关联 diffs/artifacts/previews/items/checkpoints;`AdmissionState == pending` 的 run 不参与该自动清理,未决 admission 的收口语义见 `api/dispatch.md`。Checkpoint 在 run 完成时保留,在 run 清理或所属 thread 删除时随 run 移除;这不删除工作区文件。 SQLite 后台清理有删除时同步提交;失败通过 `LastPersistError` 和日志留痕,下一周期即使没有新删除也会重试。关闭时先停止并等待后台清理/checkpoint 任务,再做最终持久化与数据库关闭。

`EventBus`(`internal/events/bus.go`)是基于 channel 的发布/订阅模型:4 worker 并发 observer、子 channel 缓冲(256)、gap detection(`system.gap` 事件);通过 `PersistFn` 钩子先持久化再广播。`EventLog` 是 append-only JSON-lines 事件日志(默认 50 MiB 上限,超限截断保留尾部 75%)。

Expand Down Expand Up @@ -108,8 +108,8 @@ ProcessExecutor 配置 `RunTimeout`(默认 30 分钟)、`ShutdownGracePeriod

| 方向 | 方式 |
|---|---|
| Hub -> Edge | REST callbacks + Hub WebSocket dispatch/relay |
| Edge -> Hub | 同步、状态上报 |
| Hub -> Edge | REST `POST /v1/runs` 执行 admission;WebSocket 承载适用的 relay/control frame |
| Edge -> Hub | direct callbacks、同步与状态上报 |

## Adapter 注册表

Expand Down
4 changes: 2 additions & 2 deletions docs/architecture/03-runtime-adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> 子文档 | 主索引:[architecture.md](../architecture.md)
>
> 最后更新:2026-08-20
> 最后更新:2026-09-09

## 概述

Expand Down Expand Up @@ -156,7 +156,7 @@ cc-switch 是可选增强,不是硬依赖。数据库缺失、不可读或无

- Desktop 文件操作必须经过 allowlist 和 typed Host API
- Edge 不直接暴露文件系统给 Hub
- Hub -> Edge 的执行请求通过 REST callbacks,Edge 校验后才启动 runtime
- Hub -> Edge 的执行请求通过 REST `POST /v1/runs`(admission/execution intent 合同见 `api/dispatch.md`),Edge 校验后才启动 runtime;edge-owned run 的结果再由 Edge -> Hub callbacks 回传

## 相关文档

Expand Down
4 changes: 2 additions & 2 deletions docs/architecture/10-macro-engineering-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> 子文档 | 主索引:[architecture.md](../architecture.md)
>
> 最后更新:2026-08-29
> 最后更新:2026-09-09
>
> 状态:设计基线(Accepted)。本文定义目标架构、协议分层、可靠性/安全/可观测合同与差距路线。**本文是设计合同,不是实现完成声明**:落地状态以 GitHub Issues/PR、`AGENTS.md` 验收门禁和源码为准。

Expand Down Expand Up @@ -39,7 +39,7 @@ UI Workbench(chat timeline + command center)

| 协议 | 角色 | 现状/目标 | 红线 |
|---|---|---|---|
| 自有 REST/WS | Hub/Edge 产品控制面 SSOT | 保持 `api/openapi.yaml` + `api/events.md` | 不替换 |
| 自有 REST/WS | Hub/Edge 产品控制面 SSOT | 保持 `api/openapi.yaml` + `api/events.md` + `api/dispatch.md` | 不替换 |
| ACP / Agent SDK adapter | Edge <-> coding agent runtime 进程契约 | 已有 adapter family | 只属于 Edge data plane |
| MCP | agent <-> tools/data | 已有 mcp_config + Edge MCP server(8 个 canonical 工具,见 11) | tool 需要 narrow capability,不当作通用业务协议 |
| A2A | agent <-> agent | 仅远程/跨设备协作引入;当前未引入(见 11) | 不替换自有 Hub/Edge 契约 |
Expand Down
8 changes: 4 additions & 4 deletions docs/architecture/11-protocol-capability-mapping.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
# 协议能力映射:自有契约 / MCP / A2A / AG-UI(宏观 §3 P1)

> 主索引:[architecture.md](../architecture.md)。本文件是 AgentHub 自有 REST/WS 契约与三个外部协议(MCP / A2A / AG-UI)的能力对照、引入红线与评估结论 SSOT。上游基线:`docs/architecture/10-macro-engineering-design.md`(#2065,已合入)§3 协议分层表 + §9 差距路线 P1(本文即其产出)。

## 0. 阅读约定

- **自有契约** = AgentHub Hub Server REST + WS 事件合同(SSOT:`api/openapi.yaml` + `api/events.md`)。
- **自有契约** = AgentHub Hub Server REST + WS 事件合同,以及 Hub→Edge dispatch/admission 语义(SSOT:`api/openapi.yaml` + `api/events.md` + `api/dispatch.md`)。
- **外部协议** = MCP、A2A、AG-UI;描述必须给来源链接或仓库内引用,「业界通常」不算证据。
- **引入判定** = 每个外部协议一节判定表;满足全部"引入条件"才允许进入产品代码,否则拒绝或推迟。
- **红线** = 不可让步的死规矩;违反即阻断合入。
- 仓库现状以源码为准;外部规范以官方 spec 页面为准(链接在每节末尾)。

## 1. 自有 REST/WS 契约清单

AgentHub 的产品控制面 SSOT 由两份契约文件承载,所有端(Web/Desktop/Mobile/Edge)只消费这两份契约的派生客户端
AgentHub 的产品控制面 SSOT 由 REST、WS 与跨通道 dispatch 契约共同承载,所有端(Web/Desktop/Mobile/Edge)只消费这些契约的派生客户端

| 契约 | 入口文件 | 职责 | 备注 |
|---|---|---|---|
| REST JSON API | [`api/openapi.yaml`](../../api/openapi.yaml) | Hub + Edge 全量命令/查询端点;端点级状态标签 `x-agenthub-status: implemented/planned`;组件级另有 `contract-draft`(契约已定、实现留白,不挂在任何 operation 上) | Hub success envelope `{"code":"ok","data":...}`(见 [`api/conventions.md`](../../api/conventions.md)) |
| WebSocket typed events | [`api/events.md`](../../api/events.md) | Hub/Edge 实时事件合同;at-least-once 投递、幂等语义、seq_id 语义 | SSOT 三角:`hub-server/internal/ws/frame.go` ↔ `app/shared/src/hubEvents.ts` ↔ OpenAPI `HubWebSocketFrame.type` |
| Hub→Edge dispatch/admission | [`api/dispatch.md`](../../api/dispatch.md) | Hub→Edge delivery claim/receipt、execution intent、callback ownership 与重试语义 | 与 `POST /v1/runs` 和 `edge-server/internal/runcontrol/` 同源 |
| Edge EventEnvelope | [`api/events.md`](../../api/events.md) §Edge EventEnvelope | Edge stream 单调 seq + 事件 id;断线 cursor 回放 | payload 进 transcript 前脱敏 |
| Hub Frame | [`api/events.md`](../../api/events.md) §Hub Frame | `{type, seq_id?, payload?}` + 31 常量 | `/client/ws` 仅 Hub-issued HS256 token |

**红线**:自有 REST/WS 契约是产品控制面唯一权威;任何外部协议不得替换、覆盖或绕过这两份契约(宏观 §3 红线列)。
**红线**:自有 REST/WS 与 Hub→Edge dispatch 契约是产品控制面唯一权威;任何外部协议不得替换、覆盖或绕过这些契约(宏观 §3 红线列)。

## 2. MCP:tool surface 映射与 narrow capability 红线

Expand Down