@vui-design/openclaw-plugin-feishu-progress 0.4.3 → 0.5.0

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +32 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vui-design/openclaw-plugin-feishu-progress",
3
- "version": "0.4.3",
3
+ "version": "0.5.0",
4
4
  "description": "飞书任务进度卡片插件 — 在 AI 执行复杂多步骤任务时,实时更新飞书进度卡片",
5
5
  "keywords": [
6
6
  "openclaw-plugin",
package/src/index.ts CHANGED
@@ -42,8 +42,15 @@ function buildToolLabel(toolName: string, args: Record<string, unknown>): string
42
42
  return '⚡ 执行命令';
43
43
  }
44
44
  case 'process': {
45
- const cmd = s(args?.command ?? args?.cmd, 80);
46
- return cmd ? `⚡ ${cmd.slice(0, 40)}` : '⚡ 执行进程';
45
+ // 尝试多种字段名,兼容不同 OpenClaw 版本
46
+ const cmd = s(
47
+ args?.command ?? args?.cmd ?? args?.executable ??
48
+ args?.program ?? args?.bin ?? args?.process,
49
+ 80,
50
+ );
51
+ const argList = s(args?.args ?? args?.arguments ?? args?.argv, 40);
52
+ if (cmd) return `⚡ ${cmd.slice(0, 40)}${argList ? ' ' + argList : ''}`;
53
+ return '⚡ 执行进程';
47
54
  }
48
55
  case 'read':
49
56
  case 'read_file': {
@@ -90,6 +97,16 @@ function buildToolLabel(toolName: string, args: Record<string, unknown>): string
90
97
  }
91
98
  }
92
99
 
100
+ // 判断是否为"动作前言"型 AI 短句(适合作进度提示)
101
+ // 规则:长度 ≤ 30,以":" 结尾,或以动作动词开头
102
+ // 排除超过 30 字的长句,避免把完整回复内容当作进度消息发送
103
+ function isActionSnippet(text: string): boolean {
104
+ if (!text || text.length > 30) return false;
105
+ if (text.endsWith(':') || text.endsWith(':')) return true;
106
+ if (/^(正在|开始|准备|即将|继续|尝试|检查|分析|搜索|获取|处理|生成|执行|读取|写入|删除|更新)/.test(text)) return true;
107
+ return false;
108
+ }
109
+
93
110
  // 从 AI 输出文本提取最末一句(去掉 markdown 标记符)
94
111
  function extractSnippet(text: string): string {
95
112
  const lines = text
@@ -115,6 +132,8 @@ interface RunState {
115
132
  agentId: string;
116
133
  sessionKey: string;
117
134
  assistantBuffer: string;
135
+ /** 上一条已发送标签,防止连续相同标签重复推送 */
136
+ lastLabel: string;
118
137
  /** 已发送过的 snippet,防止重复推送 */
119
138
  sentSnippets: Set<string>;
120
139
  startedAt: number;
@@ -160,7 +179,7 @@ export default {
160
179
 
161
180
  // ── Hooks ───────────────────────────────────────────────────────────────
162
181
 
163
- // 收到飞书消息 → 记录 accountId → chatId(兜底索引)
182
+ // 收到飞书消息 → 立即发送"思考中"确认 + 记录 accountId → chatId(兜底索引)
164
183
  api.on('message_received', async (_event: any, ctx: any) => {
165
184
  if (ctx.channelId !== 'feishu') return;
166
185
  if (!ctx.conversationId) return;
@@ -169,6 +188,9 @@ export default {
169
188
  ? ctx.conversationId.split(':').pop()!
170
189
  : ctx.conversationId;
171
190
  if (ctx.accountId) accountChatMap.set(ctx.accountId, rawId);
191
+
192
+ // 立即向用户发送确认,让用户知道机器人已收到消息
193
+ client.sendText(rawId, '🤔 思考中,请稍候...').catch(() => {});
172
194
  });
173
195
 
174
196
  // llm_input → 建立 runId → RunState,启动心跳
@@ -188,6 +210,7 @@ export default {
188
210
  agentId: ctx.agentId ?? '',
189
211
  sessionKey: ctx.sessionKey ?? '',
190
212
  assistantBuffer: '',
213
+ lastLabel: '',
191
214
  sentSnippets: new Set(),
192
215
  startedAt,
193
216
  lastSentAt: startedAt,
@@ -224,8 +247,8 @@ export default {
224
247
  state.assistantBuffer = ''; // 每次工具调用前消费
225
248
 
226
249
  let label: string;
227
- if (snippet && !state.sentSnippets.has(snippet)) {
228
- // AI 文本优先,且去重
250
+ if (snippet && isActionSnippet(snippet) && !state.sentSnippets.has(snippet)) {
251
+ // AI 文本优先,但仅限"动作前言"型短句,且去重
229
252
  state.sentSnippets.add(snippet);
230
253
  label = snippet;
231
254
  } else {
@@ -235,6 +258,10 @@ export default {
235
258
  );
236
259
  }
237
260
 
261
+ // 连续相同标签去重(同一工具被连续调用多次时只发一次)
262
+ if (label === state.lastLabel) return;
263
+ state.lastLabel = label;
264
+
238
265
  state.lastSentAt = Date.now();
239
266
  client.sendText(state.chatId, label).catch((err: any) => {
240
267
  api.logger?.warn(`[feishu-progress] 推送失败: ${err?.message}`);