@iletai/nzb 1.3.1 → 1.3.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/copilot/orchestrator.js +8 -0
- package/dist/telegram/bot.js +69 -7
- package/package.json +1 -1
|
@@ -419,6 +419,14 @@ export async function sendToOrchestrator(prompt, source, callback, onToolEvent,
|
|
|
419
419
|
// send a follow-up "Continue" message so the user doesn't have to
|
|
420
420
|
if (finalContent.includes("⏱ Response was cut short (timeout)")) {
|
|
421
421
|
console.log("[nzb] Auto-continuing after timeout…");
|
|
422
|
+
// Notify user that auto-continue is happening
|
|
423
|
+
if (source.type === "telegram") {
|
|
424
|
+
try {
|
|
425
|
+
const { sendProactiveMessage } = await import("../telegram/bot.js");
|
|
426
|
+
await sendProactiveMessage("🔄 Auto-continuing...");
|
|
427
|
+
}
|
|
428
|
+
catch { }
|
|
429
|
+
}
|
|
422
430
|
await sleep(1000);
|
|
423
431
|
void sendToOrchestrator("Continue from where you left off. Do not repeat what was already said.", source, callback, onToolEvent, onUsage);
|
|
424
432
|
}
|
package/dist/telegram/bot.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { autoRetry } from "@grammyjs/auto-retry";
|
|
2
2
|
import { Menu } from "@grammyjs/menu";
|
|
3
|
-
import { Bot } from "grammy";
|
|
3
|
+
import { Bot, Keyboard } from "grammy";
|
|
4
4
|
import { Agent as HttpsAgent } from "https";
|
|
5
5
|
import { config, persistEnvVar, persistModel } from "../config.js";
|
|
6
6
|
import { cancelCurrentMessage, getQueueSize, getWorkers, sendToOrchestrator } from "../copilot/orchestrator.js";
|
|
@@ -80,8 +80,7 @@ const mainMenu = new Menu("main-menu")
|
|
|
80
80
|
await ctx.reply("No memories stored.");
|
|
81
81
|
}
|
|
82
82
|
else {
|
|
83
|
-
|
|
84
|
-
await ctx.reply(lines.join("\n") + `\n\n${memories.length} total`);
|
|
83
|
+
await ctx.reply(formatMemoryList(memories), { parse_mode: "HTML" });
|
|
85
84
|
}
|
|
86
85
|
})
|
|
87
86
|
.submenu("⚙️ Settings", "settings-menu", async (ctx) => {
|
|
@@ -103,6 +102,32 @@ mainMenu.register(settingsMenu);
|
|
|
103
102
|
// This bypasses corporate proxy (HTTP_PROXY/HTTPS_PROXY env vars) without
|
|
104
103
|
// modifying process.env, so other services (Copilot SDK, MCP, npm) are unaffected.
|
|
105
104
|
const telegramAgent = new HttpsAgent({ keepAlive: true });
|
|
105
|
+
const CATEGORY_ICONS = {
|
|
106
|
+
project: "📦",
|
|
107
|
+
preference: "⚙️",
|
|
108
|
+
fact: "💡",
|
|
109
|
+
person: "👤",
|
|
110
|
+
routine: "🔄",
|
|
111
|
+
};
|
|
112
|
+
function formatMemoryList(memories) {
|
|
113
|
+
const groups = {};
|
|
114
|
+
for (const m of memories) {
|
|
115
|
+
(groups[m.category] ??= []).push(m);
|
|
116
|
+
}
|
|
117
|
+
for (const items of Object.values(groups)) {
|
|
118
|
+
items.sort((a, b) => a.id - b.id);
|
|
119
|
+
}
|
|
120
|
+
const sections = Object.entries(groups).map(([cat, items]) => {
|
|
121
|
+
const icon = CATEGORY_ICONS[cat] || "📝";
|
|
122
|
+
const header = `${icon} <b>${escapeHtml(cat.charAt(0).toUpperCase() + cat.slice(1))}</b>`;
|
|
123
|
+
const lines = items.map((m) => `${m.id}. ${escapeHtml(m.content)}`);
|
|
124
|
+
return `${header}\n${lines.join("\n")}`;
|
|
125
|
+
});
|
|
126
|
+
return `🧠 <b>${memories.length} memories</b>\n\n${sections.join("\n\n")}`;
|
|
127
|
+
}
|
|
128
|
+
function escapeHtml(text) {
|
|
129
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
130
|
+
}
|
|
106
131
|
export function createBot() {
|
|
107
132
|
if (!config.telegramBotToken) {
|
|
108
133
|
throw new Error("Telegram bot token is missing. Run 'nzb setup' and enter the bot token from @BotFather.");
|
|
@@ -132,8 +157,17 @@ export function createBot() {
|
|
|
132
157
|
});
|
|
133
158
|
// Register interactive menu plugin
|
|
134
159
|
bot.use(mainMenu);
|
|
135
|
-
//
|
|
136
|
-
|
|
160
|
+
// Persistent reply keyboard — quick actions always visible below chat input
|
|
161
|
+
const replyKeyboard = new Keyboard()
|
|
162
|
+
.text("📊 Status").text("❌ Cancel").row()
|
|
163
|
+
.text("🧠 Memory").text("🔄 Restart")
|
|
164
|
+
.resized()
|
|
165
|
+
.persistent();
|
|
166
|
+
// /start and /help — with inline menu + reply keyboard
|
|
167
|
+
bot.command("start", async (ctx) => {
|
|
168
|
+
await ctx.reply("NZB is online. Quick actions below ⬇️", { reply_markup: replyKeyboard });
|
|
169
|
+
await ctx.reply("Or use the menu:", { reply_markup: mainMenu });
|
|
170
|
+
});
|
|
137
171
|
bot.command("help", (ctx) => ctx.reply("I'm NZB, your AI daemon.\n\n" +
|
|
138
172
|
"Just send me a message and I'll handle it.\n\n" +
|
|
139
173
|
"Commands:\n" +
|
|
@@ -187,8 +221,7 @@ export function createBot() {
|
|
|
187
221
|
await ctx.reply("No memories stored.");
|
|
188
222
|
}
|
|
189
223
|
else {
|
|
190
|
-
|
|
191
|
-
await ctx.reply(lines.join("\n") + `\n\n${memories.length} total`);
|
|
224
|
+
await ctx.reply(formatMemoryList(memories), { parse_mode: "HTML" });
|
|
192
225
|
}
|
|
193
226
|
});
|
|
194
227
|
bot.command("skills", async (ctx) => {
|
|
@@ -242,6 +275,35 @@ export function createBot() {
|
|
|
242
275
|
`🤖 Model: ${config.copilotModel}\n` +
|
|
243
276
|
` └ Dùng /model <name> để đổi`, { reply_markup: settingsMenu });
|
|
244
277
|
});
|
|
278
|
+
// Reply keyboard button handlers — intercept before general text handler
|
|
279
|
+
bot.hears("📊 Status", async (ctx) => {
|
|
280
|
+
const workers = Array.from(getWorkers().values());
|
|
281
|
+
const lines = [
|
|
282
|
+
"📊 NZB Status",
|
|
283
|
+
`Model: ${config.copilotModel}`,
|
|
284
|
+
`Uptime: ${getUptimeStr()}`,
|
|
285
|
+
`Workers: ${workers.length} active`,
|
|
286
|
+
`Queue: ${getQueueSize()} pending`,
|
|
287
|
+
];
|
|
288
|
+
await ctx.reply(lines.join("\n"));
|
|
289
|
+
});
|
|
290
|
+
bot.hears("❌ Cancel", async (ctx) => {
|
|
291
|
+
const cancelled = await cancelCurrentMessage();
|
|
292
|
+
await ctx.reply(cancelled ? "Cancelled." : "Nothing to cancel.");
|
|
293
|
+
});
|
|
294
|
+
bot.hears("🧠 Memory", async (ctx) => {
|
|
295
|
+
const memories = searchMemories(undefined, undefined, 50);
|
|
296
|
+
if (memories.length === 0) {
|
|
297
|
+
await ctx.reply("No memories stored.");
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
await ctx.reply(formatMemoryList(memories), { parse_mode: "HTML" });
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
bot.hears("🔄 Restart", async (ctx) => {
|
|
304
|
+
await ctx.reply("Restarting NZB...");
|
|
305
|
+
setTimeout(() => { restartDaemon().catch(console.error); }, 500);
|
|
306
|
+
});
|
|
245
307
|
// Handle all text messages — progressive streaming with tool event feedback
|
|
246
308
|
bot.on("message:text", async (ctx) => {
|
|
247
309
|
const chatId = ctx.chat.id;
|