@carfiedli/runtime-guardrail 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.fe.md +256 -0
- package/README.hooks-security.md +1017 -0
- package/README.md +1316 -0
- package/dist/adapters/index.d.ts +1 -0
- package/dist/adapters/persistence/file-store.d.ts +18 -0
- package/dist/adapters/persistence/index.d.ts +4 -0
- package/dist/adapters/persistence/json-event-log.d.ts +31 -0
- package/dist/adapters/persistence/queue-store.d.ts +19 -0
- package/dist/adapters/persistence/snapshot-store.d.ts +14 -0
- package/dist/approval/approval-service.d.ts +27 -0
- package/dist/approval/approval-state-machine.d.ts +5 -0
- package/dist/approval/hitl/hitl-connector.d.ts +9 -0
- package/dist/approval/index.d.ts +4 -0
- package/dist/approval/run-hold-service.d.ts +16 -0
- package/dist/audit/audit-event-store.d.ts +12 -0
- package/dist/audit/audit-read-model-builder.d.ts +17 -0
- package/dist/audit/audit-service.d.ts +18 -0
- package/dist/audit/incident-query-service.d.ts +7 -0
- package/dist/audit/index.d.ts +5 -0
- package/dist/audit/metrics-projection.d.ts +10 -0
- package/dist/bootstrap/create-runtime-guardrail-plugin.d.ts +3 -0
- package/dist/bootstrap/dependency-container.d.ts +2 -0
- package/dist/bootstrap/index.d.ts +3 -0
- package/dist/bootstrap/runtime-facade.d.ts +31 -0
- package/dist/compat/index.d.ts +1 -0
- package/dist/compat/legacy-types.d.ts +29 -0
- package/dist/contracts/core.d.ts +277 -0
- package/dist/contracts/events.d.ts +35 -0
- package/dist/contracts/host.d.ts +239 -0
- package/dist/contracts/index.d.ts +6 -0
- package/dist/contracts/operator.d.ts +110 -0
- package/dist/execution/egress-mediator.d.ts +7 -0
- package/dist/execution/execution-broker.d.ts +13 -0
- package/dist/execution/execution-plan-builder.d.ts +12 -0
- package/dist/execution/index.d.ts +4 -0
- package/dist/execution/model-governance-service.d.ts +7 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +23 -0
- package/dist/openclaw/hooks/egress-adapter.d.ts +9 -0
- package/dist/openclaw/hooks/hook-registry.d.ts +21 -0
- package/dist/openclaw/hooks/hook-result-mapper.d.ts +43 -0
- package/dist/openclaw/hooks/hook-types.d.ts +31 -0
- package/dist/openclaw/hooks/index.d.ts +8 -0
- package/dist/openclaw/hooks/ingress-adapter.d.ts +14 -0
- package/dist/openclaw/hooks/llm-request-adapter.d.ts +9 -0
- package/dist/openclaw/hooks/persist-adapter.d.ts +30 -0
- package/dist/openclaw/hooks/tool-call-adapter.d.ts +7 -0
- package/dist/openclaw/index.d.ts +4 -0
- package/dist/openclaw/plugin-runtime.d.ts +103 -0
- package/dist/openclaw/rpc-handlers.d.ts +20 -0
- package/dist/openclaw/skills-availability.d.ts +10 -0
- package/dist/openclaw/skills-upload.d.ts +17 -0
- package/dist/openclaw/testing/index.d.ts +1 -0
- package/dist/openclaw/testing/mock-openclaw-api.d.ts +74 -0
- package/dist/operator/cli/register-cli.d.ts +4 -0
- package/dist/operator/command-service.d.ts +15 -0
- package/dist/operator/index.d.ts +5 -0
- package/dist/operator/query-service.d.ts +21 -0
- package/dist/operator/reporting/report-service.d.ts +9 -0
- package/dist/operator/rpc/register-rpc.d.ts +5 -0
- package/dist/policy/detectors/detector-port.d.ts +23 -0
- package/dist/policy/finding-normalizer.d.ts +3 -0
- package/dist/policy/index.d.ts +4 -0
- package/dist/policy/policy-engine.d.ts +8 -0
- package/dist/policy/stage-resolver.d.ts +7 -0
- package/dist/runtime-core/device-id.d.ts +15 -0
- package/dist/runtime-core/evaluate-service.d.ts +91 -0
- package/dist/runtime-core/index.d.ts +10 -0
- package/dist/runtime-core/memory-audit-logger.d.ts +55 -0
- package/dist/runtime-core/memory-store.d.ts +141 -0
- package/dist/runtime-core/remote-guard-request-builder.d.ts +15 -0
- package/dist/runtime-core/remote-guard-transport.d.ts +79 -0
- package/dist/runtime-core/remote-guard-types.d.ts +183 -0
- package/dist/runtime-core/remote-policy-evaluator.d.ts +51 -0
- package/dist/runtime-core/skill-name-resolver.d.ts +31 -0
- package/dist/runtime-core/sync-remote-evaluate.d.ts +29 -0
- package/dist/runtime-core/sync-remote-worker.d.ts +14 -0
- package/dist/runtime-core/sync-remote-worker.js +2 -0
- package/dist/runtime-core/telemetry-service.d.ts +94 -0
- package/dist/runtime-core/telemetry-types.d.ts +181 -0
- package/dist/types.d.ts +224 -0
- package/dist/version.d.ts +1 -0
- package/openclaw.plugin.json +76 -0
- package/package.json +71 -0
- package/remote-guard-config.json +30 -0
- package/scripts/runtime-guardrailctl.mjs +864 -0
|
@@ -0,0 +1,1017 @@
|
|
|
1
|
+
# Hook 安全检测接口数据格式定义
|
|
2
|
+
|
|
3
|
+
> 目标读者:安全策略/风控服务开发同学
|
|
4
|
+
> 目标:明确 **OpenClaw 每个 hook 向安全检测服务发送的数据格式**,便于对接专业安全服务
|
|
5
|
+
> 文档更新时间:2026-03-13
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 概述
|
|
10
|
+
|
|
11
|
+
本文档定义了 OpenClaw Runtime Guardrail 中所有 hook 向远端安全检测服务发送数据时使用的**统一接口格式**。
|
|
12
|
+
|
|
13
|
+
**设计目标:**
|
|
14
|
+
1. 所有 hook 共用同一个接口,数据格式一致
|
|
15
|
+
2. 提取关键检测字段,省略过长的数据(如历史消息、系统提示词等)
|
|
16
|
+
3. 按 hook 类型分组,events 中只有当前 hook 对应的字段有值
|
|
17
|
+
4. 清晰标识当前触发的 hook 类型
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 2. 数据结构定义
|
|
22
|
+
|
|
23
|
+
### TypeScript 类型定义
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
/** 安全检测请求(顶层结构) */
|
|
27
|
+
interface SecurityCheckRequest {
|
|
28
|
+
/** 应用 ID(必须) */
|
|
29
|
+
Appid: string;
|
|
30
|
+
|
|
31
|
+
/** 服务 ID(必须) */
|
|
32
|
+
ServiceId: string;
|
|
33
|
+
|
|
34
|
+
/** 类型(必须),固定为 1 */
|
|
35
|
+
Type: number;
|
|
36
|
+
|
|
37
|
+
/** Agent ID(必须) */
|
|
38
|
+
AgentId: string;
|
|
39
|
+
|
|
40
|
+
/** 设备 ID(必须) */
|
|
41
|
+
DeviceId: string;
|
|
42
|
+
|
|
43
|
+
/** 检测数据(必须) */
|
|
44
|
+
Data: SecurityCheckData;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 安全检测数据 */
|
|
48
|
+
interface SecurityCheckData {
|
|
49
|
+
/** Hook 名称(必须),标识当前触发的 hook */
|
|
50
|
+
hook: HookType;
|
|
51
|
+
|
|
52
|
+
/** 时间戳,毫秒(必须) */
|
|
53
|
+
timestamp: number;
|
|
54
|
+
|
|
55
|
+
/** 事件数据,按 hook 类型分组(只有当前 hook 对应的字段有值,其他为空对象) */
|
|
56
|
+
events: EventsData;
|
|
57
|
+
|
|
58
|
+
/** 上下文数据 */
|
|
59
|
+
ctx: ContextData;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type HookType =
|
|
63
|
+
| "message_received" // 用户消息到达
|
|
64
|
+
| "before_prompt_build" // 提示词构建前
|
|
65
|
+
| "llm_input" // LLM 请求发送前
|
|
66
|
+
| "before_tool_call" // 工具调用前
|
|
67
|
+
| "tool_result_persist" // 工具结果持久化前
|
|
68
|
+
| "before_message_write" // 消息写入存储前
|
|
69
|
+
| "message_sending"; // 向外部渠道发送前
|
|
70
|
+
|
|
71
|
+
interface EventsData {
|
|
72
|
+
/** 用户消息到达事件数据 */
|
|
73
|
+
message_received: MessageReceivedEvents | {};
|
|
74
|
+
|
|
75
|
+
/** 提示词构建前事件数据 */
|
|
76
|
+
before_prompt_build: BeforePromptBuildEvents | {};
|
|
77
|
+
|
|
78
|
+
/** LLM 请求发送前事件数据 */
|
|
79
|
+
llm_input: LlmInputEvents | {};
|
|
80
|
+
|
|
81
|
+
/** 工具调用前事件数据 */
|
|
82
|
+
before_tool_call: BeforeToolCallEvents | {};
|
|
83
|
+
|
|
84
|
+
/** 工具结果持久化前事件数据 */
|
|
85
|
+
tool_result_persist: ToolResultPersistEvents | {};
|
|
86
|
+
|
|
87
|
+
/** 消息写入存储前事件数据 */
|
|
88
|
+
before_message_write: BeforeMessageWriteEvents | {};
|
|
89
|
+
|
|
90
|
+
/** 向外部渠道发送前事件数据 */
|
|
91
|
+
message_sending: MessageSendingEvents | {};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ========== 各 Hook 事件数据结构 ==========
|
|
95
|
+
|
|
96
|
+
/** message_received 事件数据 */
|
|
97
|
+
interface MessageReceivedEvents {
|
|
98
|
+
from?: string;
|
|
99
|
+
content: string;
|
|
100
|
+
metadata: {
|
|
101
|
+
provider: string;
|
|
102
|
+
surface: string;
|
|
103
|
+
originatingChannel: string;
|
|
104
|
+
messageId: string;
|
|
105
|
+
senderId: string;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** before_prompt_build 事件数据 */
|
|
110
|
+
interface BeforePromptBuildEvents {
|
|
111
|
+
prompt: string;
|
|
112
|
+
// 注意:messages 数组因数据量过大,不包含在送检数据中
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** llm_input 事件数据 */
|
|
116
|
+
interface LlmInputEvents {
|
|
117
|
+
runId: string;
|
|
118
|
+
sessionId: string;
|
|
119
|
+
provider: string;
|
|
120
|
+
model: string;
|
|
121
|
+
prompt: string;
|
|
122
|
+
imagesCount: number;
|
|
123
|
+
// 注意:以下字段因数据量过大,不包含在送检数据中:
|
|
124
|
+
// - systemPrompt: 系统提示词(可能非常长)
|
|
125
|
+
// - historyMessages: 历史消息数组
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** before_tool_call 事件数据 */
|
|
129
|
+
interface BeforeToolCallEvents {
|
|
130
|
+
toolName: string;
|
|
131
|
+
params: Record<string, unknown>;
|
|
132
|
+
runId: string;
|
|
133
|
+
toolCallId: string;
|
|
134
|
+
/** Skill 名称(当检测到读取 SKILL.md 时填充,否则为空字符串) */
|
|
135
|
+
skillName: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** tool_result_persist 事件数据 */
|
|
139
|
+
interface ToolResultPersistEvents {
|
|
140
|
+
toolName: string;
|
|
141
|
+
toolCallId: string;
|
|
142
|
+
content: string; // 提取后的工具输出内容
|
|
143
|
+
isError: boolean;
|
|
144
|
+
isSynthetic: boolean;
|
|
145
|
+
// 注意:原始 message 对象因结构复杂且数据量大,已简化为 content 字符串
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** before_message_write 事件数据 */
|
|
149
|
+
interface BeforeMessageWriteEvents {
|
|
150
|
+
role: "user" | "assistant" | "toolResult";
|
|
151
|
+
content: string; // 提取后的消息内容
|
|
152
|
+
stopReason?: string; // assistant 角色特有
|
|
153
|
+
usage?: UsageInfo; // assistant 角色特有
|
|
154
|
+
toolName?: string; // toolResult 角色特有
|
|
155
|
+
isError?: boolean; // toolResult 角色特有
|
|
156
|
+
// 注意:原始 message 对象因结构复杂,已简化为扁平结构
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** message_sending 事件数据 */
|
|
160
|
+
interface MessageSendingEvents {
|
|
161
|
+
to: string;
|
|
162
|
+
content: string;
|
|
163
|
+
metadata?: Record<string, unknown>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ========== 辅助类型定义 ==========
|
|
167
|
+
|
|
168
|
+
/** Token 使用统计 */
|
|
169
|
+
interface UsageInfo {
|
|
170
|
+
input: number;
|
|
171
|
+
output: number;
|
|
172
|
+
cacheRead: number;
|
|
173
|
+
cacheWrite: number;
|
|
174
|
+
totalTokens: number;
|
|
175
|
+
cost: {
|
|
176
|
+
input: number;
|
|
177
|
+
output: number;
|
|
178
|
+
cacheRead: number;
|
|
179
|
+
cacheWrite: number;
|
|
180
|
+
total: number;
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ========== 上下文数据结构 ==========
|
|
185
|
+
|
|
186
|
+
interface ContextData {
|
|
187
|
+
/** Agent ID */
|
|
188
|
+
agentId?: string;
|
|
189
|
+
|
|
190
|
+
/** 会话 ID(UUID 格式) */
|
|
191
|
+
sessionId?: string;
|
|
192
|
+
|
|
193
|
+
/** 运行 ID(单次 LLM 调用追踪) */
|
|
194
|
+
runId?: string;
|
|
195
|
+
|
|
196
|
+
/** 工具名称(工具相关 hook) */
|
|
197
|
+
toolName?: string;
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 3. 字段详解
|
|
204
|
+
|
|
205
|
+
### 3.1 请求包装字段
|
|
206
|
+
|
|
207
|
+
| 字段 | 类型 | 必须 | 说明 |
|
|
208
|
+
|------|------|:----:|------|
|
|
209
|
+
| `Appid` | string | ✅ | 应用 ID,用于标识调用方应用 |
|
|
210
|
+
| `ServiceId` | string | ✅ | 服务 ID,用于标识安全检测服务 |
|
|
211
|
+
| `Type` | number | ✅ | 请求类型,固定为 1 |
|
|
212
|
+
| `AgentId` | string | ✅ | Agent ID,用于标识 Agent 实例 |
|
|
213
|
+
| `DeviceId` | string | ✅ | 设备 ID,用于标识设备实例 |
|
|
214
|
+
| `Data` | object | ✅ | 安全检测数据,包含 hook、timestamp、events、ctx |
|
|
215
|
+
|
|
216
|
+
### 3.2 Data 内部字段
|
|
217
|
+
|
|
218
|
+
| 字段 | 类型 | 必须 | 说明 |
|
|
219
|
+
|------|------|:----:|------|
|
|
220
|
+
| `Data.hook` | string | ✅ | Hook 名称,标识当前触发的 hook 类型 |
|
|
221
|
+
| `Data.timestamp` | number | ✅ | 事件时间戳(毫秒) |
|
|
222
|
+
| `Data.events` | object | ✅ | 事件数据,按 hook 类型分组,只有当前 hook 对应的字段有值 |
|
|
223
|
+
| `Data.ctx` | object | ✅ | 上下文数据,来源于 rawContext |
|
|
224
|
+
|
|
225
|
+
### 3.3 events 字段组
|
|
226
|
+
|
|
227
|
+
`events` 对象包含 7 个子字段,分别对应 7 种 hook 类型。**当某个 hook 触发时,只有对应的子字段有值,其他均为空对象 `{}`**。
|
|
228
|
+
|
|
229
|
+
| 子字段 | 对应 Hook | 说明 |
|
|
230
|
+
|--------|-----------|------|
|
|
231
|
+
| `message_received` | message_received | 用户消息数据 |
|
|
232
|
+
| `before_prompt_build` | before_prompt_build | 提示词构建数据 |
|
|
233
|
+
| `llm_input` | llm_input | LLM 请求数据 |
|
|
234
|
+
| `before_tool_call` | before_tool_call | 工具调用数据 |
|
|
235
|
+
| `tool_result_persist` | tool_result_persist | 工具结果数据 |
|
|
236
|
+
| `before_message_write` | before_message_write | 消息写入数据 |
|
|
237
|
+
| `message_sending` | message_sending | 出站消息数据 |
|
|
238
|
+
|
|
239
|
+
### 3.4 ctx 字段组
|
|
240
|
+
|
|
241
|
+
| 字段 | 类型 | 说明 | 使用的 Hook |
|
|
242
|
+
|------|------|------|-------------|
|
|
243
|
+
| `agentId` | string | Agent 实例 ID | 全部 |
|
|
244
|
+
| `sessionId` | string | 会话 ID(UUID 格式) | llm_input, before_tool_call |
|
|
245
|
+
| `runId` | string | 单次 LLM 调用的运行 ID | llm_input, before_tool_call |
|
|
246
|
+
| `toolName` | string | 工具名称 | before_tool_call, tool_result_persist |
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## 4. 各 Hook 事件数据详解
|
|
251
|
+
|
|
252
|
+
### 4.1 message_received
|
|
253
|
+
|
|
254
|
+
用户消息到达时的原始数据。
|
|
255
|
+
|
|
256
|
+
**触发时机**:收到用户消息时
|
|
257
|
+
**返回语义**:观察型,返回 `void`
|
|
258
|
+
|
|
259
|
+
#### events.message_received 字段
|
|
260
|
+
|
|
261
|
+
| 字段 | 类型 | 说明 |
|
|
262
|
+
|------|------|------|
|
|
263
|
+
| `from` | string | 发送者标识(可能为空) |
|
|
264
|
+
| `content` | string | 用户消息内容 |
|
|
265
|
+
| `metadata.provider` | string | 消息提供者(如 "openclaw") |
|
|
266
|
+
| `metadata.surface` | string | 消息表面(如 "ingress") |
|
|
267
|
+
| `metadata.originatingChannel` | string | 来源渠道 |
|
|
268
|
+
| `metadata.messageId` | string | 消息唯一ID |
|
|
269
|
+
| `metadata.senderId` | string | 发送者ID |
|
|
270
|
+
|
|
271
|
+
#### ctx 字段
|
|
272
|
+
|
|
273
|
+
| 字段 | 类型 | 说明 |
|
|
274
|
+
|------|------|------|
|
|
275
|
+
| `agentId` | string | Agent 标识 |
|
|
276
|
+
| `sessionId` | string | 会话ID |
|
|
277
|
+
| `runId` | string | 运行ID |
|
|
278
|
+
| `toolName` | string | 工具名称(如有) |
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
### 4.2 before_prompt_build
|
|
283
|
+
|
|
284
|
+
提示词构建前的原始数据。
|
|
285
|
+
|
|
286
|
+
**触发时机**:构建最终 prompt 前
|
|
287
|
+
**返回语义**:观察型,返回 `void`
|
|
288
|
+
|
|
289
|
+
#### events.before_prompt_build 字段
|
|
290
|
+
|
|
291
|
+
| 字段 | 类型 | 说明 |
|
|
292
|
+
|------|------|------|
|
|
293
|
+
| `prompt` | string | 格式化后的提示词 |
|
|
294
|
+
|
|
295
|
+
> ⚠️ **省略字段**:`messages` 数组(历史消息)因数据量过大,不包含在送检数据中
|
|
296
|
+
|
|
297
|
+
#### ctx 字段
|
|
298
|
+
|
|
299
|
+
| 字段 | 类型 | 说明 |
|
|
300
|
+
|------|------|------|
|
|
301
|
+
| `agentId` | string | Agent 标识 |
|
|
302
|
+
| `sessionId` | string | 会话ID |
|
|
303
|
+
| `runId` | string | 运行ID |
|
|
304
|
+
| `toolName` | string | 工具名称(如有) |
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
### 4.3 llm_input
|
|
309
|
+
|
|
310
|
+
LLM 请求发送前的原始数据。
|
|
311
|
+
|
|
312
|
+
**触发时机**:LLM 输入组装完成时
|
|
313
|
+
**返回语义**:观察型(OpenClaw 当前不消费返回值做阻断)
|
|
314
|
+
|
|
315
|
+
#### events.llm_input 字段
|
|
316
|
+
|
|
317
|
+
| 字段 | 类型 | 说明 |
|
|
318
|
+
|------|------|------|
|
|
319
|
+
| `runId` | string | 运行ID |
|
|
320
|
+
| `sessionId` | string | 会话ID |
|
|
321
|
+
| `provider` | string | LLM 提供者(如 "custom-hunyuanapi-woa-com") |
|
|
322
|
+
| `model` | string | 模型名称(如 "hunyuan-2.0-instruct-20251111") |
|
|
323
|
+
| `prompt` | string | 用户提示词(格式化后) |
|
|
324
|
+
| `imagesCount` | number | 图片数量 |
|
|
325
|
+
|
|
326
|
+
> ⚠️ **省略字段**:
|
|
327
|
+
> - `systemPrompt`:系统提示词(可能非常长,通常数万字符)
|
|
328
|
+
> - `historyMessages`:历史消息数组(数据量过大)
|
|
329
|
+
|
|
330
|
+
#### ctx 字段
|
|
331
|
+
|
|
332
|
+
| 字段 | 类型 | 说明 |
|
|
333
|
+
|------|------|------|
|
|
334
|
+
| `agentId` | string | Agent 标识 |
|
|
335
|
+
| `sessionId` | string | 会话ID |
|
|
336
|
+
| `runId` | string | 运行ID |
|
|
337
|
+
| `toolName` | string | 工具名称(如有) |
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
### 4.4 before_tool_call
|
|
342
|
+
|
|
343
|
+
工具调用执行前的原始数据。
|
|
344
|
+
|
|
345
|
+
**触发时机**:工具执行前
|
|
346
|
+
**返回语义**:可返回 `{ block?: boolean; blockReason?: string }`
|
|
347
|
+
|
|
348
|
+
#### events.before_tool_call 字段
|
|
349
|
+
|
|
350
|
+
| 字段 | 类型 | 说明 |
|
|
351
|
+
|------|------|------|
|
|
352
|
+
| `toolName` | string | 工具名称(如 "exec"、"read") |
|
|
353
|
+
| `params` | object | 工具参数对象(如 `{"command": "ls -la"}`) |
|
|
354
|
+
| `runId` | string | 运行ID |
|
|
355
|
+
| `toolCallId` | string | 工具调用ID |
|
|
356
|
+
| `skillName` | string | Skill 名称(当检测到读取 SKILL.md 时填充,否则为空字符串) |
|
|
357
|
+
|
|
358
|
+
> **Skill 名称识别逻辑**:
|
|
359
|
+
> - 当 `toolName` 为 `"read"` 且 `params.path` 以 `SKILL.md` 结尾时,会尝试识别 skill 名称
|
|
360
|
+
> - 优先从 SKILL.md 文件内容的 YAML frontmatter 中解析 `name` 字段
|
|
361
|
+
> - 如果解析失败,则从路径中提取(SKILL.md 的上一级目录名)
|
|
362
|
+
> - 如果不是读取 SKILL.md 的操作,`skillName` 为空字符串
|
|
363
|
+
|
|
364
|
+
#### ctx 字段
|
|
365
|
+
|
|
366
|
+
| 字段 | 类型 | 说明 |
|
|
367
|
+
|------|------|------|
|
|
368
|
+
| `agentId` | string | Agent 标识 |
|
|
369
|
+
| `sessionId` | string | 会话ID |
|
|
370
|
+
| `runId` | string | 运行ID |
|
|
371
|
+
| `toolName` | string | 工具名称 |
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
### 4.5 tool_result_persist
|
|
376
|
+
|
|
377
|
+
工具结果持久化前的原始数据。
|
|
378
|
+
|
|
379
|
+
**触发时机**:工具结果持久化前
|
|
380
|
+
**返回语义**:同步 hook,可返回 `{ message?: unknown }`
|
|
381
|
+
|
|
382
|
+
#### events.tool_result_persist 字段
|
|
383
|
+
|
|
384
|
+
| 字段 | 类型 | 说明 |
|
|
385
|
+
|------|------|------|
|
|
386
|
+
| `toolName` | string | 工具名称 |
|
|
387
|
+
| `toolCallId` | string | 工具调用ID |
|
|
388
|
+
| `content` | string | 工具输出内容(已提取为字符串) |
|
|
389
|
+
| `isError` | boolean | 是否错误 |
|
|
390
|
+
| `isSynthetic` | boolean | 是否合成结果 |
|
|
391
|
+
|
|
392
|
+
> ⚠️ **简化说明**:原始 `message` 对象包含复杂的嵌套结构(如 `content` 数组、`details` 对象等),已简化为 `content` 字符串以减少数据量
|
|
393
|
+
|
|
394
|
+
#### ctx 字段
|
|
395
|
+
|
|
396
|
+
| 字段 | 类型 | 说明 |
|
|
397
|
+
|------|------|------|
|
|
398
|
+
| `agentId` | string | Agent 标识 |
|
|
399
|
+
| `sessionId` | string | 会话ID |
|
|
400
|
+
| `runId` | string | 运行ID |
|
|
401
|
+
| `toolName` | string | 工具名称 |
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
### 4.6 before_message_write
|
|
406
|
+
|
|
407
|
+
消息写入存储前的原始数据。根据 `role` 不同,字段有所差异。
|
|
408
|
+
|
|
409
|
+
**触发时机**:消息写库前
|
|
410
|
+
**返回语义**:同步 hook,可返回 `{ block?: boolean; message?: unknown }`
|
|
411
|
+
|
|
412
|
+
#### events.before_message_write 字段
|
|
413
|
+
|
|
414
|
+
| 字段 | 类型 | 说明 |
|
|
415
|
+
|------|------|------|
|
|
416
|
+
| `role` | string | 消息角色:"user" / "assistant" / "toolResult" |
|
|
417
|
+
| `content` | string | 消息内容(已提取为字符串) |
|
|
418
|
+
| `stopReason` | string | 停止原因(仅 assistant 角色,如 "stop" 或 "toolUse") |
|
|
419
|
+
| `usage` | object | Token 使用统计(仅 assistant 角色,包含 input, output, totalTokens, cost 等) |
|
|
420
|
+
| `toolName` | string | 工具名称(仅 toolResult 角色) |
|
|
421
|
+
| `isError` | boolean | 是否错误(仅 toolResult 角色) |
|
|
422
|
+
|
|
423
|
+
> ⚠️ **简化说明**:原始 `message` 对象包含复杂的嵌套结构(如 `content` 数组、`timestamp` 等),已简化为扁平结构以减少数据量
|
|
424
|
+
|
|
425
|
+
#### ctx 字段
|
|
426
|
+
|
|
427
|
+
| 字段 | 类型 | 说明 |
|
|
428
|
+
|------|------|------|
|
|
429
|
+
| `agentId` | string | Agent 标识 |
|
|
430
|
+
| `sessionId` | string | 会话ID |
|
|
431
|
+
| `runId` | string | 运行ID |
|
|
432
|
+
| `toolName` | string | 工具名称(如有) |
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
### 4.7 message_sending
|
|
437
|
+
|
|
438
|
+
向外部渠道发送前的原始数据。
|
|
439
|
+
|
|
440
|
+
**触发时机**:消息发送给用户前
|
|
441
|
+
**返回语义**:可返回 `{ content?: string; cancel?: boolean }`
|
|
442
|
+
|
|
443
|
+
#### events.message_sending 字段
|
|
444
|
+
|
|
445
|
+
| 字段 | 类型 | 说明 |
|
|
446
|
+
|------|------|------|
|
|
447
|
+
| `to` | string | 消息接收者标识 |
|
|
448
|
+
| `content` | string | 发送的消息内容 |
|
|
449
|
+
| `metadata` | object | 附加元数据(可选) |
|
|
450
|
+
|
|
451
|
+
#### ctx 字段
|
|
452
|
+
|
|
453
|
+
| 字段 | 类型 | 说明 |
|
|
454
|
+
|------|------|------|
|
|
455
|
+
| `agentId` | string | Agent 标识 |
|
|
456
|
+
| `sessionId` | string | 会话ID |
|
|
457
|
+
| `runId` | string | 运行ID |
|
|
458
|
+
| `toolName` | string | 工具名称(如有) |
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## 5. 示例数据
|
|
463
|
+
|
|
464
|
+
### 5.1 message_received
|
|
465
|
+
|
|
466
|
+
```json
|
|
467
|
+
{
|
|
468
|
+
"Appid": "100001",
|
|
469
|
+
"ServiceId": "your_service_id",
|
|
470
|
+
"Type": 1,
|
|
471
|
+
"AgentId": "main",
|
|
472
|
+
"DeviceId": "openclaw_device_001",
|
|
473
|
+
"Data": {
|
|
474
|
+
"hook": "message_received",
|
|
475
|
+
"timestamp": 1741750768766,
|
|
476
|
+
"events": {
|
|
477
|
+
"message_received": {
|
|
478
|
+
"from": "",
|
|
479
|
+
"content": "帮我查看 /tmp 目录下有哪些文件",
|
|
480
|
+
"metadata": {
|
|
481
|
+
"provider": "openclaw",
|
|
482
|
+
"surface": "ingress",
|
|
483
|
+
"originatingChannel": "unknown",
|
|
484
|
+
"messageId": "msg_1741750768766",
|
|
485
|
+
"senderId": "main"
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
"before_prompt_build": {},
|
|
489
|
+
"llm_input": {},
|
|
490
|
+
"before_tool_call": {},
|
|
491
|
+
"tool_result_persist": {},
|
|
492
|
+
"before_message_write": {},
|
|
493
|
+
"message_sending": {}
|
|
494
|
+
},
|
|
495
|
+
"ctx": {
|
|
496
|
+
"agentId": "main",
|
|
497
|
+
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
|
498
|
+
"runId": "run_xyz789",
|
|
499
|
+
"toolName": ""
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### 5.2 before_prompt_build
|
|
506
|
+
|
|
507
|
+
```json
|
|
508
|
+
{
|
|
509
|
+
"Appid": "100001",
|
|
510
|
+
"ServiceId": "your_service_id",
|
|
511
|
+
"Type": 1,
|
|
512
|
+
"AgentId": "main",
|
|
513
|
+
"DeviceId": "openclaw_device_001",
|
|
514
|
+
"Data": {
|
|
515
|
+
"hook": "before_prompt_build",
|
|
516
|
+
"timestamp": 1741750768800,
|
|
517
|
+
"events": {
|
|
518
|
+
"message_received": {},
|
|
519
|
+
"before_prompt_build": {
|
|
520
|
+
"prompt": "帮我查看 /tmp 目录下有哪些文件"
|
|
521
|
+
},
|
|
522
|
+
"llm_input": {},
|
|
523
|
+
"before_tool_call": {},
|
|
524
|
+
"tool_result_persist": {},
|
|
525
|
+
"before_message_write": {},
|
|
526
|
+
"message_sending": {}
|
|
527
|
+
},
|
|
528
|
+
"ctx": {
|
|
529
|
+
"agentId": "main",
|
|
530
|
+
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
|
531
|
+
"runId": "run_xyz789",
|
|
532
|
+
"toolName": ""
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
> 注意:`messages` 数组(历史消息)因数据量过大,不包含在送检数据中
|
|
539
|
+
|
|
540
|
+
### 5.3 llm_input
|
|
541
|
+
|
|
542
|
+
```json
|
|
543
|
+
{
|
|
544
|
+
"Appid": "100001",
|
|
545
|
+
"ServiceId": "your_service_id",
|
|
546
|
+
"Type": 1,
|
|
547
|
+
"AgentId": "main",
|
|
548
|
+
"DeviceId": "openclaw_device_001",
|
|
549
|
+
"Data": {
|
|
550
|
+
"hook": "llm_input",
|
|
551
|
+
"timestamp": 1741750768949,
|
|
552
|
+
"events": {
|
|
553
|
+
"message_received": {},
|
|
554
|
+
"before_prompt_build": {},
|
|
555
|
+
"llm_input": {
|
|
556
|
+
"runId": "run_xyz789",
|
|
557
|
+
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
|
558
|
+
"provider": "custom-hunyuanapi-woa-com",
|
|
559
|
+
"model": "hunyuan-2.0-instruct-20251111",
|
|
560
|
+
"prompt": "帮我查看 /tmp 目录下有哪些文件",
|
|
561
|
+
"imagesCount": 0
|
|
562
|
+
},
|
|
563
|
+
"before_tool_call": {},
|
|
564
|
+
"tool_result_persist": {},
|
|
565
|
+
"before_message_write": {},
|
|
566
|
+
"message_sending": {}
|
|
567
|
+
},
|
|
568
|
+
"ctx": {
|
|
569
|
+
"agentId": "main",
|
|
570
|
+
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
|
571
|
+
"runId": "run_xyz789",
|
|
572
|
+
"toolName": ""
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
> 注意:以下字段因数据量过大,不包含在送检数据中:
|
|
579
|
+
> - `systemPrompt`:系统提示词(可能非常长)
|
|
580
|
+
> - `historyMessages`:历史消息数组
|
|
581
|
+
|
|
582
|
+
### 5.4 before_tool_call
|
|
583
|
+
|
|
584
|
+
```json
|
|
585
|
+
{
|
|
586
|
+
"Appid": "100001",
|
|
587
|
+
"ServiceId": "your_service_id",
|
|
588
|
+
"Type": 1,
|
|
589
|
+
"AgentId": "main",
|
|
590
|
+
"DeviceId": "openclaw_device_001",
|
|
591
|
+
"Data": {
|
|
592
|
+
"hook": "before_tool_call",
|
|
593
|
+
"timestamp": 1741750772191,
|
|
594
|
+
"events": {
|
|
595
|
+
"message_received": {},
|
|
596
|
+
"before_prompt_build": {},
|
|
597
|
+
"llm_input": {},
|
|
598
|
+
"before_tool_call": {
|
|
599
|
+
"toolName": "exec",
|
|
600
|
+
"params": {
|
|
601
|
+
"command": "ls -la /tmp"
|
|
602
|
+
},
|
|
603
|
+
"runId": "run_xyz789",
|
|
604
|
+
"toolCallId": "call_1741750772191",
|
|
605
|
+
"skillName": ""
|
|
606
|
+
},
|
|
607
|
+
"tool_result_persist": {},
|
|
608
|
+
"before_message_write": {},
|
|
609
|
+
"message_sending": {}
|
|
610
|
+
},
|
|
611
|
+
"ctx": {
|
|
612
|
+
"agentId": "main",
|
|
613
|
+
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
|
614
|
+
"runId": "run_xyz789",
|
|
615
|
+
"toolName": "exec"
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### 5.4.1 before_tool_call(读取 SKILL.md 场景)
|
|
622
|
+
|
|
623
|
+
当检测到正在读取 Skill 说明文档时,`skillName` 字段会自动填充:
|
|
624
|
+
|
|
625
|
+
```json
|
|
626
|
+
{
|
|
627
|
+
"Appid": "100001",
|
|
628
|
+
"ServiceId": "your_service_id",
|
|
629
|
+
"Type": 1,
|
|
630
|
+
"AgentId": "main",
|
|
631
|
+
"DeviceId": "openclaw_device_001",
|
|
632
|
+
"Data": {
|
|
633
|
+
"hook": "before_tool_call",
|
|
634
|
+
"timestamp": 1741750772191,
|
|
635
|
+
"events": {
|
|
636
|
+
"message_received": {},
|
|
637
|
+
"before_prompt_build": {},
|
|
638
|
+
"llm_input": {},
|
|
639
|
+
"before_tool_call": {
|
|
640
|
+
"toolName": "read",
|
|
641
|
+
"params": {
|
|
642
|
+
"path": "~/.nvm/versions/node/v22.22.1/lib/node_modules/openclaw/skills/healthcheck/SKILL.md"
|
|
643
|
+
},
|
|
644
|
+
"runId": "run_xyz789",
|
|
645
|
+
"toolCallId": "call_1741750772191",
|
|
646
|
+
"skillName": "healthcheck"
|
|
647
|
+
},
|
|
648
|
+
"tool_result_persist": {},
|
|
649
|
+
"before_message_write": {},
|
|
650
|
+
"message_sending": {}
|
|
651
|
+
},
|
|
652
|
+
"ctx": {
|
|
653
|
+
"agentId": "main",
|
|
654
|
+
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
|
655
|
+
"runId": "run_xyz789",
|
|
656
|
+
"toolName": "read"
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
> **说明**:`skillName` 的值优先从 SKILL.md 文件内容的 YAML frontmatter 中解析(格式如 `name: healthcheck`),解析失败则从路径中提取(SKILL.md 的上一级目录名)。
|
|
663
|
+
|
|
664
|
+
### 5.5 tool_result_persist
|
|
665
|
+
|
|
666
|
+
```json
|
|
667
|
+
{
|
|
668
|
+
"Appid": "100001",
|
|
669
|
+
"ServiceId": "your_service_id",
|
|
670
|
+
"Type": 1,
|
|
671
|
+
"AgentId": "main",
|
|
672
|
+
"DeviceId": "openclaw_device_001",
|
|
673
|
+
"Data": {
|
|
674
|
+
"hook": "tool_result_persist",
|
|
675
|
+
"timestamp": 1741750773781,
|
|
676
|
+
"events": {
|
|
677
|
+
"message_received": {},
|
|
678
|
+
"before_prompt_build": {},
|
|
679
|
+
"llm_input": {},
|
|
680
|
+
"before_tool_call": {},
|
|
681
|
+
"tool_result_persist": {
|
|
682
|
+
"toolName": "exec",
|
|
683
|
+
"toolCallId": "call_1741750773781",
|
|
684
|
+
"content": "total 4\ndrwxrwxrwt 2 root root 4096 Mar 12 03:26 .\ndrwxr-xr-x 1 root root 4096 Mar 12 03:25 ..",
|
|
685
|
+
"isError": false,
|
|
686
|
+
"isSynthetic": false
|
|
687
|
+
},
|
|
688
|
+
"before_message_write": {},
|
|
689
|
+
"message_sending": {}
|
|
690
|
+
},
|
|
691
|
+
"ctx": {
|
|
692
|
+
"agentId": "main",
|
|
693
|
+
"sessionId": "",
|
|
694
|
+
"runId": "",
|
|
695
|
+
"toolName": "exec"
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
> 注意:原始 `message` 对象包含复杂的嵌套结构,已简化为 `content` 字符串
|
|
702
|
+
|
|
703
|
+
### 5.6 before_message_write (role=user)
|
|
704
|
+
|
|
705
|
+
```json
|
|
706
|
+
{
|
|
707
|
+
"Appid": "100001",
|
|
708
|
+
"ServiceId": "your_service_id",
|
|
709
|
+
"Type": 1,
|
|
710
|
+
"AgentId": "main",
|
|
711
|
+
"DeviceId": "openclaw_device_001",
|
|
712
|
+
"Data": {
|
|
713
|
+
"hook": "before_message_write",
|
|
714
|
+
"timestamp": 1741750768770,
|
|
715
|
+
"events": {
|
|
716
|
+
"message_received": {},
|
|
717
|
+
"before_prompt_build": {},
|
|
718
|
+
"llm_input": {},
|
|
719
|
+
"before_tool_call": {},
|
|
720
|
+
"tool_result_persist": {},
|
|
721
|
+
"before_message_write": {
|
|
722
|
+
"role": "user",
|
|
723
|
+
"content": "帮我查看 /tmp 目录下有哪些文件"
|
|
724
|
+
},
|
|
725
|
+
"message_sending": {}
|
|
726
|
+
},
|
|
727
|
+
"ctx": {
|
|
728
|
+
"agentId": "main",
|
|
729
|
+
"sessionId": "",
|
|
730
|
+
"runId": "",
|
|
731
|
+
"toolName": ""
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
### 5.7 before_message_write (role=assistant)
|
|
738
|
+
|
|
739
|
+
```json
|
|
740
|
+
{
|
|
741
|
+
"Appid": "100001",
|
|
742
|
+
"ServiceId": "your_service_id",
|
|
743
|
+
"Type": 1,
|
|
744
|
+
"AgentId": "main",
|
|
745
|
+
"DeviceId": "openclaw_device_001",
|
|
746
|
+
"Data": {
|
|
747
|
+
"hook": "before_message_write",
|
|
748
|
+
"timestamp": 1741750782718,
|
|
749
|
+
"events": {
|
|
750
|
+
"message_received": {},
|
|
751
|
+
"before_prompt_build": {},
|
|
752
|
+
"llm_input": {},
|
|
753
|
+
"before_tool_call": {},
|
|
754
|
+
"tool_result_persist": {},
|
|
755
|
+
"before_message_write": {
|
|
756
|
+
"role": "assistant",
|
|
757
|
+
"content": "/tmp 目录下当前没有用户文件,只有标准的 . 和 .. 目录项。"
|
|
758
|
+
},
|
|
759
|
+
"message_sending": {}
|
|
760
|
+
},
|
|
761
|
+
"ctx": {
|
|
762
|
+
"agentId": "main",
|
|
763
|
+
"sessionId": "",
|
|
764
|
+
"runId": "",
|
|
765
|
+
"toolName": ""
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
> 注意:原始 `message` 对象包含 `usage`、`stopReason` 等字段,已简化
|
|
772
|
+
|
|
773
|
+
### 5.8 before_message_write (role=toolResult)
|
|
774
|
+
|
|
775
|
+
```json
|
|
776
|
+
{
|
|
777
|
+
"Appid": "100001",
|
|
778
|
+
"ServiceId": "your_service_id",
|
|
779
|
+
"Type": 1,
|
|
780
|
+
"AgentId": "main",
|
|
781
|
+
"DeviceId": "openclaw_device_001",
|
|
782
|
+
"Data": {
|
|
783
|
+
"hook": "before_message_write",
|
|
784
|
+
"timestamp": 1741750773784,
|
|
785
|
+
"events": {
|
|
786
|
+
"message_received": {},
|
|
787
|
+
"before_prompt_build": {},
|
|
788
|
+
"llm_input": {},
|
|
789
|
+
"before_tool_call": {},
|
|
790
|
+
"tool_result_persist": {},
|
|
791
|
+
"before_message_write": {
|
|
792
|
+
"role": "toolResult",
|
|
793
|
+
"content": "total 4\ndrwxrwxrwt 2 root root 4096 Mar 12 03:26 .",
|
|
794
|
+
"toolName": "exec",
|
|
795
|
+
"isError": false
|
|
796
|
+
},
|
|
797
|
+
"message_sending": {}
|
|
798
|
+
},
|
|
799
|
+
"ctx": {
|
|
800
|
+
"agentId": "main",
|
|
801
|
+
"sessionId": "",
|
|
802
|
+
"runId": "",
|
|
803
|
+
"toolName": "exec"
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
> 注意:原始 `message` 对象包含复杂的嵌套结构,已简化为扁平结构
|
|
810
|
+
|
|
811
|
+
### 5.9 message_sending
|
|
812
|
+
|
|
813
|
+
```json
|
|
814
|
+
{
|
|
815
|
+
"Appid": "100001",
|
|
816
|
+
"ServiceId": "your_service_id",
|
|
817
|
+
"Type": 1,
|
|
818
|
+
"AgentId": "main",
|
|
819
|
+
"DeviceId": "openclaw_device_001",
|
|
820
|
+
"Data": {
|
|
821
|
+
"hook": "message_sending",
|
|
822
|
+
"timestamp": 1741750782900,
|
|
823
|
+
"events": {
|
|
824
|
+
"message_received": {},
|
|
825
|
+
"before_prompt_build": {},
|
|
826
|
+
"llm_input": {},
|
|
827
|
+
"before_tool_call": {},
|
|
828
|
+
"tool_result_persist": {},
|
|
829
|
+
"before_message_write": {},
|
|
830
|
+
"message_sending": {
|
|
831
|
+
"to": "unknown",
|
|
832
|
+
"content": "/tmp 目录下当前没有用户文件,只有标准的 . 和 .. 目录项。",
|
|
833
|
+
"metadata": {}
|
|
834
|
+
}
|
|
835
|
+
},
|
|
836
|
+
"ctx": {
|
|
837
|
+
"agentId": "main",
|
|
838
|
+
"sessionId": "",
|
|
839
|
+
"runId": "",
|
|
840
|
+
"toolName": ""
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
---
|
|
847
|
+
|
|
848
|
+
## 6. 安全检测服务建议
|
|
849
|
+
|
|
850
|
+
### 6.1 按 Hook 类型的检测重点
|
|
851
|
+
|
|
852
|
+
| Hook | events 子字段 | 检测重点 |
|
|
853
|
+
|------|---------------|----------|
|
|
854
|
+
| `message_received` | `message_received` | 用户输入恶意内容检测、注入攻击检测、敏感词过滤 |
|
|
855
|
+
| `before_prompt_build` | `before_prompt_build` | 提示词注入检测、上下文污染检测 |
|
|
856
|
+
| `llm_input` | `llm_input` | 模型滥用检测 |
|
|
857
|
+
| `before_tool_call` | `before_tool_call` | 危险命令拦截、敏感文件访问检测、权限越界检测 |
|
|
858
|
+
| `tool_result_persist` | `tool_result_persist` | 敏感输出检测、数据泄露检测 |
|
|
859
|
+
| `before_message_write` | `before_message_write` | 敏感信息脱敏、内容合规检查 |
|
|
860
|
+
| `message_sending` | `message_sending` | 出站敏感信息检测、合规审查 |
|
|
861
|
+
|
|
862
|
+
### 6.2 字段优先级
|
|
863
|
+
|
|
864
|
+
安全检测时建议优先关注的字段:
|
|
865
|
+
|
|
866
|
+
**高优先级**:
|
|
867
|
+
- `message_received.content` - 用户原始输入
|
|
868
|
+
- `before_tool_call.toolName` + `before_tool_call.params` - 工具调用
|
|
869
|
+
- `llm_input.prompt` - LLM 请求内容
|
|
870
|
+
|
|
871
|
+
**中优先级**:
|
|
872
|
+
- `tool_result_persist.content` - 工具输出
|
|
873
|
+
- `before_message_write.content` - 写入消息内容
|
|
874
|
+
- `message_received.metadata.senderId` - 发送者身份
|
|
875
|
+
|
|
876
|
+
**低优先级**:
|
|
877
|
+
- `llm_input.provider` / `model` - LLM 提供者信息
|
|
878
|
+
- `ctx.*` - 上下文信息
|
|
879
|
+
|
|
880
|
+
### 6.3 建议响应格式
|
|
881
|
+
|
|
882
|
+
```json
|
|
883
|
+
{
|
|
884
|
+
"action": "allow",
|
|
885
|
+
"reason": "no-risk-detected",
|
|
886
|
+
"reasonCodes": ["SAFE"],
|
|
887
|
+
"mutations": {}
|
|
888
|
+
}
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
```json
|
|
892
|
+
{
|
|
893
|
+
"action": "block",
|
|
894
|
+
"reason": "high-risk-command",
|
|
895
|
+
"reasonCodes": ["RISK_EXEC_COMMAND"],
|
|
896
|
+
"mutations": {
|
|
897
|
+
"blockReason": "命令存在高风险,已拦截"
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
---
|
|
903
|
+
|
|
904
|
+
## 7. 重要设计说明
|
|
905
|
+
|
|
906
|
+
### 7.1 设计原则
|
|
907
|
+
|
|
908
|
+
1. **精简数据结构**:events 中的数据提取关键检测字段,省略过长的数据(如历史消息、系统提示词等),以减少网络传输和处理开销
|
|
909
|
+
2. **按 hook 分组**:events 对象包含所有 7 种 hook 的子字段,但只有当前触发的 hook 对应的字段有值
|
|
910
|
+
3. **统一接口**:所有 hook 共用同一个接口格式,便于安全检测服务统一处理
|
|
911
|
+
|
|
912
|
+
### 7.2 数据处理流程
|
|
913
|
+
|
|
914
|
+
1. 安全检测服务收到请求后,首先检查 `hook` 字段确定当前触发的 hook 类型
|
|
915
|
+
2. 根据 hook 类型,从 `events` 对象中提取对应的子字段数据
|
|
916
|
+
3. 其他子字段均为空对象 `{}`,可以忽略
|
|
917
|
+
|
|
918
|
+
### 7.3 省略字段说明
|
|
919
|
+
|
|
920
|
+
为了减少网络传输和处理开销,以下字段因数据量过大而不包含在送检数据中:
|
|
921
|
+
|
|
922
|
+
| Hook | 省略字段 | 说明 |
|
|
923
|
+
|------|---------|------|
|
|
924
|
+
| `before_prompt_build` | `messages` | 历史消息数组,可能包含大量历史对话 |
|
|
925
|
+
| `llm_input` | `systemPrompt` | 系统提示词,通常数万字符 |
|
|
926
|
+
| `llm_input` | `historyMessages` | 历史消息数组 |
|
|
927
|
+
| `tool_result_persist` | 完整 `message` 对象 | 简化为 `content` 字符串 |
|
|
928
|
+
| `before_message_write` | 完整 `message` 对象 | 简化为扁平结构 |
|
|
929
|
+
|
|
930
|
+
### 7.4 ctx 字段来源
|
|
931
|
+
|
|
932
|
+
`ctx` 字段包含当前请求的上下文信息,不同 hook 可能包含不同的字段组合:
|
|
933
|
+
|
|
934
|
+
| Hook | ctx 包含的主要字段 |
|
|
935
|
+
|------|-------------------|
|
|
936
|
+
| message_received | agentId, sessionId, runId, toolName |
|
|
937
|
+
| before_prompt_build | agentId, sessionId, runId, toolName |
|
|
938
|
+
| llm_input | agentId, sessionId, runId, toolName |
|
|
939
|
+
| before_tool_call | agentId, sessionId, runId, toolName |
|
|
940
|
+
| tool_result_persist | agentId, sessionId, runId, toolName |
|
|
941
|
+
| before_message_write | agentId, sessionId, runId, toolName |
|
|
942
|
+
| message_sending | agentId, sessionId, runId, toolName |
|
|
943
|
+
|
|
944
|
+
---
|
|
945
|
+
|
|
946
|
+
## 8. 通用数据模板
|
|
947
|
+
|
|
948
|
+
以下是一个包含所有可能字段的通用模板,实际数据只有当前 hook 对应的 events 子字段有值:
|
|
949
|
+
|
|
950
|
+
```json
|
|
951
|
+
{
|
|
952
|
+
"Appid": "100001",
|
|
953
|
+
"ServiceId": "your_service_id",
|
|
954
|
+
"Type": 1,
|
|
955
|
+
"AgentId": "main",
|
|
956
|
+
"DeviceId": "openclaw_device_001",
|
|
957
|
+
"Data": {
|
|
958
|
+
"hook": "message_received | before_prompt_build | llm_input | before_tool_call | tool_result_persist | before_message_write | message_sending",
|
|
959
|
+
"timestamp": 1741750768766,
|
|
960
|
+
"events": {
|
|
961
|
+
"message_received": {
|
|
962
|
+
"from": "发送者标识",
|
|
963
|
+
"content": "用户消息内容",
|
|
964
|
+
"metadata": {
|
|
965
|
+
"provider": "openclaw",
|
|
966
|
+
"surface": "ingress",
|
|
967
|
+
"originatingChannel": "unknown",
|
|
968
|
+
"messageId": "消息唯一ID",
|
|
969
|
+
"senderId": "发送者ID"
|
|
970
|
+
}
|
|
971
|
+
},
|
|
972
|
+
"before_prompt_build": {
|
|
973
|
+
"prompt": "格式化后的提示词"
|
|
974
|
+
},
|
|
975
|
+
"llm_input": {
|
|
976
|
+
"runId": "运行ID",
|
|
977
|
+
"sessionId": "会话ID",
|
|
978
|
+
"provider": "LLM提供者",
|
|
979
|
+
"model": "模型名称",
|
|
980
|
+
"prompt": "用户提示词",
|
|
981
|
+
"imagesCount": 0
|
|
982
|
+
},
|
|
983
|
+
"before_tool_call": {
|
|
984
|
+
"toolName": "工具名称",
|
|
985
|
+
"params": {},
|
|
986
|
+
"runId": "运行ID",
|
|
987
|
+
"toolCallId": "工具调用ID",
|
|
988
|
+
"skillName": "Skill名称(读取SKILL.md时填充)"
|
|
989
|
+
},
|
|
990
|
+
"tool_result_persist": {
|
|
991
|
+
"toolName": "工具名称",
|
|
992
|
+
"toolCallId": "工具调用ID",
|
|
993
|
+
"content": "工具输出内容",
|
|
994
|
+
"isError": false,
|
|
995
|
+
"isSynthetic": false
|
|
996
|
+
},
|
|
997
|
+
"before_message_write": {
|
|
998
|
+
"role": "user | assistant | toolResult",
|
|
999
|
+
"content": "消息内容"
|
|
1000
|
+
},
|
|
1001
|
+
"message_sending": {
|
|
1002
|
+
"to": "接收者ID",
|
|
1003
|
+
"content": "发送内容",
|
|
1004
|
+
"metadata": {}
|
|
1005
|
+
}
|
|
1006
|
+
},
|
|
1007
|
+
"ctx": {
|
|
1008
|
+
"agentId": "Agent ID",
|
|
1009
|
+
"sessionId": "会话ID (UUID)",
|
|
1010
|
+
"runId": "运行ID",
|
|
1011
|
+
"toolName": "工具名称"
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
> **说明**:实际调用时,根据 `Data.hook` 字段的值,只有对应的 `events` 子字段有数据,其他均为空对象 `{}`。
|