@alfe.ai/openclaw-chat 0.0.16 → 0.0.18
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 +27 -89
- package/dist/plugin2.js +27 -89
- package/package.json +4 -2
package/dist/plugin2.cjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
let node_module = require("node:module");
|
|
2
2
|
let _alfe_ai_chat = require("@alfe.ai/chat");
|
|
3
|
+
let _alfe_ai_config = require("@alfe.ai/config");
|
|
4
|
+
let _alfe_ai_agent_api_client = require("@alfe.ai/agent-api-client");
|
|
3
5
|
let node_fs_promises = require("node:fs/promises");
|
|
4
6
|
let node_path = require("node:path");
|
|
5
7
|
let node_os = require("node:os");
|
|
@@ -138,28 +140,6 @@ function createAlfeChannelPlugin() {
|
|
|
138
140
|
//#endregion
|
|
139
141
|
//#region src/session-keys.ts
|
|
140
142
|
/**
|
|
141
|
-
* Session key helpers — handles standardized, canonical, and legacy formats.
|
|
142
|
-
*
|
|
143
|
-
* Standardized format (Alfe-controlled):
|
|
144
|
-
* alfe:{mode}:{identity} — single-threaded (SMS, WhatsApp)
|
|
145
|
-
* alfe:{mode}:{identity}:{convId} — multi-threaded (web chat)
|
|
146
|
-
*
|
|
147
|
-
* OpenClaw canonical format (from resolveAgentRoute):
|
|
148
|
-
* agent:{ocAgentId}:alfe:[default:]direct:{senderId}[:thread:{conversationId}]
|
|
149
|
-
*
|
|
150
|
-
* Legacy formats (deprecated):
|
|
151
|
-
* sms-{agentId}-{phone}
|
|
152
|
-
* wa-{agentId}-{phone}
|
|
153
|
-
* chat-{tenantId}-{agentId}-{suffix}
|
|
154
|
-
* agent:{agentId}:chat-{tenantId}-{agentId}-{suffix}
|
|
155
|
-
*/
|
|
156
|
-
/** Single-threaded channel modes — identity IS the conversation. */
|
|
157
|
-
const SINGLE_THREADED_MODES = new Set([
|
|
158
|
-
"sms",
|
|
159
|
-
"whatsapp",
|
|
160
|
-
"mobile"
|
|
161
|
-
]);
|
|
162
|
-
/**
|
|
163
143
|
* Check if a session key belongs to the Alfe chat channel.
|
|
164
144
|
* Handles standardized, canonical, and legacy formats.
|
|
165
145
|
*/
|
|
@@ -170,60 +150,6 @@ function isAlfeSessionKey(key) {
|
|
|
170
150
|
return false;
|
|
171
151
|
}
|
|
172
152
|
/**
|
|
173
|
-
* Parse session key metadata. Returns available fields from any format.
|
|
174
|
-
*
|
|
175
|
-
* For the callback flow, `conversationId` is the critical field — it maps
|
|
176
|
-
* to the channel registry key used by getChannelCallback().
|
|
177
|
-
*/
|
|
178
|
-
function parseAlfeSessionKey(key) {
|
|
179
|
-
const standardMatch = /^alfe:(\w+):(.+)$/.exec(key);
|
|
180
|
-
if (standardMatch) {
|
|
181
|
-
const [, mode, rest] = standardMatch;
|
|
182
|
-
if (SINGLE_THREADED_MODES.has(mode)) return {
|
|
183
|
-
agentId: "",
|
|
184
|
-
userId: rest,
|
|
185
|
-
conversationId: key,
|
|
186
|
-
tenantId: "",
|
|
187
|
-
mode
|
|
188
|
-
};
|
|
189
|
-
const lastColon = rest.lastIndexOf(":");
|
|
190
|
-
if (lastColon > 0) return {
|
|
191
|
-
agentId: "",
|
|
192
|
-
userId: rest.slice(0, lastColon),
|
|
193
|
-
conversationId: key,
|
|
194
|
-
tenantId: "",
|
|
195
|
-
mode
|
|
196
|
-
};
|
|
197
|
-
return {
|
|
198
|
-
agentId: "",
|
|
199
|
-
userId: rest,
|
|
200
|
-
conversationId: key,
|
|
201
|
-
tenantId: "",
|
|
202
|
-
mode
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
const canonicalMatch = /^agent:([^:]+):alfe:(?:default:)?direct:(.+?)(?::thread:(.+))?$/.exec(key);
|
|
206
|
-
if (canonicalMatch) {
|
|
207
|
-
const [, matchAgentId, matchUserId, matchConvId] = canonicalMatch;
|
|
208
|
-
return {
|
|
209
|
-
agentId: matchAgentId,
|
|
210
|
-
userId: matchUserId,
|
|
211
|
-
conversationId: matchConvId || "",
|
|
212
|
-
tenantId: "",
|
|
213
|
-
mode: ""
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
const rawKey = key.includes(":") ? key.slice(key.lastIndexOf(":") + 1) : key;
|
|
217
|
-
const legacyMatch = /^chat-([^-]+)-([^-]+)/.exec(rawKey);
|
|
218
|
-
return {
|
|
219
|
-
agentId: legacyMatch?.[2] ?? "",
|
|
220
|
-
userId: "",
|
|
221
|
-
conversationId: "",
|
|
222
|
-
tenantId: legacyMatch?.[1] ?? "",
|
|
223
|
-
mode: "chat"
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
153
|
* Extract the channel mode from a standardized session key or conversationId.
|
|
228
154
|
* Returns the mode segment (e.g. 'sms', 'whatsapp', 'chat') or fallback.
|
|
229
155
|
*/
|
|
@@ -398,6 +324,7 @@ function resolveOpenClawSdk(log) {
|
|
|
398
324
|
let pluginRuntime = null;
|
|
399
325
|
let chatClient = null;
|
|
400
326
|
let connectingPromise = null;
|
|
327
|
+
let metricsClient = null;
|
|
401
328
|
async function handleAgentRequest(request, log) {
|
|
402
329
|
const runtime = pluginRuntime;
|
|
403
330
|
if (!runtime) {
|
|
@@ -468,10 +395,18 @@ async function handleAgentRequest(request, log) {
|
|
|
468
395
|
deliver: async (payload) => {
|
|
469
396
|
const responseText = payload.text ?? "";
|
|
470
397
|
await addMessage(sessionId, "assistant", responseText);
|
|
471
|
-
chatClient?.
|
|
398
|
+
chatClient?.notify("agent-message", {
|
|
399
|
+
conversationId: conversationId ?? legacySessionKey,
|
|
472
400
|
text: responseText,
|
|
473
401
|
sessionKey: resolvedOpenClawKey ?? legacySessionKey
|
|
474
402
|
});
|
|
403
|
+
if (metricsClient && userId) metricsClient.recordActivity({
|
|
404
|
+
userId,
|
|
405
|
+
channel: "alfe",
|
|
406
|
+
role: "assistant"
|
|
407
|
+
}).catch((err) => {
|
|
408
|
+
log.debug(`Metrics report failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
409
|
+
});
|
|
475
410
|
},
|
|
476
411
|
onRecordError: (err) => {
|
|
477
412
|
log.error(`Session record error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -480,6 +415,7 @@ async function handleAgentRequest(request, log) {
|
|
|
480
415
|
log.error(`Dispatch error (${info.kind}): ${err instanceof Error ? err.message : String(err)}`);
|
|
481
416
|
}
|
|
482
417
|
})).route.sessionKey;
|
|
418
|
+
chatClient?.sendResponse(request.id, true, { sessionKey: resolvedOpenClawKey });
|
|
483
419
|
log.info(`Agent dispatch complete: sessionKey=${resolvedOpenClawKey}`);
|
|
484
420
|
} catch (err) {
|
|
485
421
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -556,6 +492,15 @@ const plugin = {
|
|
|
556
492
|
log.info("Chat plugin registering...");
|
|
557
493
|
resolveOpenClawSdk(log);
|
|
558
494
|
pluginRuntime = api.runtime ?? null;
|
|
495
|
+
try {
|
|
496
|
+
const cfg = (0, _alfe_ai_config.resolveConfig)();
|
|
497
|
+
metricsClient = new _alfe_ai_agent_api_client.AgentApiClient({
|
|
498
|
+
apiKey: cfg.apiKey,
|
|
499
|
+
apiUrl: cfg.apiUrl
|
|
500
|
+
});
|
|
501
|
+
} catch {
|
|
502
|
+
log.debug("Metrics client not initialized — activity tracking disabled");
|
|
503
|
+
}
|
|
559
504
|
}
|
|
560
505
|
const pluginConfig = (((api.config ?? {}).plugins?.entries)?.["@alfe.ai/openclaw-chat"] ?? {}).config ?? {};
|
|
561
506
|
if (!alreadyActivated) connectingPromise = Promise.resolve().then(() => {
|
|
@@ -629,19 +574,11 @@ const plugin = {
|
|
|
629
574
|
log.info(`Chat session starting: ${key}`);
|
|
630
575
|
await createSession(key, "", "alfe");
|
|
631
576
|
}, { priority: 50 });
|
|
632
|
-
api.on("
|
|
577
|
+
api.on("message_received", async (...eventArgs) => {
|
|
633
578
|
const event = eventArgs[0];
|
|
634
|
-
const
|
|
635
|
-
if (!
|
|
636
|
-
|
|
637
|
-
if (event.role === "assistant" && chatClient) {
|
|
638
|
-
const parsed = parseAlfeSessionKey(key);
|
|
639
|
-
if (parsed.conversationId) chatClient.notify("agent-message", {
|
|
640
|
-
conversationId: parsed.conversationId,
|
|
641
|
-
text: event.content
|
|
642
|
-
});
|
|
643
|
-
}
|
|
644
|
-
} else await addMessage(key, event.role, event.content);
|
|
579
|
+
const ctx = eventArgs[1];
|
|
580
|
+
if (!ctx.conversationId || ctx.channelId === "alfe") return;
|
|
581
|
+
await addMessage(ctx.conversationId, "user", event.content, event.from);
|
|
645
582
|
});
|
|
646
583
|
api.on("session_end", (...eventArgs) => {
|
|
647
584
|
const key = eventArgs[0].sessionKey;
|
|
@@ -668,6 +605,7 @@ const plugin = {
|
|
|
668
605
|
}
|
|
669
606
|
pluginRuntime = null;
|
|
670
607
|
dispatchInbound = null;
|
|
608
|
+
metricsClient = null;
|
|
671
609
|
log.info("Chat plugin deactivated");
|
|
672
610
|
}
|
|
673
611
|
};
|
package/dist/plugin2.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { ChatServiceClient, resolveAlfeChat } from "@alfe.ai/chat";
|
|
3
|
+
import { resolveConfig } from "@alfe.ai/config";
|
|
4
|
+
import { AgentApiClient } from "@alfe.ai/agent-api-client";
|
|
3
5
|
import { mkdir, readFile, readdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
4
6
|
import { join } from "node:path";
|
|
5
7
|
import { homedir } from "node:os";
|
|
@@ -138,28 +140,6 @@ function createAlfeChannelPlugin() {
|
|
|
138
140
|
//#endregion
|
|
139
141
|
//#region src/session-keys.ts
|
|
140
142
|
/**
|
|
141
|
-
* Session key helpers — handles standardized, canonical, and legacy formats.
|
|
142
|
-
*
|
|
143
|
-
* Standardized format (Alfe-controlled):
|
|
144
|
-
* alfe:{mode}:{identity} — single-threaded (SMS, WhatsApp)
|
|
145
|
-
* alfe:{mode}:{identity}:{convId} — multi-threaded (web chat)
|
|
146
|
-
*
|
|
147
|
-
* OpenClaw canonical format (from resolveAgentRoute):
|
|
148
|
-
* agent:{ocAgentId}:alfe:[default:]direct:{senderId}[:thread:{conversationId}]
|
|
149
|
-
*
|
|
150
|
-
* Legacy formats (deprecated):
|
|
151
|
-
* sms-{agentId}-{phone}
|
|
152
|
-
* wa-{agentId}-{phone}
|
|
153
|
-
* chat-{tenantId}-{agentId}-{suffix}
|
|
154
|
-
* agent:{agentId}:chat-{tenantId}-{agentId}-{suffix}
|
|
155
|
-
*/
|
|
156
|
-
/** Single-threaded channel modes — identity IS the conversation. */
|
|
157
|
-
const SINGLE_THREADED_MODES = new Set([
|
|
158
|
-
"sms",
|
|
159
|
-
"whatsapp",
|
|
160
|
-
"mobile"
|
|
161
|
-
]);
|
|
162
|
-
/**
|
|
163
143
|
* Check if a session key belongs to the Alfe chat channel.
|
|
164
144
|
* Handles standardized, canonical, and legacy formats.
|
|
165
145
|
*/
|
|
@@ -170,60 +150,6 @@ function isAlfeSessionKey(key) {
|
|
|
170
150
|
return false;
|
|
171
151
|
}
|
|
172
152
|
/**
|
|
173
|
-
* Parse session key metadata. Returns available fields from any format.
|
|
174
|
-
*
|
|
175
|
-
* For the callback flow, `conversationId` is the critical field — it maps
|
|
176
|
-
* to the channel registry key used by getChannelCallback().
|
|
177
|
-
*/
|
|
178
|
-
function parseAlfeSessionKey(key) {
|
|
179
|
-
const standardMatch = /^alfe:(\w+):(.+)$/.exec(key);
|
|
180
|
-
if (standardMatch) {
|
|
181
|
-
const [, mode, rest] = standardMatch;
|
|
182
|
-
if (SINGLE_THREADED_MODES.has(mode)) return {
|
|
183
|
-
agentId: "",
|
|
184
|
-
userId: rest,
|
|
185
|
-
conversationId: key,
|
|
186
|
-
tenantId: "",
|
|
187
|
-
mode
|
|
188
|
-
};
|
|
189
|
-
const lastColon = rest.lastIndexOf(":");
|
|
190
|
-
if (lastColon > 0) return {
|
|
191
|
-
agentId: "",
|
|
192
|
-
userId: rest.slice(0, lastColon),
|
|
193
|
-
conversationId: key,
|
|
194
|
-
tenantId: "",
|
|
195
|
-
mode
|
|
196
|
-
};
|
|
197
|
-
return {
|
|
198
|
-
agentId: "",
|
|
199
|
-
userId: rest,
|
|
200
|
-
conversationId: key,
|
|
201
|
-
tenantId: "",
|
|
202
|
-
mode
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
const canonicalMatch = /^agent:([^:]+):alfe:(?:default:)?direct:(.+?)(?::thread:(.+))?$/.exec(key);
|
|
206
|
-
if (canonicalMatch) {
|
|
207
|
-
const [, matchAgentId, matchUserId, matchConvId] = canonicalMatch;
|
|
208
|
-
return {
|
|
209
|
-
agentId: matchAgentId,
|
|
210
|
-
userId: matchUserId,
|
|
211
|
-
conversationId: matchConvId || "",
|
|
212
|
-
tenantId: "",
|
|
213
|
-
mode: ""
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
const rawKey = key.includes(":") ? key.slice(key.lastIndexOf(":") + 1) : key;
|
|
217
|
-
const legacyMatch = /^chat-([^-]+)-([^-]+)/.exec(rawKey);
|
|
218
|
-
return {
|
|
219
|
-
agentId: legacyMatch?.[2] ?? "",
|
|
220
|
-
userId: "",
|
|
221
|
-
conversationId: "",
|
|
222
|
-
tenantId: legacyMatch?.[1] ?? "",
|
|
223
|
-
mode: "chat"
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
153
|
* Extract the channel mode from a standardized session key or conversationId.
|
|
228
154
|
* Returns the mode segment (e.g. 'sms', 'whatsapp', 'chat') or fallback.
|
|
229
155
|
*/
|
|
@@ -398,6 +324,7 @@ function resolveOpenClawSdk(log) {
|
|
|
398
324
|
let pluginRuntime = null;
|
|
399
325
|
let chatClient = null;
|
|
400
326
|
let connectingPromise = null;
|
|
327
|
+
let metricsClient = null;
|
|
401
328
|
async function handleAgentRequest(request, log) {
|
|
402
329
|
const runtime = pluginRuntime;
|
|
403
330
|
if (!runtime) {
|
|
@@ -468,10 +395,18 @@ async function handleAgentRequest(request, log) {
|
|
|
468
395
|
deliver: async (payload) => {
|
|
469
396
|
const responseText = payload.text ?? "";
|
|
470
397
|
await addMessage(sessionId, "assistant", responseText);
|
|
471
|
-
chatClient?.
|
|
398
|
+
chatClient?.notify("agent-message", {
|
|
399
|
+
conversationId: conversationId ?? legacySessionKey,
|
|
472
400
|
text: responseText,
|
|
473
401
|
sessionKey: resolvedOpenClawKey ?? legacySessionKey
|
|
474
402
|
});
|
|
403
|
+
if (metricsClient && userId) metricsClient.recordActivity({
|
|
404
|
+
userId,
|
|
405
|
+
channel: "alfe",
|
|
406
|
+
role: "assistant"
|
|
407
|
+
}).catch((err) => {
|
|
408
|
+
log.debug(`Metrics report failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
409
|
+
});
|
|
475
410
|
},
|
|
476
411
|
onRecordError: (err) => {
|
|
477
412
|
log.error(`Session record error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -480,6 +415,7 @@ async function handleAgentRequest(request, log) {
|
|
|
480
415
|
log.error(`Dispatch error (${info.kind}): ${err instanceof Error ? err.message : String(err)}`);
|
|
481
416
|
}
|
|
482
417
|
})).route.sessionKey;
|
|
418
|
+
chatClient?.sendResponse(request.id, true, { sessionKey: resolvedOpenClawKey });
|
|
483
419
|
log.info(`Agent dispatch complete: sessionKey=${resolvedOpenClawKey}`);
|
|
484
420
|
} catch (err) {
|
|
485
421
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -556,6 +492,15 @@ const plugin = {
|
|
|
556
492
|
log.info("Chat plugin registering...");
|
|
557
493
|
resolveOpenClawSdk(log);
|
|
558
494
|
pluginRuntime = api.runtime ?? null;
|
|
495
|
+
try {
|
|
496
|
+
const cfg = resolveConfig();
|
|
497
|
+
metricsClient = new AgentApiClient({
|
|
498
|
+
apiKey: cfg.apiKey,
|
|
499
|
+
apiUrl: cfg.apiUrl
|
|
500
|
+
});
|
|
501
|
+
} catch {
|
|
502
|
+
log.debug("Metrics client not initialized — activity tracking disabled");
|
|
503
|
+
}
|
|
559
504
|
}
|
|
560
505
|
const pluginConfig = (((api.config ?? {}).plugins?.entries)?.["@alfe.ai/openclaw-chat"] ?? {}).config ?? {};
|
|
561
506
|
if (!alreadyActivated) connectingPromise = Promise.resolve().then(() => {
|
|
@@ -629,19 +574,11 @@ const plugin = {
|
|
|
629
574
|
log.info(`Chat session starting: ${key}`);
|
|
630
575
|
await createSession(key, "", "alfe");
|
|
631
576
|
}, { priority: 50 });
|
|
632
|
-
api.on("
|
|
577
|
+
api.on("message_received", async (...eventArgs) => {
|
|
633
578
|
const event = eventArgs[0];
|
|
634
|
-
const
|
|
635
|
-
if (!
|
|
636
|
-
|
|
637
|
-
if (event.role === "assistant" && chatClient) {
|
|
638
|
-
const parsed = parseAlfeSessionKey(key);
|
|
639
|
-
if (parsed.conversationId) chatClient.notify("agent-message", {
|
|
640
|
-
conversationId: parsed.conversationId,
|
|
641
|
-
text: event.content
|
|
642
|
-
});
|
|
643
|
-
}
|
|
644
|
-
} else await addMessage(key, event.role, event.content);
|
|
579
|
+
const ctx = eventArgs[1];
|
|
580
|
+
if (!ctx.conversationId || ctx.channelId === "alfe") return;
|
|
581
|
+
await addMessage(ctx.conversationId, "user", event.content, event.from);
|
|
645
582
|
});
|
|
646
583
|
api.on("session_end", (...eventArgs) => {
|
|
647
584
|
const key = eventArgs[0].sessionKey;
|
|
@@ -668,6 +605,7 @@ const plugin = {
|
|
|
668
605
|
}
|
|
669
606
|
pluginRuntime = null;
|
|
670
607
|
dispatchInbound = null;
|
|
608
|
+
metricsClient = null;
|
|
671
609
|
log.info("Chat plugin deactivated");
|
|
672
610
|
}
|
|
673
611
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/openclaw-chat",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
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,7 +27,9 @@
|
|
|
27
27
|
"openclaw.plugin.json"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@alfe.ai/
|
|
30
|
+
"@alfe.ai/agent-api-client": "^0.0.7",
|
|
31
|
+
"@alfe.ai/chat": "^0.0.6",
|
|
32
|
+
"@alfe.ai/config": "^0.0.7"
|
|
31
33
|
},
|
|
32
34
|
"peerDependencies": {
|
|
33
35
|
"openclaw": ">=2026.3.0"
|