Skip to content

Commit db2f2eb

Browse files
authored
Merge pull request #4 from elizaos-plugins/odi-dm
/start support, expose sourceId, target => ChannelType & typescript fixes
2 parents adec4a6 + b34e701 commit db2f2eb

7 files changed

Lines changed: 54 additions & 23 deletions

File tree

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@elizaos/plugin-telegram",
3-
"version": "1.0.4",
3+
"version": "1.0.5",
44
"type": "module",
55
"main": "dist/index.js",
66
"module": "dist/index.js",
@@ -31,7 +31,7 @@
3131
"vitest": "1.6.1"
3232
},
3333
"scripts": {
34-
"build": "tsup",
34+
"build": "tsup && tsc",
3535
"dev": "tsup --watch",
3636
"test": "vitest run",
3737
"test:watch": "vitest",

src/messageManager.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,8 @@ export class MessageManager {
330330
const chat = message.chat as Chat;
331331
const channelType = getChannelType(chat);
332332

333+
const sourceId = createUniqueUuid(this.runtime, '' + chat.id);
334+
333335
await this.runtime.ensureConnection({
334336
entityId,
335337
roomId,
@@ -352,10 +354,11 @@ export class MessageManager {
352354
content: {
353355
text: fullText,
354356
// attachments?
355-
source: 'telegram',
357+
source: "telegram",
358+
// url?
356359
channelType: channelType,
357360
inReplyTo:
358-
'reply_to_message' in message && message.reply_to_message
361+
"reply_to_message" in message && message.reply_to_message
359362
? createUniqueUuid(this.runtime, message.reply_to_message.message_id.toString())
360363
: undefined,
361364
},
@@ -366,9 +369,11 @@ export class MessageManager {
366369
// include very technical/exact reference to this user for security reasons
367370
// don't remove or change this, spartan needs this
368371
fromId: chat.id,
372+
sourceId,
369373
// why message? all Memories contain content (which is basically a message)
370-
// what are the other types?
371-
type: 'message',
374+
// what are the other types? see MemoryType
375+
type: "message", // MemoryType.MESSAGE
376+
// scope: `shared`, `private`, or `room`
372377
},
373378
createdAt: message.date * 1000,
374379
};
@@ -380,7 +385,8 @@ export class MessageManager {
380385
if (!content.text) return [];
381386

382387
let sentMessages: boolean | Message.TextMessage[] = false
383-
if (content?.target === 'DM') {
388+
// channelType target === 'telegram'
389+
if (content?.channelType === 'DM') {
384390
sentMessages = []
385391
if (ctx.from) {
386392
// FIXME split on 4096 chars
@@ -396,7 +402,7 @@ export class MessageManager {
396402
const memories: Memory[] = [];
397403
for (let i = 0; i < sentMessages.length; i++) {
398404
const sentMessage = sentMessages[i];
399-
const _isLastMessage = i === sentMessages.length - 1;
405+
400406

401407
const responseMemory: Memory = {
402408
id: createUniqueUuid(this.runtime, sentMessage.message_id.toString()),

src/service.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@ import {
33
type Content,
44
type Entity,
55
EventType,
6-
type HandlerCallback,
76
type IAgentRuntime,
8-
type Memory,
97
Role,
108
type Room,
119
Service,
1210
type TargetInfo,
1311
type UUID,
1412
type World,
15-
WorldPayload,
1613
createUniqueUuid,
1714
logger,
1815
} from '@elizaos/core';
@@ -21,7 +18,7 @@ import { type ChatMemberOwner, type ChatMemberAdministrator, type User } from 't
2118
import { TELEGRAM_SERVICE_NAME } from './constants';
2219
import { validateTelegramConfig } from './environment';
2320
import { MessageManager } from './messageManager';
24-
import { TelegramEventTypes, TelegramWorldPayload } from './types';
21+
import { TelegramEventTypes, type TelegramWorldPayload } from './types';
2522

2623
/**
2724
* Class representing a Telegram service that allows the agent to send and receive messages on Telegram.
@@ -144,6 +141,12 @@ export class TelegramService extends Service {
144141
* @returns {Promise<void>} A Promise that resolves when the initialization is complete.
145142
*/
146143
private async initializeBot(): Promise<void> {
144+
this.bot.start(ctx => {
145+
this.runtime.emitEvent([TelegramEventTypes.SLASH_START], {
146+
// we don't need this
147+
ctx,
148+
});
149+
});
147150
this.bot.launch({
148151
dropPendingUpdates: true,
149152
allowedUpdates: ['message', 'message_reaction'],

src/tests.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import type { Telegraf } from 'telegraf';
44
import type { Context } from 'telegraf';
55
import type { MessageManager } from './messageManager';
66
import type { TelegramService } from './service';
7+
import type { TelegramContent } from './types';
8+
79

810
const TEST_IMAGE_URL =
911
'https://github.com/elizaOS/awesome-eliza/blob/main/assets/eliza-logo.jpg?raw=true';
@@ -143,7 +145,7 @@ export class TelegramTestSuite implements TestSuite {
143145
],
144146
};
145147

146-
await this.messageManager.sendMessageInChunks(mockContext as Context, messageContent);
148+
await this.messageManager.sendMessageInChunks(mockContext as Context, messageContent as TelegramContent);
147149

148150
logger.success('Message with image attachment sent successfully.');
149151
} catch (error) {

src/types.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@ export enum TelegramEventTypes {
3131
WORLD_CONNECTED = 'TELEGRAM_WORLD_CONNECTED',
3232
WORLD_LEFT = 'TELEGRAM_WORLD_LEFT',
3333

34+
export interface TelegramEventPayloadMap {
35+
[TelegramEventTypes.MESSAGE_RECEIVED]: TelegramMessageReceivedPayload;
36+
[TelegramEventTypes.MESSAGE_SENT]: TelegramMessageSentPayload;
37+
[TelegramEventTypes.REACTION_RECEIVED]: TelegramReactionReceivedPayload;
38+
[TelegramEventTypes.WORLD_JOINED]: TelegramWorldPayload;
39+
[TelegramEventTypes.WORLD_CONNECTED]: TelegramWorldPayload;
40+
[TelegramEventTypes.WORLD_LEFT]: TelegramWorldPayload;
41+
[TelegramEventTypes.SLASH_START]: { ctx: Context };
42+
[TelegramEventTypes.ENTITY_JOINED]: TelegramEntityPayload;
43+
[TelegramEventTypes.ENTITY_LEFT]: TelegramEntityPayload;
44+
[TelegramEventTypes.ENTITY_UPDATED]: TelegramEntityPayload;
45+
[TelegramEventTypes.INTERACTION_RECEIVED]: TelegramReactionReceivedPayload;
46+
}
3447
// Entity events
3548
ENTITY_JOINED = 'TELEGRAM_ENTITY_JOINED',
3649
ENTITY_LEFT = 'TELEGRAM_ENTITY_LEFT',

src/utils.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,14 @@ export function convertMarkdownToTelegram(markdown: string): string {
7474

7575
// 1. Fenced code blocks (```...```)
7676
// Matches an optional language (letters only) and then any content until the closing ```
77-
converted = converted.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
77+
converted = converted.replace(/```(\w+)?\n([\s\S]*?)```/g, (_match, lang, code) => {
7878
const escapedCode = escapeCode(code);
7979
const formatted = '```' + (lang || '') + '\n' + escapedCode + '```';
8080
return storeReplacement(formatted);
8181
});
8282

8383
// 2. Inline code (`...`)
84-
converted = converted.replace(/`([^`]+)`/g, (match, code) => {
84+
converted = converted.replace(/`([^`]+)`/g, (_match, code) => {
8585
const escapedCode = escapeCode(code);
8686
const formatted = '`' + escapedCode + '`';
8787
return storeReplacement(formatted);
@@ -90,7 +90,7 @@ export function convertMarkdownToTelegram(markdown: string): string {
9090
// 3. Links: [link text](url)
9191
converted = converted.replace(
9292
/$begin:math:display$([^$end:math:display$]+)]$begin:math:text$([^)]+)$end:math:text$/g,
93-
(match, text, url) => {
93+
(_match, text, url) => {
9494
// For link text we escape as plain text.
9595
const formattedText = escapePlainText(text);
9696
const escapedURL = escapeUrl(url);
@@ -101,15 +101,15 @@ export function convertMarkdownToTelegram(markdown: string): string {
101101

102102
// 4. Bold text: standard markdown bold **text**
103103
// Telegram bold is delimited by single asterisks: *text*
104-
converted = converted.replace(/\*\*([^*]+)\*\*/g, (match, content) => {
104+
converted = converted.replace(/\*\*([^*]+)\*\*/g, (_match, content) => {
105105
const formattedContent = escapePlainText(content);
106106
const formatted = `*${formattedContent}*`;
107107
return storeReplacement(formatted);
108108
});
109109

110110
// 5. Strikethrough: standard markdown uses ~~text~~,
111111
// while Telegram uses ~text~
112-
converted = converted.replace(/~~([^~]+)~~/g, (match, content) => {
112+
converted = converted.replace(/~~([^~]+)~~/g, (_match, content) => {
113113
const formattedContent = escapePlainText(content);
114114
const formatted = `~${formattedContent}~`;
115115
return storeReplacement(formatted);
@@ -120,13 +120,13 @@ export function convertMarkdownToTelegram(markdown: string): string {
120120
// In Telegram MarkdownV2 italic must be delimited by underscores.
121121
// Process asterisk-based italic first.
122122
// (Using negative lookbehind/lookahead to avoid matching bold **)
123-
converted = converted.replace(/(?<!\*)\*([^*\n]+)\*(?!\*)/g, (match, content) => {
123+
converted = converted.replace(/(?<!\*)\*([^*\n]+)\*(?!\*)/g, (_match, content) => {
124124
const formattedContent = escapePlainText(content);
125125
const formatted = `_${formattedContent}_`;
126126
return storeReplacement(formatted);
127127
});
128128
// Then underscore-based italic.
129-
converted = converted.replace(/_([^_\n]+)_/g, (match, content) => {
129+
converted = converted.replace(/_([^_\n]+)_/g, (_match, content) => {
130130
const formattedContent = escapePlainText(content);
131131
const formatted = `_${formattedContent}_`;
132132
return storeReplacement(formatted);
@@ -135,7 +135,7 @@ export function convertMarkdownToTelegram(markdown: string): string {
135135
// 7. Headers: Convert markdown headers (lines starting with '#' characters)
136136
// to bold text. This avoids unescaped '#' characters (which crash Telegram)
137137
// by removing them and wrapping the rest of the line in bold markers.
138-
converted = converted.replace(/^(#{1,6})\s*(.*)$/gm, (match, hashes, headerContent: string) => {
138+
converted = converted.replace(/^(#{1,6})\s*(.*)$/gm, (_match, _hashes, headerContent: string) => {
139139
// Remove any trailing whitespace and escape the header text.
140140
const formatted = `*${escapePlainText(headerContent.trim())}*`;
141141
return storeReplacement(formatted);

tsconfig.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"moduleResolution": "Bundler",
99
"strict": true,
1010
"esModuleInterop": true,
11-
"skipLibCheck": true,
11+
"skipLibCheck": false,
1212
"forceConsistentCasingInFileNames": false,
1313
"allowImportingTsExtensions": true,
1414
"declaration": true,
@@ -20,7 +20,14 @@
2020
"noEmitOnError": false,
2121
"moduleDetection": "force",
2222
"allowArbitraryExtensions": true,
23-
"baseUrl": "."
23+
"noUnusedLocals": true,
24+
"noUnusedParameters": true,
25+
"baseUrl": ".",
26+
"typeRoots": ["./types", "./node_modules/@types"],
27+
"paths": {
28+
"@elizaos/core": ["../../core/src"],
29+
"@elizaos/core/*": ["../../core/src/*"]
30+
}
2431
},
2532
"include": ["src/**/*.ts"]
2633
}

0 commit comments

Comments
 (0)