@alfe.ai/openclaw-chat 0.0.33 → 0.1.0
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/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/plugin.d.cts +71 -23
- package/dist/plugin.d.ts +71 -23
- package/dist/plugin2.cjs +115 -51
- package/dist/plugin2.js +115 -51
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/plugin.d.cts
CHANGED
|
@@ -9,31 +9,21 @@
|
|
|
9
9
|
interface AlfeChannelAccountConfig {
|
|
10
10
|
/** Whether this account is enabled. */
|
|
11
11
|
enabled?: boolean;
|
|
12
|
-
/** Allowed sender identifiers (user IDs, email addresses). */
|
|
13
|
-
allowFrom?: string | string[];
|
|
14
12
|
/** Default delivery target. */
|
|
15
13
|
defaultTo?: string;
|
|
16
|
-
/** DM policy (open, allowlist, etc.). */
|
|
17
|
-
dmPolicy?: string;
|
|
18
14
|
}
|
|
19
15
|
interface AlfeChannelConfig {
|
|
20
16
|
/** Whether the Alfe channel is enabled. */
|
|
21
17
|
enabled?: boolean;
|
|
22
|
-
/** Allowed sender identifiers. */
|
|
23
|
-
allowFrom?: string | string[];
|
|
24
18
|
/** Default delivery target for outbound messages. */
|
|
25
19
|
defaultTo?: string;
|
|
26
|
-
/** DM policy. */
|
|
27
|
-
dmPolicy?: string;
|
|
28
20
|
/** Named accounts (multi-account support). */
|
|
29
21
|
accounts?: Record<string, AlfeChannelAccountConfig>;
|
|
30
22
|
}
|
|
31
23
|
interface AlfeResolvedAccount {
|
|
32
24
|
accountId: string;
|
|
33
25
|
enabled: boolean;
|
|
34
|
-
allowFrom: string[];
|
|
35
26
|
defaultTo?: string;
|
|
36
|
-
dmPolicy?: string;
|
|
37
27
|
}
|
|
38
28
|
interface AlfePluginConfig {
|
|
39
29
|
/** Agent ID this plugin is associated with. */
|
|
@@ -43,6 +33,28 @@ interface AlfePluginConfig {
|
|
|
43
33
|
/** API key for chat service auth */
|
|
44
34
|
apiKey?: string;
|
|
45
35
|
}
|
|
36
|
+
interface AlfeOutboundChatClient {
|
|
37
|
+
notify(event: string, payload: Record<string, unknown>): void;
|
|
38
|
+
}
|
|
39
|
+
interface AlfeOutboundSessionSummary {
|
|
40
|
+
sessionId: string;
|
|
41
|
+
userId?: string;
|
|
42
|
+
createdAt: string;
|
|
43
|
+
lastMessageAt?: string;
|
|
44
|
+
}
|
|
45
|
+
interface AlfeOutboundSession {
|
|
46
|
+
sessionId: string;
|
|
47
|
+
userId?: string;
|
|
48
|
+
}
|
|
49
|
+
interface AlfeChannelOutboundDeps {
|
|
50
|
+
getChatClient: () => AlfeOutboundChatClient | null;
|
|
51
|
+
listSessions: (filters?: {
|
|
52
|
+
userId?: string;
|
|
53
|
+
}) => Promise<AlfeOutboundSessionSummary[]>;
|
|
54
|
+
getSession: (sessionId: string) => Promise<AlfeOutboundSession | null>;
|
|
55
|
+
createSession: (sessionId: string, agentId: string, channel: string, tenantId?: string, userId?: string) => Promise<unknown>;
|
|
56
|
+
addMessage: (sessionId: string, role: 'user' | 'assistant', content: string, senderId?: string, senderName?: string) => Promise<void>;
|
|
57
|
+
}
|
|
46
58
|
//#endregion
|
|
47
59
|
//#region src/alfe-channel.d.ts
|
|
48
60
|
/** OpenClaw config shape — inline to avoid runtime dependency on openclaw package */
|
|
@@ -53,13 +65,23 @@ interface OpenClawConfig {
|
|
|
53
65
|
};
|
|
54
66
|
[key: string]: unknown;
|
|
55
67
|
}
|
|
68
|
+
interface OutboundDeliveryResult {
|
|
69
|
+
channel: 'alfe';
|
|
70
|
+
messageId: string;
|
|
71
|
+
conversationId: string;
|
|
72
|
+
timestamp: number;
|
|
73
|
+
}
|
|
56
74
|
/**
|
|
57
75
|
* Creates the Alfe ChannelPlugin object for registration with OpenClaw.
|
|
58
76
|
*
|
|
59
77
|
* This follows the same pattern as built-in channels (Telegram, Discord, etc.)
|
|
60
78
|
* but is registered dynamically via api.registerChannel().
|
|
79
|
+
*
|
|
80
|
+
* `deps` enables outbound delivery and peer discovery. When omitted (e.g.
|
|
81
|
+
* during CLI metadata registration), outbound calls throw and the directory
|
|
82
|
+
* is empty — but the channel is still registered for inbound use.
|
|
61
83
|
*/
|
|
62
|
-
declare function createAlfeChannelPlugin(): {
|
|
84
|
+
declare function createAlfeChannelPlugin(deps?: AlfeChannelOutboundDeps): {
|
|
63
85
|
id: string;
|
|
64
86
|
meta: {
|
|
65
87
|
id: string;
|
|
@@ -118,15 +140,7 @@ declare function createAlfeChannelPlugin(): {
|
|
|
118
140
|
accountId: string;
|
|
119
141
|
enabled: boolean;
|
|
120
142
|
configured: boolean;
|
|
121
|
-
dmPolicy: string | undefined;
|
|
122
143
|
};
|
|
123
|
-
/**
|
|
124
|
-
* Resolve allow-from list for an account.
|
|
125
|
-
*/
|
|
126
|
-
resolveAllowFrom(params: {
|
|
127
|
-
cfg: OpenClawConfig;
|
|
128
|
-
accountId?: string | null;
|
|
129
|
-
}): string[];
|
|
130
144
|
/**
|
|
131
145
|
* Resolve default outbound target.
|
|
132
146
|
*/
|
|
@@ -136,13 +150,47 @@ declare function createAlfeChannelPlugin(): {
|
|
|
136
150
|
}): string | undefined;
|
|
137
151
|
};
|
|
138
152
|
/**
|
|
139
|
-
* Outbound delivery via
|
|
140
|
-
*
|
|
141
|
-
*
|
|
153
|
+
* Outbound delivery via the plugin (`deliveryMode: 'direct'`).
|
|
154
|
+
*
|
|
155
|
+
* OpenClaw calls `resolveTarget` to validate the agent-supplied `to`,
|
|
156
|
+
* then `sendText` / `sendMedia` per chunk. We push each chunk to the
|
|
157
|
+
* chat relay service via `chatClient.notify('agent-message', …)`,
|
|
158
|
+
* which broadcasts to all connected web/mobile clients on that
|
|
159
|
+
* conversation and notifies offline participants.
|
|
142
160
|
*/
|
|
143
161
|
outbound: {
|
|
144
|
-
deliveryMode: "
|
|
162
|
+
deliveryMode: "direct";
|
|
145
163
|
textChunkLimit: number;
|
|
164
|
+
resolveTarget(params: {
|
|
165
|
+
to?: string;
|
|
166
|
+
}): {
|
|
167
|
+
ok: true;
|
|
168
|
+
to: string;
|
|
169
|
+
} | {
|
|
170
|
+
ok: false;
|
|
171
|
+
error: Error;
|
|
172
|
+
};
|
|
173
|
+
sendText(ctx: {
|
|
174
|
+
to: string;
|
|
175
|
+
text: string;
|
|
176
|
+
}): Promise<OutboundDeliveryResult>;
|
|
177
|
+
sendMedia(ctx: {
|
|
178
|
+
to: string;
|
|
179
|
+
text: string;
|
|
180
|
+
mediaUrl?: string;
|
|
181
|
+
}): Promise<OutboundDeliveryResult>;
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Directory adapter — exposes users the agent has chatted with so the
|
|
185
|
+
* `message` tool can suggest valid targets. Backed by the on-disk
|
|
186
|
+
* session store; live-list is the same as static-list since sessions
|
|
187
|
+
* are the only source of truth.
|
|
188
|
+
*/
|
|
189
|
+
directory: {
|
|
190
|
+
listPeers(): Promise<{
|
|
191
|
+
kind: "user";
|
|
192
|
+
id: string;
|
|
193
|
+
}[]>;
|
|
146
194
|
};
|
|
147
195
|
/**
|
|
148
196
|
* Setup adapter — minimal for Alfe since no external tokens are needed.
|
package/dist/plugin.d.ts
CHANGED
|
@@ -9,31 +9,21 @@
|
|
|
9
9
|
interface AlfeChannelAccountConfig {
|
|
10
10
|
/** Whether this account is enabled. */
|
|
11
11
|
enabled?: boolean;
|
|
12
|
-
/** Allowed sender identifiers (user IDs, email addresses). */
|
|
13
|
-
allowFrom?: string | string[];
|
|
14
12
|
/** Default delivery target. */
|
|
15
13
|
defaultTo?: string;
|
|
16
|
-
/** DM policy (open, allowlist, etc.). */
|
|
17
|
-
dmPolicy?: string;
|
|
18
14
|
}
|
|
19
15
|
interface AlfeChannelConfig {
|
|
20
16
|
/** Whether the Alfe channel is enabled. */
|
|
21
17
|
enabled?: boolean;
|
|
22
|
-
/** Allowed sender identifiers. */
|
|
23
|
-
allowFrom?: string | string[];
|
|
24
18
|
/** Default delivery target for outbound messages. */
|
|
25
19
|
defaultTo?: string;
|
|
26
|
-
/** DM policy. */
|
|
27
|
-
dmPolicy?: string;
|
|
28
20
|
/** Named accounts (multi-account support). */
|
|
29
21
|
accounts?: Record<string, AlfeChannelAccountConfig>;
|
|
30
22
|
}
|
|
31
23
|
interface AlfeResolvedAccount {
|
|
32
24
|
accountId: string;
|
|
33
25
|
enabled: boolean;
|
|
34
|
-
allowFrom: string[];
|
|
35
26
|
defaultTo?: string;
|
|
36
|
-
dmPolicy?: string;
|
|
37
27
|
}
|
|
38
28
|
interface AlfePluginConfig {
|
|
39
29
|
/** Agent ID this plugin is associated with. */
|
|
@@ -43,6 +33,28 @@ interface AlfePluginConfig {
|
|
|
43
33
|
/** API key for chat service auth */
|
|
44
34
|
apiKey?: string;
|
|
45
35
|
}
|
|
36
|
+
interface AlfeOutboundChatClient {
|
|
37
|
+
notify(event: string, payload: Record<string, unknown>): void;
|
|
38
|
+
}
|
|
39
|
+
interface AlfeOutboundSessionSummary {
|
|
40
|
+
sessionId: string;
|
|
41
|
+
userId?: string;
|
|
42
|
+
createdAt: string;
|
|
43
|
+
lastMessageAt?: string;
|
|
44
|
+
}
|
|
45
|
+
interface AlfeOutboundSession {
|
|
46
|
+
sessionId: string;
|
|
47
|
+
userId?: string;
|
|
48
|
+
}
|
|
49
|
+
interface AlfeChannelOutboundDeps {
|
|
50
|
+
getChatClient: () => AlfeOutboundChatClient | null;
|
|
51
|
+
listSessions: (filters?: {
|
|
52
|
+
userId?: string;
|
|
53
|
+
}) => Promise<AlfeOutboundSessionSummary[]>;
|
|
54
|
+
getSession: (sessionId: string) => Promise<AlfeOutboundSession | null>;
|
|
55
|
+
createSession: (sessionId: string, agentId: string, channel: string, tenantId?: string, userId?: string) => Promise<unknown>;
|
|
56
|
+
addMessage: (sessionId: string, role: 'user' | 'assistant', content: string, senderId?: string, senderName?: string) => Promise<void>;
|
|
57
|
+
}
|
|
46
58
|
//#endregion
|
|
47
59
|
//#region src/alfe-channel.d.ts
|
|
48
60
|
/** OpenClaw config shape — inline to avoid runtime dependency on openclaw package */
|
|
@@ -53,13 +65,23 @@ interface OpenClawConfig {
|
|
|
53
65
|
};
|
|
54
66
|
[key: string]: unknown;
|
|
55
67
|
}
|
|
68
|
+
interface OutboundDeliveryResult {
|
|
69
|
+
channel: 'alfe';
|
|
70
|
+
messageId: string;
|
|
71
|
+
conversationId: string;
|
|
72
|
+
timestamp: number;
|
|
73
|
+
}
|
|
56
74
|
/**
|
|
57
75
|
* Creates the Alfe ChannelPlugin object for registration with OpenClaw.
|
|
58
76
|
*
|
|
59
77
|
* This follows the same pattern as built-in channels (Telegram, Discord, etc.)
|
|
60
78
|
* but is registered dynamically via api.registerChannel().
|
|
79
|
+
*
|
|
80
|
+
* `deps` enables outbound delivery and peer discovery. When omitted (e.g.
|
|
81
|
+
* during CLI metadata registration), outbound calls throw and the directory
|
|
82
|
+
* is empty — but the channel is still registered for inbound use.
|
|
61
83
|
*/
|
|
62
|
-
declare function createAlfeChannelPlugin(): {
|
|
84
|
+
declare function createAlfeChannelPlugin(deps?: AlfeChannelOutboundDeps): {
|
|
63
85
|
id: string;
|
|
64
86
|
meta: {
|
|
65
87
|
id: string;
|
|
@@ -118,15 +140,7 @@ declare function createAlfeChannelPlugin(): {
|
|
|
118
140
|
accountId: string;
|
|
119
141
|
enabled: boolean;
|
|
120
142
|
configured: boolean;
|
|
121
|
-
dmPolicy: string | undefined;
|
|
122
143
|
};
|
|
123
|
-
/**
|
|
124
|
-
* Resolve allow-from list for an account.
|
|
125
|
-
*/
|
|
126
|
-
resolveAllowFrom(params: {
|
|
127
|
-
cfg: OpenClawConfig;
|
|
128
|
-
accountId?: string | null;
|
|
129
|
-
}): string[];
|
|
130
144
|
/**
|
|
131
145
|
* Resolve default outbound target.
|
|
132
146
|
*/
|
|
@@ -136,13 +150,47 @@ declare function createAlfeChannelPlugin(): {
|
|
|
136
150
|
}): string | undefined;
|
|
137
151
|
};
|
|
138
152
|
/**
|
|
139
|
-
* Outbound delivery via
|
|
140
|
-
*
|
|
141
|
-
*
|
|
153
|
+
* Outbound delivery via the plugin (`deliveryMode: 'direct'`).
|
|
154
|
+
*
|
|
155
|
+
* OpenClaw calls `resolveTarget` to validate the agent-supplied `to`,
|
|
156
|
+
* then `sendText` / `sendMedia` per chunk. We push each chunk to the
|
|
157
|
+
* chat relay service via `chatClient.notify('agent-message', …)`,
|
|
158
|
+
* which broadcasts to all connected web/mobile clients on that
|
|
159
|
+
* conversation and notifies offline participants.
|
|
142
160
|
*/
|
|
143
161
|
outbound: {
|
|
144
|
-
deliveryMode: "
|
|
162
|
+
deliveryMode: "direct";
|
|
145
163
|
textChunkLimit: number;
|
|
164
|
+
resolveTarget(params: {
|
|
165
|
+
to?: string;
|
|
166
|
+
}): {
|
|
167
|
+
ok: true;
|
|
168
|
+
to: string;
|
|
169
|
+
} | {
|
|
170
|
+
ok: false;
|
|
171
|
+
error: Error;
|
|
172
|
+
};
|
|
173
|
+
sendText(ctx: {
|
|
174
|
+
to: string;
|
|
175
|
+
text: string;
|
|
176
|
+
}): Promise<OutboundDeliveryResult>;
|
|
177
|
+
sendMedia(ctx: {
|
|
178
|
+
to: string;
|
|
179
|
+
text: string;
|
|
180
|
+
mediaUrl?: string;
|
|
181
|
+
}): Promise<OutboundDeliveryResult>;
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Directory adapter — exposes users the agent has chatted with so the
|
|
185
|
+
* `message` tool can suggest valid targets. Backed by the on-disk
|
|
186
|
+
* session store; live-list is the same as static-list since sessions
|
|
187
|
+
* are the only source of truth.
|
|
188
|
+
*/
|
|
189
|
+
directory: {
|
|
190
|
+
listPeers(): Promise<{
|
|
191
|
+
kind: "user";
|
|
192
|
+
id: string;
|
|
193
|
+
}[]>;
|
|
146
194
|
};
|
|
147
195
|
/**
|
|
148
196
|
* Setup adapter — minimal for Alfe since no external tokens are needed.
|
package/dist/plugin2.cjs
CHANGED
|
@@ -3,27 +3,70 @@ let node_fs_promises = require("node:fs/promises");
|
|
|
3
3
|
let node_path = require("node:path");
|
|
4
4
|
let node_os = require("node:os");
|
|
5
5
|
let _alfe_ai_chat = require("@alfe.ai/chat");
|
|
6
|
-
let
|
|
7
|
-
let _alfe_ai_agent_api_client = require("@alfe.ai/agent-api-client");
|
|
6
|
+
let node_crypto = require("node:crypto");
|
|
8
7
|
let node_fs = require("node:fs");
|
|
9
8
|
//#region src/alfe-channel.ts
|
|
9
|
+
/**
|
|
10
|
+
* Alfe channel plugin definition — registers 'alfe' as an OpenClaw channel.
|
|
11
|
+
*
|
|
12
|
+
* Web and mobile clients share the same channel and conversation sessions.
|
|
13
|
+
* Outbound delivery uses `deliveryMode: 'direct'` — the plugin's sendText /
|
|
14
|
+
* sendMedia handlers push messages through the chat relay service.
|
|
15
|
+
*
|
|
16
|
+
* Target formats accepted by `resolveTarget`:
|
|
17
|
+
* user:{clerkUserId} — most recent conversation for that user (created on demand)
|
|
18
|
+
* conv:{conversationId} — a specific existing conversation
|
|
19
|
+
*
|
|
20
|
+
* Config section: channels.alfe in openclaw.yaml
|
|
21
|
+
*/
|
|
10
22
|
const CHANNEL_ID = "alfe";
|
|
11
23
|
const DEFAULT_ACCOUNT_ID = "default";
|
|
24
|
+
async function sendViaChat(deps, ctx, mediaUrl) {
|
|
25
|
+
const client = deps.getChatClient();
|
|
26
|
+
if (!client) throw new Error("Chat service not connected — cannot deliver");
|
|
27
|
+
let conversationId;
|
|
28
|
+
if (ctx.to.startsWith("conv:")) {
|
|
29
|
+
conversationId = ctx.to.slice(5);
|
|
30
|
+
if (!await deps.getSession(conversationId)) throw new Error(`Conversation not found: ${conversationId}`);
|
|
31
|
+
} else {
|
|
32
|
+
const userId = ctx.to.startsWith("user:") ? ctx.to.slice(5) : ctx.to;
|
|
33
|
+
if (!userId) throw new Error("Empty userId in target");
|
|
34
|
+
const sessions = await deps.listSessions({ userId });
|
|
35
|
+
if (sessions.length > 0) conversationId = sessions[0].sessionId;
|
|
36
|
+
else {
|
|
37
|
+
conversationId = `alfe:chat:${userId}:${(0, node_crypto.randomUUID)()}`;
|
|
38
|
+
await deps.createSession(conversationId, "", "alfe", void 0, userId);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
await deps.addMessage(conversationId, "assistant", ctx.text);
|
|
42
|
+
const messageId = (0, node_crypto.randomUUID)();
|
|
43
|
+
client.notify("agent-message", {
|
|
44
|
+
conversationId,
|
|
45
|
+
text: ctx.text,
|
|
46
|
+
sessionKey: conversationId,
|
|
47
|
+
...mediaUrl ? { mediaUrls: [mediaUrl] } : {}
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
channel: "alfe",
|
|
51
|
+
messageId,
|
|
52
|
+
conversationId,
|
|
53
|
+
timestamp: Date.now()
|
|
54
|
+
};
|
|
55
|
+
}
|
|
12
56
|
function getChannelSection(cfg) {
|
|
13
57
|
return cfg.channels?.alfe ?? {};
|
|
14
58
|
}
|
|
15
|
-
function normalizeAllowFrom(raw) {
|
|
16
|
-
if (!raw) return [];
|
|
17
|
-
if (typeof raw === "string") return [raw];
|
|
18
|
-
return raw;
|
|
19
|
-
}
|
|
20
59
|
/**
|
|
21
60
|
* Creates the Alfe ChannelPlugin object for registration with OpenClaw.
|
|
22
61
|
*
|
|
23
62
|
* This follows the same pattern as built-in channels (Telegram, Discord, etc.)
|
|
24
63
|
* but is registered dynamically via api.registerChannel().
|
|
64
|
+
*
|
|
65
|
+
* `deps` enables outbound delivery and peer discovery. When omitted (e.g.
|
|
66
|
+
* during CLI metadata registration), outbound calls throw and the directory
|
|
67
|
+
* is empty — but the channel is still registered for inbound use.
|
|
25
68
|
*/
|
|
26
|
-
function createAlfeChannelPlugin() {
|
|
69
|
+
function createAlfeChannelPlugin(deps) {
|
|
27
70
|
return {
|
|
28
71
|
id: CHANNEL_ID,
|
|
29
72
|
meta: {
|
|
@@ -57,7 +100,7 @@ function createAlfeChannelPlugin() {
|
|
|
57
100
|
listAccountIds(cfg) {
|
|
58
101
|
const section = getChannelSection(cfg);
|
|
59
102
|
const ids = [];
|
|
60
|
-
if (section.enabled !== false &&
|
|
103
|
+
if (section.enabled !== false && section.defaultTo) ids.push(DEFAULT_ACCOUNT_ID);
|
|
61
104
|
if (section.accounts) {
|
|
62
105
|
for (const id of Object.keys(section.accounts)) if (!ids.includes(id)) ids.push(id);
|
|
63
106
|
}
|
|
@@ -71,16 +114,12 @@ function createAlfeChannelPlugin() {
|
|
|
71
114
|
if (accountSection) return {
|
|
72
115
|
accountId: id,
|
|
73
116
|
enabled: accountSection.enabled !== false,
|
|
74
|
-
|
|
75
|
-
defaultTo: accountSection.defaultTo,
|
|
76
|
-
dmPolicy: accountSection.dmPolicy
|
|
117
|
+
defaultTo: accountSection.defaultTo
|
|
77
118
|
};
|
|
78
119
|
return {
|
|
79
120
|
accountId: id,
|
|
80
121
|
enabled: section.enabled !== false,
|
|
81
|
-
|
|
82
|
-
defaultTo: section.defaultTo,
|
|
83
|
-
dmPolicy: section.dmPolicy
|
|
122
|
+
defaultTo: section.defaultTo
|
|
84
123
|
};
|
|
85
124
|
},
|
|
86
125
|
defaultAccountId() {
|
|
@@ -96,15 +135,9 @@ function createAlfeChannelPlugin() {
|
|
|
96
135
|
return {
|
|
97
136
|
accountId: account.accountId,
|
|
98
137
|
enabled: account.enabled,
|
|
99
|
-
configured: true
|
|
100
|
-
dmPolicy: account.dmPolicy
|
|
138
|
+
configured: true
|
|
101
139
|
};
|
|
102
140
|
},
|
|
103
|
-
resolveAllowFrom(params) {
|
|
104
|
-
const section = getChannelSection(params.cfg);
|
|
105
|
-
const id = params.accountId ?? DEFAULT_ACCOUNT_ID;
|
|
106
|
-
return normalizeAllowFrom((section.accounts?.[id])?.allowFrom ?? section.allowFrom);
|
|
107
|
-
},
|
|
108
141
|
resolveDefaultTo(params) {
|
|
109
142
|
const section = getChannelSection(params.cfg);
|
|
110
143
|
const id = params.accountId ?? DEFAULT_ACCOUNT_ID;
|
|
@@ -112,9 +145,58 @@ function createAlfeChannelPlugin() {
|
|
|
112
145
|
}
|
|
113
146
|
},
|
|
114
147
|
outbound: {
|
|
115
|
-
deliveryMode: "
|
|
116
|
-
textChunkLimit: 4e3
|
|
148
|
+
deliveryMode: "direct",
|
|
149
|
+
textChunkLimit: 4e3,
|
|
150
|
+
resolveTarget(params) {
|
|
151
|
+
const to = params.to;
|
|
152
|
+
if (!to) return {
|
|
153
|
+
ok: false,
|
|
154
|
+
error: /* @__PURE__ */ new Error("Missing target — use user:{userId} or conv:{conversationId}")
|
|
155
|
+
};
|
|
156
|
+
if (to.startsWith("conv:")) {
|
|
157
|
+
if (!to.slice(5)) return {
|
|
158
|
+
ok: false,
|
|
159
|
+
error: /* @__PURE__ */ new Error("Empty conversation ID")
|
|
160
|
+
};
|
|
161
|
+
return {
|
|
162
|
+
ok: true,
|
|
163
|
+
to
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const userId = to.startsWith("user:") ? to.slice(5) : to;
|
|
167
|
+
if (!userId || userId === "anon") return {
|
|
168
|
+
ok: false,
|
|
169
|
+
error: /* @__PURE__ */ new Error("Invalid target: userId is required")
|
|
170
|
+
};
|
|
171
|
+
return {
|
|
172
|
+
ok: true,
|
|
173
|
+
to: `user:${userId}`
|
|
174
|
+
};
|
|
175
|
+
},
|
|
176
|
+
async sendText(ctx) {
|
|
177
|
+
if (!deps) throw new Error("Alfe channel deps not configured — outbound disabled");
|
|
178
|
+
return await sendViaChat(deps, ctx, void 0);
|
|
179
|
+
},
|
|
180
|
+
async sendMedia(ctx) {
|
|
181
|
+
if (!deps) throw new Error("Alfe channel deps not configured — outbound disabled");
|
|
182
|
+
return await sendViaChat(deps, ctx, ctx.mediaUrl);
|
|
183
|
+
}
|
|
117
184
|
},
|
|
185
|
+
directory: { async listPeers() {
|
|
186
|
+
if (!deps) return [];
|
|
187
|
+
const sessions = await deps.listSessions();
|
|
188
|
+
const seen = /* @__PURE__ */ new Set();
|
|
189
|
+
const peers = [];
|
|
190
|
+
for (const s of sessions) {
|
|
191
|
+
if (!s.userId || seen.has(s.userId)) continue;
|
|
192
|
+
seen.add(s.userId);
|
|
193
|
+
peers.push({
|
|
194
|
+
kind: "user",
|
|
195
|
+
id: s.userId
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return peers;
|
|
199
|
+
} },
|
|
118
200
|
setup: {
|
|
119
201
|
resolveAccountId(params) {
|
|
120
202
|
return params.accountId ?? DEFAULT_ACCOUNT_ID;
|
|
@@ -283,6 +365,8 @@ async function listSessions(filters, limit = 50) {
|
|
|
283
365
|
sessionId: session.sessionId,
|
|
284
366
|
agentId: session.agentId,
|
|
285
367
|
channel: session.channel,
|
|
368
|
+
...session.tenantId ? { tenantId: session.tenantId } : {},
|
|
369
|
+
...session.userId ? { userId: session.userId } : {},
|
|
286
370
|
createdAt: session.createdAt,
|
|
287
371
|
lastMessageAt: lastMsg ? new Date(lastMsg.timestamp).toISOString() : void 0,
|
|
288
372
|
preview: lastMsg?.content.slice(0, 100),
|
|
@@ -552,7 +636,6 @@ function resolveOpenClawSdk(log) {
|
|
|
552
636
|
let pluginRuntime = null;
|
|
553
637
|
let chatClient = null;
|
|
554
638
|
let connectingPromise = null;
|
|
555
|
-
let metricsClient = null;
|
|
556
639
|
const MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
557
640
|
const DOWNLOAD_TIMEOUT_MS = 3e4;
|
|
558
641
|
const MAX_REDIRECTS = 5;
|
|
@@ -644,13 +727,6 @@ async function handleAgentRequest(request, log) {
|
|
|
644
727
|
const sessionId = conversationId ?? legacySessionKey;
|
|
645
728
|
if (!await getSession(sessionId)) await createSession(sessionId, "", "alfe", tenantId, userId);
|
|
646
729
|
await addMessage(sessionId, "user", message, userId ?? senderId, displayName ?? senderId);
|
|
647
|
-
if (metricsClient && userId) metricsClient.recordActivity({
|
|
648
|
-
userId,
|
|
649
|
-
channel: "alfe",
|
|
650
|
-
role: "user"
|
|
651
|
-
}).catch((err) => {
|
|
652
|
-
log.warn(`Metrics report failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
653
|
-
});
|
|
654
730
|
let resolvedOpenClawKey = null;
|
|
655
731
|
const unsubscribe = runtime.events.onAgentEvent((evt) => {
|
|
656
732
|
if (!evt.sessionKey) return;
|
|
@@ -732,13 +808,6 @@ async function handleAgentRequest(request, log) {
|
|
|
732
808
|
sessionKey: resolvedOpenClawKey ?? legacySessionKey,
|
|
733
809
|
...mediaUrls.length ? { mediaUrls } : {}
|
|
734
810
|
});
|
|
735
|
-
if (metricsClient && userId) metricsClient.recordActivity({
|
|
736
|
-
userId,
|
|
737
|
-
channel: "alfe",
|
|
738
|
-
role: "assistant"
|
|
739
|
-
}).catch((err) => {
|
|
740
|
-
log.warn(`Metrics report failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
741
|
-
});
|
|
742
811
|
},
|
|
743
812
|
onRecordError: (err) => {
|
|
744
813
|
log.error(`Session record error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -822,7 +891,13 @@ const plugin = {
|
|
|
822
891
|
activate(api) {
|
|
823
892
|
const log = api.logger;
|
|
824
893
|
const alreadyActivated = globalThis.__alfeChatPluginActivated === true;
|
|
825
|
-
const alfeChannel = createAlfeChannelPlugin(
|
|
894
|
+
const alfeChannel = createAlfeChannelPlugin({
|
|
895
|
+
getChatClient: () => chatClient,
|
|
896
|
+
listSessions,
|
|
897
|
+
getSession,
|
|
898
|
+
createSession,
|
|
899
|
+
addMessage
|
|
900
|
+
});
|
|
826
901
|
api.registerChannel(alfeChannel);
|
|
827
902
|
log.info(`Registered channel: ${alfeChannel.id}`);
|
|
828
903
|
const pluginConfig = (((api.config ?? {}).plugins?.entries)?.["@alfe.ai/openclaw-chat"] ?? {}).config ?? {};
|
|
@@ -835,15 +910,6 @@ const plugin = {
|
|
|
835
910
|
log.info("Chat plugin registering...");
|
|
836
911
|
resolveOpenClawSdk(log);
|
|
837
912
|
pluginRuntime = api.runtime ?? null;
|
|
838
|
-
try {
|
|
839
|
-
const cfg = (0, _alfe_ai_config.resolveConfig)();
|
|
840
|
-
metricsClient = new _alfe_ai_agent_api_client.AgentApiClient({
|
|
841
|
-
apiKey: cfg.apiKey,
|
|
842
|
-
apiUrl: cfg.apiUrl
|
|
843
|
-
});
|
|
844
|
-
} catch {
|
|
845
|
-
log.debug("Metrics client not initialized — activity tracking disabled");
|
|
846
|
-
}
|
|
847
913
|
connectingPromise = Promise.resolve().then(() => {
|
|
848
914
|
try {
|
|
849
915
|
const { apiKey, chatWsUrl } = (0, _alfe_ai_chat.resolveAlfeChat)({
|
|
@@ -923,7 +989,6 @@ const plugin = {
|
|
|
923
989
|
}
|
|
924
990
|
pluginRuntime = null;
|
|
925
991
|
dispatchInbound = null;
|
|
926
|
-
metricsClient = null;
|
|
927
992
|
log.info("Chat plugin deactivated");
|
|
928
993
|
};
|
|
929
994
|
if (typeof api.registerGatewayMethod === "function") {
|
|
@@ -990,7 +1055,6 @@ const plugin = {
|
|
|
990
1055
|
}
|
|
991
1056
|
pluginRuntime = null;
|
|
992
1057
|
dispatchInbound = null;
|
|
993
|
-
metricsClient = null;
|
|
994
1058
|
log.info("Chat plugin deactivated");
|
|
995
1059
|
}
|
|
996
1060
|
};
|
package/dist/plugin2.js
CHANGED
|
@@ -3,27 +3,70 @@ import { mkdir, readFile, readdir, stat, unlink, writeFile } from "node:fs/promi
|
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { ChatServiceClient, resolveAlfeChat } from "@alfe.ai/chat";
|
|
6
|
-
import {
|
|
7
|
-
import { AgentApiClient } from "@alfe.ai/agent-api-client";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
8
7
|
import { existsSync } from "node:fs";
|
|
9
8
|
//#region src/alfe-channel.ts
|
|
9
|
+
/**
|
|
10
|
+
* Alfe channel plugin definition — registers 'alfe' as an OpenClaw channel.
|
|
11
|
+
*
|
|
12
|
+
* Web and mobile clients share the same channel and conversation sessions.
|
|
13
|
+
* Outbound delivery uses `deliveryMode: 'direct'` — the plugin's sendText /
|
|
14
|
+
* sendMedia handlers push messages through the chat relay service.
|
|
15
|
+
*
|
|
16
|
+
* Target formats accepted by `resolveTarget`:
|
|
17
|
+
* user:{clerkUserId} — most recent conversation for that user (created on demand)
|
|
18
|
+
* conv:{conversationId} — a specific existing conversation
|
|
19
|
+
*
|
|
20
|
+
* Config section: channels.alfe in openclaw.yaml
|
|
21
|
+
*/
|
|
10
22
|
const CHANNEL_ID = "alfe";
|
|
11
23
|
const DEFAULT_ACCOUNT_ID = "default";
|
|
24
|
+
async function sendViaChat(deps, ctx, mediaUrl) {
|
|
25
|
+
const client = deps.getChatClient();
|
|
26
|
+
if (!client) throw new Error("Chat service not connected — cannot deliver");
|
|
27
|
+
let conversationId;
|
|
28
|
+
if (ctx.to.startsWith("conv:")) {
|
|
29
|
+
conversationId = ctx.to.slice(5);
|
|
30
|
+
if (!await deps.getSession(conversationId)) throw new Error(`Conversation not found: ${conversationId}`);
|
|
31
|
+
} else {
|
|
32
|
+
const userId = ctx.to.startsWith("user:") ? ctx.to.slice(5) : ctx.to;
|
|
33
|
+
if (!userId) throw new Error("Empty userId in target");
|
|
34
|
+
const sessions = await deps.listSessions({ userId });
|
|
35
|
+
if (sessions.length > 0) conversationId = sessions[0].sessionId;
|
|
36
|
+
else {
|
|
37
|
+
conversationId = `alfe:chat:${userId}:${randomUUID()}`;
|
|
38
|
+
await deps.createSession(conversationId, "", "alfe", void 0, userId);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
await deps.addMessage(conversationId, "assistant", ctx.text);
|
|
42
|
+
const messageId = randomUUID();
|
|
43
|
+
client.notify("agent-message", {
|
|
44
|
+
conversationId,
|
|
45
|
+
text: ctx.text,
|
|
46
|
+
sessionKey: conversationId,
|
|
47
|
+
...mediaUrl ? { mediaUrls: [mediaUrl] } : {}
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
channel: "alfe",
|
|
51
|
+
messageId,
|
|
52
|
+
conversationId,
|
|
53
|
+
timestamp: Date.now()
|
|
54
|
+
};
|
|
55
|
+
}
|
|
12
56
|
function getChannelSection(cfg) {
|
|
13
57
|
return cfg.channels?.alfe ?? {};
|
|
14
58
|
}
|
|
15
|
-
function normalizeAllowFrom(raw) {
|
|
16
|
-
if (!raw) return [];
|
|
17
|
-
if (typeof raw === "string") return [raw];
|
|
18
|
-
return raw;
|
|
19
|
-
}
|
|
20
59
|
/**
|
|
21
60
|
* Creates the Alfe ChannelPlugin object for registration with OpenClaw.
|
|
22
61
|
*
|
|
23
62
|
* This follows the same pattern as built-in channels (Telegram, Discord, etc.)
|
|
24
63
|
* but is registered dynamically via api.registerChannel().
|
|
64
|
+
*
|
|
65
|
+
* `deps` enables outbound delivery and peer discovery. When omitted (e.g.
|
|
66
|
+
* during CLI metadata registration), outbound calls throw and the directory
|
|
67
|
+
* is empty — but the channel is still registered for inbound use.
|
|
25
68
|
*/
|
|
26
|
-
function createAlfeChannelPlugin() {
|
|
69
|
+
function createAlfeChannelPlugin(deps) {
|
|
27
70
|
return {
|
|
28
71
|
id: CHANNEL_ID,
|
|
29
72
|
meta: {
|
|
@@ -57,7 +100,7 @@ function createAlfeChannelPlugin() {
|
|
|
57
100
|
listAccountIds(cfg) {
|
|
58
101
|
const section = getChannelSection(cfg);
|
|
59
102
|
const ids = [];
|
|
60
|
-
if (section.enabled !== false &&
|
|
103
|
+
if (section.enabled !== false && section.defaultTo) ids.push(DEFAULT_ACCOUNT_ID);
|
|
61
104
|
if (section.accounts) {
|
|
62
105
|
for (const id of Object.keys(section.accounts)) if (!ids.includes(id)) ids.push(id);
|
|
63
106
|
}
|
|
@@ -71,16 +114,12 @@ function createAlfeChannelPlugin() {
|
|
|
71
114
|
if (accountSection) return {
|
|
72
115
|
accountId: id,
|
|
73
116
|
enabled: accountSection.enabled !== false,
|
|
74
|
-
|
|
75
|
-
defaultTo: accountSection.defaultTo,
|
|
76
|
-
dmPolicy: accountSection.dmPolicy
|
|
117
|
+
defaultTo: accountSection.defaultTo
|
|
77
118
|
};
|
|
78
119
|
return {
|
|
79
120
|
accountId: id,
|
|
80
121
|
enabled: section.enabled !== false,
|
|
81
|
-
|
|
82
|
-
defaultTo: section.defaultTo,
|
|
83
|
-
dmPolicy: section.dmPolicy
|
|
122
|
+
defaultTo: section.defaultTo
|
|
84
123
|
};
|
|
85
124
|
},
|
|
86
125
|
defaultAccountId() {
|
|
@@ -96,15 +135,9 @@ function createAlfeChannelPlugin() {
|
|
|
96
135
|
return {
|
|
97
136
|
accountId: account.accountId,
|
|
98
137
|
enabled: account.enabled,
|
|
99
|
-
configured: true
|
|
100
|
-
dmPolicy: account.dmPolicy
|
|
138
|
+
configured: true
|
|
101
139
|
};
|
|
102
140
|
},
|
|
103
|
-
resolveAllowFrom(params) {
|
|
104
|
-
const section = getChannelSection(params.cfg);
|
|
105
|
-
const id = params.accountId ?? DEFAULT_ACCOUNT_ID;
|
|
106
|
-
return normalizeAllowFrom((section.accounts?.[id])?.allowFrom ?? section.allowFrom);
|
|
107
|
-
},
|
|
108
141
|
resolveDefaultTo(params) {
|
|
109
142
|
const section = getChannelSection(params.cfg);
|
|
110
143
|
const id = params.accountId ?? DEFAULT_ACCOUNT_ID;
|
|
@@ -112,9 +145,58 @@ function createAlfeChannelPlugin() {
|
|
|
112
145
|
}
|
|
113
146
|
},
|
|
114
147
|
outbound: {
|
|
115
|
-
deliveryMode: "
|
|
116
|
-
textChunkLimit: 4e3
|
|
148
|
+
deliveryMode: "direct",
|
|
149
|
+
textChunkLimit: 4e3,
|
|
150
|
+
resolveTarget(params) {
|
|
151
|
+
const to = params.to;
|
|
152
|
+
if (!to) return {
|
|
153
|
+
ok: false,
|
|
154
|
+
error: /* @__PURE__ */ new Error("Missing target — use user:{userId} or conv:{conversationId}")
|
|
155
|
+
};
|
|
156
|
+
if (to.startsWith("conv:")) {
|
|
157
|
+
if (!to.slice(5)) return {
|
|
158
|
+
ok: false,
|
|
159
|
+
error: /* @__PURE__ */ new Error("Empty conversation ID")
|
|
160
|
+
};
|
|
161
|
+
return {
|
|
162
|
+
ok: true,
|
|
163
|
+
to
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const userId = to.startsWith("user:") ? to.slice(5) : to;
|
|
167
|
+
if (!userId || userId === "anon") return {
|
|
168
|
+
ok: false,
|
|
169
|
+
error: /* @__PURE__ */ new Error("Invalid target: userId is required")
|
|
170
|
+
};
|
|
171
|
+
return {
|
|
172
|
+
ok: true,
|
|
173
|
+
to: `user:${userId}`
|
|
174
|
+
};
|
|
175
|
+
},
|
|
176
|
+
async sendText(ctx) {
|
|
177
|
+
if (!deps) throw new Error("Alfe channel deps not configured — outbound disabled");
|
|
178
|
+
return await sendViaChat(deps, ctx, void 0);
|
|
179
|
+
},
|
|
180
|
+
async sendMedia(ctx) {
|
|
181
|
+
if (!deps) throw new Error("Alfe channel deps not configured — outbound disabled");
|
|
182
|
+
return await sendViaChat(deps, ctx, ctx.mediaUrl);
|
|
183
|
+
}
|
|
117
184
|
},
|
|
185
|
+
directory: { async listPeers() {
|
|
186
|
+
if (!deps) return [];
|
|
187
|
+
const sessions = await deps.listSessions();
|
|
188
|
+
const seen = /* @__PURE__ */ new Set();
|
|
189
|
+
const peers = [];
|
|
190
|
+
for (const s of sessions) {
|
|
191
|
+
if (!s.userId || seen.has(s.userId)) continue;
|
|
192
|
+
seen.add(s.userId);
|
|
193
|
+
peers.push({
|
|
194
|
+
kind: "user",
|
|
195
|
+
id: s.userId
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return peers;
|
|
199
|
+
} },
|
|
118
200
|
setup: {
|
|
119
201
|
resolveAccountId(params) {
|
|
120
202
|
return params.accountId ?? DEFAULT_ACCOUNT_ID;
|
|
@@ -283,6 +365,8 @@ async function listSessions(filters, limit = 50) {
|
|
|
283
365
|
sessionId: session.sessionId,
|
|
284
366
|
agentId: session.agentId,
|
|
285
367
|
channel: session.channel,
|
|
368
|
+
...session.tenantId ? { tenantId: session.tenantId } : {},
|
|
369
|
+
...session.userId ? { userId: session.userId } : {},
|
|
286
370
|
createdAt: session.createdAt,
|
|
287
371
|
lastMessageAt: lastMsg ? new Date(lastMsg.timestamp).toISOString() : void 0,
|
|
288
372
|
preview: lastMsg?.content.slice(0, 100),
|
|
@@ -552,7 +636,6 @@ function resolveOpenClawSdk(log) {
|
|
|
552
636
|
let pluginRuntime = null;
|
|
553
637
|
let chatClient = null;
|
|
554
638
|
let connectingPromise = null;
|
|
555
|
-
let metricsClient = null;
|
|
556
639
|
const MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
557
640
|
const DOWNLOAD_TIMEOUT_MS = 3e4;
|
|
558
641
|
const MAX_REDIRECTS = 5;
|
|
@@ -644,13 +727,6 @@ async function handleAgentRequest(request, log) {
|
|
|
644
727
|
const sessionId = conversationId ?? legacySessionKey;
|
|
645
728
|
if (!await getSession(sessionId)) await createSession(sessionId, "", "alfe", tenantId, userId);
|
|
646
729
|
await addMessage(sessionId, "user", message, userId ?? senderId, displayName ?? senderId);
|
|
647
|
-
if (metricsClient && userId) metricsClient.recordActivity({
|
|
648
|
-
userId,
|
|
649
|
-
channel: "alfe",
|
|
650
|
-
role: "user"
|
|
651
|
-
}).catch((err) => {
|
|
652
|
-
log.warn(`Metrics report failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
653
|
-
});
|
|
654
730
|
let resolvedOpenClawKey = null;
|
|
655
731
|
const unsubscribe = runtime.events.onAgentEvent((evt) => {
|
|
656
732
|
if (!evt.sessionKey) return;
|
|
@@ -732,13 +808,6 @@ async function handleAgentRequest(request, log) {
|
|
|
732
808
|
sessionKey: resolvedOpenClawKey ?? legacySessionKey,
|
|
733
809
|
...mediaUrls.length ? { mediaUrls } : {}
|
|
734
810
|
});
|
|
735
|
-
if (metricsClient && userId) metricsClient.recordActivity({
|
|
736
|
-
userId,
|
|
737
|
-
channel: "alfe",
|
|
738
|
-
role: "assistant"
|
|
739
|
-
}).catch((err) => {
|
|
740
|
-
log.warn(`Metrics report failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
741
|
-
});
|
|
742
811
|
},
|
|
743
812
|
onRecordError: (err) => {
|
|
744
813
|
log.error(`Session record error: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -822,7 +891,13 @@ const plugin = {
|
|
|
822
891
|
activate(api) {
|
|
823
892
|
const log = api.logger;
|
|
824
893
|
const alreadyActivated = globalThis.__alfeChatPluginActivated === true;
|
|
825
|
-
const alfeChannel = createAlfeChannelPlugin(
|
|
894
|
+
const alfeChannel = createAlfeChannelPlugin({
|
|
895
|
+
getChatClient: () => chatClient,
|
|
896
|
+
listSessions,
|
|
897
|
+
getSession,
|
|
898
|
+
createSession,
|
|
899
|
+
addMessage
|
|
900
|
+
});
|
|
826
901
|
api.registerChannel(alfeChannel);
|
|
827
902
|
log.info(`Registered channel: ${alfeChannel.id}`);
|
|
828
903
|
const pluginConfig = (((api.config ?? {}).plugins?.entries)?.["@alfe.ai/openclaw-chat"] ?? {}).config ?? {};
|
|
@@ -835,15 +910,6 @@ const plugin = {
|
|
|
835
910
|
log.info("Chat plugin registering...");
|
|
836
911
|
resolveOpenClawSdk(log);
|
|
837
912
|
pluginRuntime = api.runtime ?? null;
|
|
838
|
-
try {
|
|
839
|
-
const cfg = resolveConfig();
|
|
840
|
-
metricsClient = new AgentApiClient({
|
|
841
|
-
apiKey: cfg.apiKey,
|
|
842
|
-
apiUrl: cfg.apiUrl
|
|
843
|
-
});
|
|
844
|
-
} catch {
|
|
845
|
-
log.debug("Metrics client not initialized — activity tracking disabled");
|
|
846
|
-
}
|
|
847
913
|
connectingPromise = Promise.resolve().then(() => {
|
|
848
914
|
try {
|
|
849
915
|
const { apiKey, chatWsUrl } = resolveAlfeChat({
|
|
@@ -923,7 +989,6 @@ const plugin = {
|
|
|
923
989
|
}
|
|
924
990
|
pluginRuntime = null;
|
|
925
991
|
dispatchInbound = null;
|
|
926
|
-
metricsClient = null;
|
|
927
992
|
log.info("Chat plugin deactivated");
|
|
928
993
|
};
|
|
929
994
|
if (typeof api.registerGatewayMethod === "function") {
|
|
@@ -990,7 +1055,6 @@ const plugin = {
|
|
|
990
1055
|
}
|
|
991
1056
|
pluginRuntime = null;
|
|
992
1057
|
dispatchInbound = null;
|
|
993
|
-
metricsClient = null;
|
|
994
1058
|
log.info("Chat plugin deactivated");
|
|
995
1059
|
}
|
|
996
1060
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/openclaw-chat",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
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,7 @@
|
|
|
27
27
|
"openclaw.plugin.json"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@alfe.ai/agent-api-client": "^0.
|
|
30
|
+
"@alfe.ai/agent-api-client": "^0.1.1",
|
|
31
31
|
"@alfe.ai/chat": "^0.0.8",
|
|
32
32
|
"@alfe.ai/config": "^0.0.8"
|
|
33
33
|
},
|