@iletai/nzb 1.6.0 → 1.6.2
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/config.js
CHANGED
|
@@ -63,6 +63,14 @@ export const config = {
|
|
|
63
63
|
set showReasoning(value) {
|
|
64
64
|
process.env.SHOW_REASONING = value ? "true" : "false";
|
|
65
65
|
},
|
|
66
|
+
/** Usage display mode: off | tokens | full */
|
|
67
|
+
usageMode: (process.env.USAGE_MODE || "off"),
|
|
68
|
+
/** Verbose mode: when on, instructs the AI to be more detailed */
|
|
69
|
+
verboseMode: process.env.VERBOSE_MODE === "true",
|
|
70
|
+
/** Thinking level: off | low | medium | high */
|
|
71
|
+
thinkingLevel: (process.env.THINKING_LEVEL || "off"),
|
|
72
|
+
/** Group chat: when true, bot only responds when mentioned in groups */
|
|
73
|
+
groupMentionOnly: process.env.GROUP_MENTION_ONLY !== "false",
|
|
66
74
|
};
|
|
67
75
|
/** Persist an env variable to ~/.nzb/.env */
|
|
68
76
|
export function persistEnvVar(key, value) {
|
|
@@ -31,6 +31,8 @@ let healthCheckTimer;
|
|
|
31
31
|
let orchestratorSession;
|
|
32
32
|
// Coalesces concurrent ensureOrchestratorSession calls
|
|
33
33
|
let sessionCreatePromise;
|
|
34
|
+
// Tracks in-flight context recovery injection so we don't race with real messages
|
|
35
|
+
let recoveryInjectionPromise;
|
|
34
36
|
const messageQueue = [];
|
|
35
37
|
let processing = false;
|
|
36
38
|
let currentCallback;
|
|
@@ -244,16 +246,22 @@ async function createOrResumeSession() {
|
|
|
244
246
|
setState(ORCHESTRATOR_SESSION_KEY, session.sessionId);
|
|
245
247
|
console.log(`[nzb] Created orchestrator session ${session.sessionId.slice(0, 8)}…`);
|
|
246
248
|
// Recover conversation context if available (session was lost, not first run)
|
|
247
|
-
//
|
|
249
|
+
// Runs concurrently but is awaited before any real message is sent on the session
|
|
248
250
|
const recentHistory = getRecentConversation(10);
|
|
249
251
|
if (recentHistory) {
|
|
250
|
-
console.log(`[nzb] Injecting recent conversation context into new session
|
|
251
|
-
session
|
|
252
|
+
console.log(`[nzb] Injecting recent conversation context into new session`);
|
|
253
|
+
recoveryInjectionPromise = session
|
|
252
254
|
.sendAndWait({
|
|
253
255
|
prompt: `[System: Session recovered] Your previous session was lost. Here's the recent conversation for context — do NOT respond to these messages, just absorb the context silently:\n\n${recentHistory}\n\n(End of recovery context. Wait for the next real message.)`,
|
|
254
256
|
}, 20_000)
|
|
257
|
+
.then(() => {
|
|
258
|
+
console.log(`[nzb] Context recovery injection completed`);
|
|
259
|
+
})
|
|
255
260
|
.catch((err) => {
|
|
256
261
|
console.log(`[nzb] Context recovery injection failed (non-fatal): ${err instanceof Error ? err.message : err}`);
|
|
262
|
+
})
|
|
263
|
+
.finally(() => {
|
|
264
|
+
recoveryInjectionPromise = undefined;
|
|
257
265
|
});
|
|
258
266
|
}
|
|
259
267
|
return session;
|
|
@@ -291,6 +299,11 @@ export async function initOrchestrator(client) {
|
|
|
291
299
|
/** Send a prompt on the persistent session, return the response. */
|
|
292
300
|
async function executeOnSession(prompt, callback, onToolEvent, onUsage) {
|
|
293
301
|
const session = await ensureOrchestratorSession();
|
|
302
|
+
// Wait for any in-flight context recovery injection to finish before sending
|
|
303
|
+
if (recoveryInjectionPromise) {
|
|
304
|
+
console.log(`[nzb] Waiting for context recovery injection to complete before sending…`);
|
|
305
|
+
await recoveryInjectionPromise;
|
|
306
|
+
}
|
|
294
307
|
currentCallback = callback;
|
|
295
308
|
let accumulated = "";
|
|
296
309
|
let toolCallExecuted = false;
|
|
@@ -408,6 +421,17 @@ export async function sendToOrchestrator(prompt, source, callback, onToolEvent,
|
|
|
408
421
|
if (freshMemory) {
|
|
409
422
|
taggedPrompt = `<reminder>\n${freshMemory}\n</reminder>\n\n${taggedPrompt}`;
|
|
410
423
|
}
|
|
424
|
+
// Inject thinking level and verbose mode hints
|
|
425
|
+
const hints = [];
|
|
426
|
+
if (config.thinkingLevel !== "off") {
|
|
427
|
+
hints.push(`[Thinking level: ${config.thinkingLevel} — reason through this at ${config.thinkingLevel} depth]`);
|
|
428
|
+
}
|
|
429
|
+
if (config.verboseMode) {
|
|
430
|
+
hints.push("[Verbose mode: ON — provide detailed, thorough explanations with examples]");
|
|
431
|
+
}
|
|
432
|
+
if (hints.length > 0) {
|
|
433
|
+
taggedPrompt = `${hints.join("\n")}\n\n${taggedPrompt}`;
|
|
434
|
+
}
|
|
411
435
|
}
|
|
412
436
|
// Log role: background events are "system", user messages are "user"
|
|
413
437
|
const logRole = source.type === "background" ? "system" : "user";
|
|
@@ -468,8 +492,7 @@ export async function sendToOrchestrator(prompt, source, callback, onToolEvent,
|
|
|
468
492
|
await callback(finalContent, true, { assistantLogId });
|
|
469
493
|
// Auto-continue: if the response was cut short by timeout, automatically
|
|
470
494
|
// send a follow-up "Continue" message so the user doesn't have to
|
|
471
|
-
if (finalContent.includes("⏱ Response was cut short (timeout)") &&
|
|
472
|
-
_autoContinueCount < MAX_AUTO_CONTINUE) {
|
|
495
|
+
if (finalContent.includes("⏱ Response was cut short (timeout)") && _autoContinueCount < MAX_AUTO_CONTINUE) {
|
|
473
496
|
console.log(`[nzb] Auto-continuing after timeout (${_autoContinueCount + 1}/${MAX_AUTO_CONTINUE})…`);
|
|
474
497
|
await sleep(1000);
|
|
475
498
|
void sendToOrchestrator("Continue from where you left off. Do not repeat what was already said.", source, callback, onToolEvent, onUsage, _autoContinueCount + 1);
|
|
@@ -532,4 +555,45 @@ export function getWorkers() {
|
|
|
532
555
|
export function getQueueSize() {
|
|
533
556
|
return messageQueue.length;
|
|
534
557
|
}
|
|
558
|
+
/** Reset the orchestrator session — destroys current session and creates a fresh one. */
|
|
559
|
+
export async function resetSession() {
|
|
560
|
+
// Drain any queued messages first
|
|
561
|
+
while (messageQueue.length > 0) {
|
|
562
|
+
const item = messageQueue.shift();
|
|
563
|
+
item.reject(new Error("Session reset"));
|
|
564
|
+
}
|
|
565
|
+
// Abort in-flight request
|
|
566
|
+
if (orchestratorSession && currentCallback) {
|
|
567
|
+
try {
|
|
568
|
+
await orchestratorSession.abort();
|
|
569
|
+
}
|
|
570
|
+
catch { }
|
|
571
|
+
}
|
|
572
|
+
// Destroy the existing session
|
|
573
|
+
if (orchestratorSession) {
|
|
574
|
+
try {
|
|
575
|
+
await orchestratorSession.destroy();
|
|
576
|
+
}
|
|
577
|
+
catch { }
|
|
578
|
+
orchestratorSession = undefined;
|
|
579
|
+
}
|
|
580
|
+
// Clear persisted session ID so a fresh session is created
|
|
581
|
+
deleteState(ORCHESTRATOR_SESSION_KEY);
|
|
582
|
+
console.log("[nzb] Session reset — will create fresh session on next message");
|
|
583
|
+
}
|
|
584
|
+
/** Compact the session by sending a compaction prompt (summarize context). */
|
|
585
|
+
export async function compactSession() {
|
|
586
|
+
const session = await ensureOrchestratorSession();
|
|
587
|
+
try {
|
|
588
|
+
const result = await session.sendAndWait({
|
|
589
|
+
prompt: "[System: Context compaction requested] Summarize everything important from our conversation so far into a concise internal note. " +
|
|
590
|
+
"Include: key decisions, pending tasks, user preferences, and any context you'd need to continue helping. " +
|
|
591
|
+
"This summary will be used to maintain continuity. Be thorough but concise.",
|
|
592
|
+
}, 30_000);
|
|
593
|
+
return result?.data?.content || "(Compaction completed)";
|
|
594
|
+
}
|
|
595
|
+
catch (err) {
|
|
596
|
+
return `Compaction failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
535
599
|
//# sourceMappingURL=orchestrator.js.map
|
package/dist/telegram/bot.js
CHANGED
|
@@ -133,8 +133,13 @@ export async function startBot() {
|
|
|
133
133
|
await bot.api.setMyCommands([
|
|
134
134
|
{ command: "start", description: "Start the bot" },
|
|
135
135
|
{ command: "help", description: "Show help text" },
|
|
136
|
+
{ command: "new", description: "Reset session (fresh context)" },
|
|
137
|
+
{ command: "compact", description: "Compact session context" },
|
|
136
138
|
{ command: "cancel", description: "Cancel current message" },
|
|
137
139
|
{ command: "model", description: "Show/switch AI model" },
|
|
140
|
+
{ command: "think", description: "Set thinking level (off/low/medium/high)" },
|
|
141
|
+
{ command: "verbose", description: "Toggle verbose responses" },
|
|
142
|
+
{ command: "usage", description: "Set usage display (off/tokens/full)" },
|
|
138
143
|
{ command: "status", description: "Show system status" },
|
|
139
144
|
{ command: "workers", description: "List active workers" },
|
|
140
145
|
{ command: "skills", description: "List installed skills" },
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { config, persistModel } from "../../config.js";
|
|
2
|
-
import { cancelCurrentMessage, getQueueSize, getWorkers } from "../../copilot/orchestrator.js";
|
|
1
|
+
import { config, persistEnvVar, persistModel } from "../../config.js";
|
|
2
|
+
import { cancelCurrentMessage, compactSession, getQueueSize, getWorkers, resetSession } from "../../copilot/orchestrator.js";
|
|
3
3
|
import { listSkills } from "../../copilot/skills.js";
|
|
4
4
|
import { restartDaemon } from "../../daemon.js";
|
|
5
5
|
import { searchMemories } from "../../store/db.js";
|
|
6
|
-
import { getReactionHelpText } from "./reactions.js";
|
|
7
6
|
import { buildSettingsText, formatMemoryList } from "../menus.js";
|
|
7
|
+
import { getReactionHelpText } from "./reactions.js";
|
|
8
8
|
export function registerCommandHandlers(bot, deps) {
|
|
9
9
|
const { replyKeyboard, mainMenu, settingsMenu, getUptimeStr } = deps;
|
|
10
10
|
// /start and /help — with inline menu + reply keyboard
|
|
@@ -14,27 +14,89 @@ export function registerCommandHandlers(bot, deps) {
|
|
|
14
14
|
});
|
|
15
15
|
bot.command("help", (ctx) => ctx.reply("I'm NZB, your AI daemon.\n\n" +
|
|
16
16
|
"Just send me a message and I'll handle it.\n\n" +
|
|
17
|
-
"
|
|
18
|
-
"/
|
|
19
|
-
"/
|
|
20
|
-
"/
|
|
21
|
-
"
|
|
22
|
-
"/
|
|
23
|
-
"/
|
|
24
|
-
"/
|
|
25
|
-
"/
|
|
26
|
-
"/
|
|
27
|
-
"
|
|
17
|
+
"Session:\n" +
|
|
18
|
+
"/new — Reset session (fresh context)\n" +
|
|
19
|
+
"/compact — Compact session context\n" +
|
|
20
|
+
"/cancel — Cancel the current message\n\n" +
|
|
21
|
+
"Config:\n" +
|
|
22
|
+
"/model — Show/switch AI model\n" +
|
|
23
|
+
"/think <level> — off|low|medium|high\n" +
|
|
24
|
+
"/verbose — Toggle verbose responses\n" +
|
|
25
|
+
"/usage — off|tokens|full\n" +
|
|
26
|
+
"/settings — Bot settings\n\n" +
|
|
27
|
+
"Info:\n" +
|
|
28
|
+
"/status — System status\n" +
|
|
29
|
+
"/memory — Stored memories\n" +
|
|
30
|
+
"/skills — Installed skills\n" +
|
|
31
|
+
"/workers — Active worker sessions\n" +
|
|
32
|
+
"/restart — Restart NZB\n\n" +
|
|
28
33
|
"⚡ Breakthrough Features:\n" +
|
|
29
34
|
"• @bot query — Use me inline in any chat!\n" +
|
|
30
35
|
"• React to any message to trigger AI:\n" +
|
|
31
36
|
getReactionHelpText() +
|
|
32
37
|
"\n" +
|
|
33
|
-
"• Smart suggestions appear after each response"
|
|
38
|
+
"• Smart suggestions appear after each response\n" +
|
|
39
|
+
"• Works in groups — mention me to activate!", { reply_markup: mainMenu }));
|
|
34
40
|
bot.command("cancel", async (ctx) => {
|
|
35
41
|
const cancelled = await cancelCurrentMessage();
|
|
36
42
|
await ctx.reply(cancelled ? "Cancelled." : "Nothing to cancel.");
|
|
37
43
|
});
|
|
44
|
+
bot.command("new", async (ctx) => {
|
|
45
|
+
await ctx.reply("🔄 Resetting session…");
|
|
46
|
+
try {
|
|
47
|
+
await resetSession();
|
|
48
|
+
await ctx.reply("✅ Session reset. Fresh context — send me a message to start.");
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
await ctx.reply(`❌ Reset failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
bot.command("compact", async (ctx) => {
|
|
55
|
+
await ctx.reply("📦 Compacting session context…");
|
|
56
|
+
try {
|
|
57
|
+
const summary = await compactSession();
|
|
58
|
+
const preview = summary.length > 500 ? summary.slice(0, 500) + "…" : summary;
|
|
59
|
+
await ctx.reply(`✅ Context compacted.\n\n${preview}`);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
await ctx.reply(`❌ Compaction failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
bot.command("think", async (ctx) => {
|
|
66
|
+
const THINK_LEVELS = ["off", "low", "medium", "high"];
|
|
67
|
+
const arg = ctx.match?.trim().toLowerCase();
|
|
68
|
+
if (arg && THINK_LEVELS.includes(arg)) {
|
|
69
|
+
config.thinkingLevel = arg;
|
|
70
|
+
persistEnvVar("THINKING_LEVEL", arg);
|
|
71
|
+
await ctx.reply(`🧠 Thinking level → ${arg}`);
|
|
72
|
+
}
|
|
73
|
+
else if (arg) {
|
|
74
|
+
await ctx.reply(`Invalid level: ${arg}\nValid: ${THINK_LEVELS.join(", ")}`);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
await ctx.reply(`🧠 Thinking level: ${config.thinkingLevel}\nSet with: /think off|low|medium|high`);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
bot.command("usage", async (ctx) => {
|
|
81
|
+
const USAGE_MODES = ["off", "tokens", "full"];
|
|
82
|
+
const arg = ctx.match?.trim().toLowerCase();
|
|
83
|
+
if (arg && USAGE_MODES.includes(arg)) {
|
|
84
|
+
config.usageMode = arg;
|
|
85
|
+
persistEnvVar("USAGE_MODE", arg);
|
|
86
|
+
await ctx.reply(`📊 Usage display → ${arg}`);
|
|
87
|
+
}
|
|
88
|
+
else if (arg) {
|
|
89
|
+
await ctx.reply(`Invalid mode: ${arg}\nValid: ${USAGE_MODES.join(", ")}`);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
await ctx.reply(`📊 Usage display: ${config.usageMode}\nSet with: /usage off|tokens|full`);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
bot.command("verbose", async (ctx) => {
|
|
96
|
+
config.verboseMode = !config.verboseMode;
|
|
97
|
+
persistEnvVar("VERBOSE_MODE", config.verboseMode ? "true" : "false");
|
|
98
|
+
await ctx.reply(`📝 Verbose mode ${config.verboseMode ? "ON — detailed responses" : "OFF — concise responses"}`);
|
|
99
|
+
});
|
|
38
100
|
bot.command("model", async (ctx) => {
|
|
39
101
|
const arg = ctx.match?.trim();
|
|
40
102
|
if (arg) {
|
|
@@ -99,6 +161,9 @@ export function registerCommandHandlers(bot, deps) {
|
|
|
99
161
|
const lines = [
|
|
100
162
|
"📊 NZB Status",
|
|
101
163
|
`Model: ${config.copilotModel}`,
|
|
164
|
+
`Thinking: ${config.thinkingLevel}`,
|
|
165
|
+
`Verbose: ${config.verboseMode ? "on" : "off"}`,
|
|
166
|
+
`Usage: ${config.usageMode}`,
|
|
102
167
|
`Uptime: ${getUptimeStr()}`,
|
|
103
168
|
`Workers: ${workers.length} active`,
|
|
104
169
|
`Queue: ${getQueueSize()} pending`,
|
|
@@ -122,6 +187,9 @@ export function registerCommandHandlers(bot, deps) {
|
|
|
122
187
|
const lines = [
|
|
123
188
|
"📊 NZB Status",
|
|
124
189
|
`Model: ${config.copilotModel}`,
|
|
190
|
+
`Thinking: ${config.thinkingLevel}`,
|
|
191
|
+
`Verbose: ${config.verboseMode ? "on" : "off"}`,
|
|
192
|
+
`Usage: ${config.usageMode}`,
|
|
125
193
|
`Uptime: ${getUptimeStr()}`,
|
|
126
194
|
`Workers: ${workers.length} active`,
|
|
127
195
|
`Queue: ${getQueueSize()} pending`,
|
|
@@ -11,8 +11,17 @@ export function registerMessageHandler(bot, getBot) {
|
|
|
11
11
|
const chatId = ctx.chat.id;
|
|
12
12
|
const userMessageId = ctx.message.message_id;
|
|
13
13
|
const replyParams = { message_id: userMessageId };
|
|
14
|
+
// Group chat support — only respond when mentioned or replied to
|
|
15
|
+
const isGroup = ctx.chat.type === "group" || ctx.chat.type === "supergroup";
|
|
16
|
+
if (isGroup && config.groupMentionOnly) {
|
|
17
|
+
const botUsername = ctx.me.username;
|
|
18
|
+
const isMentioned = botUsername && ctx.message.text.includes(`@${botUsername}`);
|
|
19
|
+
const isReplyToBot = ctx.message.reply_to_message?.from?.id === ctx.me.id;
|
|
20
|
+
if (!isMentioned && !isReplyToBot)
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
14
23
|
const msgPreview = ctx.message.text.length > 80 ? ctx.message.text.slice(0, 80) + "…" : ctx.message.text;
|
|
15
|
-
void logInfo(`📩 Message: ${msgPreview}`);
|
|
24
|
+
void logInfo(`📩 Message${isGroup ? " (group)" : ""}: ${msgPreview}`);
|
|
16
25
|
// React with 👀 to acknowledge message received
|
|
17
26
|
try {
|
|
18
27
|
await ctx.react("👀");
|
|
@@ -163,6 +172,10 @@ export function registerMessageHandler(bot, getBot) {
|
|
|
163
172
|
};
|
|
164
173
|
// If user replies to a message, include surrounding conversation context
|
|
165
174
|
let userPrompt = ctx.message.text;
|
|
175
|
+
// Strip bot mention from the prompt in group chats
|
|
176
|
+
if (isGroup && ctx.me.username) {
|
|
177
|
+
userPrompt = userPrompt.replace(new RegExp(`@${ctx.me.username}\\b`, "gi"), "").trim();
|
|
178
|
+
}
|
|
166
179
|
const replyMsg = ctx.message.reply_to_message;
|
|
167
180
|
if (replyMsg && "text" in replyMsg && replyMsg.text) {
|
|
168
181
|
// Try to find full conversation context around the replied message
|
|
@@ -209,15 +222,15 @@ export function registerMessageHandler(bot, getBot) {
|
|
|
209
222
|
return;
|
|
210
223
|
}
|
|
211
224
|
let textWithMeta = text;
|
|
212
|
-
if (usageInfo) {
|
|
225
|
+
if (usageInfo && config.usageMode !== "off") {
|
|
213
226
|
const fmtTokens = (n) => (n >= 1000 ? `${(n / 1000).toFixed(1)}K` : String(n));
|
|
214
227
|
const parts = [];
|
|
215
|
-
if (usageInfo.model)
|
|
228
|
+
if (config.usageMode === "full" && usageInfo.model)
|
|
216
229
|
parts.push(usageInfo.model);
|
|
217
230
|
parts.push(`⬆${fmtTokens(usageInfo.inputTokens)} ⬇${fmtTokens(usageInfo.outputTokens)}`);
|
|
218
231
|
const totalTokens = usageInfo.inputTokens + usageInfo.outputTokens;
|
|
219
232
|
parts.push(`Σ${fmtTokens(totalTokens)}`);
|
|
220
|
-
if (usageInfo.duration)
|
|
233
|
+
if (config.usageMode === "full" && usageInfo.duration)
|
|
221
234
|
parts.push(`${(usageInfo.duration / 1000).toFixed(1)}s`);
|
|
222
235
|
textWithMeta += `\n\n📊 ${parts.join(" · ")}`;
|
|
223
236
|
}
|
package/dist/telegram/menus.js
CHANGED
|
@@ -43,6 +43,9 @@ export function buildSettingsText(getUptimeStr) {
|
|
|
43
43
|
return ("⚙️ Settings\n\n" +
|
|
44
44
|
`⏱ Worker Timeout: ${getTimeoutLabel()}\n` +
|
|
45
45
|
`🤖 Model: ${config.copilotModel}\n` +
|
|
46
|
+
`🧠 Thinking: ${config.thinkingLevel}\n` +
|
|
47
|
+
`📝 Verbose: ${config.verboseMode ? "✅ ON" : "❌ OFF"}\n` +
|
|
48
|
+
`📊 Usage: ${config.usageMode}\n` +
|
|
46
49
|
`🔧 Show Reasoning: ${config.showReasoning ? "✅ ON" : "❌ OFF"}\n\n` +
|
|
47
50
|
`📌 v${process.env.npm_package_version || "?"} · uptime ${getUptimeStr()}`);
|
|
48
51
|
}
|
|
@@ -103,6 +106,35 @@ export function createMenus(getUptimeStr) {
|
|
|
103
106
|
ctx.menu.update();
|
|
104
107
|
await ctx.editMessageText(buildSettingsText(getUptimeStr));
|
|
105
108
|
await ctx.answerCallbackQuery(`Reasoning ${config.showReasoning ? "ON" : "OFF"}`);
|
|
109
|
+
})
|
|
110
|
+
.row()
|
|
111
|
+
.text(() => `🧠 Think: ${config.thinkingLevel}`, async (ctx) => {
|
|
112
|
+
const levels = ["off", "low", "medium", "high"];
|
|
113
|
+
const idx = levels.indexOf(config.thinkingLevel);
|
|
114
|
+
const next = levels[(idx + 1) % levels.length];
|
|
115
|
+
config.thinkingLevel = next;
|
|
116
|
+
persistEnvVar("THINKING_LEVEL", next);
|
|
117
|
+
ctx.menu.update();
|
|
118
|
+
await ctx.editMessageText(buildSettingsText(getUptimeStr));
|
|
119
|
+
await ctx.answerCallbackQuery(`Thinking → ${next}`);
|
|
120
|
+
})
|
|
121
|
+
.text(() => `📝 ${config.verboseMode ? "Verbose" : "Concise"}`, async (ctx) => {
|
|
122
|
+
config.verboseMode = !config.verboseMode;
|
|
123
|
+
persistEnvVar("VERBOSE_MODE", config.verboseMode ? "true" : "false");
|
|
124
|
+
ctx.menu.update();
|
|
125
|
+
await ctx.editMessageText(buildSettingsText(getUptimeStr));
|
|
126
|
+
await ctx.answerCallbackQuery(`Verbose ${config.verboseMode ? "ON" : "OFF"}`);
|
|
127
|
+
})
|
|
128
|
+
.row()
|
|
129
|
+
.text(() => `📊 Usage: ${config.usageMode}`, async (ctx) => {
|
|
130
|
+
const modes = ["off", "tokens", "full"];
|
|
131
|
+
const idx = modes.indexOf(config.usageMode);
|
|
132
|
+
const next = modes[(idx + 1) % modes.length];
|
|
133
|
+
config.usageMode = next;
|
|
134
|
+
persistEnvVar("USAGE_MODE", next);
|
|
135
|
+
ctx.menu.update();
|
|
136
|
+
await ctx.editMessageText(buildSettingsText(getUptimeStr));
|
|
137
|
+
await ctx.answerCallbackQuery(`Usage → ${next}`);
|
|
106
138
|
})
|
|
107
139
|
.row()
|
|
108
140
|
.text(() => `📌 v${process.env.npm_package_version || "?"} · uptime ${getUptimeStr()}`, async (ctx) => {
|
|
@@ -119,6 +151,9 @@ export function createMenus(getUptimeStr) {
|
|
|
119
151
|
const lines = [
|
|
120
152
|
"📊 NZB Status",
|
|
121
153
|
`Model: ${config.copilotModel}`,
|
|
154
|
+
`Thinking: ${config.thinkingLevel}`,
|
|
155
|
+
`Verbose: ${config.verboseMode ? "on" : "off"}`,
|
|
156
|
+
`Usage: ${config.usageMode}`,
|
|
122
157
|
`Uptime: ${getUptimeStr()}`,
|
|
123
158
|
`Workers: ${workers.length} active`,
|
|
124
159
|
`Queue: ${getQueueSize()} pending`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iletai/nzb",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.2",
|
|
4
4
|
"description": "NZB — a personal AI assistant for developers, built on the GitHub Copilot SDK",
|
|
5
5
|
"bin": {
|
|
6
6
|
"nzb": "dist/cli.js"
|
|
@@ -69,4 +69,4 @@
|
|
|
69
69
|
"typescript": "^5.9.3",
|
|
70
70
|
"vitest": "^4.1.0"
|
|
71
71
|
}
|
|
72
|
-
}
|
|
72
|
+
}
|