feat: add docs website

This commit is contained in:
lintianle
2026-07-09 16:07:58 +08:00
parent dabc5e6225
commit 87a1774fef
35 changed files with 3540 additions and 0 deletions
+85
View File
@@ -0,0 +1,85 @@
# Context
上下文对象是 Cordis 的核心。所有服务、方法、属性都通过 `ctx` 访问。
## 服务与混入
Context 基于组合式 API 设计,大部分属性和方法挂载在服务上。以下是核心 API:
- [`ctx.on`](./events#ctx-on) — 注册事件监听器
- [`ctx.emit`](./events#ctx-emit) — 触发事件
- [`ctx.bail`](./events#ctx-bail) — 短路事件
- [`ctx.serial`](./events#ctx-serial) — 顺序异步事件
- [`ctx.waterfall`](./events#ctx-waterfall) — 管道事件
- [`ctx.effect`](./fiber#fiber-effect) — 注册可逆效果
- [`ctx.plugin`](./registry#ctx-plugin) — 加载子插件
- [`ctx.inject`](./registry#ctx-inject) — 获取依赖的插件
- [`ctx.get`](#ctx-get) — 获取服务
- [`ctx.set`](#ctx-set) — 设置服务
- [`ctx.provide`](#ctx-provide) — 声明服务
## 实例属性
### ctx.fiber
- **类型:** [`Fiber`](./fiber)
当前上下文的作用域对象。
## 实例方法
### ctx.extend(meta)
- **meta:** `object`
- **返回值:** `Context`
构造一个以当前上下文为原型的新上下文实例。
### ctx.intercept(name, config)
- **name:** `string` 服务名称
- **config:** `object` 配置拦截
- **返回值:** `Context`
为指定服务添加一层配置拦截,返回新的上下文实例。
### ctx.isolate(name, label?)
- **name:** `string` 服务名称
- **label:** `symbol` 隔离域符号(可选)
- **返回值:** `Context`
创建一个针对指定服务的隔离域,返回新的上下文实例。隔离域中的同名服务互不影响。
### ctx.get(name)
- **name:** `string` 服务名称
- **返回值:** `Service | undefined`
获取指定名称的服务实例。
### ctx.set(name, value)
- **name:** `string` 服务名称
- **value:** `any` 服务值
设置指定名称的服务。
### ctx.provide(name, value?, options?)
- **name:** `string` 服务名称
- **value:** `any` 初始值(可选)
- **options:** `object`
- **返回值:** `void`
声明一个服务。声明后其他插件可以通过 `inject` 依赖它。
## 静态属性
### Context.events
内置事件服务的 symbol key。
### Context.current
当前活跃的 Context 实例(在异步链中通过 AsyncLocalStorage 追踪)。
+120
View File
@@ -0,0 +1,120 @@
# Events
`ctx.events` 是内置服务,提供事件系统相关的全部 API。
## 实例方法
### ctx.on(event, listener, options?) {#ctx-on}
- **event:** `string` 事件名称
- **listener:** `Function` 事件监听器
- **options:** `object`
- **prepend:** `boolean` 是否注册为前置(默认 `false`)
- **global:** `boolean` 是否注册为全局(默认 `false`)
- **返回值:** `() => void` 取消注册函数
注册一个事件监听器。返回的函数可用于手动取消注册,但通常不需要——插件卸载时会自动清理。
```typescript
ctx.on('agent/turn-end', (data) => {
console.log('turn ended:', data)
})
```
### ctx.emit(thisArg?, event, ...args) {#ctx-emit}
- **thisArg:** `any` 监听器的 `this` 参数(可选)
- **event:** `string` 事件名称
- **args:** `any[]` 事件参数
- **返回值:** `void`
同步触发所有匹配的监听器(并行,不等待异步完成)。
### ctx.parallel(thisArg?, event, ...args)
- 签名同 `emit`
- **返回值:** `Promise<void>`
异步触发所有匹配的监听器(并行等待)。
### ctx.bail(thisArg?, event, ...args) {#ctx-bail}
- **返回值:** `any`
同步依次触发监听器。第一个返回非 `undefined`/`null`/`false` 值的监听器停止链并返回该值。
### ctx.serial(thisArg?, event, ...args) {#ctx-serial}
- **返回值:** `Promise<any>`
异步依次触发监听器。语义同 `bail` 的异步版本。
### ctx.waterfall(thisArg?, event, ...args) {#ctx-waterfall}
- **返回值:** `Promise<any>`
管道模式:每个监听器接收前一个的输出。监听器内部必须调用 `next()` 才会传递给下一个。
```typescript
// 注册
ctx.on('llm/pre-request', async (messages, next) => {
messages.push(extraMsg)
return next(messages) // 必须调用
})
// 触发
const result = await ctx.waterfall('llm/pre-request', initialMessages)
```
::: warning
不调用 `next()` 即为否决 (veto)——管道终止。这是设计行为,用于拦截/网关。
:::
## Harness 内置事件
### agent/pre-step
- **触发模式:** serial
- **参数:** `{ agentId, turnIndex }`
Agent 执行一步之前触发。
### agent/post-step
- **触发模式:** emit
- **参数:** `{ agentId, turnIndex, blocks }`
Agent 执行一步之后触发。
### tool/call
- **触发模式:** emit
- **参数:** `{ name, args, callId }`
Tool 被模型调用时触发。
### tool/result
- **触发模式:** emit
- **参数:** `{ name, result, callId }`
Tool 返回结果时触发。
### session/event
- **触发模式:** emit
- **参数:** `SessionEvent`
会话事件被记录时触发。
### compact/start
- **触发模式:** emit
上下文压缩开始。
### compact/end
- **触发模式:** emit
上下文压缩结束。
+108
View File
@@ -0,0 +1,108 @@
# Fiber
Fiber(作用域)是插件实例的运行时容器,管理其生命周期和效果。
## 状态机
```
PENDING → LOADING → ACTIVE → UNLOADING → DISPOSED
↘ FAILED
```
| 状态 | 数值 | 含义 |
|------|------|------|
| PENDING | 0 | 依赖未就绪,等待中 |
| LOADING | 1 | 正在执行 `apply` |
| ACTIVE | 2 | 运行中 |
| FAILED | 3 | `apply` 抛出异常 |
| UNLOADING | 4 | 正在撤销效果 |
| DISPOSED | 5 | 已完全卸载 |
## 实例属性
### fiber.uid
- **类型:** `number`
Fiber 的唯一标识符。
### fiber.status
- **类型:** `number`
当前状态(见状态机)。
### fiber.config
- **类型:** `object`
传递给插件的配置对象。
### fiber.error
- **类型:** `Error | undefined`
如果状态是 FAILED,包含导致失败的异常。
## 实例方法
### fiber.effect(callback) {#fiber-effect}
- **callback:** `() => (() => void) | void`
- **返回值:** `() => void`
注册一个效果。`callback` 在 Fiber 激活时执行;如果返回函数,该函数在 Fiber dispose 时执行。
```typescript
ctx.effect(() => {
const timer = setInterval(tick, 1000)
return () => clearInterval(timer)
})
```
等价地可以通过 `ctx.effect()` 调用(ctx 代理到当前 fiber)。
### fiber.dispose()
- **返回值:** `Promise<void>`
手动 dispose 该 Fiber。按注册逆序撤销所有效果,递归 dispose 所有子 Fiber。
```typescript
const child = ctx.plugin(somePlugin)
// 之后:
await child.dispose()
```
### fiber.update(config)
- **config:** `object` 新配置
- **返回值:** `void`
热更新配置。如果新旧配置不同,触发 dispose + 重新 apply。
### fiber.restart()
- **返回值:** `void`
强制重启:dispose 后重新加载。
### fiber.then(resolve, reject?)
- **返回值:** `Promise<void>`
使 Fiber 可以被 `await`:等到状态进入 ACTIVE 或 FAILED。
```typescript
const fiber = ctx.plugin(myPlugin)
await fiber // 等待插件加载完成
```
## 访问当前 Fiber
```typescript
export function apply(ctx: Context) {
const fiber = ctx.fiber // 当前插件的 Fiber
console.log(fiber.status) // 1 (LOADING, 因为正在 apply 中)
}
```
+87
View File
@@ -0,0 +1,87 @@
# Registry
插件注册表,管理插件的加载和依赖解析。
## 实例方法
### ctx.plugin(plugin, config?) {#ctx-plugin}
- **plugin:** `Plugin` 插件(函数、对象或类)
- **config:** `object` 传递给插件的配置(可选)
- **返回值:** `Fiber`
加载一个子插件,返回其 Fiber。子 Fiber 的生命周期绑定到父上下文。
```typescript
// 函数插件
ctx.plugin(myPlugin, { key: 'value' })
// 类插件
ctx.plugin(MyService)
// 返回的 Fiber 可以 await 或 dispose
const fiber = ctx.plugin(myPlugin)
await fiber
```
### ctx.inject(names, callback) {#ctx-inject}
- **names:** `string[]` 服务名列表
- **callback:** `(ctx: Context) => void`
- **返回值:** `() => void`
等待指定服务全部就绪后执行 callback。如果服务消失,callback 的效果会自动撤销;服务恢复后重新执行。
```typescript
ctx.inject(['tools', 'llm'], (ctx) => {
// tools 和 llm 都就绪了
ctx.tools.register(/* ... */)
})
```
这是 `export const inject = [...]` 声明的底层 API。大多数情况下直接使用声明式写法即可。
## 插件形态
`ctx.plugin()` 接受三种插件形态:
### 函数插件
```typescript
function myPlugin(ctx: Context, config?: Config) {
// ...
}
myPlugin.name = 'my-plugin'
myPlugin.inject = ['tools']
```
### 对象插件
```typescript
const myPlugin = {
name: 'my-plugin',
inject: ['tools'],
apply(ctx: Context, config?: Config) {
// ...
},
}
```
### 类插件(Service)
```typescript
class MyService extends Service {
static inject = ['tools']
constructor(ctx: Context) {
super(ctx, 'myService')
}
}
```
## 插件元信息
| 属性 | 类型 | 说明 |
|------|------|------|
| `name` | `string` | 插件名称(日志用) |
| `inject` | `string[] \| { required?: string[], optional?: string[] }` | 依赖声明 |
| `Config` | `Schema \| object` | 配置 schema 或默认值 |
+97
View File
@@ -0,0 +1,97 @@
# Service
Service 基类,用于创建对外暴露能力的插件。
## 基本用法
```typescript
import { Service, type Context } from 'cordis'
declare module 'cordis' {
interface Context {
myService: MyService
}
}
export default class MyService extends Service {
constructor(ctx: Context) {
super(ctx, 'myService')
}
// 公开方法
doSomething() {
// ...
}
}
```
加载后,其他插件可通过 `ctx.myService` 访问。
## 构造函数
### new Service(ctx, name)
- **ctx:** `Context` 上下文
- **name:** `string` 服务名(注册到 `ctx[name]`)
## 实例属性
### service.ctx
- **类型:** `Context`
该服务绑定的上下文。
### service\[Service.tracker\]
- **类型:** `object`
服务追踪信息(名称、绑定状态等)。
## 生命周期
Service 子类可以覆写以下方法:
### start()
服务激活时调用。在这里初始化资源。
### stop()
服务停用时调用。在这里释放资源。
## 静态属性
### Service.inject
- **类型:** `string[] | { required?: string[], optional?: string[] }`
声明本服务依赖的其他服务。
## 与 inject 的关系
当一个 Service 被加载:
1. 框架为该服务名创建声明 (`ctx.provide`)
2. 实例赋值到 `ctx[name]`
3. 依赖该服务的所有 Fiber 从 PENDING 转为 LOADING
当 Service 被卸载:
1. `ctx[name]` 被置为 `undefined`
2. 依赖它的 Fiber 被 dispose
3. 当新的 provider 出现时,dependant Fiber 重新加载
## 示例:Harness 中的 Service
```typescript
// dsh-tools 的 ToolRegistry 就是一个 Service
export class ToolRegistry extends Service {
constructor(ctx: Context) {
super(ctx, 'tools')
}
register(tool: ToolDefinition): () => void {
// ...注册逻辑
return dispose
}
}
```