@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 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?.sendResponse(request.id, true, {
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("message", async (...eventArgs) => {
577
+ api.on("message_received", async (...eventArgs) => {
633
578
  const event = eventArgs[0];
634
- const key = event.sessionKey;
635
- if (!key) return;
636
- if (isAlfeSessionKey(key)) {
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?.sendResponse(request.id, true, {
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("message", async (...eventArgs) => {
577
+ api.on("message_received", async (...eventArgs) => {
633
578
  const event = eventArgs[0];
634
- const key = event.sessionKey;
635
- if (!key) return;
636
- if (isAlfeSessionKey(key)) {
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.16",
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/chat": "^0.0.6"
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"