feat: add docs website
This commit is contained in:
@@ -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 追踪)。
|
||||
@@ -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
|
||||
|
||||
上下文压缩结束。
|
||||
@@ -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 中)
|
||||
}
|
||||
```
|
||||
@@ -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 或默认值 |
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user