@alfe.ai/openclaw-metrics 0.0.2
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/plugin.d.ts +29 -0
- package/dist/plugin.js +92 -0
- package/openclaw.plugin.json +8 -0
- package/package.json +44 -0
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/plugin.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* @alfe.ai/openclaw-metrics — OpenClaw metrics plugin for Alfe.
|
|
4
|
+
*
|
|
5
|
+
* Hooks into the global `message` event to track per-user activity
|
|
6
|
+
* across all channels (Alfe chat, Discord, Slack, etc.).
|
|
7
|
+
*
|
|
8
|
+
* On each message, fires a fire-and-forget POST to the Alfe API
|
|
9
|
+
* via the AgentApiClient. The backend resolves agentId + tenantId
|
|
10
|
+
* from the agent's API key — the plugin never needs to know or send
|
|
11
|
+
* the Alfe agentId.
|
|
12
|
+
*/
|
|
13
|
+
interface PluginLogger {
|
|
14
|
+
info(msg: string, ...args: unknown[]): void;
|
|
15
|
+
warn(msg: string, ...args: unknown[]): void;
|
|
16
|
+
error(msg: string, ...args: unknown[]): void;
|
|
17
|
+
debug(msg: string, ...args: unknown[]): void;
|
|
18
|
+
}
|
|
19
|
+
interface PluginApi {
|
|
20
|
+
logger: PluginLogger;
|
|
21
|
+
on(event: string, handler: (...args: unknown[]) => void | Promise<void>): void;
|
|
22
|
+
}
|
|
23
|
+
declare const plugin: {
|
|
24
|
+
id: string;
|
|
25
|
+
activate(api: PluginApi): void;
|
|
26
|
+
deactivate(api: PluginApi): void;
|
|
27
|
+
};
|
|
28
|
+
//#endregion
|
|
29
|
+
export { plugin as default };
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { resolveConfig } from "@alfe.ai/config";
|
|
2
|
+
import { AgentApiClient } from "@alfe.ai/agent-api-client";
|
|
3
|
+
//#region src/session-keys.ts
|
|
4
|
+
/** Known channel segments in canonical session keys. */
|
|
5
|
+
const KNOWN_CHANNELS = new Set([
|
|
6
|
+
"alfe",
|
|
7
|
+
"discord",
|
|
8
|
+
"slack",
|
|
9
|
+
"telegram",
|
|
10
|
+
"whatsapp",
|
|
11
|
+
"signal",
|
|
12
|
+
"irc",
|
|
13
|
+
"googlechat",
|
|
14
|
+
"msteams",
|
|
15
|
+
"imessage",
|
|
16
|
+
"feishu"
|
|
17
|
+
]);
|
|
18
|
+
/**
|
|
19
|
+
* Parse a session key for userId and channel.
|
|
20
|
+
*
|
|
21
|
+
* Returns empty strings for fields that cannot be determined.
|
|
22
|
+
*/
|
|
23
|
+
function parseSessionKey(key) {
|
|
24
|
+
const canonicalMatch = /^agent:[^:]+:([^:]+):(?:default:)?direct:([^:]+)/.exec(key);
|
|
25
|
+
if (canonicalMatch) {
|
|
26
|
+
const [, channel, userId] = canonicalMatch;
|
|
27
|
+
return {
|
|
28
|
+
userId,
|
|
29
|
+
channel: KNOWN_CHANNELS.has(channel) ? channel : "unknown"
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (key.includes("chat-")) return {
|
|
33
|
+
userId: "",
|
|
34
|
+
channel: "alfe"
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
userId: "",
|
|
38
|
+
channel: "unknown"
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/plugin.ts
|
|
43
|
+
/**
|
|
44
|
+
* @alfe.ai/openclaw-metrics — OpenClaw metrics plugin for Alfe.
|
|
45
|
+
*
|
|
46
|
+
* Hooks into the global `message` event to track per-user activity
|
|
47
|
+
* across all channels (Alfe chat, Discord, Slack, etc.).
|
|
48
|
+
*
|
|
49
|
+
* On each message, fires a fire-and-forget POST to the Alfe API
|
|
50
|
+
* via the AgentApiClient. The backend resolves agentId + tenantId
|
|
51
|
+
* from the agent's API key — the plugin never needs to know or send
|
|
52
|
+
* the Alfe agentId.
|
|
53
|
+
*/
|
|
54
|
+
let client = null;
|
|
55
|
+
const plugin = {
|
|
56
|
+
id: "@alfe.ai/openclaw-metrics",
|
|
57
|
+
activate(api) {
|
|
58
|
+
const log = api.logger;
|
|
59
|
+
log.info("Alfe Metrics plugin activating...");
|
|
60
|
+
resolveConfig().then((cfg) => {
|
|
61
|
+
client = new AgentApiClient({
|
|
62
|
+
apiKey: cfg.apiKey,
|
|
63
|
+
apiUrl: cfg.apiUrl
|
|
64
|
+
});
|
|
65
|
+
log.info("Alfe Metrics plugin ready — API client initialized");
|
|
66
|
+
}).catch((err) => {
|
|
67
|
+
log.warn(`Failed to resolve Alfe config — metrics will not be reported: ${err instanceof Error ? err.message : String(err)}`);
|
|
68
|
+
});
|
|
69
|
+
api.on("message", (...eventArgs) => {
|
|
70
|
+
if (!client) return;
|
|
71
|
+
const { sessionKey, role } = eventArgs[0];
|
|
72
|
+
if (!sessionKey) return;
|
|
73
|
+
const parsed = parseSessionKey(sessionKey);
|
|
74
|
+
if (!parsed.userId) return;
|
|
75
|
+
client.recordActivity({
|
|
76
|
+
userId: parsed.userId,
|
|
77
|
+
channel: parsed.channel,
|
|
78
|
+
role
|
|
79
|
+
}).catch((err) => {
|
|
80
|
+
log.debug(`Metrics report failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
log.info("Alfe Metrics plugin registered");
|
|
84
|
+
},
|
|
85
|
+
deactivate(api) {
|
|
86
|
+
const log = api.logger;
|
|
87
|
+
client = null;
|
|
88
|
+
log.info("Alfe Metrics plugin deactivated");
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
//#endregion
|
|
92
|
+
export { plugin as default };
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@alfe.ai/openclaw-metrics",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "OpenClaw metrics plugin for Alfe — per-user activity tracking",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/plugin.js",
|
|
7
|
+
"types": "./dist/plugin.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
"./plugin": {
|
|
10
|
+
"import": "./dist/plugin.js",
|
|
11
|
+
"types": "./dist/plugin.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"openclaw": {
|
|
15
|
+
"extensions": [
|
|
16
|
+
"./dist/plugin.js"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"openclaw.plugin.json"
|
|
22
|
+
],
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@alfe.ai/config": "^0.0.5",
|
|
25
|
+
"@alfe.ai/agent-api-client": "^0.0.3"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"openclaw": ">=2026.3.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependenciesMeta": {
|
|
31
|
+
"openclaw": {
|
|
32
|
+
"optional": true
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"license": "UNLICENSED",
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsdown",
|
|
38
|
+
"dev": "tsdown --watch",
|
|
39
|
+
"test": "vitest run --passWithNoTests",
|
|
40
|
+
"test:watch": "vitest",
|
|
41
|
+
"typecheck": "tsc --noEmit",
|
|
42
|
+
"lint": "eslint ."
|
|
43
|
+
}
|
|
44
|
+
}
|