@saccolabs/tars 1.7.8 → 1.8.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/dist/supervisor/gemini-engine.d.ts +1 -1
- package/dist/supervisor/gemini-engine.js +41 -11
- package/dist/supervisor/gemini-engine.js.map +1 -1
- package/dist/supervisor/main.js +4 -3
- package/dist/supervisor/main.js.map +1 -1
- package/dist/supervisor/session-manager.d.ts +4 -0
- package/dist/supervisor/session-manager.js +25 -5
- package/dist/supervisor/session-manager.js.map +1 -1
- package/dist/supervisor/supervisor.js +2 -2
- package/dist/supervisor/supervisor.js.map +1 -1
- package/package.json +1 -1
- package/dist/discord/discord-bot.d.ts +0 -37
- package/dist/discord/discord-bot.js +0 -210
- package/dist/discord/discord-bot.js.map +0 -1
- package/dist/discord/message-formatter.d.ts +0 -95
- package/dist/discord/message-formatter.js +0 -482
- package/dist/discord/message-formatter.js.map +0 -1
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import { Client, GatewayIntentBits, ChannelType, Partials } from 'discord.js';
|
|
2
|
-
import logger from '../utils/logger.js';
|
|
3
|
-
import { MessageFormatter } from './message-formatter.js';
|
|
4
|
-
import { AttachmentProcessor } from '../utils/attachment-processor.js';
|
|
5
|
-
/**
|
|
6
|
-
* Discord bot wrapper for Tars
|
|
7
|
-
*/
|
|
8
|
-
export class DiscordBot {
|
|
9
|
-
config;
|
|
10
|
-
client;
|
|
11
|
-
supervisor;
|
|
12
|
-
processor;
|
|
13
|
-
lastChannelId = null;
|
|
14
|
-
constructor(supervisor, config) {
|
|
15
|
-
this.config = config;
|
|
16
|
-
this.supervisor = supervisor;
|
|
17
|
-
this.processor = new AttachmentProcessor(config);
|
|
18
|
-
this.client = new Client({
|
|
19
|
-
intents: [
|
|
20
|
-
GatewayIntentBits.Guilds,
|
|
21
|
-
GatewayIntentBits.GuildMessages,
|
|
22
|
-
GatewayIntentBits.MessageContent,
|
|
23
|
-
GatewayIntentBits.DirectMessages
|
|
24
|
-
],
|
|
25
|
-
partials: [Partials.Channel, Partials.Message]
|
|
26
|
-
});
|
|
27
|
-
this.setupEventHandlers();
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Start the Discord bot
|
|
31
|
-
*/
|
|
32
|
-
async start() {
|
|
33
|
-
await this.client.login(this.config.discordToken);
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Stop the Discord bot
|
|
37
|
-
*/
|
|
38
|
-
async stop() {
|
|
39
|
-
this.client.destroy();
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Send a proactive notification to the primary contact
|
|
43
|
-
*/
|
|
44
|
-
async notify(content) {
|
|
45
|
-
if (!this.config.discordOwnerId || !content.trim())
|
|
46
|
-
return;
|
|
47
|
-
try {
|
|
48
|
-
const user = await this.client.users.fetch(this.config.discordOwnerId);
|
|
49
|
-
if (user) {
|
|
50
|
-
const formatted = MessageFormatter.format(content);
|
|
51
|
-
if (formatted.length > 8000) {
|
|
52
|
-
const filePath = this.processor.saveResponse(content, 'md');
|
|
53
|
-
await user.send({
|
|
54
|
-
content: `🔔 **Task Notification** (Response too long, see attached):`,
|
|
55
|
-
files: [filePath]
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
const chunks = MessageFormatter.split(formatted);
|
|
60
|
-
for (let i = 0; i < chunks.length; i++) {
|
|
61
|
-
const prefix = i === 0 ? `🔔 **Task Notification:**\n` : ``;
|
|
62
|
-
await user.send(prefix + chunks[i]);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
catch (e) {
|
|
68
|
-
logger.error(`Failed to send proactive notification: ${e.message}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Setup event handlers
|
|
73
|
-
*/
|
|
74
|
-
setupEventHandlers() {
|
|
75
|
-
this.client.once('clientReady', (c) => {
|
|
76
|
-
logger.info(`🚀 ${this.config.assistantName} online as ${c.user.tag}`);
|
|
77
|
-
logger.info(`🧠 Gemini Model: ${this.config.geminiModel}`);
|
|
78
|
-
if (this.config.discordOwnerId) {
|
|
79
|
-
logger.info(`👤 Primary Contact ID: ${this.config.discordOwnerId}`);
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
logger.warn(`⚠️ No Primary Contact ID set. Will bind to the first user who sends a message.`);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
this.client.on('messageCreate', this.handleMessage.bind(this));
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Handle incoming messages
|
|
89
|
-
*/
|
|
90
|
-
async handleMessage(message) {
|
|
91
|
-
if (message.author.bot)
|
|
92
|
-
return;
|
|
93
|
-
const userPrompt = this.extractPrompt(message);
|
|
94
|
-
// If null, message wasn't for us. If empty string, check for attachments.
|
|
95
|
-
if (userPrompt === null)
|
|
96
|
-
return;
|
|
97
|
-
// Auto-Bind on first interaction if not set
|
|
98
|
-
if (!this.config.discordOwnerId) {
|
|
99
|
-
this.config.discordOwnerId = message.author.id;
|
|
100
|
-
this.config.saveSettings();
|
|
101
|
-
logger.info(`🔒 Automatically bound Primary Contact to user: ${message.author.id}`);
|
|
102
|
-
await message.reply(`🔒 **System Alert:** I have permanently bound my background notification channel to your account. I will send proactive alerts here.`);
|
|
103
|
-
}
|
|
104
|
-
if (!userPrompt && message.attachments.size === 0)
|
|
105
|
-
return;
|
|
106
|
-
logger.info(`Received request from ${message.author.tag}: "${userPrompt || '[Attachment Only]'}"`);
|
|
107
|
-
// Handle Attachments
|
|
108
|
-
const attachments = [];
|
|
109
|
-
let attachmentContextText = '';
|
|
110
|
-
if (message.attachments.size > 0) {
|
|
111
|
-
for (const [id, attachment] of message.attachments) {
|
|
112
|
-
try {
|
|
113
|
-
const filePath = await this.processor.download(attachment);
|
|
114
|
-
if (attachment.contentType) {
|
|
115
|
-
attachments.push({
|
|
116
|
-
path: filePath,
|
|
117
|
-
mimeType: attachment.contentType
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
attachmentContextText += `\n[User attached file (${attachment.contentType}): ${filePath}]`;
|
|
121
|
-
}
|
|
122
|
-
catch (err) {
|
|
123
|
-
logger.error(`Failed to download attachment: ${err.message}`);
|
|
124
|
-
await message.reply(`⚠️ Failed to download ${attachment.name}: ${err.message}`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
const fullPrompt = `${userPrompt}${attachmentContextText}`.trim();
|
|
129
|
-
if (!fullPrompt && attachments.length === 0)
|
|
130
|
-
return;
|
|
131
|
-
let typingInterval = null;
|
|
132
|
-
// Start typing indicator loop (Discord typing status lasts 10s)
|
|
133
|
-
if ('sendTyping' in message.channel) {
|
|
134
|
-
// Initial typing
|
|
135
|
-
await message.channel.sendTyping().catch(() => { });
|
|
136
|
-
// Loop every 9s to keep it active
|
|
137
|
-
typingInterval = setInterval(() => {
|
|
138
|
-
if ('sendTyping' in message.channel) {
|
|
139
|
-
message.channel.sendTyping().catch(() => { });
|
|
140
|
-
}
|
|
141
|
-
}, 9000);
|
|
142
|
-
}
|
|
143
|
-
try {
|
|
144
|
-
let fullResponse = '';
|
|
145
|
-
await this.supervisor.run(fullPrompt, async (event) => {
|
|
146
|
-
if ((event.type === 'text' || event.type === 'message') &&
|
|
147
|
-
event.content &&
|
|
148
|
-
event.role !== 'user') {
|
|
149
|
-
fullResponse += event.content;
|
|
150
|
-
}
|
|
151
|
-
else if (event.type === 'error') {
|
|
152
|
-
await message.reply(`❌ **Error:** ${event.error}`);
|
|
153
|
-
}
|
|
154
|
-
else if (event.type === 'done') {
|
|
155
|
-
if (fullResponse.trim()) {
|
|
156
|
-
const formatted = MessageFormatter.format(fullResponse);
|
|
157
|
-
if (formatted.length > 8000) {
|
|
158
|
-
const filePath = this.processor.saveResponse(fullResponse, 'md');
|
|
159
|
-
await message.reply({
|
|
160
|
-
content: `📄 **Response too long** (${formatted.length} chars). See attached file:`,
|
|
161
|
-
files: [filePath]
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
const chunks = MessageFormatter.split(formatted);
|
|
166
|
-
for (const chunk of chunks) {
|
|
167
|
-
await message.reply(chunk);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
logger.warn('Gemini returned an empty response.');
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}, undefined, attachments);
|
|
176
|
-
}
|
|
177
|
-
catch (error) {
|
|
178
|
-
logger.error(`Discord handling error: ${error.message}`);
|
|
179
|
-
await message.reply(`❌ **Supervisor Error:** ${error.message}`);
|
|
180
|
-
}
|
|
181
|
-
finally {
|
|
182
|
-
if (typingInterval)
|
|
183
|
-
clearInterval(typingInterval);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Extract prompt and handle prefix
|
|
188
|
-
*/
|
|
189
|
-
extractPrompt(message) {
|
|
190
|
-
const isDM = message.channel.type === ChannelType.DM;
|
|
191
|
-
const isMentioned = this.client.user && message.mentions.has(this.client.user);
|
|
192
|
-
const customPrefix = `!${this.config.assistantName.toLowerCase()}`;
|
|
193
|
-
const hasCustomCommand = message.content.toLowerCase().startsWith(customPrefix);
|
|
194
|
-
const hasLegacyCommand = message.content.toLowerCase().startsWith('!tars');
|
|
195
|
-
if (!isDM && !isMentioned && !hasCustomCommand && !hasLegacyCommand)
|
|
196
|
-
return null;
|
|
197
|
-
let prompt = message.content;
|
|
198
|
-
if (hasCustomCommand) {
|
|
199
|
-
prompt = prompt.substring(customPrefix.length);
|
|
200
|
-
}
|
|
201
|
-
else if (hasLegacyCommand) {
|
|
202
|
-
prompt = prompt.substring(6); // length of '!tars'
|
|
203
|
-
}
|
|
204
|
-
if (isMentioned && this.client.user) {
|
|
205
|
-
prompt = prompt.replace(new RegExp(`<@!?${this.client.user.id}>`, 'g'), '');
|
|
206
|
-
}
|
|
207
|
-
return prompt.trim();
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
//# sourceMappingURL=discord-bot.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"discord-bot.js","sourceRoot":"","sources":["../../src/discord/discord-bot.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Discord Message Formatter
|
|
3
|
-
*
|
|
4
|
-
* Transforms Gemini CLI output (GitHub Flavored Markdown)
|
|
5
|
-
* into Discord-compatible formatting.
|
|
6
|
-
*
|
|
7
|
-
* Discord supports:
|
|
8
|
-
* - Bold: **text**
|
|
9
|
-
* - Italic: *text* or _text_
|
|
10
|
-
* - Underline: __text__
|
|
11
|
-
* - Strikethrough: ~~text~~
|
|
12
|
-
* - Code inline: `text`
|
|
13
|
-
* - Code block: ```lang\ncode\n```
|
|
14
|
-
* - Blockquotes: > text
|
|
15
|
-
* - Headers: # (only #, ##, ###)
|
|
16
|
-
*
|
|
17
|
-
* Discord does NOT support:
|
|
18
|
-
* - Markdown tables (we instruct the LLM to avoid these)
|
|
19
|
-
* - #### or deeper headers
|
|
20
|
-
* - Small text (-#)
|
|
21
|
-
*/
|
|
22
|
-
export declare class MessageFormatter {
|
|
23
|
-
private static readonly MAX_MESSAGE_LENGTH;
|
|
24
|
-
/**
|
|
25
|
-
* Format text for Discord
|
|
26
|
-
*/
|
|
27
|
-
static format(text: string): string;
|
|
28
|
-
/**
|
|
29
|
-
* Fix critical spacing issues from LLM output
|
|
30
|
-
* These are the most common formatting bugs that break Discord rendering
|
|
31
|
-
*/
|
|
32
|
-
private static fixSpacing;
|
|
33
|
-
/**
|
|
34
|
-
* Fix broken asterisks patterns
|
|
35
|
-
* Only fixes obviously broken patterns, avoids aggressive matching
|
|
36
|
-
*/
|
|
37
|
-
private static fixAsterisks;
|
|
38
|
-
/**
|
|
39
|
-
* Normalize bullet points for Discord
|
|
40
|
-
*/
|
|
41
|
-
private static normalizeBullets;
|
|
42
|
-
/**
|
|
43
|
-
* Normalize markdown headers to Discord-friendly format
|
|
44
|
-
* Discord supports #, ##, ### natively now.
|
|
45
|
-
*/
|
|
46
|
-
private static normalizeHeaders;
|
|
47
|
-
/**
|
|
48
|
-
* Fix blockquote formatting
|
|
49
|
-
*/
|
|
50
|
-
private static fixBlockquotes;
|
|
51
|
-
/**
|
|
52
|
-
* Detect and wrap JSON-like content in code blocks
|
|
53
|
-
*/
|
|
54
|
-
private static formatJsonBlocks;
|
|
55
|
-
/**
|
|
56
|
-
* Strip markdown tables - they don't render well on mobile Discord
|
|
57
|
-
* This is a fallback; the LLM should be instructed not to generate tables
|
|
58
|
-
*/
|
|
59
|
-
private static stripTables;
|
|
60
|
-
/**
|
|
61
|
-
* Fix small text markers (-#) that Discord doesn't support
|
|
62
|
-
*/
|
|
63
|
-
private static fixSmallText;
|
|
64
|
-
/**
|
|
65
|
-
* Split long messages into Discord-safe chunks intelligently
|
|
66
|
-
* Respects semantic boundaries: headers, code blocks, paragraphs
|
|
67
|
-
*/
|
|
68
|
-
static split(text: string, maxLength?: number): string[];
|
|
69
|
-
/**
|
|
70
|
-
* Find the optimal split point respecting semantic boundaries
|
|
71
|
-
* Priority: Header > Code block boundary > Paragraph > Sentence > Hard cut
|
|
72
|
-
*/
|
|
73
|
-
private static findSemanticSplitPoint;
|
|
74
|
-
/**
|
|
75
|
-
* Format and split in one operation
|
|
76
|
-
* Ensures summary line (first line with actionable emoji) stays at the top
|
|
77
|
-
*/
|
|
78
|
-
static formatAndSplit(text: string): string[];
|
|
79
|
-
/**
|
|
80
|
-
* Extract the summary line from the beginning of formatted text
|
|
81
|
-
* Summary lines start with key actionable emojis: 🎯 ⚖️ 📊 ⚠️ ✅ ❓
|
|
82
|
-
*/
|
|
83
|
-
private static extractSummaryLine;
|
|
84
|
-
/**
|
|
85
|
-
* Parse markdown into sections based on headers (##)
|
|
86
|
-
*/
|
|
87
|
-
static parseSections(text: string): {
|
|
88
|
-
title: string;
|
|
89
|
-
content: string;
|
|
90
|
-
}[];
|
|
91
|
-
/**
|
|
92
|
-
* Format a data object as a clean Discord-friendly list
|
|
93
|
-
*/
|
|
94
|
-
static formatDataAsEmbed(title: string, data: Record<string, unknown>): string;
|
|
95
|
-
}
|