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
63 changes: 63 additions & 0 deletions llmdoc/architecture.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
description: Watt 的整体定位、规范真源、模块边界、核心数据流与部署形态;用于首次进入仓库或判断跨域影响面。
kind: architecture
relations:
related:
- contracts/events-and-results.mdx
- contracts/auth-and-errors.mdx
- contracts/htbp-and-platform-apis.mdx
- operations/topology-and-provisioning.mdx
code:
paths:
- Docs/*.md
- DOD.md
- LOOP.md
- pnpm-workspace.yaml
- packages/*/package.json
- packages/gateway/src/index.ts
- packages/gateway/wrangler.jsonc
---

# Watt 整体架构

## 项目定位与真源

Watt 是运行在 Cloudflare 上的 Agent 基础设施,不是新的 Agent framework。任意 harness 通过开放协议接入组织的事件、上下文、工具、长任务和模型渠道;平台负责身份、路由、持久化、审计与管理入口。

规范优先级是:`Docs/Proto.md` 定接口与横切契约,`Docs/Architecture.md` 定模块和拓扑,`Docs/Plugin.md` 定扩展边界,`Docs/Vision.md` 定产品目标;`DOD.md` 定可重跑验收,`LOOP.md` 定开发纪律。实现与规范冲突时,先澄清或修改规范,再对齐实现。

## 模块与所有权

| 模块 | 责任 | 主要运行位置与持久化 |
|---|---|---|
| Event Gateway | 渠道规约、发布、订阅、会话粘性、留痕、出站 | gateway Worker、Queues、Router DO、D1 |
| Agent Runtime | 定义、实例、派生、生命周期、harness | Agents SDK Durable Object;heavy runtime 预留给 Container/Sandbox |
| Context Layer | object、structured、vector 上下文与 namespace mount | R2、D1、Vectorize、Context Registry DO |
| Tool Layer | 工具发现、虚拟化、调用与授权执行点 | tool-bridge Worker;gateway 提供鉴权代理 |
| Auth | Principal、Policy、委托链衰减、身份映射 | gateway PEP、D1 Policy、Identity Mapper |
| Scheduler | cron 与 publish、agent、script 三类动作 | Scheduler DO;script 使用一次性 isolate |
| Task | 跨时长工作与 human checkpoint | Cloudflare Workflows 与 TaskStore |
| Model Provider | provider 注册、默认路由与模型调用 | Provider D1、AI Gateway 或兼容上游 |
| Observability | usage、metrics、audit | Analytics Engine 与 D1 |
| Management | Dashboard、manage agent、Watt CLI 三个对等入口 | 全部复用 Platform API,不设管理旁路 |
| Plugin System | 扩展注册、认证、探活与生命周期 | Plugin Registry、独立 Worker 或外部 HTTP 服务 |

Registry 类接口遵循 `List/Get/Write/Update` 的共同动词;Provider 类接口按领域定义。Agent 对平台的逻辑消费面是一棵 HTBP 树:tools、context、platform 三个分支。物理上 gateway 自持 platform/context,tool-bridge 承载 tools,gateway 的 tools 代理负责统一身份和 `Authorizer.Check`;物理分治不能变成逻辑旁路。

## 核心数据流

入站渠道先 Verify/Decode 为统一 Event,再经 EventBus、Queues 与 Router DO 路由。带 session 的订阅由稳定 instance key 粘到同一 Agent DO;Agent 访问 Context、Tool 或 Platform API 时携带调用者和派生链身份,每个入口都执行衰减式授权。Agent 不直接向 IM SDK 发送消息,而是发布 `outbound.message`,由 channel adapter/plugin 统一发送。

Agent-to-Agent 仍走 Event Bus。带 correlationId 的 `agent.result` 与 `agent.failed` 定向回送等待方,不进入普通订阅匹配。Task 的 human checkpoint 发布标准事件,渠道把它渲染为交互卡片;用户动作经过 `task://` 的 `signal` 授权后恢复 Workflow。

## 扩展与管理边界

Plugin 分为 context-provider、tool-provider、channel-adapter、agent-harness。模型渠道只是 ModelProviderRegistry 数据,不是 Plugin。Plugin 只能实现声明的接口并以受限 plugin token 回调平台;新增渠道或工具不得要求修改 gateway 的领域硬编码。

Dashboard、manage agent 与 CLI 必须调用同一套 Platform API,并产生相同的授权与审计语义。前端为了体验增加的查询 filter 可以扩展既有接口,但不能引入只有某个管理入口可用的专用后门。

## 部署形态

仓库是 pnpm monorepo。gateway、tool-bridge 和独立 plugin Worker 组成边缘数据面;Durable Objects、Workflows、Queues、D1、KV、R2、Vectorize 和 Analytics Engine 按模块 ownership 绑定。Dashboard 静态产物由 gateway 同域分发;CLI 是远程 Platform API 客户端。

具体契约从 `contracts/` 检索,运行时语义从 `runtime/` 检索,部署与开发流程从 `operations/` 检索,飞书与 Plugin 从 `integrations/` 检索,Dashboard 从 `dashboard/` 检索。V3 不维护手写 index 或 startup 阅读顺序,使用 `llmdoc tree/index/search/context/show` 渐进检索。
97 changes: 0 additions & 97 deletions llmdoc/architecture/modules-and-flows.md

This file was deleted.

69 changes: 69 additions & 0 deletions llmdoc/contracts/auth-and-errors.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
description: CallContext、Policy 与 Agent 委托链授权、Token 引导、SecretStore 和 WattError 的规范边界。
kind: reference
relations:
requires:
- architecture.mdx
related:
- runtime/agents-and-tools.mdx
- operations/credentials-and-recovery.mdx
code:
paths:
- Docs/Proto.md
- packages/shared/src/error.ts
- packages/core/src/auth/**
- packages/core/src/authz/**
- packages/gateway/src/authz/**
- packages/gateway/src/http/auth.ts
- packages/gateway/src/http/errors.ts
- packages/gateway/src/http/oauth.ts
- packages/gateway/src/secrets/**
---

# 授权、凭据与错误契约

## CallContext 与身份

CallContext 携带最终受益人 principal、roles、可选 AgentChainRef 和 traceId。principal 可以是 user、service 或定义级 agent;实例身份只放在 token claims 的 `agent_inst` 与 CallContext.agent 中,不能拿实例 ID 充当最终受益人。

HTTP 绑定下 CallContext 只通过 `X-Watt-Context` 传输,body 不复制。渠道身份先经 IdentityMapper 解析;纯 user/service token 没有 agent 链时只做 principal Policy 判定。

## 衰减式授权

授权不变量是:

```text
allow = P(principal) ∩ P(current agent definition) ∩ P(each ancestor/system segment)
```

Policy 先按 subject、resource 与 action 求 principal 许可,deny 优先。带 agent claims 时再检查当前 AgentDefinition.grants,并沿 chain 检查祖先 definition。`cron:<jobId>` 只有 script action 把 job grants 作为额外上限;publish/agent action 不追加该段上限;job 已删除或禁用时拒绝。

gateway 的 Authorizer 通过 AgentDefLoader 惰性装载 `claims.agent_def`,避免空索引把所有 agent 主体误拒。cron script 则以当前 job 自足播种 cronJobs。任何新的 PEP 只要接收含 agent/cron 链的 claims,就必须确保判定点能解析链上引用的数据,不能把空索引当成正常运行态。

Agent 工具调用还要同时满足 toolScopes 前缀、principal Policy 和 AgentDefinition.grants;管理员直调只能证明工具可用,不能证明 agent 主体有权调用。

## Token 与引导

JWT 使用非对称 Ed25519 签名并通过 JWKS 暴露公钥,签验由 jose 完成。JWT 私钥只来自部署期 secret,不进入 SecretStore。替换 JWT 签名私钥会吊销所有由旧 key 签发的 user、agent 与 plugin token,属于破坏性轮换。

人类登录走 RFC 8628 device flow。RFC 定义的 authorize/token 端点返回 OAuth 错误形状;平台自有的 approve 动作仍返回 WattError。非交互环境通过 `WATT_TOKEN` 提供已签 user token。

Root Key 是只保存 SHA-256 摘要的长期引导凭据,明文只在创建时展示一次,不能作为 Bearer 调平台接口。它只能调用 root exchange 换发 admin user token;换发使用当前 JWT 私钥,不触发签名根轮换。

SecretStore 用专用 AES-256-GCM 根密钥加密运行时 secret,AAD 绑定 secret 名称,密文放 KV。`resolveSecret` 先查 Worker env,再查 SecretStore;JWT 私钥明确排除,避免信任根循环。List/Get 管理面只返回元数据,永不回显明文。

## WattError

WattError 只有七个 code:`not_found`、`permission_denied`、`invalid_argument`、`conflict`、`unavailable`、`rate_limited`、`internal`。body 顶层就是 `{code,message,retryable}`,没有 `{error: ...}` 信封。

| HTTP | code |
|---|---|
| 400 | `invalid_argument` |
| 401、403 | `permission_denied` |
| 404 | `not_found` |
| 409 | `conflict` |
| 429 | `rate_limited` |
| 500 | `internal` |
| 501、503 | `unavailable` |

只有 `rate_limited`、`unavailable`、`internal` 可以标 retryable。调用方只对 429 或 5xx 且 retryable 为 true 的响应做指数退避。OAuth RFC 端点是明确例外,不得为了统一外观把 OAuth error 包成 WattError。
Loading
Loading