@alfe.ai/openclaw-chat 0.9.12 → 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 +21 -11
- package/dist/plugin2.js +21 -11
- package/package.json +4 -4
package/dist/plugin2.cjs
CHANGED
|
@@ -34,8 +34,8 @@ let _alfe_ai_config = require("@alfe.ai/config");
|
|
|
34
34
|
* - The size cap mirrors the presign endpoint's 25 MB / 10-files limits —
|
|
35
35
|
* NOT the plugin's 50 MB inbound download cap — so oversize files fail
|
|
36
36
|
* fast locally instead of as an opaque presign 400.
|
|
37
|
-
* - The presigned PUT is signed with `ContentType
|
|
38
|
-
*
|
|
37
|
+
* - The presigned PUT is signed with `ContentType` and encryption headers;
|
|
38
|
+
* the raw fetch MUST send both. (This raw fetch to a presigned S3 URL
|
|
39
39
|
* is the sanctioned exception to the no-raw-fetch rule.)
|
|
40
40
|
* - `resolveConfig()` throws on self-hosted agents without env/config.toml
|
|
41
41
|
* (and on unknown token prefixes). With no client, local refs resolve to
|
|
@@ -207,7 +207,10 @@ async function uploadLocalFile(localPath, log, deps) {
|
|
|
207
207
|
try {
|
|
208
208
|
const res = await fetchFn(presigned.uploadUrl, {
|
|
209
209
|
method: "PUT",
|
|
210
|
-
headers: {
|
|
210
|
+
headers: {
|
|
211
|
+
...presigned.uploadHeaders,
|
|
212
|
+
"Content-Type": mimeType
|
|
213
|
+
},
|
|
211
214
|
body,
|
|
212
215
|
signal: controller.signal
|
|
213
216
|
});
|
|
@@ -2263,8 +2266,9 @@ function buildToolActivity(data) {
|
|
|
2263
2266
|
/**
|
|
2264
2267
|
* Workstream C, item 5: strip OpenClaw's leaked tool-summary console line
|
|
2265
2268
|
* from assistant `responseText` before it's stored / notified as a chat
|
|
2266
|
-
* bubble. OpenClaw upstream composes a `⚠️ 🛠️ … (+N steps) failed`
|
|
2267
|
-
*
|
|
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
|
|
2268
2272
|
* TOOL exit status, not a chat-level failure, and it now has a proper
|
|
2269
2273
|
* structured tool row (see buildToolActivity). This is a BOUNDED, clearly
|
|
2270
2274
|
* scoped strip of that one known pattern — it must not touch normal prose.
|
|
@@ -2281,9 +2285,10 @@ function buildToolActivity(data) {
|
|
|
2281
2285
|
* intact. Per-line, line-anchored, non-global.
|
|
2282
2286
|
*/
|
|
2283
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;
|
|
2284
2289
|
function stripLeakedToolSummary(text) {
|
|
2285
|
-
if (!text.includes("step")) return text;
|
|
2286
|
-
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();
|
|
2287
2292
|
}
|
|
2288
2293
|
/**
|
|
2289
2294
|
* Build the `a2a-complete` notify payload. ALWAYS fired for an A2A turn —
|
|
@@ -2778,16 +2783,17 @@ function resolveAbortTargetKeys(active, abortSessionKey) {
|
|
|
2778
2783
|
return keys;
|
|
2779
2784
|
}
|
|
2780
2785
|
/**
|
|
2781
|
-
* `chat.abort` handler —
|
|
2786
|
+
* `chat.abort` handler — attempts to cancel the RUNNING turn on the daemon.
|
|
2782
2787
|
*
|
|
2783
2788
|
* Invoked OUT-OF-BAND (never through the serialised agent-turn queue) so it
|
|
2784
2789
|
* executes immediately while a turn is mid-flight. Resolves the live run's
|
|
2785
2790
|
* sessionId from the target session key and fires the run handle's
|
|
2786
2791
|
* AbortController via `abortEmbeddedAgentRun`. The in-flight dispatch then
|
|
2787
2792
|
* settles (AbortError), so `handleAgentRequest` sends its RPC response and the
|
|
2788
|
-
* chat service
|
|
2789
|
-
*
|
|
2790
|
-
*
|
|
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.
|
|
2791
2797
|
*/
|
|
2792
2798
|
function handleChatAbort(request, log) {
|
|
2793
2799
|
const { sessionKey } = request.params;
|
|
@@ -3061,6 +3067,7 @@ async function handleAgentRequest(request, log) {
|
|
|
3061
3067
|
const conversationLabel = conversationType === "group" ? shortConvId ? `[${channelLabel}] Group (${shortConvId})` : `[${channelLabel}] Group` : shortConvId ? `[${channelLabel}] ${userLabel} (${shortConvId})` : `[${channelLabel}] ${userLabel}`;
|
|
3062
3068
|
let a2aResponseBuffer = "";
|
|
3063
3069
|
const outboundMediaCtx = createOutboundMediaContext();
|
|
3070
|
+
let visibleDeliveryIndex = 0;
|
|
3064
3071
|
if (isA2A) resetA2AEndSignal();
|
|
3065
3072
|
const peer = conversationType === "group" ? {
|
|
3066
3073
|
kind: "group",
|
|
@@ -3126,6 +3133,8 @@ async function handleAgentRequest(request, log) {
|
|
|
3126
3133
|
const note = formatMediaFailureNote(media.newFailures);
|
|
3127
3134
|
responseText = responseText ? `${responseText}\n\n${note}` : note;
|
|
3128
3135
|
}
|
|
3136
|
+
if (!responseText && media.mediaUrls.length === 0) return;
|
|
3137
|
+
const deliveryIndex = visibleDeliveryIndex++;
|
|
3129
3138
|
await addMessage(sessionId, "assistant", responseText, void 0, void 0, void 0, assistantMediaToStored(media.attachments));
|
|
3130
3139
|
if (isA2A) a2aResponseBuffer += (a2aResponseBuffer && responseText ? "\n\n" : "") + responseText;
|
|
3131
3140
|
chatClient?.notify("agent-message", {
|
|
@@ -3133,6 +3142,7 @@ async function handleAgentRequest(request, log) {
|
|
|
3133
3142
|
text: responseText,
|
|
3134
3143
|
sessionKey: runGate.sessionKey ?? legacySessionKey,
|
|
3135
3144
|
messageId: chatMessageId ?? request.id,
|
|
3145
|
+
deliveryIndex,
|
|
3136
3146
|
...media.mediaUrls.length ? {
|
|
3137
3147
|
mediaUrls: media.mediaUrls,
|
|
3138
3148
|
attachments: media.attachments
|
package/dist/plugin2.js
CHANGED
|
@@ -34,8 +34,8 @@ import { resolveConfig } from "@alfe.ai/config";
|
|
|
34
34
|
* - The size cap mirrors the presign endpoint's 25 MB / 10-files limits —
|
|
35
35
|
* NOT the plugin's 50 MB inbound download cap — so oversize files fail
|
|
36
36
|
* fast locally instead of as an opaque presign 400.
|
|
37
|
-
* - The presigned PUT is signed with `ContentType
|
|
38
|
-
*
|
|
37
|
+
* - The presigned PUT is signed with `ContentType` and encryption headers;
|
|
38
|
+
* the raw fetch MUST send both. (This raw fetch to a presigned S3 URL
|
|
39
39
|
* is the sanctioned exception to the no-raw-fetch rule.)
|
|
40
40
|
* - `resolveConfig()` throws on self-hosted agents without env/config.toml
|
|
41
41
|
* (and on unknown token prefixes). With no client, local refs resolve to
|
|
@@ -207,7 +207,10 @@ async function uploadLocalFile(localPath, log, deps) {
|
|
|
207
207
|
try {
|
|
208
208
|
const res = await fetchFn(presigned.uploadUrl, {
|
|
209
209
|
method: "PUT",
|
|
210
|
-
headers: {
|
|
210
|
+
headers: {
|
|
211
|
+
...presigned.uploadHeaders,
|
|
212
|
+
"Content-Type": mimeType
|
|
213
|
+
},
|
|
211
214
|
body,
|
|
212
215
|
signal: controller.signal
|
|
213
216
|
});
|
|
@@ -2263,8 +2266,9 @@ function buildToolActivity(data) {
|
|
|
2263
2266
|
/**
|
|
2264
2267
|
* Workstream C, item 5: strip OpenClaw's leaked tool-summary console line
|
|
2265
2268
|
* from assistant `responseText` before it's stored / notified as a chat
|
|
2266
|
-
* bubble. OpenClaw upstream composes a `⚠️ 🛠️ … (+N steps) failed`
|
|
2267
|
-
*
|
|
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
|
|
2268
2272
|
* TOOL exit status, not a chat-level failure, and it now has a proper
|
|
2269
2273
|
* structured tool row (see buildToolActivity). This is a BOUNDED, clearly
|
|
2270
2274
|
* scoped strip of that one known pattern — it must not touch normal prose.
|
|
@@ -2281,9 +2285,10 @@ function buildToolActivity(data) {
|
|
|
2281
2285
|
* intact. Per-line, line-anchored, non-global.
|
|
2282
2286
|
*/
|
|
2283
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;
|
|
2284
2289
|
function stripLeakedToolSummary(text) {
|
|
2285
|
-
if (!text.includes("step")) return text;
|
|
2286
|
-
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();
|
|
2287
2292
|
}
|
|
2288
2293
|
/**
|
|
2289
2294
|
* Build the `a2a-complete` notify payload. ALWAYS fired for an A2A turn —
|
|
@@ -2778,16 +2783,17 @@ function resolveAbortTargetKeys(active, abortSessionKey) {
|
|
|
2778
2783
|
return keys;
|
|
2779
2784
|
}
|
|
2780
2785
|
/**
|
|
2781
|
-
* `chat.abort` handler —
|
|
2786
|
+
* `chat.abort` handler — attempts to cancel the RUNNING turn on the daemon.
|
|
2782
2787
|
*
|
|
2783
2788
|
* Invoked OUT-OF-BAND (never through the serialised agent-turn queue) so it
|
|
2784
2789
|
* executes immediately while a turn is mid-flight. Resolves the live run's
|
|
2785
2790
|
* sessionId from the target session key and fires the run handle's
|
|
2786
2791
|
* AbortController via `abortEmbeddedAgentRun`. The in-flight dispatch then
|
|
2787
2792
|
* settles (AbortError), so `handleAgentRequest` sends its RPC response and the
|
|
2788
|
-
* chat service
|
|
2789
|
-
*
|
|
2790
|
-
*
|
|
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.
|
|
2791
2797
|
*/
|
|
2792
2798
|
function handleChatAbort(request, log) {
|
|
2793
2799
|
const { sessionKey } = request.params;
|
|
@@ -3061,6 +3067,7 @@ async function handleAgentRequest(request, log) {
|
|
|
3061
3067
|
const conversationLabel = conversationType === "group" ? shortConvId ? `[${channelLabel}] Group (${shortConvId})` : `[${channelLabel}] Group` : shortConvId ? `[${channelLabel}] ${userLabel} (${shortConvId})` : `[${channelLabel}] ${userLabel}`;
|
|
3062
3068
|
let a2aResponseBuffer = "";
|
|
3063
3069
|
const outboundMediaCtx = createOutboundMediaContext();
|
|
3070
|
+
let visibleDeliveryIndex = 0;
|
|
3064
3071
|
if (isA2A) resetA2AEndSignal();
|
|
3065
3072
|
const peer = conversationType === "group" ? {
|
|
3066
3073
|
kind: "group",
|
|
@@ -3126,6 +3133,8 @@ async function handleAgentRequest(request, log) {
|
|
|
3126
3133
|
const note = formatMediaFailureNote(media.newFailures);
|
|
3127
3134
|
responseText = responseText ? `${responseText}\n\n${note}` : note;
|
|
3128
3135
|
}
|
|
3136
|
+
if (!responseText && media.mediaUrls.length === 0) return;
|
|
3137
|
+
const deliveryIndex = visibleDeliveryIndex++;
|
|
3129
3138
|
await addMessage(sessionId, "assistant", responseText, void 0, void 0, void 0, assistantMediaToStored(media.attachments));
|
|
3130
3139
|
if (isA2A) a2aResponseBuffer += (a2aResponseBuffer && responseText ? "\n\n" : "") + responseText;
|
|
3131
3140
|
chatClient?.notify("agent-message", {
|
|
@@ -3133,6 +3142,7 @@ async function handleAgentRequest(request, log) {
|
|
|
3133
3142
|
text: responseText,
|
|
3134
3143
|
sessionKey: runGate.sessionKey ?? legacySessionKey,
|
|
3135
3144
|
messageId: chatMessageId ?? request.id,
|
|
3145
|
+
deliveryIndex,
|
|
3136
3146
|
...media.mediaUrls.length ? {
|
|
3137
3147
|
mediaUrls: media.mediaUrls,
|
|
3138
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.
|
|
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.16.0",
|
|
31
30
|
"@alfe.ai/chat": "^0.0.18",
|
|
32
|
-
"@alfe.ai/
|
|
33
|
-
"@alfe.ai/
|
|
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"
|