morpheus-cli 0.4.11 → 0.4.13
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/channels/telegram.js +111 -93
- package/package.json +1 -1
|
@@ -19,6 +19,7 @@ import { Construtor } from '../runtime/tools/factory.js';
|
|
|
19
19
|
* Unsupported tags (e.g. tables) have their special chars escaped so they
|
|
20
20
|
* render as plain text instead of breaking the parse.
|
|
21
21
|
* Truncates to Telegram's 4096-char hard limit.
|
|
22
|
+
* Use for dynamic LLM/Oracle output.
|
|
22
23
|
*/
|
|
23
24
|
function toMd(text) {
|
|
24
25
|
const MAX = 4096;
|
|
@@ -26,6 +27,20 @@ function toMd(text) {
|
|
|
26
27
|
const safe = converted.length > MAX ? converted.slice(0, MAX - 3) + '\\.\\.\\.' : converted;
|
|
27
28
|
return { text: safe, parse_mode: 'MarkdownV2' };
|
|
28
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Escapes special characters in a plain string segment so it's safe to embed
|
|
32
|
+
* inside a manually-built MarkdownV2 message. Does NOT touch * _ ` [ ] chars
|
|
33
|
+
* (those are intentional MarkdownV2 formatting from our own code).
|
|
34
|
+
* Use for dynamic values (usernames, numbers, paths) interpolated into fixed templates.
|
|
35
|
+
*/
|
|
36
|
+
function escMd(value) {
|
|
37
|
+
// Escape all MarkdownV2 special characters that are NOT used as intentional
|
|
38
|
+
// formatters in our static templates (*bold*, _italic_, `code`, [link]).
|
|
39
|
+
// Per Telegram docs: _ * [ ] ( ) ~ ` # + - = | { } . ! must be escaped.
|
|
40
|
+
// We skip * _ ` [ ] here because those are our intentional formatters.
|
|
41
|
+
// The - must be at end of character class to avoid being treated as a range.
|
|
42
|
+
return String(value).replace(/([.!?(){}#+~|=>$@\\-])/g, '\\$1');
|
|
43
|
+
}
|
|
29
44
|
export class TelegramAdapter {
|
|
30
45
|
bot = null;
|
|
31
46
|
isConnected = false;
|
|
@@ -46,18 +61,18 @@ export class TelegramAdapter {
|
|
|
46
61
|
this.rateLimiter.set(userId, now);
|
|
47
62
|
return false;
|
|
48
63
|
}
|
|
49
|
-
HELP_MESSAGE = `/start
|
|
50
|
-
/status
|
|
51
|
-
/doctor
|
|
52
|
-
/stats
|
|
53
|
-
/help
|
|
54
|
-
/zaion
|
|
55
|
-
/sati <qnt>
|
|
56
|
-
/newsession
|
|
57
|
-
/sessions
|
|
58
|
-
/restart
|
|
59
|
-
/mcpreload
|
|
60
|
-
/mcp or /mcps
|
|
64
|
+
HELP_MESSAGE = `/start \\- Show this welcome message and available commands
|
|
65
|
+
/status \\- Check the status of the Morpheus agent
|
|
66
|
+
/doctor \\- Diagnose environment and configuration issues
|
|
67
|
+
/stats \\- Show token usage statistics
|
|
68
|
+
/help \\- Show available commands
|
|
69
|
+
/zaion \\- Show system configurations
|
|
70
|
+
/sati <qnt> \\- Show specific memories
|
|
71
|
+
/newsession \\- Archive current session and start fresh
|
|
72
|
+
/sessions \\- List all sessions with titles and switch between them
|
|
73
|
+
/restart \\- Restart the Morpheus agent
|
|
74
|
+
/mcpreload \\- Reload MCP servers without restarting
|
|
75
|
+
/mcp or /mcps \\- List registered MCP servers`;
|
|
61
76
|
constructor(oracle) {
|
|
62
77
|
this.oracle = oracle;
|
|
63
78
|
}
|
|
@@ -249,7 +264,7 @@ export class TelegramAdapter {
|
|
|
249
264
|
const data = ctx.callbackQuery.data;
|
|
250
265
|
const sessionId = data.replace('ask_archive_session_', '');
|
|
251
266
|
// Fetch session title for better UX (optional, but nice) - for now just use ID
|
|
252
|
-
await ctx.reply(`⚠️
|
|
267
|
+
await ctx.reply(`⚠️ *ARCHIVE SESSION?*\n\nAre you sure you want to archive session \`${escMd(sessionId)}\`?\n\nIt will be moved to long\\-term memory \\(SATI\\) and removed from the active list\\. This action cannot be easily undone via Telegram\\.`, {
|
|
253
268
|
parse_mode: 'MarkdownV2',
|
|
254
269
|
reply_markup: {
|
|
255
270
|
inline_keyboard: [
|
|
@@ -272,7 +287,7 @@ export class TelegramAdapter {
|
|
|
272
287
|
if (ctx.updateType === 'callback_query') {
|
|
273
288
|
ctx.deleteMessage().catch(() => { });
|
|
274
289
|
}
|
|
275
|
-
await ctx.reply(`✅ Session \`${sessionId}\` has been archived and moved to long
|
|
290
|
+
await ctx.reply(`✅ Session \`${escMd(sessionId)}\` has been archived and moved to long\\-term memory\\.`, { parse_mode: 'MarkdownV2' });
|
|
276
291
|
}
|
|
277
292
|
catch (error) {
|
|
278
293
|
await ctx.answerCbQuery(`Error archiving: ${error.message}`, { show_alert: true });
|
|
@@ -282,7 +297,7 @@ export class TelegramAdapter {
|
|
|
282
297
|
this.bot.action(/^ask_delete_session_/, async (ctx) => {
|
|
283
298
|
const data = ctx.callbackQuery.data;
|
|
284
299
|
const sessionId = data.replace('ask_delete_session_', '');
|
|
285
|
-
await ctx.reply(`🚫
|
|
300
|
+
await ctx.reply(`🚫 *DELETE SESSION?*\n\nAre you sure you want to PERMANENTLY DELETE session \`${escMd(sessionId)}\`?\n\nThis action is *IRREVERSIBLE*\\. All data will be lost\\.`, {
|
|
286
301
|
parse_mode: 'MarkdownV2',
|
|
287
302
|
reply_markup: {
|
|
288
303
|
inline_keyboard: [
|
|
@@ -305,7 +320,7 @@ export class TelegramAdapter {
|
|
|
305
320
|
if (ctx.updateType === 'callback_query') {
|
|
306
321
|
ctx.deleteMessage().catch(() => { });
|
|
307
322
|
}
|
|
308
|
-
await ctx.reply(`🗑️ Session \`${sessionId}\` has been permanently deleted
|
|
323
|
+
await ctx.reply(`🗑️ Session \`${escMd(sessionId)}\` has been permanently deleted\\.`, { parse_mode: 'MarkdownV2' });
|
|
309
324
|
}
|
|
310
325
|
catch (error) {
|
|
311
326
|
await ctx.answerCbQuery(`Error deleting: ${error.message}`, { show_alert: true });
|
|
@@ -402,17 +417,22 @@ export class TelegramAdapter {
|
|
|
402
417
|
this.display.log('No allowed Telegram users configured — skipping notification.', { source: 'Telegram', level: 'warning' });
|
|
403
418
|
return;
|
|
404
419
|
}
|
|
405
|
-
//
|
|
406
|
-
const
|
|
407
|
-
const safeText = text.length > MAX_LEN ? text.slice(0, MAX_LEN - 3) + '...' : text;
|
|
420
|
+
// toMd() already truncates to 4096 chars (Telegram's hard limit)
|
|
421
|
+
const { text: mdText, parse_mode } = toMd(text);
|
|
408
422
|
for (const userId of allowedUsers) {
|
|
409
423
|
try {
|
|
410
|
-
|
|
411
|
-
// causes "Can't find end of entity" errors with parse_mode: 'MarkdownV2'.
|
|
412
|
-
await this.bot.telegram.sendMessage(userId, safeText);
|
|
424
|
+
await this.bot.telegram.sendMessage(userId, mdText, { parse_mode });
|
|
413
425
|
}
|
|
414
|
-
catch
|
|
415
|
-
|
|
426
|
+
catch {
|
|
427
|
+
// Fallback to plain text if MarkdownV2 conversion still fails
|
|
428
|
+
try {
|
|
429
|
+
const MAX_LEN = 4096;
|
|
430
|
+
const plain = text.length > MAX_LEN ? text.slice(0, MAX_LEN - 3) + '...' : text;
|
|
431
|
+
await this.bot.telegram.sendMessage(userId, plain);
|
|
432
|
+
}
|
|
433
|
+
catch (err) {
|
|
434
|
+
this.display.log(`Failed to send message to Telegram user ${userId}: ${err.message}`, { source: 'Telegram', level: 'error' });
|
|
435
|
+
}
|
|
416
436
|
}
|
|
417
437
|
}
|
|
418
438
|
}
|
|
@@ -486,7 +506,7 @@ export class TelegramAdapter {
|
|
|
486
506
|
}
|
|
487
507
|
async handleNewSessionCommand(ctx, user) {
|
|
488
508
|
try {
|
|
489
|
-
await ctx.reply("Are you ready to start a new session
|
|
509
|
+
await ctx.reply("Are you ready to start a new session\\? Please confirm\\.", {
|
|
490
510
|
parse_mode: 'MarkdownV2', reply_markup: {
|
|
491
511
|
inline_keyboard: [
|
|
492
512
|
[{ text: 'Yes, start new session', callback_data: 'confirm_new_session' }, { text: 'No, cancel', callback_data: 'cancel_new_session' }]
|
|
@@ -513,7 +533,7 @@ export class TelegramAdapter {
|
|
|
513
533
|
const history = new SQLiteChatMessageHistory({ sessionId: "" });
|
|
514
534
|
const sessions = await history.listSessions();
|
|
515
535
|
if (sessions.length === 0) {
|
|
516
|
-
await ctx.reply('No active or paused sessions found
|
|
536
|
+
await ctx.reply('No active or paused sessions found\\.', { parse_mode: 'MarkdownV2' });
|
|
517
537
|
return;
|
|
518
538
|
}
|
|
519
539
|
let response = '*Sessions:*\n\n';
|
|
@@ -521,10 +541,10 @@ export class TelegramAdapter {
|
|
|
521
541
|
for (const session of sessions) {
|
|
522
542
|
const title = session.title || 'Untitled Session';
|
|
523
543
|
const statusEmoji = session.status === 'active' ? '🟢' : '🟡';
|
|
524
|
-
response += `${statusEmoji} *${title}*\n`;
|
|
525
|
-
response +=
|
|
526
|
-
response +=
|
|
527
|
-
response +=
|
|
544
|
+
response += `${statusEmoji} *${escMd(title)}*\n`;
|
|
545
|
+
response += `\\- ID: ${escMd(session.id)}\n`;
|
|
546
|
+
response += `\\- Status: ${escMd(session.status)}\n`;
|
|
547
|
+
response += `\\- Started: ${escMd(new Date(session.started_at).toLocaleString())}\n\n`;
|
|
528
548
|
// Adicionar botão inline para alternar para esta sessão
|
|
529
549
|
const sessionButtons = [];
|
|
530
550
|
if (session.status !== 'active') {
|
|
@@ -588,10 +608,10 @@ How can I assist you today?`;
|
|
|
588
608
|
const nodeVersion = process.version;
|
|
589
609
|
const majorVersion = parseInt(nodeVersion.replace('v', '').split('.')[0], 10);
|
|
590
610
|
if (majorVersion >= 18) {
|
|
591
|
-
response +=
|
|
611
|
+
response += `✅ Node\\.js: ${escMd(nodeVersion)}\n`;
|
|
592
612
|
}
|
|
593
613
|
else {
|
|
594
|
-
response +=
|
|
614
|
+
response += `❌ Node\\.js: ${escMd(nodeVersion)} \\(Required: >=18\\)\n`;
|
|
595
615
|
}
|
|
596
616
|
if (config) {
|
|
597
617
|
response += '✅ Configuration: Valid\n';
|
|
@@ -613,10 +633,10 @@ How can I assist you today?`;
|
|
|
613
633
|
const llmProvider = config.llm?.provider;
|
|
614
634
|
if (llmProvider && llmProvider !== 'ollama') {
|
|
615
635
|
if (hasApiKey(llmProvider, config.llm?.api_key)) {
|
|
616
|
-
response += `✅ Oracle API key (${llmProvider})\n`;
|
|
636
|
+
response += `✅ Oracle API key \\(${escMd(llmProvider)}\\)\n`;
|
|
617
637
|
}
|
|
618
638
|
else {
|
|
619
|
-
response += `❌ Oracle API key missing (${llmProvider})\n`;
|
|
639
|
+
response += `❌ Oracle API key missing \\(${escMd(llmProvider)}\\)\n`;
|
|
620
640
|
}
|
|
621
641
|
}
|
|
622
642
|
// Sati
|
|
@@ -624,10 +644,10 @@ How can I assist you today?`;
|
|
|
624
644
|
const satiProvider = sati?.provider || llmProvider;
|
|
625
645
|
if (satiProvider && satiProvider !== 'ollama') {
|
|
626
646
|
if (hasApiKey(satiProvider, sati?.api_key ?? config.llm?.api_key)) {
|
|
627
|
-
response += `✅ Sati API key (${satiProvider})\n`;
|
|
647
|
+
response += `✅ Sati API key \\(${escMd(satiProvider)}\\)\n`;
|
|
628
648
|
}
|
|
629
649
|
else {
|
|
630
|
-
response += `❌ Sati API key missing (${satiProvider})\n`;
|
|
650
|
+
response += `❌ Sati API key missing \\(${escMd(satiProvider)}\\)\n`;
|
|
631
651
|
}
|
|
632
652
|
}
|
|
633
653
|
// Apoc
|
|
@@ -635,10 +655,10 @@ How can I assist you today?`;
|
|
|
635
655
|
const apocProvider = apoc?.provider || llmProvider;
|
|
636
656
|
if (apocProvider && apocProvider !== 'ollama') {
|
|
637
657
|
if (hasApiKey(apocProvider, apoc?.api_key ?? config.llm?.api_key)) {
|
|
638
|
-
response += `✅ Apoc API key (${apocProvider})\n`;
|
|
658
|
+
response += `✅ Apoc API key \\(${escMd(apocProvider)}\\)\n`;
|
|
639
659
|
}
|
|
640
660
|
else {
|
|
641
|
-
response += `❌ Apoc API key missing (${apocProvider})\n`;
|
|
661
|
+
response += `❌ Apoc API key missing \\(${escMd(apocProvider)}\\)\n`;
|
|
642
662
|
}
|
|
643
663
|
}
|
|
644
664
|
// Telegram token
|
|
@@ -682,31 +702,31 @@ How can I assist you today?`;
|
|
|
682
702
|
const totalAudioSeconds = groupedStats.reduce((sum, s) => sum + (s.totalAudioSeconds || 0), 0);
|
|
683
703
|
const totalCost = stats.totalEstimatedCostUsd;
|
|
684
704
|
let response = '*Token Usage Statistics*\n\n';
|
|
685
|
-
response += `Input Tokens: ${stats.totalInputTokens.toLocaleString()}\n`;
|
|
686
|
-
response += `Output Tokens: ${stats.totalOutputTokens.toLocaleString()}\n`;
|
|
687
|
-
response += `Total Tokens: ${totalTokens.toLocaleString()}\n`;
|
|
705
|
+
response += `Input Tokens: ${escMd(stats.totalInputTokens.toLocaleString())}\n`;
|
|
706
|
+
response += `Output Tokens: ${escMd(stats.totalOutputTokens.toLocaleString())}\n`;
|
|
707
|
+
response += `Total Tokens: ${escMd(totalTokens.toLocaleString())}\n`;
|
|
688
708
|
if (totalAudioSeconds > 0) {
|
|
689
|
-
response += `Audio Processed: ${totalAudioSeconds.toFixed(1)}s\n`;
|
|
709
|
+
response += `Audio Processed: ${escMd(totalAudioSeconds.toFixed(1))}s\n`;
|
|
690
710
|
}
|
|
691
711
|
if (totalCost != null) {
|
|
692
|
-
response += `Estimated Cost:
|
|
712
|
+
response += `Estimated Cost: \\$${escMd(totalCost.toFixed(4))}\n`;
|
|
693
713
|
}
|
|
694
714
|
response += '\n';
|
|
695
715
|
if (groupedStats.length > 0) {
|
|
696
716
|
response += '*By Provider/Model:*\n';
|
|
697
717
|
for (const stat of groupedStats) {
|
|
698
|
-
response += `\n*${stat.provider}/${stat.model}*\n`;
|
|
699
|
-
response += ` Tokens: ${stat.totalTokens.toLocaleString()} (${stat.messageCount} msgs)\n`;
|
|
718
|
+
response += `\n*${escMd(stat.provider)}/${escMd(stat.model)}*\n`;
|
|
719
|
+
response += ` Tokens: ${escMd(stat.totalTokens.toLocaleString())} \\(${escMd(stat.messageCount)} msgs\\)\n`;
|
|
700
720
|
if (stat.totalAudioSeconds > 0) {
|
|
701
|
-
response += ` Audio: ${stat.totalAudioSeconds.toFixed(1)}s\n`;
|
|
721
|
+
response += ` Audio: ${escMd(stat.totalAudioSeconds.toFixed(1))}s\n`;
|
|
702
722
|
}
|
|
703
723
|
if (stat.estimatedCostUsd != null) {
|
|
704
|
-
response += ` Cost:
|
|
724
|
+
response += ` Cost: \\$${escMd(stat.estimatedCostUsd.toFixed(4))}\n`;
|
|
705
725
|
}
|
|
706
726
|
}
|
|
707
727
|
}
|
|
708
728
|
else {
|
|
709
|
-
response += 'No detailed usage statistics available
|
|
729
|
+
response += 'No detailed usage statistics available\\.';
|
|
710
730
|
}
|
|
711
731
|
await ctx.reply(response, { parse_mode: 'MarkdownV2' });
|
|
712
732
|
history.close();
|
|
@@ -725,7 +745,7 @@ How can I assist you today?`;
|
|
|
725
745
|
let response = await this.oracle.chat(prompt);
|
|
726
746
|
if (response) {
|
|
727
747
|
try {
|
|
728
|
-
await ctx.reply(response, { parse_mode: 'MarkdownV2' });
|
|
748
|
+
await ctx.reply(toMd(response).text, { parse_mode: 'MarkdownV2' });
|
|
729
749
|
}
|
|
730
750
|
catch {
|
|
731
751
|
await ctx.reply(response);
|
|
@@ -734,62 +754,57 @@ How can I assist you today?`;
|
|
|
734
754
|
// await ctx.reply(`Command not recognized. Type /help to see available commands.`);
|
|
735
755
|
}
|
|
736
756
|
async handleHelpCommand(ctx, user) {
|
|
737
|
-
const helpMessage =
|
|
738
|
-
*Available Commands:*
|
|
739
|
-
|
|
740
|
-
${this.HELP_MESSAGE}
|
|
741
|
-
|
|
742
|
-
How can I assist you today?`;
|
|
757
|
+
const helpMessage = `*Available Commands:*\n\n${this.HELP_MESSAGE}\n\nHow can I assist you today\\?`;
|
|
743
758
|
await ctx.reply(helpMessage, { parse_mode: 'MarkdownV2' });
|
|
744
759
|
}
|
|
745
760
|
async handleZaionCommand(ctx, user) {
|
|
746
761
|
const config = this.config.get();
|
|
747
762
|
let response = '*System Configuration*\n\n';
|
|
748
763
|
response += `*Agent:*\n`;
|
|
749
|
-
response +=
|
|
750
|
-
response +=
|
|
751
|
-
response += `*Oracle (LLM):*\n`;
|
|
752
|
-
response +=
|
|
753
|
-
response +=
|
|
754
|
-
response +=
|
|
755
|
-
response +=
|
|
764
|
+
response += `\\- Name: ${escMd(config.agent.name)}\n`;
|
|
765
|
+
response += `\\- Personality: ${escMd(config.agent.personality)}\n\n`;
|
|
766
|
+
response += `*Oracle \\(LLM\\):*\n`;
|
|
767
|
+
response += `\\- Provider: ${escMd(config.llm.provider)}\n`;
|
|
768
|
+
response += `\\- Model: ${escMd(config.llm.model)}\n`;
|
|
769
|
+
response += `\\- Temperature: ${escMd(config.llm.temperature)}\n`;
|
|
770
|
+
response += `\\- Context Window: ${escMd(config.llm.context_window || 100)}\n\n`;
|
|
756
771
|
// Sati config (falls back to llm if not set)
|
|
757
772
|
const sati = config.sati;
|
|
758
|
-
response += `*Sati (Memory):*\n`;
|
|
773
|
+
response += `*Sati \\(Memory\\):*\n`;
|
|
759
774
|
if (sati?.provider) {
|
|
760
|
-
response +=
|
|
761
|
-
response +=
|
|
762
|
-
response +=
|
|
763
|
-
response +=
|
|
775
|
+
response += `\\- Provider: ${escMd(sati.provider)}\n`;
|
|
776
|
+
response += `\\- Model: ${escMd(sati.model || config.llm.model)}\n`;
|
|
777
|
+
response += `\\- Temperature: ${escMd(sati.temperature ?? config.llm.temperature)}\n`;
|
|
778
|
+
response += `\\- Memory Limit: ${escMd(sati.memory_limit ?? 1000)}\n`;
|
|
764
779
|
}
|
|
765
780
|
else {
|
|
766
|
-
response +=
|
|
781
|
+
response += `\\- Inherits Oracle config\n`;
|
|
767
782
|
}
|
|
768
783
|
response += '\n';
|
|
769
784
|
// Apoc config (falls back to llm if not set)
|
|
770
785
|
const apoc = config.apoc;
|
|
771
|
-
response += `*Apoc (DevTools):*\n`;
|
|
786
|
+
response += `*Apoc \\(DevTools\\):*\n`;
|
|
772
787
|
if (apoc?.provider) {
|
|
773
|
-
response +=
|
|
774
|
-
response +=
|
|
775
|
-
response +=
|
|
788
|
+
response += `\\- Provider: ${escMd(apoc.provider)}\n`;
|
|
789
|
+
response += `\\- Model: ${escMd(apoc.model || config.llm.model)}\n`;
|
|
790
|
+
response += `\\- Temperature: ${escMd(apoc.temperature ?? 0.2)}\n`;
|
|
776
791
|
if (apoc.working_dir)
|
|
777
|
-
response +=
|
|
778
|
-
response +=
|
|
792
|
+
response += `\\- Working Dir: ${escMd(apoc.working_dir)}\n`;
|
|
793
|
+
response += `\\- Timeout: ${escMd(apoc.timeout_ms ?? 30000)}ms\n`;
|
|
779
794
|
}
|
|
780
795
|
else {
|
|
781
|
-
response +=
|
|
796
|
+
response += `\\- Inherits Oracle config\n`;
|
|
782
797
|
}
|
|
783
798
|
response += '\n';
|
|
784
799
|
response += `*Channels:*\n`;
|
|
785
|
-
response +=
|
|
786
|
-
response +=
|
|
800
|
+
response += `\\- Telegram Enabled: ${escMd(config.channels.telegram.enabled)}\n`;
|
|
801
|
+
response += `\\- Discord Enabled: ${escMd(config.channels.discord.enabled)}\n\n`;
|
|
787
802
|
response += `*UI:*\n`;
|
|
788
|
-
response +=
|
|
789
|
-
response +=
|
|
803
|
+
response += `\\- Enabled: ${escMd(config.ui.enabled)}\n`;
|
|
804
|
+
response += `\\- Port: ${escMd(config.ui.port)}\n\n`;
|
|
790
805
|
response += `*Audio:*\n`;
|
|
791
|
-
response +=
|
|
792
|
-
response +=
|
|
806
|
+
response += `\\- Enabled: ${escMd(config.audio.enabled)}\n`;
|
|
807
|
+
response += `\\- Max Duration: ${escMd(config.audio.maxDurationSeconds)}s\n`;
|
|
793
808
|
await ctx.reply(response, { parse_mode: 'MarkdownV2' });
|
|
794
809
|
}
|
|
795
810
|
async handleSatiCommand(ctx, user, args) {
|
|
@@ -814,11 +829,14 @@ How can I assist you today?`;
|
|
|
814
829
|
if (limit !== null) {
|
|
815
830
|
selectedMemories = memories.slice(0, Math.min(limit, memories.length));
|
|
816
831
|
}
|
|
817
|
-
|
|
832
|
+
const countLabel = limit !== null
|
|
833
|
+
? `${escMd(selectedMemories.length)} SATI Memories \\(Showing first ${escMd(selectedMemories.length)}\\)`
|
|
834
|
+
: `${escMd(selectedMemories.length)} SATI Memories`;
|
|
835
|
+
let response = `*${countLabel}:*\n\n`;
|
|
818
836
|
for (const memory of selectedMemories) {
|
|
819
837
|
// Limitar o tamanho do resumo para evitar mensagens muito longas
|
|
820
838
|
const truncatedSummary = memory.summary.length > 200 ? memory.summary.substring(0, 200) + '...' : memory.summary;
|
|
821
|
-
response += `*${memory.category} (${memory.importance}):* ${truncatedSummary}\n\n`;
|
|
839
|
+
response += `*${escMd(memory.category)} \\(${escMd(memory.importance)}\\):* ${escMd(truncatedSummary)}\n\n`;
|
|
822
840
|
}
|
|
823
841
|
await ctx.reply(response, { parse_mode: 'MarkdownV2' });
|
|
824
842
|
}
|
|
@@ -914,11 +932,11 @@ How can I assist you today?`;
|
|
|
914
932
|
Construtor.probe(),
|
|
915
933
|
]);
|
|
916
934
|
if (servers.length === 0) {
|
|
917
|
-
await ctx.reply('*No MCP Servers Configured*\n\nThere are currently no MCP servers configured in the system
|
|
935
|
+
await ctx.reply('*No MCP Servers Configured*\n\nThere are currently no MCP servers configured in the system\\.', { parse_mode: 'MarkdownV2' });
|
|
918
936
|
return;
|
|
919
937
|
}
|
|
920
938
|
const probeMap = new Map(probeResults.map(r => [r.name, r]));
|
|
921
|
-
let response = `*MCP Servers (${servers.length})*\n\n`;
|
|
939
|
+
let response = `*MCP Servers \\(${escMd(servers.length)}\\)*\n\n`;
|
|
922
940
|
const keyboard = [];
|
|
923
941
|
servers.forEach((server, index) => {
|
|
924
942
|
const enabledStatus = server.enabled ? '✅ Enabled' : '❌ Disabled';
|
|
@@ -926,25 +944,25 @@ How can I assist you today?`;
|
|
|
926
944
|
const probe = probeMap.get(server.name);
|
|
927
945
|
const connectionStatus = probe
|
|
928
946
|
? probe.ok
|
|
929
|
-
? `🟢 Connected (${probe.toolCount} tools)`
|
|
947
|
+
? `🟢 Connected \\(${escMd(probe.toolCount)} tools\\)`
|
|
930
948
|
: `🔴 Failed`
|
|
931
949
|
: '⚪ Unknown';
|
|
932
|
-
response += `*${index + 1}
|
|
950
|
+
response += `*${escMd(index + 1)}\\. ${escMd(server.name)}*\n`;
|
|
933
951
|
response += `Status: ${enabledStatus}\n`;
|
|
934
952
|
response += `Connection: ${connectionStatus}\n`;
|
|
935
|
-
response += `Transport: ${transport}\n`;
|
|
953
|
+
response += `Transport: ${escMd(transport)}\n`;
|
|
936
954
|
if (server.config.transport === 'stdio') {
|
|
937
|
-
response += `Command: \`${server.config.command}\`\n`;
|
|
955
|
+
response += `Command: \`${escMd(server.config.command)}\`\n`;
|
|
938
956
|
if (server.config.args && server.config.args.length > 0) {
|
|
939
|
-
response += `Args: \`${server.config.args.join(' ')}\`\n`;
|
|
957
|
+
response += `Args: \`${escMd(server.config.args.join(' '))}\`\n`;
|
|
940
958
|
}
|
|
941
959
|
}
|
|
942
960
|
else if (server.config.transport === 'http') {
|
|
943
|
-
response += `URL: \`${server.config.url}\`\n`;
|
|
961
|
+
response += `URL: \`${escMd(server.config.url)}\`\n`;
|
|
944
962
|
}
|
|
945
963
|
if (probe && !probe.ok && probe.error) {
|
|
946
964
|
const shortError = probe.error.length > 80 ? probe.error.slice(0, 80) + '…' : probe.error;
|
|
947
|
-
response += `Error: \`${shortError}\`\n`;
|
|
965
|
+
response += `Error: \`${escMd(shortError)}\`\n`;
|
|
948
966
|
}
|
|
949
967
|
response += '\n';
|
|
950
968
|
if (server.enabled) {
|
|
@@ -961,7 +979,7 @@ How can I assist you today?`;
|
|
|
961
979
|
}
|
|
962
980
|
catch (error) {
|
|
963
981
|
this.display.log('Error listing MCP servers: ' + (error instanceof Error ? error.message : String(error)), { source: 'Telegram', level: 'error' });
|
|
964
|
-
await ctx.reply('An error occurred while retrieving the list of MCP servers
|
|
982
|
+
await ctx.reply('An error occurred while retrieving the list of MCP servers\\. Please check the logs for more details\\.', { parse_mode: 'MarkdownV2' });
|
|
965
983
|
}
|
|
966
984
|
}
|
|
967
985
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "morpheus-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
4
|
"description": "Morpheus is a local AI agent for developers, running as a CLI daemon that connects to LLMs, local tools, and MCPs, enabling interaction via Terminal, Telegram, and Discord. Inspired by the character Morpheus from *The Matrix*, the project acts as an intelligent orchestrator, bridging the gap between the developer and complex systems.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"morpheus": "./bin/morpheus.js"
|