openclaw-glance-plugin 0.1.18 → 0.1.21
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/openclaw.plugin.json +0 -4
- package/package.json +1 -1
- package/skills/glance-watch/SKILL.md +57 -481
- package/skills/glance-watch/references/channels.md +80 -0
- package/skills/glance-watch/references/examples.md +43 -0
- package/skills/glance-watch/references/query-and-symbol.md +69 -0
- package/skills/glance-watch/references/troubleshooting.md +40 -0
- package/skills/glance-watch/references/watch-contract.md +132 -0
- package/src/config/runtime-config.js +1 -15
- package/src/plugin/index.js +19 -41
- package/src/plugin/watch-notify-contacts.js +0 -478
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -3,31 +3,19 @@ name: glance-watch
|
|
|
3
3
|
description: 智能盯盘插件,用于监控A股、港股、比特币等金融市场行情并在条件触发时发送提醒。当用户要求盯盘、监控价格、设置提醒、需要通过邮件/电话/短信/钉钉发起通知时自动触发,例如"帮我盯着比特币"、监控某只股票、涨跌幅提醒、短信通知我等。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Glance Watch
|
|
6
|
+
# Glance Watch 智能盯盘(主入口)
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## 目标
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
用最小上下文完成三类任务:
|
|
11
|
+
- 查行情:`watch.query_ticker`
|
|
12
|
+
- 建/管策略:`watch.create` / `watch.list` / `watch.pause` / `watch.activate` / `watch.remove`
|
|
13
|
+
- 立即通知:`notify.sms` / `notify.call` / `notify.email` / `notify.dingtalk`
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
- `product_code`: 产品代码
|
|
16
|
-
- `product_type`: 市场类型 (stock/index/hk_stock/crypto)
|
|
17
|
-
- `operator_type`: 固定为 `rule`
|
|
18
|
-
- `operator_parameters.condition`: 条件表达式
|
|
19
|
-
- `operator_parameters.variables`: 变量值
|
|
20
|
-
|
|
21
|
-
3. **通过已安装运行时提交盯盘请求**(长连接由宿主运行时维护)
|
|
22
|
-
4. **用户要求“查行情/看当前价格/报价”时**,优先调用 `queryTickerData` 获取实时数据,再决定是否创建盯盘策略。
|
|
23
|
-
5. **用户要求“发短信/打电话/发邮件/发钉钉”时**,调用对应 `notify.*` 动作直接发送。
|
|
24
|
-
|
|
25
|
-
## 调用契约(必须遵循)
|
|
15
|
+
## 调用契约(硬约束)
|
|
26
16
|
|
|
27
17
|
### 统一动作名
|
|
28
18
|
|
|
29
|
-
宿主需将已安装插件/包接口映射为以下动作名(建议保持一致):
|
|
30
|
-
|
|
31
19
|
- `watch.query_ticker`
|
|
32
20
|
- `watch.create`
|
|
33
21
|
- `watch.list`
|
|
@@ -41,483 +29,71 @@ description: 智能盯盘插件,用于监控A股、港股、比特币等金融
|
|
|
41
29
|
|
|
42
30
|
### 调用顺序
|
|
43
31
|
|
|
44
|
-
1.
|
|
45
|
-
2.
|
|
46
|
-
3.
|
|
47
|
-
4.
|
|
48
|
-
5.
|
|
49
|
-
|
|
50
|
-
禁止跳步:创建盯盘前若缺关键字段必须先追问。
|
|
51
|
-
|
|
52
|
-
### 动作参数与成功判定
|
|
53
|
-
|
|
54
|
-
#### `watch.query_ticker`
|
|
32
|
+
1. 用户问“现在多少钱/查行情” -> 先 `watch.query_ticker`
|
|
33
|
+
2. 用户要“盯盘/提醒” -> 补齐参数后 `watch.create`
|
|
34
|
+
3. 用户要“看我的策略” -> `watch.list`
|
|
35
|
+
4. 用户要“暂停/恢复/删除” -> `watch.pause` / `watch.activate` / `watch.remove`
|
|
36
|
+
5. 用户要“马上发通知” -> 对应 `notify.*`
|
|
55
37
|
|
|
56
|
-
|
|
57
|
-
- `stockCode`(或 `productCode`)
|
|
58
|
-
- `productType`
|
|
59
|
-
- `market`(`crypto` 可传空字符串)
|
|
38
|
+
### 创建策略最小必填
|
|
60
39
|
|
|
61
|
-
成功判定:
|
|
62
|
-
- 返回 `code = "000000"` 或 `success = true`
|
|
63
|
-
|
|
64
|
-
失败处理:
|
|
65
|
-
- 返回失败原因
|
|
66
|
-
- 引导用户确认代码/市场后重试
|
|
67
|
-
|
|
68
|
-
#### `watch.create`
|
|
69
|
-
|
|
70
|
-
参数(最少):
|
|
71
40
|
- `product_code`
|
|
72
|
-
- `product_type`
|
|
73
|
-
- `operator_type`
|
|
74
|
-
- `operator_parameters`
|
|
75
|
-
|
|
76
|
-
建议附加:
|
|
77
|
-
- `channels`(默认至少包含 `openclaw`)
|
|
78
|
-
- 对应渠道配置(`channel_configs.email/call/sms/dingtalk`)
|
|
79
|
-
|
|
80
|
-
**OpenClaw 会话路由(含 `openclaw` 渠道时必须带上)**
|
|
81
|
-
触发后要把提醒发回**当前群聊/私聊**,须把路由写入 `channel_configs.openclaw`(或由宿主 `context` 注入,由插件运行时合并)。字段与 openclaw-bridge 一致(snake_case;部分宿主可用 camelCase,由插件归一):
|
|
82
|
-
|
|
83
|
-
| 字段 | 含义 |
|
|
84
|
-
|------|------|
|
|
85
|
-
| `channel` / `source_channel` | 来源渠道(钉钉/飞书等与宿主约定) |
|
|
86
|
-
| `account_id` | 多账号场景下的账号标识 |
|
|
87
|
-
| `session_key` | 推荐:可区分群/私聊、多会话的会话键 |
|
|
88
|
-
| `conversation_id` / `chat_id` | 宿主侧发送目标会话 ID |
|
|
89
|
-
|
|
90
|
-
可从**当前 OpenClaw 上下文**映射到上述字段;**禁止**在拿不到会话信息时留空 `openclaw: {}` 仍假装已配置。宿主通过工具调用传入的 `context`(如 `channelId`、`sessionKey`、`conversationId`)时,插件运行时会合并进 `channel_configs.openclaw`。
|
|
91
|
-
触发后解析 `watch.triggered` 的 **`payload.channel_configs.openclaw`**(及并列路由字段)再回复到对应会话。
|
|
92
|
-
|
|
93
|
-
固定模板(必须按此结构构造,字段名不要改):
|
|
94
|
-
|
|
95
|
-
```javascript
|
|
96
|
-
{
|
|
97
|
-
product_code: 'BTCUSDT',
|
|
98
|
-
product_type: 'crypto',
|
|
99
|
-
operator_type: 'rule', // 必须是 rule,不可改成条件表达式
|
|
100
|
-
operator_parameters: {
|
|
101
|
-
condition: 'change_percent <= cp_threshold',
|
|
102
|
-
variables: {
|
|
103
|
-
cp_threshold: -0.02,
|
|
104
|
-
product_name: '比特币'
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
channels: ['openclaw', 'dingtalk', 'sms'],
|
|
108
|
-
// 注意:必须是对象,不要传 JSON 字符串
|
|
109
|
-
channel_configs: {
|
|
110
|
-
openclaw: {
|
|
111
|
-
channel: 'dingtalk',
|
|
112
|
-
account_id: 'default',
|
|
113
|
-
session_key: 'agent:main:dingtalk:group:<conversation_id>',
|
|
114
|
-
conversation_id: '<conversation_id>'
|
|
115
|
-
},
|
|
116
|
-
dingtalk: {
|
|
117
|
-
cas_id: 'jinguo.xie',
|
|
118
|
-
template_id: 3,
|
|
119
|
-
msg_type: 'text',
|
|
120
|
-
content: '比特币跌幅超2%!当前价格 ${price},跌幅 ${change_percent}%。建议卖出!'
|
|
121
|
-
},
|
|
122
|
-
sms: {
|
|
123
|
-
receiver: '18616726853',
|
|
124
|
-
template_id: 90010,
|
|
125
|
-
content: '比特币跌幅超2%!当前价格 ${price},建议卖出!'
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
禁止项(任何一条命中都必须先修正再调用):
|
|
132
|
-
- `operator_type` 不是 `rule`(例如写成 `change_percent <=`)
|
|
133
|
-
- 把 `condition` 放在顶层,而不是 `operator_parameters.condition`
|
|
134
|
-
- 把 `channel_configs` 下的渠道配置传成 JSON 字符串
|
|
135
|
-
- 用户未要求某渠道,却默认附加该渠道配置
|
|
136
|
-
|
|
137
|
-
渠道参数要求(必须):
|
|
138
|
-
- 只要 `channels` 包含 `email`,必须提供 `channel_configs.email.to_address/template_id/title/content`
|
|
139
|
-
- 只要 `channels` 包含 `call`,必须提供 `channel_configs.call.phone/customer_name/condition`
|
|
140
|
-
- 只要 `channels` 包含 `sms`,必须提供 `channel_configs.sms.receiver(或phone)/template_id/content`
|
|
141
|
-
- 只要 `channels` 包含 `dingtalk`,必须提供 `channel_configs.dingtalk.cas_id/template_id/msg_type/content`
|
|
142
|
-
|
|
143
|
-
成功判定:
|
|
144
|
-
- 返回 `success = true`
|
|
145
|
-
|
|
146
|
-
失败处理:
|
|
147
|
-
- 明确返回失败原因,不要静默重试
|
|
148
|
-
- 提示用户补充或修正参数
|
|
149
|
-
- 若是超时/网络波动导致的重试,必须使用同一组创建参数再次调用 `watch.create`(不要改字段和值),避免重复创建策略
|
|
150
|
-
- `request_id` 由插件运行时自动生成并在同 payload 重试时自动复用;大模型无需手动设置 `request_id`
|
|
151
|
-
|
|
152
|
-
小模型(7B)执行策略(强约束):
|
|
153
|
-
1. 先用固定模板生成 payload 骨架,不要自由发挥字段名
|
|
154
|
-
2. 仅替换值:`product_code/product_type/operator_parameters/channels/channel_configs`
|
|
155
|
-
3. 发送前逐条自检“禁止项”
|
|
156
|
-
4. 若失败返回 `400` 且提示“未注册的算子类型”,立即把 `operator_type` 纠正为 `rule` 并重试
|
|
157
|
-
|
|
158
|
-
#### `watch.pause` / `watch.activate` / `watch.remove`
|
|
159
|
-
|
|
160
|
-
参数:
|
|
161
|
-
- `strategyId`(或 `strategy_id`)
|
|
162
|
-
|
|
163
|
-
成功判定:
|
|
164
|
-
- 返回 `success = true`
|
|
165
|
-
|
|
166
|
-
失败处理:
|
|
167
|
-
- 返回失败原因并提示用户确认策略 ID
|
|
168
|
-
|
|
169
|
-
#### `watch.list`
|
|
170
|
-
|
|
171
|
-
参数(可选):
|
|
172
|
-
- `status`:策略状态过滤。可传 `active` / `paused` / `completed` / `failed` / `expired`;不传表示查询该用户全部策略
|
|
173
|
-
- `product_code`(或 `productCode`):按标的代码过滤
|
|
174
|
-
|
|
175
|
-
成功判定:
|
|
176
|
-
- 返回 `success = true`
|
|
177
|
-
- `data.total` 为命中策略数,`data.strategies` 为策略列表
|
|
178
|
-
|
|
179
|
-
失败处理:
|
|
180
|
-
- 返回失败原因,不要静默重试
|
|
181
|
-
- 若筛选条件为空结果,明确告知“当前条件下没有策略”
|
|
182
|
-
|
|
183
|
-
安全约束(必须):
|
|
184
|
-
- `watch.list` 只能查询当前连接用户自己的策略
|
|
185
|
-
- 不要尝试通过参数传 `user_id` / `use_id` 越权查询
|
|
186
|
-
|
|
187
|
-
#### `notify.sms` / `notify.call` / `notify.email` / `notify.dingtalk`
|
|
188
|
-
|
|
189
|
-
参数:
|
|
190
|
-
- `notify.sms`:必须提供 `receiver`(或 `phone`)、`template_id`、`content`
|
|
191
|
-
- `notify.call`:必须提供 `phone`、`customer_name`、`condition`
|
|
192
|
-
- `notify.email`:必须提供 `to_address`、`template_id`、`title`、`content`
|
|
193
|
-
- `notify.dingtalk`:必须提供 `cas_id`、`template_id`、`msg_type`、`content`
|
|
194
|
-
|
|
195
|
-
固定模板(必须按此结构,不要增删字段名):
|
|
196
|
-
|
|
197
|
-
```javascript
|
|
198
|
-
// notify.sms
|
|
199
|
-
{ receiver: '13800138000', template_id: 90010, content: '测试消息1' }
|
|
200
|
-
|
|
201
|
-
// notify.call
|
|
202
|
-
{ phone: '13800138000', customer_name: 'Demo', condition: '比特币跌幅超过2%' }
|
|
203
|
-
|
|
204
|
-
// notify.email
|
|
205
|
-
{ to_address: 'demo@example.com', template_id: 4, title: '监控提醒', content: '测试消息1' }
|
|
206
|
-
|
|
207
|
-
// notify.dingtalk
|
|
208
|
-
{ cas_id: 'user.dingtalk', template_id: 3, msg_type: 'text', content: '测试消息1' }
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
禁止项(任何一条命中都必须先修正再调用):
|
|
212
|
-
- 把手机号写成非数字字符串(空格、`+86-`、中划线等)
|
|
213
|
-
- 把 `template_id` 写成字符串(应传数字)
|
|
214
|
-
- `msg_type` 传非 `text/markdown`
|
|
215
|
-
- 传入 `request_id`(通知请求由插件运行时自动生成并复用)
|
|
216
|
-
|
|
217
|
-
成功判定:
|
|
218
|
-
- 返回 `success = true`
|
|
219
|
-
|
|
220
|
-
失败处理:
|
|
221
|
-
- 明确返回失败原因,不要静默重试
|
|
222
|
-
- 若是超时/网络波动导致的重试,必须使用同一组通知参数再次调用(不要改字段和值)
|
|
223
|
-
- `request_id` 由插件运行时自动生成并在同 payload 重试时自动复用;大模型无需手动设置 `request_id`
|
|
224
|
-
- 若返回缺字段错误(如 `MISSING_REQUIRED_FIELD`),只补缺失字段,其他字段保持不变再重试
|
|
225
|
-
|
|
226
|
-
回执说明:
|
|
227
|
-
- 直连通知发送完成后,客户端会收到 `notify.sent` 事件(`overall_status/success_count/failed_count/deliveries`)
|
|
228
|
-
|
|
229
|
-
离线补发识别(`watch.triggered`):
|
|
230
|
-
- 若事件包含 `delivery_mode = "offline_replay"` 或 `replayed = true`,表示这是用户离线期间触发后补发的消息
|
|
231
|
-
- `trigger_time` 表示原始触发时间,`replayed_at` 表示补发时间
|
|
232
|
-
- 向用户描述时应明确区分:例如“这条是离线期间触发,现已补发到当前会话”
|
|
233
|
-
|
|
234
|
-
## 调用判定规则
|
|
235
|
-
|
|
236
|
-
只有在用户明确表达以下意图时调用插件:
|
|
237
|
-
- “帮我盯盘/监控/提醒”
|
|
238
|
-
- “涨到/跌到某个价格提醒我”
|
|
239
|
-
- “达到某个涨跌幅提醒我”
|
|
240
|
-
|
|
241
|
-
调用前必须确认:
|
|
242
|
-
- `product_code`(标的代码)
|
|
243
41
|
- `product_type`(`stock/index/hk_stock/crypto`)
|
|
244
|
-
- `
|
|
245
|
-
- `operator_parameters.
|
|
246
|
-
|
|
247
|
-
缺任一项时先追问,不要猜测阈值。
|
|
248
|
-
|
|
249
|
-
### 调用前最终检查(小尺寸模型 必做)
|
|
250
|
-
|
|
251
|
-
在实际调用工具前,逐条检查:
|
|
252
|
-
1. `watch.create` 是否使用 `snake_case`:`product_code/product_type/operator_type/operator_parameters/channel_configs`
|
|
253
|
-
2. `operator_type` 是否固定为 `rule`
|
|
254
|
-
3. `operator_parameters.condition` 与 `operator_parameters.variables` 是否都存在
|
|
255
|
-
4. `channels` 是否与 `channel_configs` 一一对应(选了哪个渠道就必须有哪个配置)
|
|
256
|
-
5. 所有配置是否为对象而非 JSON 字符串
|
|
257
|
-
6. `request_id` 默认不手动传;由插件自动生成并在同 payload 重试时复用。仅当宿主框架明确要求外部指定时才传,并且重试必须保持不变
|
|
258
|
-
|
|
259
|
-
### 买卖意图与条件方向
|
|
260
|
-
|
|
261
|
-
用户设置价格提醒时,往往不会说"大于等于"或"小于等于",而是说"到了XX提醒我"。此时需要判断用户的**买卖意图**来决定条件方向:
|
|
262
|
-
|
|
263
|
-
| 用户意图 | 条件方向 | 说明 |
|
|
264
|
-
|---------|---------|------|
|
|
265
|
-
| 想买入(逢低买入) | `price <= threshold` | 价格**跌到**目标价时提醒,抄底机会 |
|
|
266
|
-
| 想卖出(止盈/止损) | `price >= threshold` | 价格**涨到**目标价时提醒,落袋为安 |
|
|
267
|
-
|
|
268
|
-
**判断流程:**
|
|
269
|
-
|
|
270
|
-
1. 如果用户明确说了方向(如"涨到XX"、"跌到XX"),直接使用对应条件
|
|
271
|
-
2. 如果用户只说"到了XX提醒我",**必须追问一句**:
|
|
272
|
-
- "你是想在价格涨到XX时卖出,还是跌到XX时买入?"
|
|
273
|
-
- 或者更简洁地问:"这个是准备买还是卖?买的话我帮你盯跌到XX,卖的话盯涨到XX"
|
|
274
|
-
3. 根据用户回答设置条件:
|
|
275
|
-
- 买入 → `price <= threshold`
|
|
276
|
-
- 卖出 → `price >= threshold`
|
|
277
|
-
|
|
278
|
-
**常见表达映射:**
|
|
279
|
-
- "涨到/涨过/突破/冲到" → `price >= threshold`(卖出方向)
|
|
280
|
-
- "跌到/跌破/回调到/回到" → `price <= threshold`(买入方向)
|
|
281
|
-
- "到了/到达/价格到" → **方向不明确,需追问买还是卖**
|
|
282
|
-
|
|
283
|
-
## 标的检索规则(必须遵循)
|
|
284
|
-
|
|
285
|
-
当不能直接确定 `product_code`/`product_type` 时,必须先在本地标的数据中检索,再和用户确认。
|
|
286
|
-
|
|
287
|
-
数据文件(CSV,字段为 `类型,代码,名称,完整代码,市场`):
|
|
288
|
-
- `data/stock_a.csv`:A股个股列表(`productType=stock`)
|
|
289
|
-
- `data/stock_hk.csv`:港股个股列表(`productType=hk_stock`)
|
|
290
|
-
- `data/index_a.csv`:A股指数列表(`productType=index`)
|
|
291
|
-
- `data/index_hk.csv`:港股指数列表(支持指数代码和中文名称查询)
|
|
292
|
-
|
|
293
|
-
### 场景1:用户只说股票简称/名称
|
|
294
|
-
- 使用模糊搜索在上述 CSV 中查找名称。
|
|
295
|
-
- 若命中多条,必须把候选项(代码 + 名称 + 市场)发给用户确认,不要自行猜测。
|
|
296
|
-
- 用户确认后再创建策略。
|
|
297
|
-
|
|
298
|
-
### 场景2:不知道某个标的代码或所属市场
|
|
299
|
-
- 使用 `rg`(或 `grep`)在四个 CSV 中搜索标的名称或代码。
|
|
300
|
-
- 根据命中结果判断市场并映射 `productType`:
|
|
301
|
-
- A股个股 -> `stock`
|
|
302
|
-
- 港股个股 -> `hk_stock`
|
|
303
|
-
- A股指数 -> `index`
|
|
304
|
-
- 港股指数 -> `index`(`market=HK`)
|
|
305
|
-
- 若搜索结果不唯一或冲突,先向用户确认后再继续。
|
|
306
|
-
|
|
307
|
-
### 推荐检索命令
|
|
308
|
-
|
|
309
|
-
```bash
|
|
310
|
-
# 按名称模糊查找(推荐)
|
|
311
|
-
rg -n "平安银行|腾讯|沪深300|BTC" data/stock_a.csv data/stock_hk.csv data/index_a.csv
|
|
312
|
-
rg -n "恒生科技指数|恒生指数|HSTECH|HSI" data/index_hk.csv
|
|
313
|
-
|
|
314
|
-
# 按代码查找
|
|
315
|
-
rg -n "000001|00700|399001" data/stock_a.csv data/stock_hk.csv data/index_a.csv
|
|
316
|
-
rg -n "HSTECH|HSI|VHSI" data/index_hk.csv
|
|
317
|
-
|
|
318
|
-
# grep 兜底(无 rg 时)
|
|
319
|
-
grep -nE "平安银行|腾讯|沪深300|000001|00700|恒生科技指数|HSTECH" data/stock_a.csv data/stock_hk.csv data/index_a.csv data/index_hk.csv
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
## 行情查询(queryTickerData)
|
|
323
|
-
|
|
324
|
-
当用户问“现在多少钱”“最新价格”“查一下某标的行情”等问题时,执行以下流程:
|
|
325
|
-
|
|
326
|
-
1. 先根据用户输入确定标的代码与市场:
|
|
327
|
-
- 如果是简称/名称,先在 `data/*.csv` 里模糊搜索并向用户确认候选。
|
|
328
|
-
- 如果是明确代码,按代码在 `data/*.csv` 查对应 `市场`。
|
|
329
|
-
- 港股指数可直接用代码(如 `HSTECH`)或中文名称(如 `恒生科技指数`)查询;命中 `index_hk.csv` 时优先使用 `market=HK`。
|
|
330
|
-
|
|
331
|
-
2. 调用已安装插件/包暴露的查询接口(例如 `queryTickerData`):
|
|
332
|
-
|
|
333
|
-
```javascript
|
|
334
|
-
await runtime.queryTickerData({
|
|
335
|
-
stockCode: '00700', // 或 productCode
|
|
336
|
-
market: 'HK', // SH/SZ/HK,crypto 可传 ''
|
|
337
|
-
productType: 'hk_stock'
|
|
338
|
-
})
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
3. 根据返回结果给用户反馈:
|
|
342
|
-
- `code = "000000"`:返回行情数据(如最新价格、涨跌幅等)。
|
|
343
|
-
- 非 `000000`:返回失败原因,并建议用户确认代码/市场后重试。
|
|
344
|
-
|
|
345
|
-
## 渠道参数填写
|
|
346
|
-
|
|
347
|
-
`openclaw` 渠道必传,`email` / `call` / `sms` / `dingtalk` 可选。如用户没明确说明使用邮件(email)、电话/外呼(call)、短信(sms)、钉钉(dingtalk)通知提醒,则只需要传入`openclaw`渠道。
|
|
348
|
-
|
|
349
|
-
### 插件侧联系人记忆与自动补全(openclaw-plugin-node)
|
|
350
|
-
|
|
351
|
-
宿主在调用 `watch_create`、`notify_*` 等工具时,应把**当前发送者上下文**传入 `context`(与 `openclaw` 路由合并所用上下文一致)。与 OpenClaw `buildSenderContext` 对齐时,推荐优先使用嵌套对象 **`context.senderContext`**(或顶层同名字段),例如:
|
|
352
|
-
|
|
353
|
-
- `senderContext.channel`(或 `channel` / `channelId`):来源渠道(钉钉建议为 `dingtalk`)
|
|
354
|
-
- `senderContext.senderId`(或顶层 `senderId` / `sender_id`):发送者唯一标识;钉钉下通常与 `cas_id` 一致
|
|
355
|
-
- 仍兼容:`senderDingtalkId`、`event.metadata.senderDingtalkId` 等历史字段
|
|
356
|
-
- `senderContext.senderName` / `senderName` / `displayName`:展示名(可用于外呼 `customer_name` 兜底)
|
|
357
|
-
|
|
358
|
-
插件内等价解析函数为 `extractSenderContext`;`buildSenderContext` 为其别名(单参 `buildSenderContext(context)` 即可)。
|
|
359
|
-
|
|
360
|
-
插件会在发 `watch.create` / `notify.send` 前:
|
|
361
|
-
|
|
362
|
-
1. 按 `channel:sender_id` 读写独立 JSON(默认路径:`~/.openclaw/workspace/memory/watch-notify-contacts.json`,可通过插件配置 `contactsStorePath` 或环境变量 `OPENCLAW_CONTACTS_STORE_PATH` 覆盖)。
|
|
363
|
-
2. 对 **sms / dingtalk / email / call** 缺省字段用该发送者已保存的默认值补全。
|
|
364
|
-
3. **钉钉**:若当前会话渠道为 `dingtalk` 且未提供 `cas_id`,则用当前发送者 ID 作为默认 `cas_id` 并写入记忆。
|
|
365
|
-
4. **外呼**:`customer_name` 优先用户本轮输入 → 记忆 → 发送者展示名。
|
|
366
|
-
|
|
367
|
-
若补全后仍缺必填项(如从未提供过手机号),bridge 仍会报错,此时应追问用户;用户一旦提供有效值,插件会更新记忆,后续同发送者无需重复填写。
|
|
368
|
-
|
|
369
|
-
向用户确认时**避免完整回显手机号**,可用尾号提示。
|
|
370
|
-
|
|
371
|
-
用户选择了某个通知渠道时,**最终**发往 bridge 的 payload 仍须满足各渠道必填项(插件会先按上文规则补全;补全后仍缺的,由 Agent 追问用户补齐):
|
|
372
|
-
|
|
373
|
-
- 选择 `email`:`channel_configs.email.to_address/template_id/title/content`
|
|
374
|
-
- 选择 `call`:`channel_configs.call.phone/customer_name/condition`
|
|
375
|
-
- 选择 `sms`:`channel_configs.sms.receiver(或phone)/template_id/content`
|
|
376
|
-
- 选择 `dingtalk`:`channel_configs.dingtalk.cas_id/template_id/msg_type/content`
|
|
377
|
-
|
|
378
|
-
### email 参数(channel_configs.email)
|
|
379
|
-
- `to_address`:收件人邮箱(必填,缺失不可创建/不可发送)
|
|
380
|
-
- `template_id`:邮件模板 ID(必填,默认为4,不需要修改)
|
|
381
|
-
- `title`: 收到邮件的标题(必填)
|
|
382
|
-
- `content`: 消息内容(必填)
|
|
383
|
-
示例:
|
|
384
|
-
```javascript
|
|
385
|
-
channel_configs: {
|
|
386
|
-
email: {
|
|
387
|
-
to_address: 'demo@example.com',
|
|
388
|
-
template_id: 4,
|
|
389
|
-
title: '监控提醒',
|
|
390
|
-
content: '测试消息1'
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
```
|
|
394
|
-
用户收到的是一封title为"监控提醒",内容为"测试消息1"的一封邮件
|
|
395
|
-
|
|
396
|
-
### call 参数(channel_configs.call)
|
|
397
|
-
- `phone`:手机号(必填,缺失不可创建/不可发送)
|
|
398
|
-
- `customer_name`:客户名称(必填)
|
|
399
|
-
- `condition`:外呼内容(必填)
|
|
400
|
-
|
|
401
|
-
示例:
|
|
402
|
-
```javascript
|
|
403
|
-
channel_configs: {
|
|
404
|
-
call: {
|
|
405
|
-
phone: '13800138000',
|
|
406
|
-
customer_name: 'Demo',
|
|
407
|
-
condition: '比特币价格突破阈值'
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
```
|
|
411
|
-
用户收到的是一通打给手机号码为13800138000的电话,电话内容为'比特币价格突破阈值'
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
### sms 参数(channel_configs.sms)
|
|
415
|
-
- `receiver`:手机号(必填,必须是纯数字;缺失不可创建/不可发送)
|
|
416
|
-
- `template_id`:短信模板 ID(必填,默认 90010,不需要修改)
|
|
417
|
-
- `content`:短信变量内容(必填)
|
|
418
|
-
|
|
419
|
-
示例:
|
|
420
|
-
```javascript
|
|
421
|
-
channel_configs: {
|
|
422
|
-
sms: {
|
|
423
|
-
receiver: '13800138000',
|
|
424
|
-
template_id: 90010,
|
|
425
|
-
content: '测试消息1'
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
```
|
|
429
|
-
用户收到的是一封发送给手机号码为13800138000的短信,短信内容为'测试消息1'
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
### 钉钉 参数(channel_configs.dingtalk)
|
|
433
|
-
- `cas_id`:钉钉用户ID(必填,缺失不可创建/不可发送)
|
|
434
|
-
- `template_id`:钉钉模板 ID(必填,默认 3,不需要修改)
|
|
435
|
-
- `msg_type`: 消息类型(必填):`text`/`markdown`
|
|
436
|
-
- `content`:消息内容(必填)
|
|
437
|
-
|
|
438
|
-
示例:
|
|
439
|
-
```javascript
|
|
440
|
-
channel_configs: {
|
|
441
|
-
dingtalk: {
|
|
442
|
-
cas_id: 'user.dingtalk',
|
|
443
|
-
template_id: 3,
|
|
444
|
-
msg_type: 'text',
|
|
445
|
-
content: '测试消息1'
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
```
|
|
449
|
-
用户收到的是一条发送给钉钉号为user.dingtalk的单聊消息,消息内容为'测试消息1'
|
|
450
|
-
|
|
42
|
+
- `operator_type`(固定 `rule`)
|
|
43
|
+
- `operator_parameters.condition`
|
|
44
|
+
- `operator_parameters.variables`
|
|
451
45
|
|
|
452
|
-
|
|
46
|
+
缺任一项先追问,不猜测阈值。
|
|
453
47
|
|
|
454
|
-
|
|
455
|
-
|------|-------------|------|------|
|
|
456
|
-
| A股个股 | stock | 000001 | 每3秒行情 |
|
|
457
|
-
| A股指数 | index | 000300 | 每3秒行情 |
|
|
458
|
-
| 港股指数 | index | HSTECH / 恒生科技指数 | 查询时 `market=HK` |
|
|
459
|
-
| 港股 | hk_stock | 00700 | 延迟15分钟 |
|
|
460
|
-
| 加密货币 | crypto | BTCUSDT | 每10秒行情 |
|
|
48
|
+
### 绝对禁止项
|
|
461
49
|
|
|
462
|
-
|
|
463
|
-
-
|
|
464
|
-
-
|
|
465
|
-
-
|
|
466
|
-
-
|
|
50
|
+
- `operator_type` 不是 `rule`
|
|
51
|
+
- 把 `condition` 放到顶层(必须在 `operator_parameters.condition`)
|
|
52
|
+
- 把 `channel_configs.*` 传成 JSON 字符串(必须是对象)
|
|
53
|
+
- 用户未要求的渠道被默认附加
|
|
54
|
+
- 通过 `watch.list` 传 `user_id/use_id` 越权查询
|
|
467
55
|
|
|
468
|
-
|
|
56
|
+
## 渐进式披露(按需读取)
|
|
469
57
|
|
|
470
|
-
|
|
58
|
+
仅在命中场景时读取对应文档,不要一次性加载全部 references。
|
|
471
59
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
variables: { threshold: 73000, cp_threshold: 0.01, product_name: 'Bitcoin' }
|
|
479
|
-
}
|
|
480
|
-
// 注意: crypto 不支持 turnover_rate
|
|
481
|
-
```
|
|
60
|
+
- `watch.create/list/pause/activate/remove` 细节与成功判定:`references/watch-contract.md`
|
|
61
|
+
- 标的检索、行情查询流程:`references/query-and-symbol.md`
|
|
62
|
+
- 渠道参数、OpenClaw 路由、联系人记忆、`notify.*` 模板:`references/channels.md`
|
|
63
|
+
- 示例 payload:`references/examples.md`
|
|
64
|
+
- 重试、错误码、离线补发:`references/troubleshooting.md`
|
|
65
|
+
- 市场与代码速查:`references/markets.md`
|
|
482
66
|
|
|
483
|
-
|
|
484
|
-
```javascript
|
|
485
|
-
// 条件: 价格 >= 12.5 且换手率 >= 1%(放在 operator_parameters 内)
|
|
486
|
-
operator_type: 'rule'
|
|
487
|
-
operator_parameters: {
|
|
488
|
-
condition: 'price >= threshold and turnover_rate >= tr_threshold',
|
|
489
|
-
variables: { threshold: 12.5, tr_threshold: 0.01, product_name: '平安银行' }
|
|
490
|
-
}
|
|
491
|
-
```
|
|
67
|
+
## 决策表(强约束)
|
|
492
68
|
|
|
493
|
-
|
|
494
|
-
```javascript
|
|
495
|
-
// 条件: 价格 >= 420(放在 operator_parameters 内)
|
|
496
|
-
operator_type: 'rule'
|
|
497
|
-
operator_parameters: {
|
|
498
|
-
condition: 'price >= threshold',
|
|
499
|
-
variables: { threshold: 420, product_name: '腾讯控股' }
|
|
500
|
-
}
|
|
501
|
-
```
|
|
69
|
+
先判定用户主意图,再只读取最小文档集合:
|
|
502
70
|
|
|
503
|
-
|
|
71
|
+
| 用户主意图 | 必读文档(最小集合) |
|
|
72
|
+
|---|---|
|
|
73
|
+
| 查行情/当前价格/报价 | `references/query-and-symbol.md` |
|
|
74
|
+
| 创建盯盘策略(代码和市场已明确) | `references/watch-contract.md` |
|
|
75
|
+
| 创建盯盘策略(名称或市场不明确) | `references/watch-contract.md` + `references/query-and-symbol.md` |
|
|
76
|
+
| 创建盯盘 + 指定通知渠道 | `references/watch-contract.md` + `references/channels.md` |
|
|
77
|
+
| 管理策略(list/pause/activate/remove) | `references/watch-contract.md` |
|
|
78
|
+
| 立即发通知(notify.*) | `references/channels.md` |
|
|
79
|
+
| 失败排查/补发说明 | `references/troubleshooting.md` |
|
|
80
|
+
| 市场或代码速查 | `references/markets.md` |
|
|
504
81
|
|
|
505
|
-
|
|
506
|
-
1.
|
|
507
|
-
2.
|
|
508
|
-
3.
|
|
509
|
-
4. 根据触发消息构建友好的提醒文案
|
|
82
|
+
执行规则:
|
|
83
|
+
1. 一次请求默认只读 1-2 个 references 文件。
|
|
84
|
+
2. 仅当当前文档无法回答时,再追加读取下一个文档。
|
|
85
|
+
3. 读取顺序遵循上表,不按“完整性”一次加载所有文档。
|
|
510
86
|
|
|
511
|
-
|
|
512
|
-
- 明确返回失败原因给用户
|
|
513
|
-
- 引导用户补充或修正参数后再次创建
|
|
87
|
+
## 小模型执行模板(7B)
|
|
514
88
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
- 若 `code=UPSTREAM_UNAVAILABLE`,提示“notification 服务不可用或超时,请稍后重试”
|
|
89
|
+
1. 先按固定字段骨架生成 payload,不自创字段名。
|
|
90
|
+
2. 只替换值:`product_code/product_type/operator_parameters/channels/channel_configs`。
|
|
91
|
+
3. 调用前逐条自检“绝对禁止项”。
|
|
92
|
+
4. 若报 `400` 且提示“未注册的算子类型”,把 `operator_type` 纠正为 `rule` 后重试。
|
|
520
93
|
|
|
521
|
-
##
|
|
94
|
+
## 快速分流
|
|
522
95
|
|
|
523
|
-
-
|
|
96
|
+
- 用户说“帮我盯 BTC 跌 2% 提醒” -> 读取 `references/watch-contract.md` + `references/channels.md`
|
|
97
|
+
- 用户说“腾讯现在多少钱” -> 读取 `references/query-and-symbol.md`
|
|
98
|
+
- 用户说“发短信给我” -> 读取 `references/channels.md`
|
|
99
|
+
- 用户说“为什么没发出来” -> 读取 `references/troubleshooting.md`
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# 渠道与通知参数
|
|
2
|
+
|
|
3
|
+
## 渠道策略
|
|
4
|
+
|
|
5
|
+
- `openclaw` 渠道默认必带(用于回当前会话)。
|
|
6
|
+
- `email/call/sms/dingtalk` 仅在用户明确要求时添加。
|
|
7
|
+
|
|
8
|
+
## OpenClaw 会话路由
|
|
9
|
+
|
|
10
|
+
当 `channels` 包含 `openclaw` 时,`channel_configs.openclaw` 必须可定位当前会话。
|
|
11
|
+
|
|
12
|
+
常用字段:
|
|
13
|
+
- `channel` 或 `source_channel`
|
|
14
|
+
- `account_id`
|
|
15
|
+
- `session_key`
|
|
16
|
+
- `conversation_id` 或 `chat_id`
|
|
17
|
+
|
|
18
|
+
约束:
|
|
19
|
+
- 拿不到路由信息时,不得传空对象 `openclaw: {}` 假装已配置。
|
|
20
|
+
- 宿主传入 `context` 时,插件运行时只负责合并 openclaw 路由字段。
|
|
21
|
+
|
|
22
|
+
## 联系人记忆(Agent/OpenClaw 侧 CSV)
|
|
23
|
+
|
|
24
|
+
真源:`~/.openclaw/workspace/memory/watch-notify-contacts.csv`
|
|
25
|
+
|
|
26
|
+
建议表头:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
channel,sender_id,sender_name,phone,email,dingtalk_cas_id,customer_name,updated_at,notes
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
取值优先级:
|
|
33
|
+
1. 本轮用户明确提供
|
|
34
|
+
2. CSV 历史默认值
|
|
35
|
+
3. 仍缺必填字段 -> 追问
|
|
36
|
+
|
|
37
|
+
查询示例:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
rg -n '^dingtalk,jinguo\.xie,' ~/.openclaw/workspace/memory/watch-notify-contacts.csv
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## `watch.create` 渠道必填
|
|
44
|
+
|
|
45
|
+
- 选 `email` -> `channel_configs.email.to_address/template_id/title/content`
|
|
46
|
+
- 选 `call` -> `channel_configs.call.phone/customer_name/condition`
|
|
47
|
+
- 选 `sms` -> `channel_configs.sms.receiver(或phone)/template_id/content`
|
|
48
|
+
- 选 `dingtalk` -> `channel_configs.dingtalk.cas_id/template_id/msg_type/content`
|
|
49
|
+
|
|
50
|
+
## `notify.*` 参数
|
|
51
|
+
|
|
52
|
+
- `notify.sms`: `receiver(或phone)`、`template_id`、`content`
|
|
53
|
+
- `notify.call`: `phone`、`customer_name`、`condition`
|
|
54
|
+
- `notify.email`: `to_address`、`template_id`、`title`、`content`
|
|
55
|
+
- `notify.dingtalk`: `cas_id`、`template_id`、`msg_type`、`content`
|
|
56
|
+
|
|
57
|
+
固定模板:
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
// notify.sms
|
|
61
|
+
{ receiver: '13800138000', template_id: 90010, content: '测试消息1' }
|
|
62
|
+
|
|
63
|
+
// notify.call
|
|
64
|
+
{ phone: '13800138000', customer_name: 'Demo', condition: '比特币跌幅超过2%' }
|
|
65
|
+
|
|
66
|
+
// notify.email
|
|
67
|
+
{ to_address: 'demo@example.com', template_id: 4, title: '监控提醒', content: '测试消息1' }
|
|
68
|
+
|
|
69
|
+
// notify.dingtalk
|
|
70
|
+
{ cas_id: 'user.dingtalk', template_id: 3, msg_type: 'text', content: '测试消息1' }
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
禁止项:
|
|
74
|
+
- 手机号含空格、`+86-`、中划线等非纯数字
|
|
75
|
+
- `template_id` 传字符串
|
|
76
|
+
- `msg_type` 非 `text/markdown`
|
|
77
|
+
- 手动传 `request_id`
|
|
78
|
+
|
|
79
|
+
成功判定:
|
|
80
|
+
- `success = true`
|