@ducci/jarvis 1.0.78 → 1.0.79
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/package.json +1 -1
- package/src/channels/telegram/index.js +77 -50
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import { Bot } from 'grammy';
|
|
3
|
+
import { Bot, InlineKeyboard } from 'grammy';
|
|
4
4
|
import { run } from '@grammyjs/runner';
|
|
5
5
|
import { handleChat, requestAbort } from '../../server/agent.js';
|
|
6
6
|
import { loadSession } from '../../server/sessions.js';
|
|
@@ -164,7 +164,6 @@ export async function startTelegramChannel(config) {
|
|
|
164
164
|
{ command: 'usage', description: 'Token usage for the active slot' },
|
|
165
165
|
{ command: 'stop', description: 'Stop the running agent on the active slot' },
|
|
166
166
|
{ command: 'slots', description: 'Show all slots and their status' },
|
|
167
|
-
{ command: 'slot', description: 'Switch or delete a slot: /slot 2 or /slot del 2' },
|
|
168
167
|
]);
|
|
169
168
|
|
|
170
169
|
bot.command('usage', async (ctx) => {
|
|
@@ -234,11 +233,7 @@ export async function startTelegramChannel(config) {
|
|
|
234
233
|
await ctx.reply(`New session started on slot ${slot}.`);
|
|
235
234
|
});
|
|
236
235
|
|
|
237
|
-
|
|
238
|
-
const userId = ctx.from?.id;
|
|
239
|
-
if (!allowedUserIds.includes(userId)) return;
|
|
240
|
-
|
|
241
|
-
const chatId = ctx.chat.id;
|
|
236
|
+
function buildSlotsDisplay(chatId) {
|
|
242
237
|
const d = sessions[chatId];
|
|
243
238
|
const activeSlot = getActiveSlot(chatId);
|
|
244
239
|
|
|
@@ -250,7 +245,10 @@ export async function startTelegramChannel(config) {
|
|
|
250
245
|
}
|
|
251
246
|
|
|
252
247
|
const slotNums = [...new Set(['1', ...Object.keys(slotsMap)])].sort((a, b) => Number(a) - Number(b));
|
|
248
|
+
const maxSlot = Math.max(...slotNums.map(Number));
|
|
249
|
+
const nextSlot = maxSlot + 1;
|
|
253
250
|
|
|
251
|
+
// Status text
|
|
254
252
|
const lines = ['<b>Slots:</b>'];
|
|
255
253
|
for (const sn of slotNums) {
|
|
256
254
|
const n = Number(sn);
|
|
@@ -275,64 +273,93 @@ export async function startTelegramChannel(config) {
|
|
|
275
273
|
}
|
|
276
274
|
lines.push(`Slot ${n}: ${statusIcon}${activeMarker}`);
|
|
277
275
|
}
|
|
278
|
-
|
|
279
|
-
// Always show one empty slot beyond the highest existing one
|
|
280
|
-
const maxSlot = Math.max(...slotNums.map(Number));
|
|
281
|
-
const nextSlot = maxSlot + 1;
|
|
282
276
|
if (!isRunning.has(slotKey(chatId, nextSlot)) && !slotsMap[String(nextSlot)]) {
|
|
283
277
|
lines.push(`Slot ${nextSlot}: ➕ leer`);
|
|
284
278
|
}
|
|
285
279
|
|
|
286
|
-
|
|
287
|
-
|
|
280
|
+
// Inline keyboard
|
|
281
|
+
const kb = new InlineKeyboard();
|
|
282
|
+
for (const sn of slotNums) {
|
|
283
|
+
const n = Number(sn);
|
|
284
|
+
const sid = slotsMap[sn] ?? null;
|
|
285
|
+
const key = slotKey(chatId, n);
|
|
286
|
+
const running = isRunning.has(key);
|
|
287
|
+
if (n === activeSlot) {
|
|
288
|
+
kb.text(`✓ Slot ${n} (aktiv)`, `slots_noop`);
|
|
289
|
+
} else {
|
|
290
|
+
kb.text(`↩️ Slot ${n}`, `slots_switch_${n}`);
|
|
291
|
+
}
|
|
292
|
+
if (sid && !running) {
|
|
293
|
+
kb.text(`🗑️`, `slots_del_${n}`);
|
|
294
|
+
}
|
|
295
|
+
kb.row();
|
|
296
|
+
}
|
|
297
|
+
// Button for the next empty slot
|
|
298
|
+
kb.text(`➕ Slot ${nextSlot} (neu)`, `slots_switch_${nextSlot}`);
|
|
299
|
+
|
|
300
|
+
return { text: lines.join('\n'), keyboard: kb };
|
|
301
|
+
}
|
|
288
302
|
|
|
289
|
-
bot.command('
|
|
303
|
+
bot.command('slots', async (ctx) => {
|
|
290
304
|
const userId = ctx.from?.id;
|
|
291
305
|
if (!allowedUserIds.includes(userId)) return;
|
|
292
306
|
|
|
293
307
|
const chatId = ctx.chat.id;
|
|
294
|
-
const
|
|
308
|
+
const { text, keyboard } = buildSlotsDisplay(chatId);
|
|
309
|
+
await ctx.reply(text, { parse_mode: 'HTML', reply_markup: keyboard });
|
|
310
|
+
});
|
|
295
311
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if (!n || n < 1) { await ctx.reply('Usage: /slot del <number>'); return; }
|
|
300
|
-
const key = slotKey(chatId, n);
|
|
301
|
-
if (isRunning.has(key) || pendingMessages.has(key)) {
|
|
302
|
-
await ctx.reply(`Slot ${n} ist gerade aktiv. Erst /stop, dann löschen.`);
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
const oldSid = getSessionId(chatId, n);
|
|
306
|
-
if (oldSid) {
|
|
307
|
-
await appendTelegramChatLog(chatId, oldSid, 'SYSTEM', `--- /slot del ${n} ---`);
|
|
308
|
-
}
|
|
309
|
-
setSessionId(chatId, n, null);
|
|
310
|
-
pendingMessages.delete(key);
|
|
311
|
-
runStartTimes.delete(key);
|
|
312
|
-
if (getActiveSlot(chatId) === n) {
|
|
313
|
-
setActiveSlot(chatId, 1);
|
|
314
|
-
await ctx.reply(`Slot ${n} gelöscht. Zu Slot 1 gewechselt.`);
|
|
315
|
-
} else {
|
|
316
|
-
await ctx.reply(`Slot ${n} gelöscht.`);
|
|
317
|
-
}
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
312
|
+
bot.callbackQuery(/^slots_switch_(\d+)$/, async (ctx) => {
|
|
313
|
+
const userId = ctx.from?.id;
|
|
314
|
+
if (!allowedUserIds.includes(userId)) { await ctx.answerCallbackQuery(); return; }
|
|
320
315
|
|
|
321
|
-
|
|
322
|
-
const n = parseInt(
|
|
323
|
-
if (!n || n < 1) { await ctx.reply('Usage: /slot <number> oder /slot del <number>'); return; }
|
|
316
|
+
const chatId = ctx.chat.id;
|
|
317
|
+
const n = parseInt(ctx.match[1], 10);
|
|
324
318
|
setActiveSlot(chatId, n);
|
|
325
|
-
const sid = getSessionId(chatId, n);
|
|
326
319
|
const key = slotKey(chatId, n);
|
|
320
|
+
const sid = getSessionId(chatId, n);
|
|
327
321
|
let status;
|
|
328
|
-
if (isRunning.has(key))
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
|
|
322
|
+
if (isRunning.has(key)) status = '🟢 läuft';
|
|
323
|
+
else if (sid) status = '💬 bereit';
|
|
324
|
+
else status = '➕ leer (neue Session beim nächsten Message)';
|
|
325
|
+
|
|
326
|
+
const { text, keyboard } = buildSlotsDisplay(chatId);
|
|
327
|
+
await ctx.editMessageText(text, { parse_mode: 'HTML', reply_markup: keyboard });
|
|
328
|
+
await ctx.answerCallbackQuery(`Slot ${n} aktiv — ${status}`);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
bot.callbackQuery(/^slots_del_(\d+)$/, async (ctx) => {
|
|
332
|
+
const userId = ctx.from?.id;
|
|
333
|
+
if (!allowedUserIds.includes(userId)) { await ctx.answerCallbackQuery(); return; }
|
|
334
|
+
|
|
335
|
+
const chatId = ctx.chat.id;
|
|
336
|
+
const n = parseInt(ctx.match[1], 10);
|
|
337
|
+
const key = slotKey(chatId, n);
|
|
338
|
+
|
|
339
|
+
if (isRunning.has(key) || pendingMessages.has(key)) {
|
|
340
|
+
await ctx.answerCallbackQuery(`Slot ${n} läuft gerade — erst /stop`);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const oldSid = getSessionId(chatId, n);
|
|
345
|
+
if (oldSid) {
|
|
346
|
+
await appendTelegramChatLog(chatId, oldSid, 'SYSTEM', `--- slot del ${n} (via keyboard) ---`);
|
|
334
347
|
}
|
|
335
|
-
|
|
348
|
+
setSessionId(chatId, n, null);
|
|
349
|
+
pendingMessages.delete(key);
|
|
350
|
+
runStartTimes.delete(key);
|
|
351
|
+
|
|
352
|
+
if (getActiveSlot(chatId) === n) {
|
|
353
|
+
setActiveSlot(chatId, 1);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const { text, keyboard } = buildSlotsDisplay(chatId);
|
|
357
|
+
await ctx.editMessageText(text, { parse_mode: 'HTML', reply_markup: keyboard });
|
|
358
|
+
await ctx.answerCallbackQuery(`Slot ${n} gelöscht`);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
bot.callbackQuery('slots_noop', async (ctx) => {
|
|
362
|
+
await ctx.answerCallbackQuery();
|
|
336
363
|
});
|
|
337
364
|
|
|
338
365
|
// Runs one or more batches until the pending queue is drained.
|