@ocdb/tool-sdk
v0.1.1
Published
为业务工具添加调试元数据的轻量 SDK。
Readme
@ocdb/tool-sdk
为业务工具添加调试元数据的轻量 SDK。
通过 defineDebugTool() 包装业务工具,声明其副作用级别和默认 replay 策略,使 @ocdb/plugin 的 Tool Cassette 在 fork/replay 时能做出正确的处理决策。
可选但强烈推荐:未包装的工具仍会被 capture,但 replay 时只能使用默认的
re_execute策略,无法自动跳过副作用或复用历史结果。
安装
npm install @ocdb/tool-sdk快速上手
import { defineDebugTool } from '@ocdb/tool-sdk'
// 只读查询:replay 时直接复用历史结果
export const queryMetadata = defineDebugTool({
name: 'query_metadata',
sideEffectLevel: 'read_only',
defaultReplayPolicy: 'reuse_result',
execute: async (args: { reportId: string }) => {
return await metadataService.query(args.reportId)
},
})defineDebugTool(options) API
function defineDebugTool<TArgs, TResult>(
options: DebugToolOptions<TArgs, TResult>
): DebugToolDef<TArgs, TResult>参数
| 字段 | 类型 | 说明 |
|------|------|------|
| name | string | 工具名称,需与 OpenClaw tool 注册名一致 |
| sideEffectLevel | SideEffectLevel | 副作用级别(见下表) |
| defaultReplayPolicy | ReplayPolicy | 默认 replay 策略(见下表) |
| execute | (args: TArgs) => Promise<TResult> | 原始实现,不需要修改 |
返回值
interface DebugToolDef<TArgs, TResult> {
name: string
sideEffectLevel: SideEffectLevel
defaultReplayPolicy: ReplayPolicy
execute: (args: TArgs) => Promise<TResult>
__isDebugTool: true // 标记,供 plugin 识别
}副作用级别(SideEffectLevel)
| 值 | 含义 | 典型工具 |
|---|---|---|
| 'none' | 纯函数,无任何副作用 | 格式转换、计算 |
| 'read_only' | 只读查询,不修改状态 | 查询数据库、读取配置 |
| 'expensive_read' | 只读但代价高(慢/贵) | 大 SQL 查询、外部 API 调用 |
| 'write' | 写入操作,可能影响后续状态 | 保存报表、更新数据库 |
| 'external_irreversible' | 外部不可逆操作 | 发送消息、提交工单、扣费 |
Replay 策略(ReplayPolicy)
| 值 | 含义 | 适用场景 |
|---|---|---|
| 'reuse_result' | 直接返回历史结果,跳过真实调用 | 只读/昂贵读工具,结果稳定 |
| 're_execute' | 重新真实调用 | 无副作用工具,或需要最新数据 |
| 'mock_result' | 返回 --mock-tool 配置的数据 | 测试特定工具输出的影响 |
| 'manual_confirm' | 需要人工确认(当前版本等同于 re_execute) | 写入类工具的交互式调试 |
| 'forbid_replay' | 阻止重放并报错 | 写入/不可逆工具,防止意外重复执行 |
注意:
defaultReplayPolicy是默认值。ocdb replay --tool-policy <tool>=<policy>可以在单次 fork 时覆盖。
完整示例
import { defineDebugTool } from '@ocdb/tool-sdk'
// ✅ 元数据查询 — 幂等,总是复用历史结果
export const queryReportMetadata = defineDebugTool({
name: 'query_report_metadata',
sideEffectLevel: 'read_only',
defaultReplayPolicy: 'reuse_result',
execute: async (args: { reportId: string; version?: number }) => {
return await reportDB.getMetadata(args.reportId, args.version)
},
})
// ✅ SQL 执行 — 昂贵,复用结果避免重复费用
export const executeBigQuery = defineDebugTool({
name: 'execute_bigquery',
sideEffectLevel: 'expensive_read',
defaultReplayPolicy: 'reuse_result',
execute: async (args: { sql: string; params?: unknown[] }) => {
return await bigquery.query(args.sql, args.params)
},
})
// ✅ 图表生成 — 无副作用,可自由重跑
export const generateChartOption = defineDebugTool({
name: 'generate_chart_option',
sideEffectLevel: 'none',
defaultReplayPolicy: 're_execute',
execute: async (args: { data: unknown[]; chartType: string }) => {
return chartEngine.compile(args)
},
})
// ⚠️ 报表保存 — 有写入副作用,默认禁止 replay
export const saveArtifact = defineDebugTool({
name: 'save_artifact',
sideEffectLevel: 'write',
defaultReplayPolicy: 'forbid_replay',
execute: async (args: { reportId: string; content: unknown }) => {
return await artifactStore.save(args)
},
})
// 🚫 通知发送 — 不可逆,严格禁止 replay
export const sendUserNotification = defineDebugTool({
name: 'send_user_notification',
sideEffectLevel: 'external_irreversible',
defaultReplayPolicy: 'forbid_replay',
execute: async (args: { userId: string; message: string }) => {
return await notifyService.send(args)
},
})与 ocdb replay 配合使用
声明了 defaultReplayPolicy 之后,ocdb replay 默认遵从工具自身的策略。也可以在命令行临时覆盖:
# 默认行为:每个工具用自己声明的策略
ocdb replay run-xxx --from ckp-yyy
# 临时覆盖:强制让 save_artifact 使用 mock 数据而不是报错
ocdb replay run-xxx --from ckp-yyy \
--tool-policy save_artifact=mock_result
# 全局覆盖:所有工具都复用历史结果(最快,适合定位 prompt 问题)
ocdb replay run-xxx --from ckp-yyy \
--tool-policy reuse_result
# 混合:全局复用 + 特定工具重新执行
ocdb replay run-xxx --from ckp-yyy \
--tool-policy reuse_result \
--tool-policy generate_chart_option=re_execute类型导出
export { defineDebugTool }
export type { DebugToolDef, DebugToolOptions }
// 以下类型从 @ocdb/core 重新导出(方便使用,无需额外安装):
// SideEffectLevel, ReplayPolicy