@ebowwa/glm-daemon 0.4.1 → 0.4.3
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/bin/discord-cli.js +100736 -0
- package/dist/bin/manager.js +143 -0
- package/dist/bin/telegram-cli.js +100732 -0
- package/dist/index.js +100932 -0
- package/package.json +2 -3
- package/src/channels/base.ts +74 -14
- package/src/channels/telegram.ts +56 -318
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ebowwa/glm-daemon",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Autonomous GLM 4.7 daemon with hooks, tools, teammates, and communication channels (Telegram, Discord)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -54,18 +54,17 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@ebowwa/ai": "^0.1.2",
|
|
57
|
+
"@ebowwa/channel-telegram": "^1.13.0",
|
|
57
58
|
"@ebowwa/channel-types": "^0.1.1",
|
|
58
59
|
"@ebowwa/codespaces-types": "^1.4.0",
|
|
59
60
|
"@ebowwa/structured-prompts": "^0.3.2",
|
|
60
61
|
"@ebowwa/teammates": "^0.1.2",
|
|
61
62
|
"discord.js": "^14.16.3",
|
|
62
|
-
"node-telegram-bot-api": "^0.66.0",
|
|
63
63
|
"zod": "^4.3.5"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@types/bun": "catalog:dev",
|
|
67
67
|
"@types/node": "catalog:dev",
|
|
68
|
-
"@types/node-telegram-bot-api": "^0.64.13",
|
|
69
68
|
"typescript": "catalog:",
|
|
70
69
|
"bun-types": "catalog:dev"
|
|
71
70
|
},
|
package/src/channels/base.ts
CHANGED
|
@@ -20,7 +20,8 @@ import {
|
|
|
20
20
|
RICH_CAPABILITIES,
|
|
21
21
|
} from "@ebowwa/channel-types";
|
|
22
22
|
import { GLMClient } from "@ebowwa/ai";
|
|
23
|
-
import { GLMDaemon, type GLMDaemonConfig } from "
|
|
23
|
+
import { GLMDaemon, type GLMDaemonConfig } from "../daemon.js";
|
|
24
|
+
import { BUILTIN_TOOLS, toGLMFormat, executeBuiltinTool } from "../builtin-tools.js";
|
|
24
25
|
|
|
25
26
|
// ============================================================
|
|
26
27
|
// CHANNEL CONFIG (extends base config from channel-types)
|
|
@@ -331,7 +332,7 @@ export abstract class BaseChannel implements ChannelConnector {
|
|
|
331
332
|
// ============================================================
|
|
332
333
|
|
|
333
334
|
/**
|
|
334
|
-
* Handle chat messages locally with GLM
|
|
335
|
+
* Handle chat messages locally with GLM + tools
|
|
335
336
|
*/
|
|
336
337
|
protected async handleChat(content: string, context: MessageContext): Promise<RouteResult> {
|
|
337
338
|
const start = Date.now();
|
|
@@ -340,20 +341,28 @@ export abstract class BaseChannel implements ChannelConnector {
|
|
|
340
341
|
const history = this.conversationHistory.get(context.userId) || [];
|
|
341
342
|
|
|
342
343
|
// Build system prompt with context
|
|
343
|
-
const systemPrompt = `You are a helpful AI assistant. You have access to conversation history and user context.
|
|
344
|
+
const systemPrompt = `You are a helpful AI assistant with tool access. You have access to conversation history and user context.
|
|
344
345
|
|
|
345
346
|
User: ${context.userName || context.userId}
|
|
346
347
|
Time: ${context.timestamp.toISOString()}
|
|
348
|
+
Working Directory: ${this.config.daemonWorkdir || process.cwd()}
|
|
347
349
|
|
|
348
|
-
|
|
349
|
-
-
|
|
350
|
-
-
|
|
351
|
-
-
|
|
350
|
+
You have access to tools for:
|
|
351
|
+
- File operations (read_file, write_file, edit_file, list_dir)
|
|
352
|
+
- Shell commands (run_command) - use for git, system info, etc.
|
|
353
|
+
- Git operations (git_status)
|
|
354
|
+
- System info (system_info)
|
|
352
355
|
|
|
353
|
-
|
|
356
|
+
USE TOOLS when the user asks you to do something (not just chat). Examples:
|
|
357
|
+
- "list files" → use list_dir
|
|
358
|
+
- "read package.json" → use read_file
|
|
359
|
+
- "what's the git status" → use git_status
|
|
360
|
+
- "run npm test" → use run_command
|
|
361
|
+
|
|
362
|
+
Always use tools when appropriate. Be helpful and execute tasks.`;
|
|
354
363
|
|
|
355
364
|
// Build messages array with system prompt and history
|
|
356
|
-
const messages: Array<{ role: "system" | "user" | "assistant"; content: string }> = [
|
|
365
|
+
const messages: Array<{ role: "system" | "user" | "assistant"; content: string; tool_calls?: unknown[]; tool_call_id?: string }> = [
|
|
357
366
|
{ role: "system", content: systemPrompt },
|
|
358
367
|
...history.slice(-10).map(msg => ({
|
|
359
368
|
role: msg.role as "user" | "assistant",
|
|
@@ -362,22 +371,73 @@ For complex coding tasks, suggest the user phrase it as a task request.`;
|
|
|
362
371
|
{ role: "user", content }
|
|
363
372
|
];
|
|
364
373
|
|
|
365
|
-
|
|
374
|
+
// Get tools in GLM format
|
|
375
|
+
const tools = toGLMFormat(BUILTIN_TOOLS);
|
|
376
|
+
|
|
377
|
+
// First call with tools
|
|
378
|
+
let response = await this.glmClient.chatCompletion(messages, {
|
|
366
379
|
temperature: 0.7,
|
|
367
|
-
maxTokens: 4096
|
|
380
|
+
maxTokens: 4096,
|
|
381
|
+
tools
|
|
368
382
|
});
|
|
369
383
|
|
|
370
|
-
//
|
|
371
|
-
|
|
384
|
+
// Handle tool calls in a loop (max 5 iterations to prevent infinite loops)
|
|
385
|
+
let iterations = 0;
|
|
386
|
+
const maxIterations = 5;
|
|
387
|
+
let responseMessage = response.choices?.[0]?.message;
|
|
388
|
+
|
|
389
|
+
while (responseMessage?.tool_calls && iterations < maxIterations) {
|
|
390
|
+
iterations++;
|
|
391
|
+
console.log(`[${this.constructor.name}] Tool call iteration ${iterations}`);
|
|
392
|
+
|
|
393
|
+
// Add assistant message with tool calls to history
|
|
394
|
+
messages.push({
|
|
395
|
+
role: "assistant",
|
|
396
|
+
content: responseMessage.content || "",
|
|
397
|
+
tool_calls: responseMessage.tool_calls
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// Execute each tool call
|
|
401
|
+
for (const toolCall of responseMessage.tool_calls as Array<{ id: string; function: { name: string; arguments: string } }>) {
|
|
402
|
+
const toolName = toolCall.function.name;
|
|
403
|
+
const toolArgs = JSON.parse(toolCall.function.arguments);
|
|
404
|
+
|
|
405
|
+
console.log(`[${this.constructor.name}] Executing tool: ${toolName}(${JSON.stringify(toolArgs).slice(0, 100)})`);
|
|
406
|
+
|
|
407
|
+
// Execute the tool
|
|
408
|
+
const toolResult = await executeBuiltinTool(toolName, toolArgs);
|
|
409
|
+
|
|
410
|
+
console.log(`[${this.constructor.name}] Tool result: ${toolResult.slice(0, 100)}...`);
|
|
411
|
+
|
|
412
|
+
// Add tool result to messages
|
|
413
|
+
messages.push({
|
|
414
|
+
role: "tool",
|
|
415
|
+
content: toolResult,
|
|
416
|
+
tool_call_id: toolCall.id
|
|
417
|
+
} as any);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Get next response (without tools to get final answer)
|
|
421
|
+
response = await this.glmClient.chatCompletion(messages, {
|
|
422
|
+
temperature: 0.7,
|
|
423
|
+
maxTokens: 4096,
|
|
424
|
+
tools
|
|
425
|
+
});
|
|
426
|
+
responseMessage = response.choices?.[0]?.message;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Extract final response text
|
|
430
|
+
const responseText = responseMessage?.content || "No response generated.";
|
|
372
431
|
|
|
373
432
|
this.addToHistory(context.userId, { role: "assistant", content: responseText });
|
|
374
433
|
|
|
375
434
|
return {
|
|
376
435
|
source: "butler",
|
|
377
436
|
response: responseText,
|
|
378
|
-
metadata: { executionTime: Date.now() - start },
|
|
437
|
+
metadata: { executionTime: Date.now() - start, toolIterations: iterations },
|
|
379
438
|
};
|
|
380
439
|
} catch (error) {
|
|
440
|
+
console.error(`[${this.constructor.name}] handleChat error:`, error);
|
|
381
441
|
return {
|
|
382
442
|
source: "error",
|
|
383
443
|
response: `Sorry, I encountered an error: ${error instanceof Error ? error.message : String(error)}`,
|
package/src/channels/telegram.ts
CHANGED
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Telegram Channel
|
|
2
|
+
* Telegram Channel for GLM Daemon
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Wraps @ebowwa/channel-telegram (pure protocol adapter)
|
|
5
|
+
* with GLM Daemon intelligence (GLM client, daemon delegation, routing).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import TelegramBot from "node-telegram-bot-api";
|
|
9
8
|
import {
|
|
10
9
|
type ChannelId,
|
|
11
|
-
type ChannelMessage,
|
|
12
|
-
type ChannelResponse,
|
|
13
10
|
type ChannelCapabilities,
|
|
14
|
-
type MessageSender,
|
|
15
|
-
type MessageContext,
|
|
16
|
-
createChannelId,
|
|
17
|
-
RICH_CAPABILITIES,
|
|
18
11
|
} from "@ebowwa/channel-types";
|
|
12
|
+
import {
|
|
13
|
+
TelegramChannel as TelegramProtocolAdapter,
|
|
14
|
+
type TelegramConfig as ProtocolConfig,
|
|
15
|
+
} from "@ebowwa/channel-telegram";
|
|
19
16
|
import {
|
|
20
17
|
BaseChannel,
|
|
21
18
|
type GLMChannelConfig,
|
|
22
|
-
type BaseChannelConfig,
|
|
23
|
-
type MessageContext as InternalMessageContext,
|
|
24
|
-
type RouteResult,
|
|
25
19
|
} from "./base.js";
|
|
26
20
|
|
|
27
21
|
// ============================================================
|
|
@@ -44,7 +38,7 @@ export interface TelegramChannelConfig extends GLMChannelConfig {
|
|
|
44
38
|
export type { TelegramChannelConfig as TelegramConfig };
|
|
45
39
|
|
|
46
40
|
// ============================================================
|
|
47
|
-
// TELEGRAM CHANNEL
|
|
41
|
+
// TELEGRAM CHANNEL (Wraps @ebowwa/channel-telegram)
|
|
48
42
|
// ============================================================
|
|
49
43
|
|
|
50
44
|
export class TelegramChannel extends BaseChannel {
|
|
@@ -56,7 +50,7 @@ export class TelegramChannel extends BaseChannel {
|
|
|
56
50
|
media: true,
|
|
57
51
|
replies: true,
|
|
58
52
|
threads: false,
|
|
59
|
-
reactions: true,
|
|
53
|
+
reactions: true,
|
|
60
54
|
editing: true,
|
|
61
55
|
streaming: false,
|
|
62
56
|
},
|
|
@@ -70,20 +64,26 @@ export class TelegramChannel extends BaseChannel {
|
|
|
70
64
|
},
|
|
71
65
|
};
|
|
72
66
|
|
|
73
|
-
private
|
|
74
|
-
private
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
67
|
+
private protocolAdapter: TelegramProtocolAdapter;
|
|
68
|
+
private telegramConfig: {
|
|
69
|
+
botToken: string;
|
|
70
|
+
testChatId?: string;
|
|
71
|
+
allowedUsers?: number[];
|
|
72
|
+
allowedChats?: number[];
|
|
73
|
+
};
|
|
78
74
|
|
|
79
75
|
constructor(config: TelegramChannelConfig) {
|
|
80
76
|
super(config);
|
|
81
|
-
|
|
82
|
-
this.
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
|
|
78
|
+
this.telegramConfig = {
|
|
79
|
+
botToken: config.botToken,
|
|
80
|
+
testChatId: config.testChatId,
|
|
81
|
+
allowedUsers: config.allowedUsers,
|
|
82
|
+
allowedChats: config.allowedChats,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
85
|
this.id = this.createId();
|
|
86
|
-
this.
|
|
86
|
+
this.protocolAdapter = new TelegramProtocolAdapter(this.telegramConfig);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// ============================================================
|
|
@@ -91,339 +91,77 @@ export class TelegramChannel extends BaseChannel {
|
|
|
91
91
|
// ============================================================
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* Send response to Telegram
|
|
94
|
+
* Send response to Telegram via protocol adapter
|
|
95
95
|
*/
|
|
96
|
-
async send(response:
|
|
97
|
-
|
|
98
|
-
if (!chatId) {
|
|
99
|
-
console.error("[Telegram] Cannot send: no chat ID in response");
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
await this.sendResponse(chatId, response.content.text);
|
|
96
|
+
async send(response: Parameters<TelegramProtocolAdapter['send']>[0]): Promise<void> {
|
|
97
|
+
await this.protocolAdapter.send(response);
|
|
104
98
|
}
|
|
105
99
|
|
|
106
100
|
// ============================================================
|
|
107
|
-
// Platform-Specific Implementation
|
|
101
|
+
// Platform-Specific Implementation (BaseChannel abstract methods)
|
|
108
102
|
// ============================================================
|
|
109
103
|
|
|
110
104
|
/**
|
|
111
|
-
* Start Telegram bot
|
|
105
|
+
* Start Telegram bot via protocol adapter
|
|
112
106
|
*/
|
|
113
107
|
protected async startPlatform(): Promise<void> {
|
|
114
|
-
console.log("[
|
|
115
|
-
|
|
116
|
-
// Start polling with all required update types
|
|
117
|
-
this.bot = new TelegramBot(this.token, {
|
|
118
|
-
polling: {
|
|
119
|
-
interval: 300,
|
|
120
|
-
autoStart: true,
|
|
121
|
-
params: {
|
|
122
|
-
allowed_updates: ['message', 'edited_message', 'message_reaction', 'callback_query']
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// Handle /start command
|
|
128
|
-
this.bot.onText(/\/start/, async (msg: TelegramBot.Message) => {
|
|
129
|
-
const chatId = msg.chat.id;
|
|
130
|
-
await this.bot.sendMessage(
|
|
131
|
-
chatId,
|
|
132
|
-
"👋 Hello! I'm the GLM Daemon Telegram Bot.\n\n" +
|
|
133
|
-
"I can help you with:\n" +
|
|
134
|
-
"- Chat and questions (handled locally)\n" +
|
|
135
|
-
"- Coding tasks and features (delegated to daemon)\n\n" +
|
|
136
|
-
"Just send me a message!"
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// Handle all text messages (with reply context)
|
|
141
|
-
this.bot.on("message", async (msg: TelegramBot.Message) => {
|
|
142
|
-
if (!msg.text) return;
|
|
143
|
-
if (msg.text.startsWith("/")) return;
|
|
144
|
-
|
|
145
|
-
const chatId = msg.chat.id;
|
|
146
|
-
const userId = msg.from?.id;
|
|
147
|
-
|
|
148
|
-
// Check allowlist
|
|
149
|
-
if (!this.isAllowed(userId, chatId)) {
|
|
150
|
-
console.log(`[Telegram] Blocked message from unauthorized user/chat: ${userId}/${chatId}`);
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const userName = msg.from?.first_name || msg.from?.username || "User";
|
|
155
|
-
|
|
156
|
-
// Check if this is a reply
|
|
157
|
-
const replyContext = msg.reply_to_message ? {
|
|
158
|
-
originalText: msg.reply_to_message.text,
|
|
159
|
-
originalFrom: msg.reply_to_message.from?.first_name || 'User',
|
|
160
|
-
originalMessageId: msg.reply_to_message.message_id
|
|
161
|
-
} : null;
|
|
162
|
-
|
|
163
|
-
if (replyContext) {
|
|
164
|
-
console.log(`[Telegram] ${userName} (replying to ${replyContext.originalFrom}): ${msg.text}`);
|
|
165
|
-
} else {
|
|
166
|
-
console.log(`[Telegram] ${userName}: ${msg.text}`);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Build message with reply context
|
|
170
|
-
let messageText = msg.text;
|
|
171
|
-
if (replyContext?.originalText) {
|
|
172
|
-
messageText = `[Replying to ${replyContext.originalFrom}: "${replyContext.originalText.slice(0, 100)}"]\n\n${msg.text}`;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Show typing indicator
|
|
176
|
-
await this.bot.sendChatAction(chatId, "typing");
|
|
177
|
-
|
|
178
|
-
try {
|
|
179
|
-
// Create normalized ChannelMessage
|
|
180
|
-
const message = this.createChannelMessage(msg);
|
|
181
|
-
if (replyContext) {
|
|
182
|
-
message.text = messageText; // Override with context
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Route through base channel
|
|
186
|
-
const response = await this.routeChannelMessage(message);
|
|
187
|
-
|
|
188
|
-
// Send response - thread to original if reply
|
|
189
|
-
if (replyContext) {
|
|
190
|
-
await this.bot.sendMessage(chatId, response.content.text, {
|
|
191
|
-
reply_to_message_id: msg.message_id,
|
|
192
|
-
parse_mode: "Markdown"
|
|
193
|
-
});
|
|
194
|
-
} else {
|
|
195
|
-
await this.send(response);
|
|
196
|
-
}
|
|
197
|
-
} catch (error) {
|
|
198
|
-
console.error("[Telegram] Error handling message:", error);
|
|
199
|
-
await this.bot.sendMessage(
|
|
200
|
-
chatId,
|
|
201
|
-
`Sorry, I encountered an error: ${error instanceof Error ? error.message : String(error)}`
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
// Handle message edits
|
|
207
|
-
this.bot.on("edited_message", async (msg: TelegramBot.Message) => {
|
|
208
|
-
if (!msg.text) return;
|
|
209
|
-
|
|
210
|
-
const chatId = msg.chat.id;
|
|
211
|
-
const userId = msg.from?.id;
|
|
212
|
-
const userName = msg.from?.first_name || "User";
|
|
213
|
-
|
|
214
|
-
if (!this.isAllowed(userId, chatId)) return;
|
|
215
|
-
|
|
216
|
-
console.log(`[Telegram] EDIT ${userName}: ${msg.text.slice(0, 50)}...`);
|
|
217
|
-
|
|
218
|
-
// Notify about edit and re-process
|
|
219
|
-
await this.bot.sendChatAction(chatId, "typing");
|
|
220
|
-
|
|
221
|
-
try {
|
|
222
|
-
const message = this.createChannelMessage(msg);
|
|
223
|
-
message.text = `[User edited their message to: "${msg.text}"]`;
|
|
108
|
+
console.log("[TelegramChannel] Starting via protocol adapter...");
|
|
224
109
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
} catch (error) {
|
|
230
|
-
console.error("[Telegram] Error handling edit:", error);
|
|
231
|
-
}
|
|
110
|
+
// Connect protocol adapter to our routing logic
|
|
111
|
+
this.protocolAdapter.onMessage(async (message) => {
|
|
112
|
+
// Route through BaseChannel's routing logic (GLM + daemon)
|
|
113
|
+
return this.routeChannelMessage(message);
|
|
232
114
|
});
|
|
233
115
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
(this.bot as any).on("message_reaction", async (reaction: {
|
|
237
|
-
chat: { id: number };
|
|
238
|
-
message_id: number;
|
|
239
|
-
user: { id: number; first_name?: string };
|
|
240
|
-
old_reaction: Array<{ type: string; emoji?: string }>;
|
|
241
|
-
new_reaction: Array<{ type: string; emoji?: string }>;
|
|
242
|
-
}) => {
|
|
243
|
-
const chatId = reaction.chat.id;
|
|
244
|
-
const userName = reaction.user.first_name || "User";
|
|
245
|
-
|
|
246
|
-
const newEmojis = reaction.new_reaction
|
|
247
|
-
.filter(r => r.type === 'emoji' && r.emoji)
|
|
248
|
-
.map(r => r.emoji!);
|
|
249
|
-
|
|
250
|
-
const oldEmojis = reaction.old_reaction
|
|
251
|
-
.filter(r => r.type === 'emoji' && r.emoji)
|
|
252
|
-
.map(r => r.emoji!);
|
|
253
|
-
|
|
254
|
-
const added = newEmojis.filter(e => !oldEmojis.includes(e));
|
|
255
|
-
const removed = oldEmojis.filter(e => !newEmojis.includes(e));
|
|
256
|
-
|
|
257
|
-
console.log(`[Telegram] REACTION by ${userName}: +${added.join(',')} -${removed.join(',')} on msg ${reaction.message_id}`);
|
|
258
|
-
|
|
259
|
-
// Respond to negative feedback
|
|
260
|
-
if (added.includes('👎')) {
|
|
261
|
-
await this.bot.sendMessage(chatId, `Thanks for the feedback, ${userName}. I'll try to do better!`);
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
// Handle callback queries (inline button reactions)
|
|
266
|
-
this.bot.on("callback_query", async (query: TelegramBot.CallbackQuery) => {
|
|
267
|
-
const chatId = query.message?.chat.id;
|
|
268
|
-
const data = query.data;
|
|
269
|
-
const userName = query.from.first_name || "User";
|
|
270
|
-
|
|
271
|
-
if (!chatId || !data) {
|
|
272
|
-
await this.bot.answerCallbackQuery(query.id);
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
console.log(`[Telegram] CALLBACK ${userName}: ${data}`);
|
|
277
|
-
|
|
278
|
-
const [action, value] = data.split(':');
|
|
279
|
-
|
|
280
|
-
switch (action) {
|
|
281
|
-
case 'react': {
|
|
282
|
-
const count = parseInt(value) || 0;
|
|
283
|
-
const newCount = count + 1;
|
|
284
|
-
await this.bot.editMessageReplyMarkup(
|
|
285
|
-
{ inline_keyboard: [[
|
|
286
|
-
{ text: `👍 ${newCount}`, callback_data: `react:${newCount}` }
|
|
287
|
-
]]},
|
|
288
|
-
{ chat_id: chatId, message_id: query.message?.message_id }
|
|
289
|
-
);
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
case 'approve':
|
|
293
|
-
await this.bot.sendMessage(chatId, `✅ Approved by ${userName}`);
|
|
294
|
-
break;
|
|
295
|
-
case 'reject':
|
|
296
|
-
await this.bot.sendMessage(chatId, `❌ Rejected by ${userName}`);
|
|
297
|
-
break;
|
|
298
|
-
case 'cancel':
|
|
299
|
-
await this.bot.sendMessage(chatId, `🛑 Task cancelled by ${userName}`);
|
|
300
|
-
break;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
await this.bot.answerCallbackQuery(query.id);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
// Handle polling errors
|
|
307
|
-
this.bot.on("polling_error", (error: Error) => {
|
|
308
|
-
console.error("[Telegram] Polling error:", error);
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
console.log("[Telegram] Bot is running!");
|
|
312
|
-
|
|
313
|
-
// Send test message if chat ID provided
|
|
314
|
-
if (this.testChatId) {
|
|
315
|
-
await this.sendTestMessage(Number(this.testChatId));
|
|
316
|
-
}
|
|
116
|
+
await this.protocolAdapter.start();
|
|
117
|
+
console.log("[TelegramChannel] Protocol adapter started");
|
|
317
118
|
}
|
|
318
119
|
|
|
319
120
|
/**
|
|
320
|
-
* Stop Telegram bot
|
|
121
|
+
* Stop Telegram bot via protocol adapter
|
|
321
122
|
*/
|
|
322
123
|
protected async stopPlatform(): Promise<void> {
|
|
323
|
-
console.log("[
|
|
324
|
-
await this.
|
|
124
|
+
console.log("[TelegramChannel] Stopping protocol adapter...");
|
|
125
|
+
await this.protocolAdapter.stop();
|
|
325
126
|
}
|
|
326
127
|
|
|
327
128
|
// ============================================================
|
|
328
|
-
// Telegram-Specific Helpers
|
|
129
|
+
// Telegram-Specific Helpers (delegated to protocol adapter)
|
|
329
130
|
// ============================================================
|
|
330
131
|
|
|
331
132
|
/**
|
|
332
|
-
*
|
|
133
|
+
* Get underlying bot instance for advanced operations
|
|
333
134
|
*/
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
id: msg.from?.id?.toString() || msg.chat.id.toString(),
|
|
337
|
-
username: msg.from?.username,
|
|
338
|
-
displayName: msg.from?.first_name || msg.from?.username,
|
|
339
|
-
isBot: msg.from?.is_bot || false,
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
const context: MessageContext = {
|
|
343
|
-
isDM: msg.chat.type === "private",
|
|
344
|
-
groupName: msg.chat.type !== "private" ? msg.chat.title : undefined,
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
return {
|
|
348
|
-
messageId: msg.message_id.toString(),
|
|
349
|
-
channelId: this.id,
|
|
350
|
-
timestamp: new Date(msg.date * 1000),
|
|
351
|
-
sender,
|
|
352
|
-
text: msg.text || "",
|
|
353
|
-
context,
|
|
354
|
-
replyTo: msg.reply_to_message
|
|
355
|
-
? {
|
|
356
|
-
messageId: msg.reply_to_message.message_id.toString(),
|
|
357
|
-
channelId: this.id,
|
|
358
|
-
}
|
|
359
|
-
: undefined,
|
|
360
|
-
};
|
|
135
|
+
getBot() {
|
|
136
|
+
return this.protocolAdapter.getBot();
|
|
361
137
|
}
|
|
362
138
|
|
|
363
139
|
/**
|
|
364
|
-
*
|
|
140
|
+
* Send a simple message
|
|
365
141
|
*/
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
if (!this.allowedUsers?.length && !this.allowedChats?.length) {
|
|
369
|
-
return true;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Check user allowlist
|
|
373
|
-
if (this.allowedUsers?.length && userId) {
|
|
374
|
-
if (this.allowedUsers.includes(userId)) return true;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Check chat allowlist
|
|
378
|
-
if (this.allowedChats?.length && chatId) {
|
|
379
|
-
if (this.allowedChats.includes(chatId)) return true;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
return false;
|
|
142
|
+
async sendMessage(chatId: number, text: string) {
|
|
143
|
+
await this.protocolAdapter.sendMessage(chatId, text);
|
|
383
144
|
}
|
|
384
145
|
|
|
385
146
|
/**
|
|
386
|
-
*
|
|
147
|
+
* Start typing indicator
|
|
387
148
|
*/
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const accountId = replyTo.channelId.accountId;
|
|
391
|
-
// Try to parse as number, fallback to null
|
|
392
|
-
const parsed = parseInt(accountId, 10);
|
|
393
|
-
return isNaN(parsed) ? null : parsed;
|
|
149
|
+
startTypingIndicator(chatId: number) {
|
|
150
|
+
this.protocolAdapter.startTypingIndicator(chatId);
|
|
394
151
|
}
|
|
395
152
|
|
|
396
153
|
/**
|
|
397
|
-
*
|
|
154
|
+
* Stop typing indicator
|
|
398
155
|
*/
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
if (response.length > maxLength) {
|
|
403
|
-
const chunks = response.match(/[\s\S]{1,4000}/g) || [];
|
|
404
|
-
for (const chunk of chunks) {
|
|
405
|
-
await this.bot.sendMessage(chatId, chunk, { parse_mode: "Markdown" });
|
|
406
|
-
}
|
|
407
|
-
} else {
|
|
408
|
-
await this.bot.sendMessage(chatId, response, { parse_mode: "Markdown" });
|
|
409
|
-
}
|
|
156
|
+
stopTypingIndicator(chatId: number) {
|
|
157
|
+
this.protocolAdapter.stopTypingIndicator(chatId);
|
|
410
158
|
}
|
|
411
159
|
|
|
412
160
|
/**
|
|
413
|
-
*
|
|
161
|
+
* Check if user/chat is allowed
|
|
414
162
|
*/
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
chatId,
|
|
418
|
-
"✅ GLM Daemon Telegram Bot is NOW ONLINE!\n\n" +
|
|
419
|
-
"🎉 The bot is working correctly!\n\n" +
|
|
420
|
-
"Commands:\n" +
|
|
421
|
-
"/start - Show welcome message\n" +
|
|
422
|
-
'Any message - Chat or task\n' +
|
|
423
|
-
'"status" - Check daemon status\n\n' +
|
|
424
|
-
"I'll route your messages appropriately!"
|
|
425
|
-
);
|
|
426
|
-
console.log(`[Telegram] Test message sent to chat ${chatId}`);
|
|
163
|
+
isAllowed(userId?: number, chatId?: number): boolean {
|
|
164
|
+
return this.protocolAdapter.isAllowed(userId, chatId);
|
|
427
165
|
}
|
|
428
166
|
}
|
|
429
167
|
|