@openviking/openclaw-plugin 2026.5.8 → 2026.5.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.
@@ -1,66 +1,3 @@
1
- import { Socket } from "node:net";
2
- export function waitForHealth(baseUrl, timeoutMs, intervalMs) {
3
- const deadline = Date.now() + timeoutMs;
4
- return new Promise((resolve, reject) => {
5
- const tick = () => {
6
- if (Date.now() > deadline) {
7
- reject(new Error(`OpenViking health check timeout at ${baseUrl}`));
8
- return;
9
- }
10
- fetch(`${baseUrl}/health`)
11
- .then((r) => r.json())
12
- .then((body) => {
13
- if (body?.status === "ok") {
14
- resolve();
15
- return;
16
- }
17
- setTimeout(tick, intervalMs);
18
- })
19
- .catch(() => setTimeout(tick, intervalMs));
20
- };
21
- tick();
22
- });
23
- }
24
- export function waitForHealthOrExit(baseUrl, timeoutMs, intervalMs, child) {
25
- const exited = child.killed || child.exitCode !== null || child.signalCode !== null;
26
- if (exited) {
27
- return Promise.reject(new Error(`OpenViking subprocess exited before health check ` +
28
- `(code=${child.exitCode}, signal=${child.signalCode})`));
29
- }
30
- return new Promise((resolve, reject) => {
31
- let settled = false;
32
- const cleanup = () => {
33
- child.off?.("error", onError);
34
- child.off?.("exit", onExit);
35
- };
36
- const finishResolve = () => {
37
- if (settled) {
38
- return;
39
- }
40
- settled = true;
41
- cleanup();
42
- resolve();
43
- };
44
- const finishReject = (err) => {
45
- if (settled) {
46
- return;
47
- }
48
- settled = true;
49
- cleanup();
50
- reject(err instanceof Error ? err : new Error(String(err)));
51
- };
52
- const onError = (err) => {
53
- finishReject(err);
54
- };
55
- const onExit = (code, signal) => {
56
- finishReject(new Error(`OpenViking subprocess exited before health check ` +
57
- `(code=${code}, signal=${signal})`));
58
- };
59
- child.once("error", onError);
60
- child.once("exit", onExit);
61
- waitForHealth(baseUrl, timeoutMs, intervalMs).then(finishResolve, finishReject);
62
- });
63
- }
64
1
  export function withTimeout(promise, timeoutMs, timeoutMessage) {
65
2
  return new Promise((resolve, reject) => {
66
3
  const timer = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs);
@@ -73,30 +10,6 @@ export function withTimeout(promise, timeoutMs, timeoutMessage) {
73
10
  });
74
11
  });
75
12
  }
76
- export function quickTcpProbe(host, port, timeoutMs) {
77
- return new Promise((resolve) => {
78
- const socket = new Socket();
79
- let done = false;
80
- const finish = (ok) => {
81
- if (done) {
82
- return;
83
- }
84
- done = true;
85
- socket.destroy();
86
- resolve(ok);
87
- };
88
- socket.setTimeout(timeoutMs);
89
- socket.once("connect", () => finish(true));
90
- socket.once("timeout", () => finish(false));
91
- socket.once("error", () => finish(false));
92
- try {
93
- socket.connect(port, host);
94
- }
95
- catch {
96
- finish(false);
97
- }
98
- });
99
- }
100
13
  export async function quickHealthCheck(baseUrl, timeoutMs) {
101
14
  const controller = new AbortController();
102
15
  const timer = setTimeout(() => controller.abort(), timeoutMs);
@@ -1,7 +1,4 @@
1
1
  const _env = globalThis["process"];
2
- export function sysEnv() {
3
- return _env.env;
4
- }
5
2
  export function getEnv(key) {
6
3
  return _env.env[key];
7
4
  }
@@ -21,7 +21,6 @@ const NON_CONTENT_TEXT_RE = /^[\p{P}\p{S}\s]+$/u;
21
21
  const SUBAGENT_CONTEXT_RE = /^\s*\[Subagent Context\]/i;
22
22
  const MEMORY_INTENT_RE = /记住|记下|remember|save|store|偏好|preference|规则|rule|事实|fact/i;
23
23
  const QUESTION_CUE_RE = /[??]|\b(?:what|when|where|who|why|how|which|can|could|would|did|does|is|are)\b|^(?:请问|能否|可否|怎么|如何|什么时候|谁|什么|哪|是否)/i;
24
- export const CAPTURE_LIMIT = 3;
25
24
  function resolveCaptureMinLength(text) {
26
25
  return CJK_CHAR_REGEX.test(text) ? 4 : 10;
27
26
  }
@@ -232,21 +231,6 @@ export function extractTextsFromUserMessages(messages) {
232
231
  }
233
232
  return texts;
234
233
  }
235
- function formatToolUseBlock(b) {
236
- const name = typeof b.name === "string" ? b.name : "unknown";
237
- let inputStr = "";
238
- if (b.input !== undefined && b.input !== null) {
239
- try {
240
- inputStr = typeof b.input === "string" ? b.input : JSON.stringify(b.input);
241
- }
242
- catch {
243
- inputStr = String(b.input);
244
- }
245
- }
246
- return inputStr
247
- ? `[toolUse: ${name}]\n${inputStr}`
248
- : `[toolUse: ${name}]`;
249
- }
250
234
  function formatToolResultContent(content) {
251
235
  if (typeof content === "string")
252
236
  return content.trim();
@@ -270,40 +254,6 @@ function formatToolResultContent(content) {
270
254
  }
271
255
  return "";
272
256
  }
273
- /**
274
- * Extract text from a single message without a `[role]:` prefix.
275
- * Used by afterTurn to send messages with their actual role.
276
- */
277
- export function extractSingleMessageText(msg) {
278
- if (!msg || typeof msg !== "object")
279
- return "";
280
- const m = msg;
281
- const role = m.role;
282
- if (!role || role === "system")
283
- return "";
284
- if (role === "toolResult") {
285
- const toolName = typeof m.toolName === "string" ? m.toolName : "tool";
286
- const resultText = formatToolResultContent(m.content);
287
- return resultText ? `[${toolName} result]: ${resultText}` : "";
288
- }
289
- const content = m.content;
290
- if (typeof content === "string")
291
- return content.trim();
292
- if (Array.isArray(content)) {
293
- const parts = [];
294
- for (const block of content) {
295
- const b = block;
296
- if (b?.type === "text" && typeof b.text === "string") {
297
- parts.push(b.text.trim());
298
- }
299
- else if (b?.type === "toolUse") {
300
- parts.push(formatToolUseBlock(b));
301
- }
302
- }
303
- return parts.join("\n");
304
- }
305
- return "";
306
- }
307
257
  /**
308
258
  * 提取消息中的一个 part 的文本内容,并清理时间戳等噪音
309
259
  */
@@ -394,7 +344,6 @@ export function extractNewTurnMessages(messages, startIndex) {
394
344
  continue;
395
345
  }
396
346
  // user/assistant -> type: "text"
397
- // 统一 role 为 user
398
347
  const content = msg.content;
399
348
  const text = extractPartText(content);
400
349
  if (text) {
@@ -412,6 +361,37 @@ export function extractNewTurnMessages(messages, startIndex) {
412
361
  });
413
362
  }
414
363
  }
364
+ else {
365
+ /// 如果原始消息有 toolCall,提取所有工具名并生成占位符
366
+ if (role === "assistant" && Array.isArray(content)) {
367
+ const toolNames = [];
368
+ // 收集所有 toolCall 的 tool_name
369
+ for (const block of content) {
370
+ const b = block;
371
+ const blockType = b?.type;
372
+ if (blockType === "toolCall" ||
373
+ blockType === "toolUse" ||
374
+ blockType === "tool_use" ||
375
+ blockType === "tool_call") {
376
+ const name = b?.name || b?.toolName;
377
+ if (name && typeof name === "string" && name.trim()) {
378
+ toolNames.push(name.trim());
379
+ }
380
+ }
381
+ }
382
+ // 只有找到 toolCall 时才添加占位符
383
+ if (toolNames.length > 0) {
384
+ const toolNamesStr = toolNames.join(", ");
385
+ result.push({
386
+ role: "assistant",
387
+ parts: [{
388
+ type: "text",
389
+ text: `[tool: ${toolNamesStr}]`,
390
+ }],
391
+ });
392
+ }
393
+ }
394
+ }
415
395
  }
416
396
  return { messages: result, newCount: count };
417
397
  }