@eclaw/openclaw-channel 1.0.10 → 1.0.11
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/gateway.js +2 -1
- package/dist/webhook-handler.d.ts +5 -2
- package/dist/webhook-handler.js +62 -29
- package/package.json +1 -1
package/dist/gateway.js
CHANGED
|
@@ -72,7 +72,8 @@ export async function startAccount(ctx) {
|
|
|
72
72
|
// The callback URL points to /eclaw-webhook on the main gateway HTTP server
|
|
73
73
|
const callbackUrl = `${publicUrl || 'http://localhost'}/eclaw-webhook`;
|
|
74
74
|
// Register handler in the per-token registry
|
|
75
|
-
|
|
75
|
+
// Pass ctx.cfg so the handler can dispatch to the correct OpenClaw agent
|
|
76
|
+
const handler = createWebhookHandler(callbackToken, accountId, ctx.cfg);
|
|
76
77
|
registerWebhookToken(callbackToken, accountId, handler);
|
|
77
78
|
console.log(`[E-Claw] Webhook registered at: ${callbackUrl}`);
|
|
78
79
|
try {
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* Create an HTTP request handler for inbound messages from E-Claw.
|
|
3
3
|
*
|
|
4
4
|
* When a user sends a message on E-Claw, the backend POSTs structured JSON
|
|
5
|
-
* to this webhook. We normalize it
|
|
5
|
+
* to this webhook. We normalize it into OpenClaw's native PascalCase context
|
|
6
|
+
* format and dispatch to the agent via dispatchReplyWithBufferedBlockDispatcher.
|
|
7
|
+
*
|
|
8
|
+
* The `deliver` callback sends the AI reply back to E-Claw via the API client.
|
|
6
9
|
*/
|
|
7
|
-
export declare function createWebhookHandler(expectedToken: string, accountId: string): (req: any, res: any) => Promise<void>;
|
|
10
|
+
export declare function createWebhookHandler(expectedToken: string, accountId: string, cfg: any): (req: any, res: any) => Promise<void>;
|
package/dist/webhook-handler.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { getPluginRuntime } from './runtime.js';
|
|
2
|
+
import { getClient } from './outbound.js';
|
|
2
3
|
/**
|
|
3
4
|
* Create an HTTP request handler for inbound messages from E-Claw.
|
|
4
5
|
*
|
|
5
6
|
* When a user sends a message on E-Claw, the backend POSTs structured JSON
|
|
6
|
-
* to this webhook. We normalize it
|
|
7
|
+
* to this webhook. We normalize it into OpenClaw's native PascalCase context
|
|
8
|
+
* format and dispatch to the agent via dispatchReplyWithBufferedBlockDispatcher.
|
|
9
|
+
*
|
|
10
|
+
* The `deliver` callback sends the AI reply back to E-Claw via the API client.
|
|
7
11
|
*/
|
|
8
|
-
export function createWebhookHandler(expectedToken, accountId
|
|
12
|
+
export function createWebhookHandler(expectedToken, accountId,
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
cfg // full openclaw config (ctx.cfg from startAccount)
|
|
15
|
+
) {
|
|
9
16
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
17
|
return async (req, res) => {
|
|
11
18
|
// Verify callback token
|
|
@@ -22,36 +29,62 @@ export function createWebhookHandler(expectedToken, accountId) {
|
|
|
22
29
|
// Dispatch to OpenClaw agent
|
|
23
30
|
try {
|
|
24
31
|
const rt = getPluginRuntime();
|
|
32
|
+
const client = getClient(accountId);
|
|
25
33
|
const conversationId = msg.conversationId || `${msg.deviceId}:${msg.entityId}`;
|
|
26
|
-
// Map E-Claw media
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
// Map E-Claw media type to OpenClaw media type
|
|
35
|
+
const ocMediaType = msg.mediaType === 'photo' ? 'image'
|
|
36
|
+
: msg.mediaType === 'voice' ? 'audio'
|
|
37
|
+
: msg.mediaType === 'video' ? 'video'
|
|
38
|
+
: msg.mediaType ? 'file'
|
|
39
|
+
: undefined;
|
|
40
|
+
// Build context in OpenClaw's native PascalCase format
|
|
41
|
+
// (same convention as Telegram/LINE/WhatsApp channels)
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
43
|
const inboundCtx = {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
Surface: 'eclaw',
|
|
45
|
+
Provider: 'eclaw',
|
|
46
|
+
OriginatingChannel: 'eclaw',
|
|
47
|
+
AccountId: accountId,
|
|
48
|
+
From: msg.from,
|
|
49
|
+
To: conversationId,
|
|
50
|
+
OriginatingTo: msg.from,
|
|
51
|
+
SessionKey: conversationId,
|
|
52
|
+
Body: msg.text || '',
|
|
53
|
+
RawBody: msg.text || '',
|
|
54
|
+
CommandBody: msg.text || '',
|
|
55
|
+
ChatType: 'direct',
|
|
56
|
+
...(ocMediaType && msg.mediaUrl ? {
|
|
57
|
+
MediaType: ocMediaType,
|
|
58
|
+
MediaUrl: msg.mediaUrl,
|
|
59
|
+
} : {}),
|
|
51
60
|
};
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
const ctxPayload = rt.channel.reply.finalizeInboundContext(inboundCtx);
|
|
62
|
+
await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
63
|
+
ctx: ctxPayload,
|
|
64
|
+
cfg,
|
|
65
|
+
dispatcherOptions: {
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
67
|
+
deliver: async (payload) => {
|
|
68
|
+
if (!client)
|
|
69
|
+
return;
|
|
70
|
+
const text = typeof payload.text === 'string' ? payload.text.trim() : '';
|
|
71
|
+
if (text) {
|
|
72
|
+
await client.sendMessage(text, 'IDLE');
|
|
73
|
+
}
|
|
74
|
+
else if (payload.mediaUrl) {
|
|
75
|
+
const rawType = typeof payload.mediaType === 'string' ? payload.mediaType : '';
|
|
76
|
+
const mediaType = rawType === 'image' ? 'photo'
|
|
77
|
+
: rawType === 'audio' ? 'voice'
|
|
78
|
+
: rawType === 'video' ? 'video'
|
|
79
|
+
: 'file';
|
|
80
|
+
await client.sendMessage('', 'IDLE', mediaType, payload.mediaUrl);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
onError: (err) => {
|
|
84
|
+
console.error('[E-Claw] Reply delivery error:', err);
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
});
|
|
55
88
|
}
|
|
56
89
|
catch (err) {
|
|
57
90
|
console.error('[E-Claw] Webhook dispatch error:', err);
|