openclaw-lark-multi-agent 1.2.5 → 1.2.6

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.
@@ -123,28 +123,19 @@ export declare class FeishuBot {
123
123
  private isLegacyBridgeControlMessage;
124
124
  private isRuntimeFailureText;
125
125
  /**
126
- * Heuristic: does this reply look truncated / mid-task? Bias toward false
127
- * positives (“宁可错杀不放过”) — a false positive only costs one invisible
128
- * confirmation round, and the session self-check is the real arbiter. We gate
129
- * only on cheap text shape here, never on stopReason (the upstream rarely
130
- * provides one for normal-looking-but-truncated finals).
131
- */
132
- /**
133
- * Heuristic: does this reply look genuinely truncated / cut off mid-task?
126
+ * Heuristic: does this reply look truncated / cut off mid-task? Used as the
127
+ * SOLE auto-retry trigger — if true, we ask the session a one-line “done?” probe.
134
128
  *
135
- * IMPORTANT (per Stephen): only retry when there is CLEAR evidence the agent
136
- * did not finish — do NOT retry just because a reply lacks a trailing period.
137
- * Many complete replies legitimately end without sentence punctuation (a terse
138
- * “好的”, a bullet list, a path, a number, a closing word). Treating those as
139
- * truncated caused needless extra probe rounds, which hurts UX. So we gate on
140
- * strong structural signals only:
129
+ * Signals (any one is enough):
141
130
  * 1. Unbalanced code fence — almost certainly cut off mid code block.
142
- * 2. Ends with a dangling connector / lead-in (“然后”, “接下来”, “let me”…)
143
- * or a trailing clause-joining punctuation (comma/colon/semicolon),
144
- * which means a sentence was left hanging.
145
- * 3. Ends mid-word inside a Latin word right after a connector-less clause
146
- * (very rare; only when the last “word” is unusually long), kept minimal.
147
- * A plain “no sentence-ending punctuation” is deliberately NOT sufficient.
131
+ * 2. Trailing clause-joining punctuation (comma/colon/semicolon/、) — a
132
+ * sentence was left hanging.
133
+ * 3. A dangling connector / lead-in (“然后”, “接下来”, “let me”, “and”…).
134
+ * 4. Ends without ANY sentence-ending punctuation / closer (no terminal
135
+ * punctuation, closing bracket/quote, code fence, or wrap-up emoji).
136
+ * Per Stephen: a reply that ends with no punctuation at all is also
137
+ * treated as likely unfinished. A false positive only costs one cheap,
138
+ * invisible confirmation probe; the session itself is the real arbiter.
148
139
  */
149
140
  private looksTruncated;
150
141
  /** Current context usage percent for a session (totalTokens / contextTokens),
@@ -1647,28 +1647,19 @@ export class FeishuBot {
1647
1647
  return text.startsWith("⚠️ Agent 未正常完成") || /\n原因:\s*rpc\b/.test(text);
1648
1648
  }
1649
1649
  /**
1650
- * Heuristic: does this reply look truncated / mid-task? Bias toward false
1651
- * positives (“宁可错杀不放过”) — a false positive only costs one invisible
1652
- * confirmation round, and the session self-check is the real arbiter. We gate
1653
- * only on cheap text shape here, never on stopReason (the upstream rarely
1654
- * provides one for normal-looking-but-truncated finals).
1655
- */
1656
- /**
1657
- * Heuristic: does this reply look genuinely truncated / cut off mid-task?
1650
+ * Heuristic: does this reply look truncated / cut off mid-task? Used as the
1651
+ * SOLE auto-retry trigger — if true, we ask the session a one-line “done?” probe.
1658
1652
  *
1659
- * IMPORTANT (per Stephen): only retry when there is CLEAR evidence the agent
1660
- * did not finish — do NOT retry just because a reply lacks a trailing period.
1661
- * Many complete replies legitimately end without sentence punctuation (a terse
1662
- * “好的”, a bullet list, a path, a number, a closing word). Treating those as
1663
- * truncated caused needless extra probe rounds, which hurts UX. So we gate on
1664
- * strong structural signals only:
1653
+ * Signals (any one is enough):
1665
1654
  * 1. Unbalanced code fence — almost certainly cut off mid code block.
1666
- * 2. Ends with a dangling connector / lead-in (“然后”, “接下来”, “let me”…)
1667
- * or a trailing clause-joining punctuation (comma/colon/semicolon),
1668
- * which means a sentence was left hanging.
1669
- * 3. Ends mid-word inside a Latin word right after a connector-less clause
1670
- * (very rare; only when the last “word” is unusually long), kept minimal.
1671
- * A plain “no sentence-ending punctuation” is deliberately NOT sufficient.
1655
+ * 2. Trailing clause-joining punctuation (comma/colon/semicolon/、) — a
1656
+ * sentence was left hanging.
1657
+ * 3. A dangling connector / lead-in (“然后”, “接下来”, “let me”, “and”…).
1658
+ * 4. Ends without ANY sentence-ending punctuation / closer (no terminal
1659
+ * punctuation, closing bracket/quote, code fence, or wrap-up emoji).
1660
+ * Per Stephen: a reply that ends with no punctuation at all is also
1661
+ * treated as likely unfinished. A false positive only costs one cheap,
1662
+ * invisible confirmation probe; the session itself is the real arbiter.
1672
1663
  */
1673
1664
  looksTruncated(text) {
1674
1665
  const t = (text || "").trim();
@@ -1684,6 +1675,16 @@ export class FeishuBot {
1684
1675
  // (2b) Ends on an explicit continuation cue / lead-in.
1685
1676
  if (/(接下来|然后|首先|现在我|让我|下一步|我先|我来|我接着|接着|稍等|let me|now i|next|first|\b(?:and|then|so|to|the|a)\b)\s*$/iu.test(t))
1686
1677
  return true;
1678
+ // (2c) Ends without ANY sentence-ending punctuation / closer. A finished
1679
+ // reply normally ends with terminal punctuation, a closing bracket/
1680
+ // quote, a code fence, or a wrap-up emoji; if none of those are present
1681
+ // the reply was most likely cut off mid-sentence. (Stephen: “结尾没有
1682
+ // 任何标点符号也算疑似未结束”.)
1683
+ const endOk = /[。!?.!?…)\]」』】)"'`”’~~—✨✅👍🙏🎉🙌]\s*$/u.test(t)
1684
+ || /```\s*$/.test(t)
1685
+ || /[}\]]\s*$/.test(t);
1686
+ if (!endOk)
1687
+ return true;
1687
1688
  return false;
1688
1689
  }
1689
1690
  /** Current context usage percent for a session (totalTokens / contextTokens),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-lark-multi-agent",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "description": "Multi-bot Lark/Feishu bridge for OpenClaw, with per-bot model routing and isolated sessions",
5
5
  "type": "module",
6
6
  "scripts": {