@alfe.ai/openclaw-chat 0.9.13 → 0.9.14

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/dist/plugin2.cjs CHANGED
@@ -2266,8 +2266,9 @@ function buildToolActivity(data) {
2266
2266
  /**
2267
2267
  * Workstream C, item 5: strip OpenClaw's leaked tool-summary console line
2268
2268
  * from assistant `responseText` before it's stored / notified as a chat
2269
- * bubble. OpenClaw upstream composes a `⚠️ 🛠️ … (+N steps) failed` summary
2270
- * into the assistant text for a non-zero-exit tool run; `failed` there is a
2269
+ * bubble. OpenClaw upstream composes either a `⚠️ 🛠️ … (+N steps) failed`
2270
+ * summary or a step-count-free `⚠️ 🛠️ … → … failed` pipeline into the
2271
+ * assistant text for a non-zero-exit tool run; `failed` there is a
2271
2272
  * TOOL exit status, not a chat-level failure, and it now has a proper
2272
2273
  * structured tool row (see buildToolActivity). This is a BOUNDED, clearly
2273
2274
  * scoped strip of that one known pattern — it must not touch normal prose.
@@ -2284,9 +2285,10 @@ function buildToolActivity(data) {
2284
2285
  * intact. Per-line, line-anchored, non-global.
2285
2286
  */
2286
2287
  const LEAKED_TOOL_SUMMARY_LINE = /^\s*(?:⚠️|🛠️).*\(\+\d+\s+steps?\)\s*(?:failed|succeeded|done)\.?\s*$/iu;
2288
+ const LEAKED_TOOL_PIPELINE_LINE = /^\s*⚠️\s*🛠️\s+.+(?:\s+→\s+.+)+\s+(?:failed|succeeded|done)\.?\s*$/iu;
2287
2289
  function stripLeakedToolSummary(text) {
2288
- if (!text.includes("step")) return text;
2289
- return text.split("\n").filter((line) => !LEAKED_TOOL_SUMMARY_LINE.test(line)).join("\n").replace(/\n{3,}/g, "\n\n").trim();
2290
+ if (!text.includes("step") && !(text.includes("⚠️") && text.includes("🛠️") && text.includes("→"))) return text;
2291
+ return text.split("\n").filter((line) => !LEAKED_TOOL_SUMMARY_LINE.test(line) && !LEAKED_TOOL_PIPELINE_LINE.test(line)).join("\n").replace(/\n{3,}/g, "\n\n").trim();
2290
2292
  }
2291
2293
  /**
2292
2294
  * Build the `a2a-complete` notify payload. ALWAYS fired for an A2A turn —
@@ -2781,16 +2783,17 @@ function resolveAbortTargetKeys(active, abortSessionKey) {
2781
2783
  return keys;
2782
2784
  }
2783
2785
  /**
2784
- * `chat.abort` handler — genuinely cancels the RUNNING turn on the daemon.
2786
+ * `chat.abort` handler — attempts to cancel the RUNNING turn on the daemon.
2785
2787
  *
2786
2788
  * Invoked OUT-OF-BAND (never through the serialised agent-turn queue) so it
2787
2789
  * executes immediately while a turn is mid-flight. Resolves the live run's
2788
2790
  * sessionId from the target session key and fires the run handle's
2789
2791
  * AbortController via `abortEmbeddedAgentRun`. The in-flight dispatch then
2790
2792
  * settles (AbortError), so `handleAgentRequest` sends its RPC response and the
2791
- * chat service seals the UI. When the abort primitives are unavailable (older
2792
- * openclaw), this degrades to a logged no-op: the UI is still sealed by the
2793
- * chat service's optimistic idle broadcast, but the turn completes server-side.
2793
+ * chat service can settle the UI. When the abort primitives are unavailable
2794
+ * (older OpenClaw), this returns `{aborted:false}`. The service must keep the
2795
+ * turn active until its real terminal frame because the response may still be
2796
+ * persisted.
2794
2797
  */
2795
2798
  function handleChatAbort(request, log) {
2796
2799
  const { sessionKey } = request.params;
@@ -3064,6 +3067,7 @@ async function handleAgentRequest(request, log) {
3064
3067
  const conversationLabel = conversationType === "group" ? shortConvId ? `[${channelLabel}] Group (${shortConvId})` : `[${channelLabel}] Group` : shortConvId ? `[${channelLabel}] ${userLabel} (${shortConvId})` : `[${channelLabel}] ${userLabel}`;
3065
3068
  let a2aResponseBuffer = "";
3066
3069
  const outboundMediaCtx = createOutboundMediaContext();
3070
+ let visibleDeliveryIndex = 0;
3067
3071
  if (isA2A) resetA2AEndSignal();
3068
3072
  const peer = conversationType === "group" ? {
3069
3073
  kind: "group",
@@ -3129,6 +3133,8 @@ async function handleAgentRequest(request, log) {
3129
3133
  const note = formatMediaFailureNote(media.newFailures);
3130
3134
  responseText = responseText ? `${responseText}\n\n${note}` : note;
3131
3135
  }
3136
+ if (!responseText && media.mediaUrls.length === 0) return;
3137
+ const deliveryIndex = visibleDeliveryIndex++;
3132
3138
  await addMessage(sessionId, "assistant", responseText, void 0, void 0, void 0, assistantMediaToStored(media.attachments));
3133
3139
  if (isA2A) a2aResponseBuffer += (a2aResponseBuffer && responseText ? "\n\n" : "") + responseText;
3134
3140
  chatClient?.notify("agent-message", {
@@ -3136,6 +3142,7 @@ async function handleAgentRequest(request, log) {
3136
3142
  text: responseText,
3137
3143
  sessionKey: runGate.sessionKey ?? legacySessionKey,
3138
3144
  messageId: chatMessageId ?? request.id,
3145
+ deliveryIndex,
3139
3146
  ...media.mediaUrls.length ? {
3140
3147
  mediaUrls: media.mediaUrls,
3141
3148
  attachments: media.attachments
package/dist/plugin2.js CHANGED
@@ -2266,8 +2266,9 @@ function buildToolActivity(data) {
2266
2266
  /**
2267
2267
  * Workstream C, item 5: strip OpenClaw's leaked tool-summary console line
2268
2268
  * from assistant `responseText` before it's stored / notified as a chat
2269
- * bubble. OpenClaw upstream composes a `⚠️ 🛠️ … (+N steps) failed` summary
2270
- * into the assistant text for a non-zero-exit tool run; `failed` there is a
2269
+ * bubble. OpenClaw upstream composes either a `⚠️ 🛠️ … (+N steps) failed`
2270
+ * summary or a step-count-free `⚠️ 🛠️ … → … failed` pipeline into the
2271
+ * assistant text for a non-zero-exit tool run; `failed` there is a
2271
2272
  * TOOL exit status, not a chat-level failure, and it now has a proper
2272
2273
  * structured tool row (see buildToolActivity). This is a BOUNDED, clearly
2273
2274
  * scoped strip of that one known pattern — it must not touch normal prose.
@@ -2284,9 +2285,10 @@ function buildToolActivity(data) {
2284
2285
  * intact. Per-line, line-anchored, non-global.
2285
2286
  */
2286
2287
  const LEAKED_TOOL_SUMMARY_LINE = /^\s*(?:⚠️|🛠️).*\(\+\d+\s+steps?\)\s*(?:failed|succeeded|done)\.?\s*$/iu;
2288
+ const LEAKED_TOOL_PIPELINE_LINE = /^\s*⚠️\s*🛠️\s+.+(?:\s+→\s+.+)+\s+(?:failed|succeeded|done)\.?\s*$/iu;
2287
2289
  function stripLeakedToolSummary(text) {
2288
- if (!text.includes("step")) return text;
2289
- return text.split("\n").filter((line) => !LEAKED_TOOL_SUMMARY_LINE.test(line)).join("\n").replace(/\n{3,}/g, "\n\n").trim();
2290
+ if (!text.includes("step") && !(text.includes("⚠️") && text.includes("🛠️") && text.includes("→"))) return text;
2291
+ return text.split("\n").filter((line) => !LEAKED_TOOL_SUMMARY_LINE.test(line) && !LEAKED_TOOL_PIPELINE_LINE.test(line)).join("\n").replace(/\n{3,}/g, "\n\n").trim();
2290
2292
  }
2291
2293
  /**
2292
2294
  * Build the `a2a-complete` notify payload. ALWAYS fired for an A2A turn —
@@ -2781,16 +2783,17 @@ function resolveAbortTargetKeys(active, abortSessionKey) {
2781
2783
  return keys;
2782
2784
  }
2783
2785
  /**
2784
- * `chat.abort` handler — genuinely cancels the RUNNING turn on the daemon.
2786
+ * `chat.abort` handler — attempts to cancel the RUNNING turn on the daemon.
2785
2787
  *
2786
2788
  * Invoked OUT-OF-BAND (never through the serialised agent-turn queue) so it
2787
2789
  * executes immediately while a turn is mid-flight. Resolves the live run's
2788
2790
  * sessionId from the target session key and fires the run handle's
2789
2791
  * AbortController via `abortEmbeddedAgentRun`. The in-flight dispatch then
2790
2792
  * settles (AbortError), so `handleAgentRequest` sends its RPC response and the
2791
- * chat service seals the UI. When the abort primitives are unavailable (older
2792
- * openclaw), this degrades to a logged no-op: the UI is still sealed by the
2793
- * chat service's optimistic idle broadcast, but the turn completes server-side.
2793
+ * chat service can settle the UI. When the abort primitives are unavailable
2794
+ * (older OpenClaw), this returns `{aborted:false}`. The service must keep the
2795
+ * turn active until its real terminal frame because the response may still be
2796
+ * persisted.
2794
2797
  */
2795
2798
  function handleChatAbort(request, log) {
2796
2799
  const { sessionKey } = request.params;
@@ -3064,6 +3067,7 @@ async function handleAgentRequest(request, log) {
3064
3067
  const conversationLabel = conversationType === "group" ? shortConvId ? `[${channelLabel}] Group (${shortConvId})` : `[${channelLabel}] Group` : shortConvId ? `[${channelLabel}] ${userLabel} (${shortConvId})` : `[${channelLabel}] ${userLabel}`;
3065
3068
  let a2aResponseBuffer = "";
3066
3069
  const outboundMediaCtx = createOutboundMediaContext();
3070
+ let visibleDeliveryIndex = 0;
3067
3071
  if (isA2A) resetA2AEndSignal();
3068
3072
  const peer = conversationType === "group" ? {
3069
3073
  kind: "group",
@@ -3129,6 +3133,8 @@ async function handleAgentRequest(request, log) {
3129
3133
  const note = formatMediaFailureNote(media.newFailures);
3130
3134
  responseText = responseText ? `${responseText}\n\n${note}` : note;
3131
3135
  }
3136
+ if (!responseText && media.mediaUrls.length === 0) return;
3137
+ const deliveryIndex = visibleDeliveryIndex++;
3132
3138
  await addMessage(sessionId, "assistant", responseText, void 0, void 0, void 0, assistantMediaToStored(media.attachments));
3133
3139
  if (isA2A) a2aResponseBuffer += (a2aResponseBuffer && responseText ? "\n\n" : "") + responseText;
3134
3140
  chatClient?.notify("agent-message", {
@@ -3136,6 +3142,7 @@ async function handleAgentRequest(request, log) {
3136
3142
  text: responseText,
3137
3143
  sessionKey: runGate.sessionKey ?? legacySessionKey,
3138
3144
  messageId: chatMessageId ?? request.id,
3145
+ deliveryIndex,
3139
3146
  ...media.mediaUrls.length ? {
3140
3147
  mediaUrls: media.mediaUrls,
3141
3148
  attachments: media.attachments
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/openclaw-chat",
3
- "version": "0.9.13",
3
+ "version": "0.9.14",
4
4
  "description": "OpenClaw chat plugin for Alfe — web widget and mobile app channels",
5
5
  "type": "module",
6
6
  "main": "./dist/plugin.js",
@@ -27,10 +27,10 @@
27
27
  "openclaw.plugin.json"
28
28
  ],
29
29
  "dependencies": {
30
- "@alfe.ai/agent-api-client": "^0.17.0",
31
30
  "@alfe.ai/chat": "^0.0.18",
32
- "@alfe.ai/config": "^0.4.1",
33
- "@alfe.ai/openclaw-plugin-kit": "0.2.0"
31
+ "@alfe.ai/openclaw-plugin-kit": "0.2.0",
32
+ "@alfe.ai/agent-api-client": "^0.17.0",
33
+ "@alfe.ai/config": "^0.4.1"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "openclaw": ">=2026.3.0"