visionclaw 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/README.md +116 -0
- package/dist/agent/context.d.ts +56 -0
- package/dist/agent/context.d.ts.map +1 -0
- package/dist/agent/context.js +142 -0
- package/dist/agent/context.js.map +1 -0
- package/dist/agent/loop.d.ts +18 -0
- package/dist/agent/loop.d.ts.map +1 -0
- package/dist/agent/loop.js +323 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/session.d.ts +49 -0
- package/dist/agent/session.d.ts.map +1 -0
- package/dist/agent/session.js +200 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/agent/system-prompt.d.ts +10 -0
- package/dist/agent/system-prompt.d.ts.map +1 -0
- package/dist/agent/system-prompt.js +167 -0
- package/dist/agent/system-prompt.js.map +1 -0
- package/dist/calendar/google-calendar.d.ts +46 -0
- package/dist/calendar/google-calendar.d.ts.map +1 -0
- package/dist/calendar/google-calendar.js +132 -0
- package/dist/calendar/google-calendar.js.map +1 -0
- package/dist/calendar/scheduler.d.ts +7 -0
- package/dist/calendar/scheduler.d.ts.map +1 -0
- package/dist/calendar/scheduler.js +33 -0
- package/dist/calendar/scheduler.js.map +1 -0
- package/dist/channels/discord.d.ts +19 -0
- package/dist/channels/discord.d.ts.map +1 -0
- package/dist/channels/discord.js +169 -0
- package/dist/channels/discord.js.map +1 -0
- package/dist/channels/gmail.d.ts +31 -0
- package/dist/channels/gmail.d.ts.map +1 -0
- package/dist/channels/gmail.js +300 -0
- package/dist/channels/gmail.js.map +1 -0
- package/dist/channels/interface.d.ts +45 -0
- package/dist/channels/interface.d.ts.map +1 -0
- package/dist/channels/interface.js +2 -0
- package/dist/channels/interface.js.map +1 -0
- package/dist/channels/manager.d.ts +36 -0
- package/dist/channels/manager.d.ts.map +1 -0
- package/dist/channels/manager.js +108 -0
- package/dist/channels/manager.js.map +1 -0
- package/dist/channels/queue.d.ts +17 -0
- package/dist/channels/queue.d.ts.map +1 -0
- package/dist/channels/queue.js +85 -0
- package/dist/channels/queue.js.map +1 -0
- package/dist/channels/slack.d.ts +17 -0
- package/dist/channels/slack.d.ts.map +1 -0
- package/dist/channels/slack.js +142 -0
- package/dist/channels/slack.js.map +1 -0
- package/dist/channels/sms.d.ts +19 -0
- package/dist/channels/sms.d.ts.map +1 -0
- package/dist/channels/sms.js +111 -0
- package/dist/channels/sms.js.map +1 -0
- package/dist/channels/telegram.d.ts +28 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +246 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/whatsapp.d.ts +28 -0
- package/dist/channels/whatsapp.d.ts.map +1 -0
- package/dist/channels/whatsapp.js +292 -0
- package/dist/channels/whatsapp.js.map +1 -0
- package/dist/config/index.d.ts +24 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +104 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +227 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +45 -0
- package/dist/config/types.js.map +1 -0
- package/dist/files.d.ts +20 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +82 -0
- package/dist/files.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +384 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory/store.d.ts +24 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +71 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/obs/server.d.ts +10 -0
- package/dist/obs/server.d.ts.map +1 -0
- package/dist/obs/server.js +406 -0
- package/dist/obs/server.js.map +1 -0
- package/dist/onboarding/google-auth.d.ts +11 -0
- package/dist/onboarding/google-auth.d.ts.map +1 -0
- package/dist/onboarding/google-auth.js +113 -0
- package/dist/onboarding/google-auth.js.map +1 -0
- package/dist/onboarding/index.d.ts +2 -0
- package/dist/onboarding/index.d.ts.map +1 -0
- package/dist/onboarding/index.js +213 -0
- package/dist/onboarding/index.js.map +1 -0
- package/dist/onboarding/macos-permissions.d.ts +37 -0
- package/dist/onboarding/macos-permissions.d.ts.map +1 -0
- package/dist/onboarding/macos-permissions.js +207 -0
- package/dist/onboarding/macos-permissions.js.map +1 -0
- package/dist/skills/install.d.ts +7 -0
- package/dist/skills/install.d.ts.map +1 -0
- package/dist/skills/install.js +63 -0
- package/dist/skills/install.js.map +1 -0
- package/dist/tools/browser.d.ts +7 -0
- package/dist/tools/browser.d.ts.map +1 -0
- package/dist/tools/browser.js +202 -0
- package/dist/tools/browser.js.map +1 -0
- package/dist/tools/calendar.d.ts +12 -0
- package/dist/tools/calendar.d.ts.map +1 -0
- package/dist/tools/calendar.js +210 -0
- package/dist/tools/calendar.js.map +1 -0
- package/dist/tools/computer-use.d.ts +28 -0
- package/dist/tools/computer-use.d.ts.map +1 -0
- package/dist/tools/computer-use.js +311 -0
- package/dist/tools/computer-use.js.map +1 -0
- package/dist/tools/coordinate-resolver.d.ts +26 -0
- package/dist/tools/coordinate-resolver.d.ts.map +1 -0
- package/dist/tools/coordinate-resolver.js +157 -0
- package/dist/tools/coordinate-resolver.js.map +1 -0
- package/dist/tools/desktop-executor.d.ts +52 -0
- package/dist/tools/desktop-executor.d.ts.map +1 -0
- package/dist/tools/desktop-executor.js +202 -0
- package/dist/tools/desktop-executor.js.map +1 -0
- package/dist/tools/finish.d.ts +5 -0
- package/dist/tools/finish.d.ts.map +1 -0
- package/dist/tools/finish.js +18 -0
- package/dist/tools/finish.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +37 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/memory.d.ts +14 -0
- package/dist/tools/memory.d.ts.map +1 -0
- package/dist/tools/memory.js +269 -0
- package/dist/tools/memory.js.map +1 -0
- package/dist/tools/notify.d.ts +12 -0
- package/dist/tools/notify.d.ts.map +1 -0
- package/dist/tools/notify.js +108 -0
- package/dist/tools/notify.js.map +1 -0
- package/dist/tools/screenshot.d.ts +7 -0
- package/dist/tools/screenshot.d.ts.map +1 -0
- package/dist/tools/screenshot.js +189 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/skill.d.ts +8 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +133 -0
- package/dist/tools/skill.js.map +1 -0
- package/dist/tools/upgrade.d.ts +5 -0
- package/dist/tools/upgrade.d.ts.map +1 -0
- package/dist/tools/upgrade.js +89 -0
- package/dist/tools/upgrade.js.map +1 -0
- package/dist/tools/wait.d.ts +5 -0
- package/dist/tools/wait.d.ts.map +1 -0
- package/dist/tools/wait.js +21 -0
- package/dist/tools/wait.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import type { VisionClawConfig } from "../config/types.js";
|
|
3
|
+
import type { ChannelAdapter, MessageAttachment } from "./interface.js";
|
|
4
|
+
/**
|
|
5
|
+
* Telegram channel adapter.
|
|
6
|
+
* Supports multimodal inbound (photos, documents, voice) and
|
|
7
|
+
* outbound (photos, documents) messages.
|
|
8
|
+
*/
|
|
9
|
+
export declare class TelegramAdapter extends EventEmitter implements ChannelAdapter {
|
|
10
|
+
readonly name = "telegram";
|
|
11
|
+
private config;
|
|
12
|
+
private bot;
|
|
13
|
+
constructor(config: VisionClawConfig);
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
stop(): Promise<void>;
|
|
16
|
+
sendMessage(to: string, message: string, attachments?: MessageAttachment[]): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Process an inbound Telegram message, downloading any media
|
|
19
|
+
* and uploading to S3 before emitting the CommandMessage.
|
|
20
|
+
*/
|
|
21
|
+
private processInboundMessage;
|
|
22
|
+
/**
|
|
23
|
+
* Download a file from Telegram and upload to S3.
|
|
24
|
+
* Returns the S3 public URL, or null on failure.
|
|
25
|
+
*/
|
|
26
|
+
private downloadAndUpload;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=telegram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/channels/telegram.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAkB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAOxF;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,YAAa,YAAW,cAAc;IACzE,QAAQ,CAAC,IAAI,cAAc;IAC3B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,GAAG,CAA4B;gBAE3B,MAAM,EAAE,gBAAgB;IAKpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2BhB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAOrB,WAAW,CACf,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,iBAAiB,EAAE,GAChC,OAAO,CAAC,IAAI,CAAC;IAuFhB;;;OAGG;YACW,qBAAqB;IAiHnC;;;OAGG;YACW,iBAAiB;CA8BhC"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import TelegramBot from "node-telegram-bot-api";
|
|
4
|
+
import { logger } from "../logger.js";
|
|
5
|
+
import { uploadMedia } from "../files.js";
|
|
6
|
+
// Enable proper fileOptions (filename, contentType) handling in node-telegram-bot-api.
|
|
7
|
+
// Without this, the library ignores the fileOptions argument and emits a deprecation warning.
|
|
8
|
+
// See: https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#file-options-metadata
|
|
9
|
+
process.env.NTBA_FIX_350 = "1";
|
|
10
|
+
/**
|
|
11
|
+
* Telegram channel adapter.
|
|
12
|
+
* Supports multimodal inbound (photos, documents, voice) and
|
|
13
|
+
* outbound (photos, documents) messages.
|
|
14
|
+
*/
|
|
15
|
+
export class TelegramAdapter extends EventEmitter {
|
|
16
|
+
name = "telegram";
|
|
17
|
+
config;
|
|
18
|
+
bot = null;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
super();
|
|
21
|
+
this.config = config;
|
|
22
|
+
}
|
|
23
|
+
start() {
|
|
24
|
+
const botToken = this.config.channels.telegram?.botToken;
|
|
25
|
+
if (!botToken) {
|
|
26
|
+
throw new Error("Telegram bot token not configured");
|
|
27
|
+
}
|
|
28
|
+
this.bot = new TelegramBot(botToken, { polling: true });
|
|
29
|
+
this.bot.on("message", (msg) => {
|
|
30
|
+
// Optionally filter by allowed chat IDs
|
|
31
|
+
const allowedChats = this.config.channels.telegram?.allowedChatIds ?? [];
|
|
32
|
+
if (allowedChats.length > 0 && !allowedChats.includes(msg.chat.id)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Process message asynchronously (to allow media downloads)
|
|
36
|
+
void this.processInboundMessage(msg);
|
|
37
|
+
});
|
|
38
|
+
this.bot.on("polling_error", (err) => {
|
|
39
|
+
this.emit("error", err);
|
|
40
|
+
});
|
|
41
|
+
return Promise.resolve();
|
|
42
|
+
}
|
|
43
|
+
async stop() {
|
|
44
|
+
if (this.bot) {
|
|
45
|
+
await this.bot.stopPolling();
|
|
46
|
+
this.bot = null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async sendMessage(to, message, attachments) {
|
|
50
|
+
if (!this.bot) {
|
|
51
|
+
throw new Error("Telegram bot not started");
|
|
52
|
+
}
|
|
53
|
+
// Extract numeric chat ID from sender string like "Name (12345)" or plain "12345"
|
|
54
|
+
const match = /\((\d+)\)/.exec(to) ?? /^(\d+)$/.exec(to);
|
|
55
|
+
const chatId = match ? Number(match[1]) : NaN;
|
|
56
|
+
if (isNaN(chatId)) {
|
|
57
|
+
throw new Error(`Invalid Telegram chat ID: ${to}`);
|
|
58
|
+
}
|
|
59
|
+
// Send attachments first
|
|
60
|
+
if (attachments && attachments.length > 0) {
|
|
61
|
+
for (const att of attachments) {
|
|
62
|
+
// Resolve the source: prefer local file path, then URL
|
|
63
|
+
let source;
|
|
64
|
+
if (att.localPath) {
|
|
65
|
+
source = att.localPath;
|
|
66
|
+
}
|
|
67
|
+
else if (att.url) {
|
|
68
|
+
// Validate URL has a proper host before sending to Telegram
|
|
69
|
+
try {
|
|
70
|
+
const parsed = new URL(att.url);
|
|
71
|
+
if (!parsed.host) {
|
|
72
|
+
logger.warn(`Telegram: Skipping attachment with empty URL host: ${att.url}`);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
source = att.url;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Not a valid URL — treat as local file path if it looks like one
|
|
79
|
+
if (att.url.startsWith("/")) {
|
|
80
|
+
source = att.url;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
logger.warn(`Telegram: Skipping attachment with invalid URL: ${att.url}`);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!source)
|
|
89
|
+
continue;
|
|
90
|
+
// For local files, use a read stream so node-telegram-bot-api
|
|
91
|
+
// sends the file content directly with the correct content type
|
|
92
|
+
// (avoids the deprecated auto-detect behaviour).
|
|
93
|
+
const isLocal = source.startsWith("/");
|
|
94
|
+
const fileSource = isLocal ? fs.createReadStream(source) : source;
|
|
95
|
+
const fileOpts = {
|
|
96
|
+
filename: att.filename ?? (isLocal ? source.split("/").pop() : undefined),
|
|
97
|
+
contentType: att.mimeType ?? "application/octet-stream",
|
|
98
|
+
};
|
|
99
|
+
try {
|
|
100
|
+
switch (att.type) {
|
|
101
|
+
case "image":
|
|
102
|
+
await this.bot.sendPhoto(chatId, fileSource, { caption: att.filename }, fileOpts);
|
|
103
|
+
break;
|
|
104
|
+
case "audio":
|
|
105
|
+
await this.bot.sendVoice(chatId, fileSource, {}, fileOpts);
|
|
106
|
+
break;
|
|
107
|
+
case "video":
|
|
108
|
+
await this.bot.sendVideo(chatId, fileSource, { caption: att.filename }, fileOpts);
|
|
109
|
+
break;
|
|
110
|
+
case "file":
|
|
111
|
+
await this.bot.sendDocument(chatId, fileSource, { caption: att.filename }, fileOpts);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
logger.warn(`Telegram: Failed to send ${att.type}: ${err instanceof Error ? err.message : String(err)}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Send text message
|
|
121
|
+
if (message.trim()) {
|
|
122
|
+
const MAX_LENGTH = 4096;
|
|
123
|
+
if (message.length <= MAX_LENGTH) {
|
|
124
|
+
await this.bot.sendMessage(chatId, message);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
for (let i = 0; i < message.length; i += MAX_LENGTH) {
|
|
128
|
+
await this.bot.sendMessage(chatId, message.substring(i, i + MAX_LENGTH));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Process an inbound Telegram message, downloading any media
|
|
135
|
+
* and uploading to S3 before emitting the CommandMessage.
|
|
136
|
+
*/
|
|
137
|
+
async processInboundMessage(msg) {
|
|
138
|
+
try {
|
|
139
|
+
const fromName = [msg.from?.first_name, msg.from?.last_name]
|
|
140
|
+
.filter(Boolean)
|
|
141
|
+
.join(" ");
|
|
142
|
+
const senderDisplay = fromName
|
|
143
|
+
? `${fromName} (${msg.chat.id})`
|
|
144
|
+
: String(msg.chat.id);
|
|
145
|
+
const commandMessage = {
|
|
146
|
+
id: `telegram-${msg.message_id}-${msg.chat.id}`,
|
|
147
|
+
channel: "telegram",
|
|
148
|
+
sender: senderDisplay,
|
|
149
|
+
text: msg.text ?? msg.caption ?? "",
|
|
150
|
+
attachments: [],
|
|
151
|
+
timestamp: new Date(msg.date * 1000).toISOString(),
|
|
152
|
+
meta: {
|
|
153
|
+
chatId: msg.chat.id,
|
|
154
|
+
messageId: msg.message_id,
|
|
155
|
+
from: msg.from,
|
|
156
|
+
chatType: msg.chat.type,
|
|
157
|
+
username: msg.from?.username,
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
// Handle photos -- download and upload to S3
|
|
161
|
+
if (msg.photo && msg.photo.length > 0) {
|
|
162
|
+
const largestPhoto = msg.photo[msg.photo.length - 1];
|
|
163
|
+
const url = await this.downloadAndUpload(largestPhoto.file_id, "photo.jpg", "image/jpeg");
|
|
164
|
+
commandMessage.attachments.push({
|
|
165
|
+
type: "image",
|
|
166
|
+
url: url ?? largestPhoto.file_id,
|
|
167
|
+
mimeType: "image/jpeg",
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// Handle documents
|
|
171
|
+
if (msg.document) {
|
|
172
|
+
const filename = msg.document.file_name ?? "document";
|
|
173
|
+
const mimeType = msg.document.mime_type ?? "application/octet-stream";
|
|
174
|
+
const url = await this.downloadAndUpload(msg.document.file_id, filename, mimeType);
|
|
175
|
+
commandMessage.attachments.push({
|
|
176
|
+
type: mimeType.startsWith("image/") ? "image" : "file",
|
|
177
|
+
url: url ?? msg.document.file_id,
|
|
178
|
+
filename,
|
|
179
|
+
mimeType,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
// Handle voice messages
|
|
183
|
+
if (msg.voice) {
|
|
184
|
+
const mimeType = msg.voice.mime_type ?? "audio/ogg";
|
|
185
|
+
const url = await this.downloadAndUpload(msg.voice.file_id, "voice.ogg", mimeType);
|
|
186
|
+
commandMessage.attachments.push({
|
|
187
|
+
type: "audio",
|
|
188
|
+
url: url ?? msg.voice.file_id,
|
|
189
|
+
mimeType,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
// Handle video
|
|
193
|
+
if (msg.video) {
|
|
194
|
+
const mimeType = msg.video.mime_type ?? "video/mp4";
|
|
195
|
+
const url = await this.downloadAndUpload(msg.video.file_id, "video.mp4", mimeType);
|
|
196
|
+
commandMessage.attachments.push({
|
|
197
|
+
type: "video",
|
|
198
|
+
url: url ?? msg.video.file_id,
|
|
199
|
+
mimeType,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
// Handle stickers as images
|
|
203
|
+
if (msg.sticker) {
|
|
204
|
+
const url = await this.downloadAndUpload(msg.sticker.file_id, "sticker.webp", "image/webp");
|
|
205
|
+
commandMessage.attachments.push({
|
|
206
|
+
type: "image",
|
|
207
|
+
url: url ?? msg.sticker.file_id,
|
|
208
|
+
mimeType: "image/webp",
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
if (commandMessage.text || commandMessage.attachments.length > 0) {
|
|
212
|
+
this.emit("message", commandMessage);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
logger.warn(`Telegram: Error processing message: ${err instanceof Error ? err.message : String(err)}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Download a file from Telegram and upload to S3.
|
|
221
|
+
* Returns the S3 public URL, or null on failure.
|
|
222
|
+
*/
|
|
223
|
+
async downloadAndUpload(fileId, filename, contentType) {
|
|
224
|
+
if (!this.bot)
|
|
225
|
+
return null;
|
|
226
|
+
try {
|
|
227
|
+
// Get download URL from Telegram
|
|
228
|
+
const fileLink = await this.bot.getFileLink(fileId);
|
|
229
|
+
// Download the file
|
|
230
|
+
const response = await fetch(fileLink);
|
|
231
|
+
if (!response.ok) {
|
|
232
|
+
logger.warn(`Telegram: Failed to download file: ${response.status}`);
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
236
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
237
|
+
// Upload to S3
|
|
238
|
+
return await uploadMedia(buffer, filename, contentType);
|
|
239
|
+
}
|
|
240
|
+
catch (err) {
|
|
241
|
+
logger.warn(`Telegram: Failed to download/upload media: ${err instanceof Error ? err.message : String(err)}`);
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=telegram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/channels/telegram.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import type { VisionClawConfig } from "../config/types.js";
|
|
3
|
+
import type { ChannelAdapter, MessageAttachment } from "./interface.js";
|
|
4
|
+
/**
|
|
5
|
+
* WhatsApp channel adapter using the WhatsApp Cloud API.
|
|
6
|
+
* Supports multimodal inbound (images, audio, video, documents) and
|
|
7
|
+
* outbound (images, documents) messages.
|
|
8
|
+
*/
|
|
9
|
+
export declare class WhatsAppAdapter extends EventEmitter implements ChannelAdapter {
|
|
10
|
+
readonly name = "whatsapp";
|
|
11
|
+
private config;
|
|
12
|
+
private server;
|
|
13
|
+
private port;
|
|
14
|
+
constructor(config: VisionClawConfig);
|
|
15
|
+
start(): Promise<void>;
|
|
16
|
+
stop(): Promise<void>;
|
|
17
|
+
sendMessage(to: string, message: string, attachments?: MessageAttachment[]): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Process inbound webhook payload. Downloads media attachments
|
|
20
|
+
* and uploads to S3 before emitting the CommandMessage.
|
|
21
|
+
*/
|
|
22
|
+
private processWebhookPayload;
|
|
23
|
+
/**
|
|
24
|
+
* Download media from WhatsApp and upload to S3.
|
|
25
|
+
*/
|
|
26
|
+
private downloadAndUploadWhatsAppMedia;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=whatsapp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whatsapp.d.ts","sourceRoot":"","sources":["../../src/channels/whatsapp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D,OAAO,KAAK,EAAE,cAAc,EAAkB,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExF;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,YAAa,YAAW,cAAc;IACzE,QAAQ,CAAC,IAAI,cAAc;IAC3B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,IAAI,CAAQ;gBAER,MAAM,EAAE,gBAAgB;IAK9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA8DtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAWrB,WAAW,CACf,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,iBAAiB,EAAE,GAChC,OAAO,CAAC,IAAI,CAAC;IA+FhB;;;OAGG;YACW,qBAAqB;IA0GnC;;OAEG;YACW,8BAA8B;CAqC7C"}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import http from "node:http";
|
|
3
|
+
import { URL } from "node:url";
|
|
4
|
+
import { logger } from "../logger.js";
|
|
5
|
+
import { uploadMedia } from "../files.js";
|
|
6
|
+
/**
|
|
7
|
+
* WhatsApp channel adapter using the WhatsApp Cloud API.
|
|
8
|
+
* Supports multimodal inbound (images, audio, video, documents) and
|
|
9
|
+
* outbound (images, documents) messages.
|
|
10
|
+
*/
|
|
11
|
+
export class WhatsAppAdapter extends EventEmitter {
|
|
12
|
+
name = "whatsapp";
|
|
13
|
+
config;
|
|
14
|
+
server = null;
|
|
15
|
+
port = 3001;
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super();
|
|
18
|
+
this.config = config;
|
|
19
|
+
}
|
|
20
|
+
async start() {
|
|
21
|
+
const whatsappConfig = this.config.channels.whatsapp;
|
|
22
|
+
if (!whatsappConfig)
|
|
23
|
+
throw new Error("WhatsApp channel not configured");
|
|
24
|
+
if (!whatsappConfig.phoneNumberId || !whatsappConfig.accessToken) {
|
|
25
|
+
throw new Error("WhatsApp phoneNumberId and accessToken are required");
|
|
26
|
+
}
|
|
27
|
+
this.server = http.createServer((req, res) => {
|
|
28
|
+
const url = new URL(req.url ?? "/", `http://localhost:${this.port}`);
|
|
29
|
+
// Webhook verification
|
|
30
|
+
if (req.method === "GET" && url.pathname === "/webhook") {
|
|
31
|
+
const mode = url.searchParams.get("hub.mode");
|
|
32
|
+
const token = url.searchParams.get("hub.verify_token");
|
|
33
|
+
const challenge = url.searchParams.get("hub.challenge");
|
|
34
|
+
if (mode === "subscribe" && token === whatsappConfig.verifyToken) {
|
|
35
|
+
res.writeHead(200);
|
|
36
|
+
res.end(challenge);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
res.writeHead(403);
|
|
40
|
+
res.end("Forbidden");
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Webhook messages
|
|
45
|
+
if (req.method === "POST" && url.pathname === "/webhook") {
|
|
46
|
+
let body = "";
|
|
47
|
+
req.on("data", (chunk) => (body += String(chunk)));
|
|
48
|
+
req.on("end", () => {
|
|
49
|
+
try {
|
|
50
|
+
const data = JSON.parse(body);
|
|
51
|
+
void this.processWebhookPayload(data);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
logger.warn(`WhatsApp: Error parsing webhook: ${err instanceof Error ? err.message : String(err)}`);
|
|
55
|
+
}
|
|
56
|
+
res.writeHead(200);
|
|
57
|
+
res.end("OK");
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
res.writeHead(404);
|
|
62
|
+
res.end("Not found");
|
|
63
|
+
});
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
const server = this.server;
|
|
66
|
+
if (server) {
|
|
67
|
+
server.listen(this.port, () => {
|
|
68
|
+
logger.channel("whatsapp", `Webhook listening on port ${this.port}`);
|
|
69
|
+
resolve();
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
resolve();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
async stop() {
|
|
78
|
+
return new Promise((resolve) => {
|
|
79
|
+
if (this.server) {
|
|
80
|
+
this.server.close(() => resolve());
|
|
81
|
+
this.server = null;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
resolve();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async sendMessage(to, message, attachments) {
|
|
89
|
+
const whatsappConfig = this.config.channels.whatsapp;
|
|
90
|
+
if (!whatsappConfig)
|
|
91
|
+
throw new Error("WhatsApp not configured");
|
|
92
|
+
if (!whatsappConfig.phoneNumberId || !whatsappConfig.accessToken) {
|
|
93
|
+
throw new Error("WhatsApp configuration incomplete");
|
|
94
|
+
}
|
|
95
|
+
const apiUrl = `https://graph.facebook.com/v18.0/${whatsappConfig.phoneNumberId}/messages`;
|
|
96
|
+
const headers = {
|
|
97
|
+
Authorization: `Bearer ${whatsappConfig.accessToken}`,
|
|
98
|
+
"Content-Type": "application/json",
|
|
99
|
+
};
|
|
100
|
+
// Send attachments first
|
|
101
|
+
if (attachments && attachments.length > 0) {
|
|
102
|
+
for (const att of attachments) {
|
|
103
|
+
const mediaUrl = att.url ?? att.localPath;
|
|
104
|
+
if (!mediaUrl)
|
|
105
|
+
continue;
|
|
106
|
+
try {
|
|
107
|
+
// For local files, we need to upload to WhatsApp media first
|
|
108
|
+
// For URLs, we can send directly via link
|
|
109
|
+
let body;
|
|
110
|
+
if (att.type === "image") {
|
|
111
|
+
body = {
|
|
112
|
+
messaging_product: "whatsapp",
|
|
113
|
+
to,
|
|
114
|
+
type: "image",
|
|
115
|
+
image: { link: mediaUrl },
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
else if (att.type === "audio") {
|
|
119
|
+
body = {
|
|
120
|
+
messaging_product: "whatsapp",
|
|
121
|
+
to,
|
|
122
|
+
type: "audio",
|
|
123
|
+
audio: { link: mediaUrl },
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
else if (att.type === "video") {
|
|
127
|
+
body = {
|
|
128
|
+
messaging_product: "whatsapp",
|
|
129
|
+
to,
|
|
130
|
+
type: "video",
|
|
131
|
+
video: { link: mediaUrl },
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
body = {
|
|
136
|
+
messaging_product: "whatsapp",
|
|
137
|
+
to,
|
|
138
|
+
type: "document",
|
|
139
|
+
document: {
|
|
140
|
+
link: mediaUrl,
|
|
141
|
+
filename: att.filename ?? "document",
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const response = await fetch(apiUrl, {
|
|
146
|
+
method: "POST",
|
|
147
|
+
headers,
|
|
148
|
+
body: JSON.stringify(body),
|
|
149
|
+
});
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
const text = await response.text();
|
|
152
|
+
logger.warn(`WhatsApp: Failed to send ${att.type}: ${response.status} ${text}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
logger.warn(`WhatsApp: Failed to send ${att.type}: ${err instanceof Error ? err.message : String(err)}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Send text message
|
|
161
|
+
if (message.trim()) {
|
|
162
|
+
const response = await fetch(apiUrl, {
|
|
163
|
+
method: "POST",
|
|
164
|
+
headers,
|
|
165
|
+
body: JSON.stringify({
|
|
166
|
+
messaging_product: "whatsapp",
|
|
167
|
+
to,
|
|
168
|
+
type: "text",
|
|
169
|
+
text: { body: message },
|
|
170
|
+
}),
|
|
171
|
+
});
|
|
172
|
+
if (!response.ok) {
|
|
173
|
+
const text = await response.text();
|
|
174
|
+
throw new Error(`WhatsApp API error: ${response.status} ${text}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Process inbound webhook payload. Downloads media attachments
|
|
180
|
+
* and uploads to S3 before emitting the CommandMessage.
|
|
181
|
+
*/
|
|
182
|
+
async processWebhookPayload(data) {
|
|
183
|
+
try {
|
|
184
|
+
const whatsappConfig = this.config.channels.whatsapp;
|
|
185
|
+
const accessToken = whatsappConfig?.accessToken ?? "";
|
|
186
|
+
const entry = data.entry ?? [];
|
|
187
|
+
for (const e of entry) {
|
|
188
|
+
const changes = e.changes ?? [];
|
|
189
|
+
for (const change of changes) {
|
|
190
|
+
const value = change.value;
|
|
191
|
+
if (typeof value !== "object" || value === null)
|
|
192
|
+
continue;
|
|
193
|
+
const valueObj = value;
|
|
194
|
+
const messages = valueObj.messages ?? [];
|
|
195
|
+
for (const msg of messages) {
|
|
196
|
+
const msgType = typeof msg.type === "string" ? msg.type : "text";
|
|
197
|
+
const msgId = typeof msg.id === "string" || typeof msg.id === "number"
|
|
198
|
+
? String(msg.id)
|
|
199
|
+
: String(Date.now());
|
|
200
|
+
const sender = typeof msg.from === "string" || typeof msg.from === "number"
|
|
201
|
+
? String(msg.from)
|
|
202
|
+
: "unknown";
|
|
203
|
+
// Extract text
|
|
204
|
+
let textBody = "";
|
|
205
|
+
if (msgType === "text") {
|
|
206
|
+
const textObj = msg.text;
|
|
207
|
+
if (typeof textObj === "object" && textObj !== null && "body" in textObj) {
|
|
208
|
+
const bodyVal = textObj.body;
|
|
209
|
+
textBody = typeof bodyVal === "string" ? bodyVal : "";
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const commandMessage = {
|
|
213
|
+
id: `whatsapp-${msgId}`,
|
|
214
|
+
channel: "whatsapp",
|
|
215
|
+
sender,
|
|
216
|
+
text: textBody,
|
|
217
|
+
attachments: [],
|
|
218
|
+
timestamp: new Date(Number(msg.timestamp ?? 0) * 1000).toISOString(),
|
|
219
|
+
meta: { waMessageId: msg.id, type: msgType },
|
|
220
|
+
};
|
|
221
|
+
// Handle media messages (image, audio, video, document)
|
|
222
|
+
const mediaTypes = ["image", "audio", "video", "document"];
|
|
223
|
+
for (const mediaType of mediaTypes) {
|
|
224
|
+
if (msgType !== mediaType)
|
|
225
|
+
continue;
|
|
226
|
+
const mediaObj = msg[mediaType];
|
|
227
|
+
if (typeof mediaObj !== "object" || mediaObj === null)
|
|
228
|
+
continue;
|
|
229
|
+
const mediaData = mediaObj;
|
|
230
|
+
const mediaId = typeof mediaData.id === "string" ? mediaData.id : null;
|
|
231
|
+
const mimeType = typeof mediaData.mime_type === "string"
|
|
232
|
+
? mediaData.mime_type
|
|
233
|
+
: "application/octet-stream";
|
|
234
|
+
if (mediaId) {
|
|
235
|
+
const url = await this.downloadAndUploadWhatsAppMedia(mediaId, accessToken, `${mediaType}-${msgId}`, mimeType);
|
|
236
|
+
const attType = mediaType === "document" ? "file" : mediaType;
|
|
237
|
+
commandMessage.attachments.push({
|
|
238
|
+
type: attType,
|
|
239
|
+
url: url ?? undefined,
|
|
240
|
+
mimeType,
|
|
241
|
+
filename: typeof mediaData.filename === "string"
|
|
242
|
+
? mediaData.filename
|
|
243
|
+
: undefined,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
// Use caption as text if available
|
|
247
|
+
if (typeof mediaData.caption === "string" && !textBody) {
|
|
248
|
+
commandMessage.text = mediaData.caption;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (commandMessage.text.length > 0 || commandMessage.attachments.length > 0) {
|
|
252
|
+
this.emit("message", commandMessage);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
logger.warn(`WhatsApp: Error processing payload: ${err instanceof Error ? err.message : String(err)}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Download media from WhatsApp and upload to S3.
|
|
264
|
+
*/
|
|
265
|
+
async downloadAndUploadWhatsAppMedia(mediaId, accessToken, filename, contentType) {
|
|
266
|
+
try {
|
|
267
|
+
// Step 1: Get media URL from WhatsApp
|
|
268
|
+
const mediaInfoRes = await fetch(`https://graph.facebook.com/v18.0/${mediaId}`, { headers: { Authorization: `Bearer ${accessToken}` } });
|
|
269
|
+
if (!mediaInfoRes.ok)
|
|
270
|
+
return null;
|
|
271
|
+
const mediaInfo = (await mediaInfoRes.json());
|
|
272
|
+
const mediaUrl = typeof mediaInfo.url === "string" ? mediaInfo.url : null;
|
|
273
|
+
if (!mediaUrl)
|
|
274
|
+
return null;
|
|
275
|
+
// Step 2: Download the media
|
|
276
|
+
const downloadRes = await fetch(mediaUrl, {
|
|
277
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
278
|
+
});
|
|
279
|
+
if (!downloadRes.ok)
|
|
280
|
+
return null;
|
|
281
|
+
const arrayBuffer = await downloadRes.arrayBuffer();
|
|
282
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
283
|
+
// Step 3: Upload to S3
|
|
284
|
+
return await uploadMedia(buffer, filename, contentType);
|
|
285
|
+
}
|
|
286
|
+
catch (err) {
|
|
287
|
+
logger.warn(`WhatsApp: Failed to download/upload media: ${err instanceof Error ? err.message : String(err)}`);
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=whatsapp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whatsapp.js","sourceRoot":"","sources":["../../src/channels/whatsapp.ts"],"names":[],"mappings":"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"}
|