@openacp/cli 0.6.6 → 0.6.7
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/{adapter-RKK7A5GI.js → adapter-7GY3N4ZH.js} +9 -9
- package/dist/{admin-SCP25TN2.js → admin-2HAFXQBG.js} +6 -4
- package/dist/{chunk-WVMSP4AF.js → chunk-2J2RBYWN.js} +2 -2
- package/dist/{chunk-ZKTIZME6.js → chunk-47B7GNOE.js} +2 -2
- package/dist/{chunk-XVL6AGMG.js → chunk-5OVPEDUB.js} +2 -2
- package/dist/{chunk-AHPRT3RY.js → chunk-5SXG7X5D.js} +523 -251
- package/dist/chunk-5SXG7X5D.js.map +1 -0
- package/dist/{chunk-F3AICYO4.js → chunk-JHYXKVV2.js} +19 -1
- package/dist/chunk-JHYXKVV2.js.map +1 -0
- package/dist/{chunk-FCLGYYTY.js → chunk-JUYDFUSN.js} +224 -2
- package/dist/chunk-JUYDFUSN.js.map +1 -0
- package/dist/{chunk-774Y4RAK.js → chunk-KIRH7TUJ.js} +94 -24
- package/dist/chunk-KIRH7TUJ.js.map +1 -0
- package/dist/{chunk-4GQ3I65A.js → chunk-LBIKITQT.js} +1 -2
- package/dist/{chunk-4GQ3I65A.js.map → chunk-LBIKITQT.js.map} +1 -1
- package/dist/{chunk-ZMVVW3BK.js → chunk-LO4Y5WQ7.js} +127 -18
- package/dist/chunk-LO4Y5WQ7.js.map +1 -0
- package/dist/{chunk-3IRAWHMC.js → chunk-MZXWCDBU.js} +3 -3
- package/dist/{chunk-YQRF3IOR.js → chunk-O7CPGUAI.js} +2 -2
- package/dist/{chunk-7KZI2236.js → chunk-RHE2JSYE.js} +2 -2
- package/dist/{chunk-3ZO3MHZN.js → chunk-SHHMBGB3.js} +4 -3
- package/dist/chunk-SHHMBGB3.js.map +1 -0
- package/dist/{chunk-JV6XQRAE.js → chunk-XANPHG7W.js} +2 -2
- package/dist/{chunk-PJVKOZTR.js → chunk-YEOY2PBJ.js} +2 -2
- package/dist/cli.js +21 -21
- package/dist/{config-B26J3XXN.js → config-CQAS6YHR.js} +2 -2
- package/dist/{config-editor-QTGUK3CD.js → config-editor-37BM56WF.js} +4 -4
- package/dist/{config-registry-7I6GGDOY.js → config-registry-HDXFES2D.js} +2 -2
- package/dist/{daemon-5DS5BQXJ.js → daemon-K33ZPSEZ.js} +3 -3
- package/dist/{discord-QKT3JMRW.js → discord-VOHXRTCH.js} +113 -131
- package/dist/discord-VOHXRTCH.js.map +1 -0
- package/dist/{doctor-QQ3YZEYV.js → doctor-HASEBMUD.js} +4 -4
- package/dist/doctor-W4VGLDVM.js +9 -0
- package/dist/index.d.ts +25 -9
- package/dist/index.js +11 -11
- package/dist/{main-B5L3DD3Y.js → main-DUXVFTDD.js} +19 -19
- package/dist/{new-session-K6UCWYOP.js → new-session-NHK7TOEW.js} +3 -3
- package/dist/{settings-RRF77IC4.js → settings-6TF4WIGJ.js} +3 -3
- package/dist/{setup-5ZKSUR26.js → setup-RJCEB6FS.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-3ZO3MHZN.js.map +0 -1
- package/dist/chunk-774Y4RAK.js.map +0 -1
- package/dist/chunk-AHPRT3RY.js.map +0 -1
- package/dist/chunk-F3AICYO4.js.map +0 -1
- package/dist/chunk-FCLGYYTY.js.map +0 -1
- package/dist/chunk-ZMVVW3BK.js.map +0 -1
- package/dist/discord-QKT3JMRW.js.map +0 -1
- package/dist/doctor-6SUCVUZB.js +0 -9
- /package/dist/{adapter-RKK7A5GI.js.map → adapter-7GY3N4ZH.js.map} +0 -0
- /package/dist/{admin-SCP25TN2.js.map → admin-2HAFXQBG.js.map} +0 -0
- /package/dist/{chunk-WVMSP4AF.js.map → chunk-2J2RBYWN.js.map} +0 -0
- /package/dist/{chunk-ZKTIZME6.js.map → chunk-47B7GNOE.js.map} +0 -0
- /package/dist/{chunk-XVL6AGMG.js.map → chunk-5OVPEDUB.js.map} +0 -0
- /package/dist/{chunk-3IRAWHMC.js.map → chunk-MZXWCDBU.js.map} +0 -0
- /package/dist/{chunk-YQRF3IOR.js.map → chunk-O7CPGUAI.js.map} +0 -0
- /package/dist/{chunk-7KZI2236.js.map → chunk-RHE2JSYE.js.map} +0 -0
- /package/dist/{chunk-JV6XQRAE.js.map → chunk-XANPHG7W.js.map} +0 -0
- /package/dist/{chunk-PJVKOZTR.js.map → chunk-YEOY2PBJ.js.map} +0 -0
- /package/dist/{config-B26J3XXN.js.map → config-CQAS6YHR.js.map} +0 -0
- /package/dist/{config-editor-QTGUK3CD.js.map → config-editor-37BM56WF.js.map} +0 -0
- /package/dist/{config-registry-7I6GGDOY.js.map → config-registry-HDXFES2D.js.map} +0 -0
- /package/dist/{daemon-5DS5BQXJ.js.map → daemon-K33ZPSEZ.js.map} +0 -0
- /package/dist/{doctor-6SUCVUZB.js.map → doctor-HASEBMUD.js.map} +0 -0
- /package/dist/{doctor-QQ3YZEYV.js.map → doctor-W4VGLDVM.js.map} +0 -0
- /package/dist/{main-B5L3DD3Y.js.map → main-DUXVFTDD.js.map} +0 -0
- /package/dist/{new-session-K6UCWYOP.js.map → new-session-NHK7TOEW.js.map} +0 -0
- /package/dist/{settings-RRF77IC4.js.map → settings-6TF4WIGJ.js.map} +0 -0
- /package/dist/{setup-5ZKSUR26.js.map → setup-RJCEB6FS.js.map} +0 -0
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PRODUCT_GUIDE,
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
STATUS_ICONS,
|
|
4
|
+
dispatchMessage,
|
|
5
|
+
evaluateNoise,
|
|
6
|
+
extractContentText,
|
|
7
|
+
formatTokens,
|
|
8
|
+
formatToolSummary,
|
|
9
|
+
formatToolTitle,
|
|
10
|
+
progressBar,
|
|
11
|
+
splitMessage,
|
|
12
|
+
stripCodeFences,
|
|
13
|
+
truncateContent
|
|
14
|
+
} from "./chunk-JUYDFUSN.js";
|
|
5
15
|
import {
|
|
6
16
|
DoctorEngine
|
|
7
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-YEOY2PBJ.js";
|
|
8
18
|
import {
|
|
9
19
|
buildMenuKeyboard,
|
|
10
20
|
buildSkillMessages,
|
|
@@ -15,16 +25,16 @@ import {
|
|
|
15
25
|
import {
|
|
16
26
|
CheckpointReader,
|
|
17
27
|
DEFAULT_MAX_TOKENS
|
|
18
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-LO4Y5WQ7.js";
|
|
19
29
|
import {
|
|
20
30
|
ChannelAdapter
|
|
21
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-LBIKITQT.js";
|
|
22
32
|
import {
|
|
23
33
|
getConfigValue,
|
|
24
34
|
getSafeFields,
|
|
25
35
|
isHotReloadable,
|
|
26
36
|
resolveOptions
|
|
27
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-JHYXKVV2.js";
|
|
28
38
|
import {
|
|
29
39
|
createChildLogger
|
|
30
40
|
} from "./chunk-GAK6PIBW.js";
|
|
@@ -80,13 +90,16 @@ function escapeHtml(text) {
|
|
|
80
90
|
function markdownToTelegramHtml(md) {
|
|
81
91
|
const codeBlocks = [];
|
|
82
92
|
const inlineCodes = [];
|
|
83
|
-
let text = md.replace(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
let text = md.replace(
|
|
94
|
+
/```(\w*)\n?([\s\S]*?)```/g,
|
|
95
|
+
(_match, lang, code) => {
|
|
96
|
+
const index = codeBlocks.length;
|
|
97
|
+
const escapedCode = escapeHtml(code);
|
|
98
|
+
const langAttr = lang ? ` class="language-${escapeHtml(lang)}"` : "";
|
|
99
|
+
codeBlocks.push(`<pre><code${langAttr}>${escapedCode}</code></pre>`);
|
|
100
|
+
return `\0CODE_BLOCK_${index}\0`;
|
|
101
|
+
}
|
|
102
|
+
);
|
|
90
103
|
text = text.replace(/`([^`]+)`/g, (_match, code) => {
|
|
91
104
|
const index = inlineCodes.length;
|
|
92
105
|
inlineCodes.push(`<code>${escapeHtml(code)}</code>`);
|
|
@@ -104,72 +117,32 @@ function markdownToTelegramHtml(md) {
|
|
|
104
117
|
});
|
|
105
118
|
return text;
|
|
106
119
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
};
|
|
113
|
-
var KIND_ICON = {
|
|
114
|
-
read: "\u{1F4D6}",
|
|
115
|
-
edit: "\u270F\uFE0F",
|
|
116
|
-
delete: "\u{1F5D1}\uFE0F",
|
|
117
|
-
execute: "\u25B6\uFE0F",
|
|
118
|
-
search: "\u{1F50D}",
|
|
119
|
-
fetch: "\u{1F310}",
|
|
120
|
-
think: "\u{1F9E0}",
|
|
121
|
-
move: "\u{1F4E6}",
|
|
122
|
-
other: "\u{1F6E0}\uFE0F"
|
|
123
|
-
};
|
|
124
|
-
function extractContentText(content, depth = 0) {
|
|
125
|
-
if (!content || depth > 5) return "";
|
|
126
|
-
if (typeof content === "string") return content;
|
|
127
|
-
if (Array.isArray(content)) {
|
|
128
|
-
return content.map((c) => extractContentText(c, depth + 1)).filter(Boolean).join("\n");
|
|
129
|
-
}
|
|
130
|
-
if (typeof content === "object" && content !== null) {
|
|
131
|
-
const c = content;
|
|
132
|
-
if (c.type === "text" && typeof c.text === "string") return c.text;
|
|
133
|
-
if (typeof c.text === "string") return c.text;
|
|
134
|
-
if (typeof c.content === "string") return c.content;
|
|
135
|
-
if (c.content && typeof c.content === "object") return extractContentText(c.content, depth + 1);
|
|
136
|
-
if (c.input) return extractContentText(c.input, depth + 1);
|
|
137
|
-
if (c.output) return extractContentText(c.output, depth + 1);
|
|
138
|
-
const keys = Object.keys(c).filter((k) => k !== "type");
|
|
139
|
-
if (keys.length === 0) return "";
|
|
140
|
-
return JSON.stringify(c, null, 2);
|
|
141
|
-
}
|
|
142
|
-
return String(content);
|
|
143
|
-
}
|
|
144
|
-
function truncateContent(text, maxLen = 3800) {
|
|
145
|
-
if (text.length <= maxLen) return text;
|
|
146
|
-
return text.slice(0, maxLen) + "\n\u2026 (truncated)";
|
|
147
|
-
}
|
|
148
|
-
function formatToolCall(tool) {
|
|
149
|
-
const si = STATUS_ICON[tool.status || ""] || "\u{1F527}";
|
|
150
|
-
const ki = KIND_ICON[tool.kind || ""] || "\u{1F6E0}\uFE0F";
|
|
151
|
-
let text = `${si} ${ki} <b>${escapeHtml(tool.name || "Tool")}</b>`;
|
|
120
|
+
function formatToolCall(tool, verbosity = "medium") {
|
|
121
|
+
const si = STATUS_ICONS[tool.status || ""] || "\u{1F527}";
|
|
122
|
+
const name = tool.name || "Tool";
|
|
123
|
+
const label = verbosity === "low" ? formatToolTitle(name, tool.rawInput) : formatToolSummary(name, tool.rawInput);
|
|
124
|
+
let text = `${si} <b>${escapeHtml(label)}</b>`;
|
|
152
125
|
text += formatViewerLinks(tool.viewerLinks, tool.viewerFilePath);
|
|
153
|
-
if (!tool.viewerLinks) {
|
|
154
|
-
const details = extractContentText(tool.content);
|
|
126
|
+
if (verbosity === "high" || verbosity === "medium" && !tool.viewerLinks) {
|
|
127
|
+
const details = stripCodeFences(extractContentText(tool.content));
|
|
155
128
|
if (details) {
|
|
156
129
|
text += `
|
|
157
|
-
<pre>${escapeHtml(truncateContent(details))}</pre>`;
|
|
130
|
+
<pre>${escapeHtml(truncateContent(details, 3800))}</pre>`;
|
|
158
131
|
}
|
|
159
132
|
}
|
|
160
133
|
return text;
|
|
161
134
|
}
|
|
162
|
-
function formatToolUpdate(update) {
|
|
163
|
-
const si =
|
|
164
|
-
const ki = KIND_ICON[update.kind || ""] || "\u{1F6E0}\uFE0F";
|
|
135
|
+
function formatToolUpdate(update, verbosity = "medium") {
|
|
136
|
+
const si = STATUS_ICONS[update.status] || "\u{1F527}";
|
|
165
137
|
const name = update.name || "Tool";
|
|
166
|
-
|
|
138
|
+
const label = verbosity === "low" ? formatToolTitle(name, update.rawInput) : formatToolSummary(name, update.rawInput);
|
|
139
|
+
let text = `${si} <b>${escapeHtml(label)}</b>`;
|
|
167
140
|
text += formatViewerLinks(update.viewerLinks, update.viewerFilePath);
|
|
168
|
-
if (!update.viewerLinks) {
|
|
169
|
-
const details = extractContentText(update.content);
|
|
141
|
+
if (verbosity === "high" || verbosity === "medium" && !update.viewerLinks) {
|
|
142
|
+
const details = stripCodeFences(extractContentText(update.content));
|
|
170
143
|
if (details) {
|
|
171
144
|
text += `
|
|
172
|
-
<pre>${escapeHtml(truncateContent(details))}</pre>`;
|
|
145
|
+
<pre>${escapeHtml(truncateContent(details, 3800))}</pre>`;
|
|
173
146
|
}
|
|
174
147
|
}
|
|
175
148
|
return text;
|
|
@@ -178,19 +151,14 @@ function formatViewerLinks(links, filePath) {
|
|
|
178
151
|
if (!links) return "";
|
|
179
152
|
const fileName = filePath ? filePath.split("/").pop() || filePath : "";
|
|
180
153
|
let text = "\n";
|
|
181
|
-
if (links.file)
|
|
154
|
+
if (links.file)
|
|
155
|
+
text += `
|
|
182
156
|
\u{1F4C4} <a href="${escapeHtml(links.file)}">View ${escapeHtml(fileName || "file")}</a>`;
|
|
183
|
-
if (links.diff)
|
|
157
|
+
if (links.diff)
|
|
158
|
+
text += `
|
|
184
159
|
\u{1F4DD} <a href="${escapeHtml(links.diff)}">View diff${fileName ? ` \u2014 ${escapeHtml(fileName)}` : ""}</a>`;
|
|
185
160
|
return text;
|
|
186
161
|
}
|
|
187
|
-
function formatTokens(n) {
|
|
188
|
-
return n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n);
|
|
189
|
-
}
|
|
190
|
-
function progressBar(ratio) {
|
|
191
|
-
const filled = Math.round(Math.min(ratio, 1) * 10);
|
|
192
|
-
return "\u2593".repeat(filled) + "\u2591".repeat(10 - filled);
|
|
193
|
-
}
|
|
194
162
|
function formatUsage(usage) {
|
|
195
163
|
const { tokensUsed, contextSize } = usage;
|
|
196
164
|
if (tokensUsed == null) return "\u{1F4CA} Usage data unavailable";
|
|
@@ -217,49 +185,30 @@ function formatUsageReport(summaries, budgetStatus) {
|
|
|
217
185
|
const lines = ["\u{1F4CA} <b>Usage Report</b>"];
|
|
218
186
|
for (const summary of summaries) {
|
|
219
187
|
lines.push("");
|
|
220
|
-
lines.push(
|
|
188
|
+
lines.push(
|
|
189
|
+
`\u2500\u2500 <b>${PERIOD_LABEL[summary.period] ?? summary.period}</b> \u2500\u2500`
|
|
190
|
+
);
|
|
221
191
|
lines.push(
|
|
222
192
|
`\u{1F4B0} ${formatCost(summary.totalCost)} \xB7 \u{1F524} ${formatTokens(summary.totalTokens)} tokens \xB7 \u{1F4CB} ${summary.sessionCount} sessions`
|
|
223
193
|
);
|
|
224
194
|
if (summary.period === "month" && budgetStatus.budget > 0) {
|
|
225
195
|
const bar = progressBar(budgetStatus.used / budgetStatus.budget);
|
|
226
|
-
lines.push(
|
|
196
|
+
lines.push(
|
|
197
|
+
`Budget: ${formatCost(budgetStatus.used)} / ${formatCost(budgetStatus.budget)} (${budgetStatus.percent}%)`
|
|
198
|
+
);
|
|
227
199
|
lines.push(`${bar} ${budgetStatus.percent}%`);
|
|
228
200
|
}
|
|
229
201
|
}
|
|
230
202
|
return lines.join("\n");
|
|
231
203
|
}
|
|
232
|
-
function
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
const wouldLeaveSmall = remaining.length < maxLength * 1.3;
|
|
242
|
-
const searchLimit = wouldLeaveSmall ? Math.floor(remaining.length / 2) + 300 : maxLength;
|
|
243
|
-
let splitAt = remaining.lastIndexOf("\n\n", searchLimit);
|
|
244
|
-
if (splitAt === -1 || splitAt < searchLimit * 0.2) {
|
|
245
|
-
splitAt = remaining.lastIndexOf("\n", searchLimit);
|
|
246
|
-
}
|
|
247
|
-
if (splitAt === -1 || splitAt < searchLimit * 0.2) {
|
|
248
|
-
splitAt = searchLimit;
|
|
249
|
-
}
|
|
250
|
-
const candidate = remaining.slice(0, splitAt);
|
|
251
|
-
const fences = candidate.match(/```/g);
|
|
252
|
-
if (fences && fences.length % 2 !== 0) {
|
|
253
|
-
const closingFence = remaining.indexOf("```", splitAt);
|
|
254
|
-
if (closingFence !== -1) {
|
|
255
|
-
const afterFence = remaining.indexOf("\n", closingFence + 3);
|
|
256
|
-
splitAt = afterFence !== -1 ? afterFence + 1 : closingFence + 3;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
chunks.push(remaining.slice(0, splitAt));
|
|
260
|
-
remaining = remaining.slice(splitAt).replace(/^\n+/, "");
|
|
261
|
-
}
|
|
262
|
-
return chunks;
|
|
204
|
+
function formatSummary(summary, sessionName) {
|
|
205
|
+
const header = sessionName ? `\u{1F4CB} <b>Summary \u2014 ${escapeHtml(sessionName)}</b>` : "\u{1F4CB} <b>Session Summary</b>";
|
|
206
|
+
return `${header}
|
|
207
|
+
|
|
208
|
+
${escapeHtml(summary)}`;
|
|
209
|
+
}
|
|
210
|
+
function splitMessage2(text, maxLength = 3800) {
|
|
211
|
+
return splitMessage(text, maxLength);
|
|
263
212
|
}
|
|
264
213
|
|
|
265
214
|
// src/adapters/telegram/commands/admin.ts
|
|
@@ -271,7 +220,10 @@ function setupDangerousModeCallbacks(bot, core) {
|
|
|
271
220
|
const session = core.sessionManager.getSession(sessionId);
|
|
272
221
|
if (session) {
|
|
273
222
|
session.dangerousMode = !session.dangerousMode;
|
|
274
|
-
log.info(
|
|
223
|
+
log.info(
|
|
224
|
+
{ sessionId, dangerousMode: session.dangerousMode },
|
|
225
|
+
"Dangerous mode toggled via button"
|
|
226
|
+
);
|
|
275
227
|
core.sessionManager.patchRecord(sessionId, { dangerousMode: session.dangerousMode }).catch(() => {
|
|
276
228
|
});
|
|
277
229
|
const toastText2 = session.dangerousMode ? "\u2620\uFE0F Dangerous mode enabled \u2014 permissions auto-approved" : "\u{1F510} Dangerous mode disabled \u2014 permissions shown normally";
|
|
@@ -281,7 +233,11 @@ function setupDangerousModeCallbacks(bot, core) {
|
|
|
281
233
|
}
|
|
282
234
|
try {
|
|
283
235
|
await ctx.editMessageReplyMarkup({
|
|
284
|
-
reply_markup: buildSessionControlKeyboard(
|
|
236
|
+
reply_markup: buildSessionControlKeyboard(
|
|
237
|
+
sessionId,
|
|
238
|
+
session.dangerousMode,
|
|
239
|
+
session.voiceMode === "on"
|
|
240
|
+
)
|
|
285
241
|
});
|
|
286
242
|
} catch {
|
|
287
243
|
}
|
|
@@ -290,7 +246,9 @@ function setupDangerousModeCallbacks(bot, core) {
|
|
|
290
246
|
const record = core.sessionManager.getSessionRecord(sessionId);
|
|
291
247
|
if (!record || record.status === "cancelled" || record.status === "error") {
|
|
292
248
|
try {
|
|
293
|
-
await ctx.answerCallbackQuery({
|
|
249
|
+
await ctx.answerCallbackQuery({
|
|
250
|
+
text: "\u26A0\uFE0F Session not found or already ended."
|
|
251
|
+
});
|
|
294
252
|
} catch {
|
|
295
253
|
}
|
|
296
254
|
return;
|
|
@@ -298,7 +256,10 @@ function setupDangerousModeCallbacks(bot, core) {
|
|
|
298
256
|
const newDangerousMode = !(record.dangerousMode ?? false);
|
|
299
257
|
core.sessionManager.patchRecord(sessionId, { dangerousMode: newDangerousMode }).catch(() => {
|
|
300
258
|
});
|
|
301
|
-
log.info(
|
|
259
|
+
log.info(
|
|
260
|
+
{ sessionId, dangerousMode: newDangerousMode },
|
|
261
|
+
"Dangerous mode toggled via button (store-only, session not in memory)"
|
|
262
|
+
);
|
|
302
263
|
const toastText = newDangerousMode ? "\u2620\uFE0F Dangerous mode enabled \u2014 permissions auto-approved" : "\u{1F510} Dangerous mode disabled \u2014 permissions shown normally";
|
|
303
264
|
try {
|
|
304
265
|
await ctx.answerCallbackQuery({ text: toastText });
|
|
@@ -306,7 +267,11 @@ function setupDangerousModeCallbacks(bot, core) {
|
|
|
306
267
|
}
|
|
307
268
|
try {
|
|
308
269
|
await ctx.editMessageReplyMarkup({
|
|
309
|
-
reply_markup: buildSessionControlKeyboard(
|
|
270
|
+
reply_markup: buildSessionControlKeyboard(
|
|
271
|
+
sessionId,
|
|
272
|
+
newDangerousMode,
|
|
273
|
+
false
|
|
274
|
+
)
|
|
310
275
|
});
|
|
311
276
|
} catch {
|
|
312
277
|
}
|
|
@@ -315,26 +280,40 @@ function setupDangerousModeCallbacks(bot, core) {
|
|
|
315
280
|
async function handleEnableDangerous(ctx, core) {
|
|
316
281
|
const threadId = ctx.message?.message_thread_id;
|
|
317
282
|
if (!threadId) {
|
|
318
|
-
await ctx.reply("\u26A0\uFE0F This command only works inside a session topic.", {
|
|
283
|
+
await ctx.reply("\u26A0\uFE0F This command only works inside a session topic.", {
|
|
284
|
+
parse_mode: "HTML"
|
|
285
|
+
});
|
|
319
286
|
return;
|
|
320
287
|
}
|
|
321
|
-
const session = core.sessionManager.getSessionByThread(
|
|
288
|
+
const session = core.sessionManager.getSessionByThread(
|
|
289
|
+
"telegram",
|
|
290
|
+
String(threadId)
|
|
291
|
+
);
|
|
322
292
|
if (session) {
|
|
323
293
|
if (session.dangerousMode) {
|
|
324
|
-
await ctx.reply("\u2620\uFE0F Dangerous mode is already enabled.", {
|
|
294
|
+
await ctx.reply("\u2620\uFE0F Dangerous mode is already enabled.", {
|
|
295
|
+
parse_mode: "HTML"
|
|
296
|
+
});
|
|
325
297
|
return;
|
|
326
298
|
}
|
|
327
299
|
session.dangerousMode = true;
|
|
328
300
|
core.sessionManager.patchRecord(session.id, { dangerousMode: true }).catch(() => {
|
|
329
301
|
});
|
|
330
302
|
} else {
|
|
331
|
-
const record = core.sessionManager.getRecordByThread(
|
|
303
|
+
const record = core.sessionManager.getRecordByThread(
|
|
304
|
+
"telegram",
|
|
305
|
+
String(threadId)
|
|
306
|
+
);
|
|
332
307
|
if (!record || record.status === "cancelled" || record.status === "error") {
|
|
333
|
-
await ctx.reply("\u26A0\uFE0F No active session in this topic.", {
|
|
308
|
+
await ctx.reply("\u26A0\uFE0F No active session in this topic.", {
|
|
309
|
+
parse_mode: "HTML"
|
|
310
|
+
});
|
|
334
311
|
return;
|
|
335
312
|
}
|
|
336
313
|
if (record.dangerousMode) {
|
|
337
|
-
await ctx.reply("\u2620\uFE0F Dangerous mode is already enabled.", {
|
|
314
|
+
await ctx.reply("\u2620\uFE0F Dangerous mode is already enabled.", {
|
|
315
|
+
parse_mode: "HTML"
|
|
316
|
+
});
|
|
338
317
|
return;
|
|
339
318
|
}
|
|
340
319
|
core.sessionManager.patchRecord(record.sessionId, { dangerousMode: true }).catch(() => {
|
|
@@ -352,32 +331,49 @@ Use /disable_dangerous to restore normal behaviour.`,
|
|
|
352
331
|
async function handleDisableDangerous(ctx, core) {
|
|
353
332
|
const threadId = ctx.message?.message_thread_id;
|
|
354
333
|
if (!threadId) {
|
|
355
|
-
await ctx.reply("\u26A0\uFE0F This command only works inside a session topic.", {
|
|
334
|
+
await ctx.reply("\u26A0\uFE0F This command only works inside a session topic.", {
|
|
335
|
+
parse_mode: "HTML"
|
|
336
|
+
});
|
|
356
337
|
return;
|
|
357
338
|
}
|
|
358
|
-
const session = core.sessionManager.getSessionByThread(
|
|
339
|
+
const session = core.sessionManager.getSessionByThread(
|
|
340
|
+
"telegram",
|
|
341
|
+
String(threadId)
|
|
342
|
+
);
|
|
359
343
|
if (session) {
|
|
360
344
|
if (!session.dangerousMode) {
|
|
361
|
-
await ctx.reply("\u{1F510} Dangerous mode is already disabled.", {
|
|
345
|
+
await ctx.reply("\u{1F510} Dangerous mode is already disabled.", {
|
|
346
|
+
parse_mode: "HTML"
|
|
347
|
+
});
|
|
362
348
|
return;
|
|
363
349
|
}
|
|
364
350
|
session.dangerousMode = false;
|
|
365
351
|
core.sessionManager.patchRecord(session.id, { dangerousMode: false }).catch(() => {
|
|
366
352
|
});
|
|
367
353
|
} else {
|
|
368
|
-
const record = core.sessionManager.getRecordByThread(
|
|
354
|
+
const record = core.sessionManager.getRecordByThread(
|
|
355
|
+
"telegram",
|
|
356
|
+
String(threadId)
|
|
357
|
+
);
|
|
369
358
|
if (!record || record.status === "cancelled" || record.status === "error") {
|
|
370
|
-
await ctx.reply("\u26A0\uFE0F No active session in this topic.", {
|
|
359
|
+
await ctx.reply("\u26A0\uFE0F No active session in this topic.", {
|
|
360
|
+
parse_mode: "HTML"
|
|
361
|
+
});
|
|
371
362
|
return;
|
|
372
363
|
}
|
|
373
364
|
if (!record.dangerousMode) {
|
|
374
|
-
await ctx.reply("\u{1F510} Dangerous mode is already disabled.", {
|
|
365
|
+
await ctx.reply("\u{1F510} Dangerous mode is already disabled.", {
|
|
366
|
+
parse_mode: "HTML"
|
|
367
|
+
});
|
|
375
368
|
return;
|
|
376
369
|
}
|
|
377
370
|
core.sessionManager.patchRecord(record.sessionId, { dangerousMode: false }).catch(() => {
|
|
378
371
|
});
|
|
379
372
|
}
|
|
380
|
-
await ctx.reply(
|
|
373
|
+
await ctx.reply(
|
|
374
|
+
"\u{1F510} <b>Dangerous mode disabled</b>\n\nPermission requests will be shown normally.",
|
|
375
|
+
{ parse_mode: "HTML" }
|
|
376
|
+
);
|
|
381
377
|
}
|
|
382
378
|
function buildSessionControlKeyboard(sessionId, dangerousMode, voiceMode) {
|
|
383
379
|
return new InlineKeyboard().text(
|
|
@@ -394,7 +390,9 @@ function setupTTSCallbacks(bot, core) {
|
|
|
394
390
|
const session = core.sessionManager.getSession(sessionId);
|
|
395
391
|
if (!session) {
|
|
396
392
|
try {
|
|
397
|
-
await ctx.answerCallbackQuery({
|
|
393
|
+
await ctx.answerCallbackQuery({
|
|
394
|
+
text: "\u26A0\uFE0F Session not found or not active."
|
|
395
|
+
});
|
|
398
396
|
} catch {
|
|
399
397
|
}
|
|
400
398
|
return;
|
|
@@ -408,7 +406,11 @@ function setupTTSCallbacks(bot, core) {
|
|
|
408
406
|
}
|
|
409
407
|
try {
|
|
410
408
|
await ctx.editMessageReplyMarkup({
|
|
411
|
-
reply_markup: buildSessionControlKeyboard(
|
|
409
|
+
reply_markup: buildSessionControlKeyboard(
|
|
410
|
+
sessionId,
|
|
411
|
+
session.dangerousMode,
|
|
412
|
+
newMode === "on"
|
|
413
|
+
)
|
|
412
414
|
});
|
|
413
415
|
} catch {
|
|
414
416
|
}
|
|
@@ -417,42 +419,113 @@ function setupTTSCallbacks(bot, core) {
|
|
|
417
419
|
async function handleTTS(ctx, core) {
|
|
418
420
|
const threadId = ctx.message?.message_thread_id;
|
|
419
421
|
if (!threadId) {
|
|
420
|
-
await ctx.reply("\u26A0\uFE0F This command only works inside a session topic.", {
|
|
422
|
+
await ctx.reply("\u26A0\uFE0F This command only works inside a session topic.", {
|
|
423
|
+
parse_mode: "HTML"
|
|
424
|
+
});
|
|
421
425
|
return;
|
|
422
426
|
}
|
|
423
427
|
const session = await core.getOrResumeSession("telegram", String(threadId));
|
|
424
428
|
if (!session) {
|
|
425
|
-
await ctx.reply("\u26A0\uFE0F No active session in this topic.", {
|
|
429
|
+
await ctx.reply("\u26A0\uFE0F No active session in this topic.", {
|
|
430
|
+
parse_mode: "HTML"
|
|
431
|
+
});
|
|
426
432
|
return;
|
|
427
433
|
}
|
|
428
434
|
const args = ctx.message?.text?.split(/\s+/).slice(1) ?? [];
|
|
429
435
|
const arg = args[0]?.toLowerCase();
|
|
430
436
|
if (arg === "on") {
|
|
431
437
|
session.setVoiceMode("on");
|
|
432
|
-
await ctx.reply("\u{1F50A} Text to Speech enabled for this session.", {
|
|
438
|
+
await ctx.reply("\u{1F50A} Text to Speech enabled for this session.", {
|
|
439
|
+
parse_mode: "HTML"
|
|
440
|
+
});
|
|
433
441
|
} else if (arg === "off") {
|
|
434
442
|
session.setVoiceMode("off");
|
|
435
443
|
await ctx.reply("\u{1F507} Text to Speech disabled.", { parse_mode: "HTML" });
|
|
436
444
|
} else {
|
|
437
445
|
session.setVoiceMode("next");
|
|
438
|
-
await ctx.reply("\u{1F50A} Text to Speech enabled for the next message.", {
|
|
446
|
+
await ctx.reply("\u{1F50A} Text to Speech enabled for the next message.", {
|
|
447
|
+
parse_mode: "HTML"
|
|
448
|
+
});
|
|
439
449
|
}
|
|
440
450
|
}
|
|
451
|
+
var VERBOSITY_LABELS = {
|
|
452
|
+
low: "\u{1F507} Low",
|
|
453
|
+
medium: "\u{1F4CA} Medium",
|
|
454
|
+
high: "\u{1F4D6} High"
|
|
455
|
+
};
|
|
456
|
+
async function handleVerbosity(ctx, core) {
|
|
457
|
+
const args = ctx.message?.text?.split(/\s+/).slice(1) ?? [];
|
|
458
|
+
const arg = args[0]?.toLowerCase();
|
|
459
|
+
if (arg === "low" || arg === "medium" || arg === "high") {
|
|
460
|
+
await core.configManager.save(
|
|
461
|
+
{ channels: { telegram: { displayVerbosity: arg } } },
|
|
462
|
+
"channels.telegram.displayVerbosity"
|
|
463
|
+
);
|
|
464
|
+
await ctx.reply(
|
|
465
|
+
`${VERBOSITY_LABELS[arg]} Display verbosity set to <b>${arg}</b>.`,
|
|
466
|
+
{ parse_mode: "HTML" }
|
|
467
|
+
);
|
|
468
|
+
} else {
|
|
469
|
+
const current = core.configManager.get().channels?.telegram?.displayVerbosity ?? "medium";
|
|
470
|
+
await ctx.reply(
|
|
471
|
+
`\u{1F4CA} Current verbosity: <b>${current}</b>
|
|
472
|
+
|
|
473
|
+
Usage: <code>/verbosity low|medium|high</code>
|
|
474
|
+
|
|
475
|
+
\u2022 <b>low</b> \u2014 minimal output, title only
|
|
476
|
+
\u2022 <b>medium</b> \u2014 balanced (default)
|
|
477
|
+
\u2022 <b>high</b> \u2014 full detail with content`,
|
|
478
|
+
{ parse_mode: "HTML" }
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
function setupVerbosityCallbacks(bot, core) {
|
|
483
|
+
bot.callbackQuery(/^vb:/, async (ctx) => {
|
|
484
|
+
const level = ctx.callbackQuery.data.slice(3);
|
|
485
|
+
if (level !== "low" && level !== "medium" && level !== "high") return;
|
|
486
|
+
await core.configManager.save(
|
|
487
|
+
{ channels: { telegram: { displayVerbosity: level } } },
|
|
488
|
+
"channels.telegram.displayVerbosity"
|
|
489
|
+
);
|
|
490
|
+
try {
|
|
491
|
+
await ctx.answerCallbackQuery({
|
|
492
|
+
text: `${VERBOSITY_LABELS[level]} Verbosity: ${level}`
|
|
493
|
+
});
|
|
494
|
+
} catch {
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
}
|
|
441
498
|
async function handleUpdate(ctx, core) {
|
|
442
499
|
if (!core.requestRestart) {
|
|
443
|
-
await ctx.reply(
|
|
500
|
+
await ctx.reply(
|
|
501
|
+
"\u26A0\uFE0F Update is not available (no restart handler registered).",
|
|
502
|
+
{ parse_mode: "HTML" }
|
|
503
|
+
);
|
|
444
504
|
return;
|
|
445
505
|
}
|
|
446
506
|
const { getCurrentVersion, getLatestVersion, compareVersions, runUpdate } = await import("./version-AXXV6IV2.js");
|
|
447
507
|
const current = getCurrentVersion();
|
|
448
|
-
const statusMsg = await ctx.reply(
|
|
508
|
+
const statusMsg = await ctx.reply(
|
|
509
|
+
`\u{1F50D} Checking for updates... (current: v${escapeHtml(current)})`,
|
|
510
|
+
{ parse_mode: "HTML" }
|
|
511
|
+
);
|
|
449
512
|
const latest = await getLatestVersion();
|
|
450
513
|
if (!latest) {
|
|
451
|
-
await ctx.api.editMessageText(
|
|
514
|
+
await ctx.api.editMessageText(
|
|
515
|
+
ctx.chat.id,
|
|
516
|
+
statusMsg.message_id,
|
|
517
|
+
"\u274C Could not check for updates.",
|
|
518
|
+
{ parse_mode: "HTML" }
|
|
519
|
+
);
|
|
452
520
|
return;
|
|
453
521
|
}
|
|
454
522
|
if (compareVersions(current, latest) >= 0) {
|
|
455
|
-
await ctx.api.editMessageText(
|
|
523
|
+
await ctx.api.editMessageText(
|
|
524
|
+
ctx.chat.id,
|
|
525
|
+
statusMsg.message_id,
|
|
526
|
+
`\u2705 Already up to date (v${escapeHtml(current)}).`,
|
|
527
|
+
{ parse_mode: "HTML" }
|
|
528
|
+
);
|
|
456
529
|
return;
|
|
457
530
|
}
|
|
458
531
|
await ctx.api.editMessageText(
|
|
@@ -463,7 +536,12 @@ async function handleUpdate(ctx, core) {
|
|
|
463
536
|
);
|
|
464
537
|
const ok = await runUpdate();
|
|
465
538
|
if (!ok) {
|
|
466
|
-
await ctx.api.editMessageText(
|
|
539
|
+
await ctx.api.editMessageText(
|
|
540
|
+
ctx.chat.id,
|
|
541
|
+
statusMsg.message_id,
|
|
542
|
+
"\u274C Update failed. Try manually: <code>npm install -g @openacp/cli@latest</code>",
|
|
543
|
+
{ parse_mode: "HTML" }
|
|
544
|
+
);
|
|
467
545
|
return;
|
|
468
546
|
}
|
|
469
547
|
await ctx.api.editMessageText(
|
|
@@ -477,10 +555,16 @@ async function handleUpdate(ctx, core) {
|
|
|
477
555
|
}
|
|
478
556
|
async function handleRestart(ctx, core) {
|
|
479
557
|
if (!core.requestRestart) {
|
|
480
|
-
await ctx.reply(
|
|
558
|
+
await ctx.reply(
|
|
559
|
+
"\u26A0\uFE0F Restart is not available (no restart handler registered).",
|
|
560
|
+
{ parse_mode: "HTML" }
|
|
561
|
+
);
|
|
481
562
|
return;
|
|
482
563
|
}
|
|
483
|
-
await ctx.reply(
|
|
564
|
+
await ctx.reply(
|
|
565
|
+
"\u{1F504} <b>Restarting OpenACP...</b>\nRebuilding and restarting. Be back shortly.",
|
|
566
|
+
{ parse_mode: "HTML" }
|
|
567
|
+
);
|
|
484
568
|
await new Promise((r) => setTimeout(r, 500));
|
|
485
569
|
await core.requestRestart();
|
|
486
570
|
}
|
|
@@ -1183,26 +1267,13 @@ async function handleArchive(ctx, core) {
|
|
|
1183
1267
|
const threadId = ctx.message?.message_thread_id;
|
|
1184
1268
|
if (!threadId) return;
|
|
1185
1269
|
const session = core.sessionManager.getSessionByThread("telegram", String(threadId));
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
"\u2139\uFE0F <b>/archive</b> works in session topics \u2014 it recreates the topic with a clean chat view while keeping your agent session alive.\n\nGo to the session topic you want to archive and type /archive there.",
|
|
1189
|
-
{ parse_mode: "HTML" }
|
|
1190
|
-
);
|
|
1191
|
-
return;
|
|
1192
|
-
}
|
|
1193
|
-
if (session.status === "initializing") {
|
|
1194
|
-
await ctx.reply("\u23F3 Please wait for session to be ready.", { parse_mode: "HTML" });
|
|
1195
|
-
return;
|
|
1196
|
-
}
|
|
1197
|
-
if (session.status !== "active") {
|
|
1198
|
-
await ctx.reply(`\u26A0\uFE0F Cannot archive \u2014 session is ${session.status}.`, { parse_mode: "HTML" });
|
|
1199
|
-
return;
|
|
1200
|
-
}
|
|
1270
|
+
const record = !session ? core.sessionManager.getRecordByThread("telegram", String(threadId)) : void 0;
|
|
1271
|
+
const identifier = session?.id ?? record?.sessionId ?? `topic:${threadId}`;
|
|
1201
1272
|
await ctx.reply(
|
|
1202
|
-
"\u26A0\uFE0F <b>Archive this session
|
|
1273
|
+
"\u26A0\uFE0F <b>Archive this session?</b>\n\nThis will:\n\u2022 Delete this topic and all messages\n\u2022 Stop the agent session (if running)\n\u2022 Remove the session record\n\n<i>This action cannot be undone.</i>",
|
|
1203
1274
|
{
|
|
1204
1275
|
parse_mode: "HTML",
|
|
1205
|
-
reply_markup: new InlineKeyboard3().text("\u{1F5D1} Yes, archive", `ar:yes:${
|
|
1276
|
+
reply_markup: new InlineKeyboard3().text("\u{1F5D1} Yes, archive", `ar:yes:${identifier}`).text("\u274C Cancel", `ar:no:${identifier}`)
|
|
1206
1277
|
}
|
|
1207
1278
|
);
|
|
1208
1279
|
}
|
|
@@ -1213,31 +1284,103 @@ async function handleArchiveConfirm(ctx, core, chatId) {
|
|
|
1213
1284
|
await ctx.answerCallbackQuery();
|
|
1214
1285
|
} catch {
|
|
1215
1286
|
}
|
|
1216
|
-
const [, action,
|
|
1287
|
+
const [, action, ...rest] = data.split(":");
|
|
1288
|
+
const identifier = rest.join(":");
|
|
1217
1289
|
if (action === "no") {
|
|
1218
1290
|
await ctx.editMessageText("Archive cancelled.", { parse_mode: "HTML" });
|
|
1219
1291
|
return;
|
|
1220
1292
|
}
|
|
1221
|
-
await ctx.editMessageText("\u{1F504} Archiving
|
|
1222
|
-
|
|
1293
|
+
await ctx.editMessageText("\u{1F504} Archiving...", { parse_mode: "HTML" });
|
|
1294
|
+
if (identifier.startsWith("topic:")) {
|
|
1295
|
+
const topicId = Number(identifier.slice("topic:".length));
|
|
1296
|
+
try {
|
|
1297
|
+
await ctx.api.deleteForumTopic(chatId, topicId);
|
|
1298
|
+
core.notificationManager.notifyAll({
|
|
1299
|
+
sessionId: "system",
|
|
1300
|
+
sessionName: `Orphan topic #${topicId}`,
|
|
1301
|
+
type: "completed",
|
|
1302
|
+
summary: `Orphan topic #${topicId} archived and deleted.`
|
|
1303
|
+
});
|
|
1304
|
+
} catch (err) {
|
|
1305
|
+
core.notificationManager.notifyAll({
|
|
1306
|
+
sessionId: "system",
|
|
1307
|
+
sessionName: `Orphan topic #${topicId}`,
|
|
1308
|
+
type: "error",
|
|
1309
|
+
summary: `Failed to delete orphan topic #${topicId}: ${err.message}`
|
|
1310
|
+
});
|
|
1311
|
+
}
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
const result = await core.archiveSession(identifier);
|
|
1223
1315
|
if (result.ok) {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1316
|
+
core.notificationManager.notifyAll({
|
|
1317
|
+
sessionId: identifier,
|
|
1318
|
+
type: "completed",
|
|
1319
|
+
summary: `Session archived and deleted.`
|
|
1228
1320
|
});
|
|
1229
1321
|
} else {
|
|
1230
1322
|
try {
|
|
1231
1323
|
await ctx.editMessageText(`\u274C Failed to archive: <code>${escapeHtml(result.error)}</code>`, { parse_mode: "HTML" });
|
|
1232
1324
|
} catch {
|
|
1233
1325
|
core.notificationManager.notifyAll({
|
|
1234
|
-
sessionId,
|
|
1326
|
+
sessionId: identifier,
|
|
1235
1327
|
type: "error",
|
|
1236
|
-
summary: `Failed to
|
|
1328
|
+
summary: `Failed to archive session "${identifier}": ${result.error}`
|
|
1237
1329
|
});
|
|
1238
1330
|
}
|
|
1239
1331
|
}
|
|
1240
1332
|
}
|
|
1333
|
+
async function handleSummary(ctx, core) {
|
|
1334
|
+
const threadId = ctx.message?.message_thread_id;
|
|
1335
|
+
if (!threadId) return;
|
|
1336
|
+
const session = core.sessionManager.getSessionByThread("telegram", String(threadId));
|
|
1337
|
+
const record = !session ? core.sessionManager.getRecordByThread("telegram", String(threadId)) : void 0;
|
|
1338
|
+
const sessionId = session?.id ?? record?.sessionId;
|
|
1339
|
+
if (!sessionId) {
|
|
1340
|
+
await ctx.reply(
|
|
1341
|
+
"\u2139\uFE0F <b>/summary</b> works in session topics \u2014 it asks the agent to summarize the session.\n\nGo to a session topic and type /summary there.",
|
|
1342
|
+
{ parse_mode: "HTML" }
|
|
1343
|
+
);
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
await ctx.replyWithChatAction("typing");
|
|
1347
|
+
const result = await core.summarizeSession(sessionId);
|
|
1348
|
+
if (result.ok) {
|
|
1349
|
+
await ctx.reply(formatSummary(result.summary, session?.name ?? record?.name), { parse_mode: "HTML" });
|
|
1350
|
+
} else {
|
|
1351
|
+
await ctx.reply(`\u26A0\uFE0F ${escapeHtml(result.error)}`, { parse_mode: "HTML" });
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
async function handleSummaryCallback(ctx, core, chatId) {
|
|
1355
|
+
const data = ctx.callbackQuery?.data;
|
|
1356
|
+
if (!data) return;
|
|
1357
|
+
const sessionId = data.replace("sm:summary:", "");
|
|
1358
|
+
try {
|
|
1359
|
+
await ctx.answerCallbackQuery();
|
|
1360
|
+
} catch {
|
|
1361
|
+
}
|
|
1362
|
+
const session = core.sessionManager.getSession(sessionId);
|
|
1363
|
+
const record = !session ? core.sessionManager.getSessionRecord(sessionId) : void 0;
|
|
1364
|
+
const threadId = session ? Number(session.threadId) : record?.platform?.topicId ?? 0;
|
|
1365
|
+
if (!threadId) return;
|
|
1366
|
+
await ctx.api.sendMessage(chatId, "\u{1F4CB} Generating summary...", {
|
|
1367
|
+
message_thread_id: threadId,
|
|
1368
|
+
parse_mode: "HTML"
|
|
1369
|
+
});
|
|
1370
|
+
const result = await core.summarizeSession(sessionId);
|
|
1371
|
+
const sessionName = session?.name ?? record?.name;
|
|
1372
|
+
if (result.ok) {
|
|
1373
|
+
await ctx.api.sendMessage(chatId, formatSummary(result.summary, sessionName), {
|
|
1374
|
+
message_thread_id: threadId,
|
|
1375
|
+
parse_mode: "HTML"
|
|
1376
|
+
});
|
|
1377
|
+
} else {
|
|
1378
|
+
await ctx.api.sendMessage(chatId, `\u26A0\uFE0F ${escapeHtml(result.error)}`, {
|
|
1379
|
+
message_thread_id: threadId,
|
|
1380
|
+
parse_mode: "HTML"
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1241
1384
|
|
|
1242
1385
|
// src/adapters/telegram/commands/agents.ts
|
|
1243
1386
|
import { InlineKeyboard as InlineKeyboard4 } from "grammy";
|
|
@@ -2396,7 +2539,9 @@ function setupCommands(bot, core, chatId, assistant) {
|
|
|
2396
2539
|
bot.command("tunnel", (ctx) => handleTunnel(ctx, core));
|
|
2397
2540
|
bot.command("tunnels", (ctx) => handleTunnels(ctx, core));
|
|
2398
2541
|
bot.command("archive", (ctx) => handleArchive(ctx, core));
|
|
2542
|
+
bot.command("summary", (ctx) => handleSummary(ctx, core));
|
|
2399
2543
|
bot.command("text_to_speech", (ctx) => handleTTS(ctx, core));
|
|
2544
|
+
bot.command("verbosity", (ctx) => handleVerbosity(ctx, core));
|
|
2400
2545
|
bot.command("resume", (ctx) => handleResume(ctx, core, chatId, assistant));
|
|
2401
2546
|
}
|
|
2402
2547
|
function setupAllCallbacks(bot, core, chatId, systemTopicIds, getAssistantSession) {
|
|
@@ -2410,9 +2555,16 @@ function setupAllCallbacks(bot, core, chatId, systemTopicIds, getAssistantSessio
|
|
|
2410
2555
|
bot.callbackQuery(/^na:/, async (ctx) => {
|
|
2411
2556
|
const agentKey = ctx.callbackQuery.data.replace("na:", "");
|
|
2412
2557
|
await ctx.answerCallbackQuery();
|
|
2413
|
-
await createSessionDirect(
|
|
2558
|
+
await createSessionDirect(
|
|
2559
|
+
ctx,
|
|
2560
|
+
core,
|
|
2561
|
+
chatId,
|
|
2562
|
+
agentKey,
|
|
2563
|
+
core.configManager.get().workspace.baseDir
|
|
2564
|
+
);
|
|
2414
2565
|
});
|
|
2415
2566
|
bot.callbackQuery(/^ar:/, (ctx) => handleArchiveConfirm(ctx, core, chatId));
|
|
2567
|
+
bot.callbackQuery(/^sm:/, (ctx) => handleSummaryCallback(ctx, core, chatId));
|
|
2416
2568
|
bot.callbackQuery(/^m:/, async (ctx) => {
|
|
2417
2569
|
const data = ctx.callbackQuery.data;
|
|
2418
2570
|
try {
|
|
@@ -2460,8 +2612,14 @@ var STATIC_COMMANDS = [
|
|
|
2460
2612
|
{ command: "install", description: "Install a new agent" },
|
|
2461
2613
|
{ command: "help", description: "Help" },
|
|
2462
2614
|
{ command: "menu", description: "Show menu" },
|
|
2463
|
-
{
|
|
2464
|
-
|
|
2615
|
+
{
|
|
2616
|
+
command: "enable_dangerous",
|
|
2617
|
+
description: "Auto-approve all permission requests (session only)"
|
|
2618
|
+
},
|
|
2619
|
+
{
|
|
2620
|
+
command: "disable_dangerous",
|
|
2621
|
+
description: "Restore normal permission prompts (session only)"
|
|
2622
|
+
},
|
|
2465
2623
|
{ command: "integrate", description: "Manage agent integrations" },
|
|
2466
2624
|
{ command: "handoff", description: "Continue this session in your terminal" },
|
|
2467
2625
|
{ command: "clear", description: "Clear assistant history" },
|
|
@@ -2472,7 +2630,9 @@ var STATIC_COMMANDS = [
|
|
|
2472
2630
|
{ command: "tunnel", description: "Create/stop tunnel for a local port" },
|
|
2473
2631
|
{ command: "tunnels", description: "List active tunnels" },
|
|
2474
2632
|
{ command: "archive", description: "Archive session topic (recreate with clean history)" },
|
|
2633
|
+
{ command: "summary", description: "Get AI summary of current session" },
|
|
2475
2634
|
{ command: "text_to_speech", description: "Toggle Text to Speech (/text_to_speech on, /text_to_speech off)" },
|
|
2635
|
+
{ command: "verbosity", description: "Set display verbosity (/verbosity low|medium|high)" },
|
|
2476
2636
|
{ command: "resume", description: "Resume with conversation history from Entire checkpoints" }
|
|
2477
2637
|
];
|
|
2478
2638
|
|
|
@@ -3272,7 +3432,7 @@ var ToolCallTracker = class {
|
|
|
3272
3432
|
this.sendQueue = sendQueue;
|
|
3273
3433
|
}
|
|
3274
3434
|
sessions = /* @__PURE__ */ new Map();
|
|
3275
|
-
async trackNewCall(sessionId, threadId, meta) {
|
|
3435
|
+
async trackNewCall(sessionId, threadId, meta, verbosity = "medium") {
|
|
3276
3436
|
if (!this.sessions.has(sessionId)) {
|
|
3277
3437
|
this.sessions.set(sessionId, /* @__PURE__ */ new Map());
|
|
3278
3438
|
}
|
|
@@ -3284,31 +3444,34 @@ var ToolCallTracker = class {
|
|
|
3284
3444
|
msgId: 0,
|
|
3285
3445
|
name: meta.name,
|
|
3286
3446
|
kind: meta.kind,
|
|
3447
|
+
rawInput: meta.rawInput,
|
|
3287
3448
|
viewerLinks: meta.viewerLinks,
|
|
3288
3449
|
viewerFilePath: meta.viewerFilePath,
|
|
3289
3450
|
ready
|
|
3290
3451
|
});
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
this.chatId,
|
|
3294
|
-
formatToolCall(meta),
|
|
3295
|
-
{
|
|
3452
|
+
try {
|
|
3453
|
+
const msg = await this.sendQueue.enqueue(
|
|
3454
|
+
() => this.bot.api.sendMessage(this.chatId, formatToolCall(meta, verbosity), {
|
|
3296
3455
|
message_thread_id: threadId,
|
|
3297
3456
|
parse_mode: "HTML",
|
|
3298
3457
|
disable_notification: true
|
|
3299
|
-
}
|
|
3300
|
-
)
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3458
|
+
})
|
|
3459
|
+
);
|
|
3460
|
+
const toolEntry = this.sessions.get(sessionId).get(meta.id);
|
|
3461
|
+
toolEntry.msgId = msg.message_id;
|
|
3462
|
+
} finally {
|
|
3463
|
+
resolveReady();
|
|
3464
|
+
}
|
|
3305
3465
|
}
|
|
3306
|
-
async updateCall(sessionId, meta) {
|
|
3466
|
+
async updateCall(sessionId, meta, verbosity = "medium") {
|
|
3307
3467
|
const toolState = this.sessions.get(sessionId)?.get(meta.id);
|
|
3308
3468
|
if (!toolState) return;
|
|
3309
3469
|
if (meta.viewerLinks) {
|
|
3310
3470
|
toolState.viewerLinks = meta.viewerLinks;
|
|
3311
|
-
log11.debug(
|
|
3471
|
+
log11.debug(
|
|
3472
|
+
{ toolId: meta.id, viewerLinks: meta.viewerLinks },
|
|
3473
|
+
"Accumulated viewerLinks"
|
|
3474
|
+
);
|
|
3312
3475
|
}
|
|
3313
3476
|
if (meta.viewerFilePath) toolState.viewerFilePath = meta.viewerFilePath;
|
|
3314
3477
|
if (meta.name) toolState.name = meta.name;
|
|
@@ -3331,10 +3494,11 @@ var ToolCallTracker = class {
|
|
|
3331
3494
|
...meta,
|
|
3332
3495
|
name: toolState.name,
|
|
3333
3496
|
kind: toolState.kind,
|
|
3497
|
+
rawInput: toolState.rawInput,
|
|
3334
3498
|
viewerLinks: toolState.viewerLinks,
|
|
3335
3499
|
viewerFilePath: toolState.viewerFilePath
|
|
3336
3500
|
};
|
|
3337
|
-
const formattedText = formatToolUpdate(merged);
|
|
3501
|
+
const formattedText = formatToolUpdate(merged, verbosity);
|
|
3338
3502
|
try {
|
|
3339
3503
|
await this.sendQueue.enqueue(
|
|
3340
3504
|
() => this.bot.api.editMessageText(
|
|
@@ -3488,7 +3652,7 @@ var MessageDraft = class {
|
|
|
3488
3652
|
} catch {
|
|
3489
3653
|
}
|
|
3490
3654
|
}
|
|
3491
|
-
const mdChunks =
|
|
3655
|
+
const mdChunks = splitMessage2(this.buffer);
|
|
3492
3656
|
const chunkPromises = [];
|
|
3493
3657
|
for (let i = 0; i < mdChunks.length; i++) {
|
|
3494
3658
|
const html = markdownToTelegramHtml(mdChunks[i]);
|
|
@@ -3740,6 +3904,12 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3740
3904
|
skillManager;
|
|
3741
3905
|
fileService;
|
|
3742
3906
|
sessionTrackers = /* @__PURE__ */ new Map();
|
|
3907
|
+
get verbosity() {
|
|
3908
|
+
const live = this.core.configManager.get().channels?.telegram;
|
|
3909
|
+
const v = live?.displayVerbosity ?? this.telegramConfig.displayVerbosity;
|
|
3910
|
+
if (v === "low" || v === "high") return v;
|
|
3911
|
+
return "medium";
|
|
3912
|
+
}
|
|
3743
3913
|
getOrCreateTracker(sessionId, threadId) {
|
|
3744
3914
|
let tracker = this.sessionTrackers.get(sessionId);
|
|
3745
3915
|
if (!tracker) {
|
|
@@ -3765,8 +3935,16 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3765
3935
|
}
|
|
3766
3936
|
});
|
|
3767
3937
|
this.fileService = this.core.fileService;
|
|
3768
|
-
this.toolTracker = new ToolCallTracker(
|
|
3769
|
-
|
|
3938
|
+
this.toolTracker = new ToolCallTracker(
|
|
3939
|
+
this.bot,
|
|
3940
|
+
this.telegramConfig.chatId,
|
|
3941
|
+
this.sendQueue
|
|
3942
|
+
);
|
|
3943
|
+
this.draftManager = new DraftManager(
|
|
3944
|
+
this.bot,
|
|
3945
|
+
this.telegramConfig.chatId,
|
|
3946
|
+
this.sendQueue
|
|
3947
|
+
);
|
|
3770
3948
|
this.skillManager = new SkillCommandManager(
|
|
3771
3949
|
this.bot,
|
|
3772
3950
|
this.telegramConfig.chatId,
|
|
@@ -3785,7 +3963,11 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3785
3963
|
return result;
|
|
3786
3964
|
}
|
|
3787
3965
|
const retryAfter = (result.parameters?.retry_after ?? 5) + 1;
|
|
3788
|
-
const rateLimitedMethods = [
|
|
3966
|
+
const rateLimitedMethods = [
|
|
3967
|
+
"sendMessage",
|
|
3968
|
+
"editMessageText",
|
|
3969
|
+
"editMessageReplyMarkup"
|
|
3970
|
+
];
|
|
3789
3971
|
if (rateLimitedMethods.includes(method)) {
|
|
3790
3972
|
this.sendQueue.onRateLimited();
|
|
3791
3973
|
}
|
|
@@ -3835,6 +4017,7 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3835
4017
|
);
|
|
3836
4018
|
setupDangerousModeCallbacks(this.bot, this.core);
|
|
3837
4019
|
setupTTSCallbacks(this.bot, this.core);
|
|
4020
|
+
setupVerbosityCallbacks(this.bot, this.core);
|
|
3838
4021
|
setupActionCallbacks(
|
|
3839
4022
|
this.bot,
|
|
3840
4023
|
this.core,
|
|
@@ -3846,7 +4029,10 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3846
4029
|
this.bot,
|
|
3847
4030
|
this.core,
|
|
3848
4031
|
this.telegramConfig.chatId,
|
|
3849
|
-
{
|
|
4032
|
+
{
|
|
4033
|
+
notificationTopicId: this.notificationTopicId,
|
|
4034
|
+
assistantTopicId: this.assistantTopicId
|
|
4035
|
+
},
|
|
3850
4036
|
() => {
|
|
3851
4037
|
if (!this.assistantSession) return void 0;
|
|
3852
4038
|
return {
|
|
@@ -3890,8 +4076,14 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3890
4076
|
});
|
|
3891
4077
|
return;
|
|
3892
4078
|
}
|
|
3893
|
-
const session = this.core.sessionManager.getSessionByThread(
|
|
3894
|
-
|
|
4079
|
+
const session = this.core.sessionManager.getSessionByThread(
|
|
4080
|
+
"telegram",
|
|
4081
|
+
String(threadId)
|
|
4082
|
+
);
|
|
4083
|
+
const record = session ? void 0 : this.core.sessionManager.getRecordByThread(
|
|
4084
|
+
"telegram",
|
|
4085
|
+
String(threadId)
|
|
4086
|
+
);
|
|
3895
4087
|
const agentName = session?.agentName ?? record?.agentName;
|
|
3896
4088
|
const agentSessionId = session?.agentSessionId ?? record?.agentSessionId;
|
|
3897
4089
|
if (!agentName || !agentSessionId) {
|
|
@@ -3932,7 +4124,9 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3932
4124
|
const agents = this.core.agentManager.getAvailableAgents();
|
|
3933
4125
|
const allRecords = this.core.sessionManager.listRecords();
|
|
3934
4126
|
const welcomeText = buildWelcomeMessage({
|
|
3935
|
-
activeCount: allRecords.filter(
|
|
4127
|
+
activeCount: allRecords.filter(
|
|
4128
|
+
(r) => r.status === "active" || r.status === "initializing"
|
|
4129
|
+
).length,
|
|
3936
4130
|
errorCount: allRecords.filter((r) => r.status === "error").length,
|
|
3937
4131
|
totalCount: allRecords.length,
|
|
3938
4132
|
agents: agents.map((a) => a.name),
|
|
@@ -3955,10 +4149,16 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3955
4149
|
);
|
|
3956
4150
|
this.assistantSession = session;
|
|
3957
4151
|
this.assistantInitializing = true;
|
|
3958
|
-
log13.info(
|
|
4152
|
+
log13.info(
|
|
4153
|
+
{ sessionId: session.id },
|
|
4154
|
+
"Assistant session ready, system prompt running in background"
|
|
4155
|
+
);
|
|
3959
4156
|
ready.then(() => {
|
|
3960
4157
|
this.assistantInitializing = false;
|
|
3961
|
-
log13.info(
|
|
4158
|
+
log13.info(
|
|
4159
|
+
{ sessionId: session.id },
|
|
4160
|
+
"Assistant ready for user messages"
|
|
4161
|
+
);
|
|
3962
4162
|
});
|
|
3963
4163
|
} catch (err) {
|
|
3964
4164
|
log13.error({ err }, "Failed to spawn assistant");
|
|
@@ -3983,10 +4183,20 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
3983
4183
|
this.bot.on("message:text", async (ctx) => {
|
|
3984
4184
|
const threadId = ctx.message.message_thread_id;
|
|
3985
4185
|
const text = ctx.message.text;
|
|
3986
|
-
if (await handlePendingWorkspaceInput(
|
|
4186
|
+
if (await handlePendingWorkspaceInput(
|
|
4187
|
+
ctx,
|
|
4188
|
+
this.core,
|
|
4189
|
+
this.telegramConfig.chatId,
|
|
4190
|
+
this.assistantTopicId
|
|
4191
|
+
)) {
|
|
3987
4192
|
return;
|
|
3988
4193
|
}
|
|
3989
|
-
if (await handlePendingResumeInput(
|
|
4194
|
+
if (await handlePendingResumeInput(
|
|
4195
|
+
ctx,
|
|
4196
|
+
this.core,
|
|
4197
|
+
this.telegramConfig.chatId,
|
|
4198
|
+
this.assistantTopicId
|
|
4199
|
+
)) {
|
|
3990
4200
|
return;
|
|
3991
4201
|
}
|
|
3992
4202
|
if (!threadId) {
|
|
@@ -4001,10 +4211,16 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
4001
4211
|
const forwardText = text.startsWith("/") ? text.slice(1) : text;
|
|
4002
4212
|
if (threadId === this.assistantTopicId) {
|
|
4003
4213
|
if (!this.assistantSession) {
|
|
4004
|
-
await ctx.reply(
|
|
4214
|
+
await ctx.reply(
|
|
4215
|
+
"\u26A0\uFE0F Assistant is not available yet. Please try again shortly.",
|
|
4216
|
+
{ parse_mode: "HTML" }
|
|
4217
|
+
);
|
|
4005
4218
|
return;
|
|
4006
4219
|
}
|
|
4007
|
-
await this.draftManager.finalize(
|
|
4220
|
+
await this.draftManager.finalize(
|
|
4221
|
+
this.assistantSession.id,
|
|
4222
|
+
this.assistantSession.id
|
|
4223
|
+
);
|
|
4008
4224
|
ctx.replyWithChatAction("typing").catch(() => {
|
|
4009
4225
|
});
|
|
4010
4226
|
handleAssistantMessage(this.assistantSession, forwardText).catch(
|
|
@@ -4012,8 +4228,12 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
4012
4228
|
);
|
|
4013
4229
|
return;
|
|
4014
4230
|
}
|
|
4015
|
-
const sessionId = this.core.sessionManager.getSessionByThread(
|
|
4016
|
-
|
|
4231
|
+
const sessionId = this.core.sessionManager.getSessionByThread(
|
|
4232
|
+
"telegram",
|
|
4233
|
+
String(threadId)
|
|
4234
|
+
)?.id;
|
|
4235
|
+
if (sessionId)
|
|
4236
|
+
await this.draftManager.finalize(sessionId, this.assistantSession?.id);
|
|
4017
4237
|
if (sessionId) {
|
|
4018
4238
|
const tracker = this.sessionTrackers.get(sessionId);
|
|
4019
4239
|
if (tracker) await tracker.onNewPrompt();
|
|
@@ -4112,25 +4332,57 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
4112
4332
|
this.draftManager.appendText(ctx.sessionId, content.text);
|
|
4113
4333
|
},
|
|
4114
4334
|
onToolCall: async (ctx, content) => {
|
|
4335
|
+
const meta = content.metadata ?? {};
|
|
4336
|
+
const toolName = meta.name ?? content.text ?? "Tool";
|
|
4337
|
+
const toolKind = String(meta.kind ?? "other");
|
|
4338
|
+
const noiseAction = evaluateNoise(toolName, toolKind, meta.rawInput);
|
|
4339
|
+
if (noiseAction === "hide" && this.verbosity !== "high") return;
|
|
4340
|
+
if (noiseAction === "collapse" && this.verbosity === "low") return;
|
|
4115
4341
|
const tracker = this.getOrCreateTracker(ctx.sessionId, ctx.threadId);
|
|
4116
4342
|
await tracker.onToolCall();
|
|
4117
|
-
await this.draftManager.finalize(
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4343
|
+
await this.draftManager.finalize(
|
|
4344
|
+
ctx.sessionId,
|
|
4345
|
+
this.assistantSession?.id
|
|
4346
|
+
);
|
|
4347
|
+
await this.toolTracker.trackNewCall(
|
|
4348
|
+
ctx.sessionId,
|
|
4349
|
+
ctx.threadId,
|
|
4350
|
+
{
|
|
4351
|
+
id: meta.id ?? "",
|
|
4352
|
+
name: meta.name ?? content.text ?? "Tool",
|
|
4353
|
+
kind: meta.kind,
|
|
4354
|
+
status: meta.status,
|
|
4355
|
+
content: meta.content,
|
|
4356
|
+
rawInput: meta.rawInput,
|
|
4357
|
+
viewerLinks: meta.viewerLinks,
|
|
4358
|
+
viewerFilePath: meta.viewerFilePath
|
|
4359
|
+
},
|
|
4360
|
+
this.verbosity
|
|
4361
|
+
);
|
|
4122
4362
|
},
|
|
4123
4363
|
onToolUpdate: async (ctx, content) => {
|
|
4124
|
-
const meta = content.metadata;
|
|
4125
|
-
await this.toolTracker.updateCall(
|
|
4126
|
-
|
|
4127
|
-
|
|
4364
|
+
const meta = content.metadata ?? {};
|
|
4365
|
+
await this.toolTracker.updateCall(
|
|
4366
|
+
ctx.sessionId,
|
|
4367
|
+
{
|
|
4368
|
+
id: meta.id ?? "",
|
|
4369
|
+
name: meta.name ?? content.text ?? "",
|
|
4370
|
+
kind: meta.kind,
|
|
4371
|
+
status: meta.status ?? "completed",
|
|
4372
|
+
content: meta.content,
|
|
4373
|
+
rawInput: meta.rawInput,
|
|
4374
|
+
viewerLinks: meta.viewerLinks,
|
|
4375
|
+
viewerFilePath: meta.viewerFilePath
|
|
4376
|
+
},
|
|
4377
|
+
this.verbosity
|
|
4378
|
+
);
|
|
4128
4379
|
},
|
|
4129
4380
|
onPlan: async (ctx, content) => {
|
|
4130
|
-
const meta = content.metadata;
|
|
4381
|
+
const meta = content.metadata ?? {};
|
|
4382
|
+
const entries = meta.entries ?? [];
|
|
4131
4383
|
const tracker = this.getOrCreateTracker(ctx.sessionId, ctx.threadId);
|
|
4132
4384
|
await tracker.onPlan(
|
|
4133
|
-
|
|
4385
|
+
entries.map((e) => ({
|
|
4134
4386
|
content: e.content,
|
|
4135
4387
|
status: e.status,
|
|
4136
4388
|
priority: e.priority ?? "medium"
|
|
@@ -4139,7 +4391,10 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
4139
4391
|
},
|
|
4140
4392
|
onUsage: async (ctx, content) => {
|
|
4141
4393
|
const meta = content.metadata;
|
|
4142
|
-
await this.draftManager.finalize(
|
|
4394
|
+
await this.draftManager.finalize(
|
|
4395
|
+
ctx.sessionId,
|
|
4396
|
+
this.assistantSession?.id
|
|
4397
|
+
);
|
|
4143
4398
|
const tracker = this.getOrCreateTracker(ctx.sessionId, ctx.threadId);
|
|
4144
4399
|
await tracker.sendUsage(meta ?? {});
|
|
4145
4400
|
if (this.notificationTopicId && ctx.sessionId !== this.assistantSession?.id) {
|
|
@@ -4167,7 +4422,14 @@ Task completed.
|
|
|
4167
4422
|
if (!content.attachment) return;
|
|
4168
4423
|
const { attachment } = content;
|
|
4169
4424
|
if (attachment.size > 50 * 1024 * 1024) {
|
|
4170
|
-
log13.warn(
|
|
4425
|
+
log13.warn(
|
|
4426
|
+
{
|
|
4427
|
+
sessionId: ctx.sessionId,
|
|
4428
|
+
fileName: attachment.fileName,
|
|
4429
|
+
size: attachment.size
|
|
4430
|
+
},
|
|
4431
|
+
"File too large for Telegram (>50MB)"
|
|
4432
|
+
);
|
|
4171
4433
|
await this.sendQueue.enqueue(
|
|
4172
4434
|
() => this.bot.api.sendMessage(
|
|
4173
4435
|
this.telegramConfig.chatId,
|
|
@@ -4204,11 +4466,17 @@ Task completed.
|
|
|
4204
4466
|
);
|
|
4205
4467
|
}
|
|
4206
4468
|
} catch (err) {
|
|
4207
|
-
log13.error(
|
|
4469
|
+
log13.error(
|
|
4470
|
+
{ err, sessionId: ctx.sessionId, fileName: attachment.fileName },
|
|
4471
|
+
"Failed to send attachment"
|
|
4472
|
+
);
|
|
4208
4473
|
}
|
|
4209
4474
|
},
|
|
4210
4475
|
onSessionEnd: async (ctx, _content) => {
|
|
4211
|
-
await this.draftManager.finalize(
|
|
4476
|
+
await this.draftManager.finalize(
|
|
4477
|
+
ctx.sessionId,
|
|
4478
|
+
this.assistantSession?.id
|
|
4479
|
+
);
|
|
4212
4480
|
this.draftManager.cleanup(ctx.sessionId);
|
|
4213
4481
|
this.toolTracker.cleanup(ctx.sessionId);
|
|
4214
4482
|
await this.skillManager.cleanup(ctx.sessionId);
|
|
@@ -4232,7 +4500,10 @@ Task completed.
|
|
|
4232
4500
|
}
|
|
4233
4501
|
},
|
|
4234
4502
|
onError: async (ctx, content) => {
|
|
4235
|
-
await this.draftManager.finalize(
|
|
4503
|
+
await this.draftManager.finalize(
|
|
4504
|
+
ctx.sessionId,
|
|
4505
|
+
this.assistantSession?.id
|
|
4506
|
+
);
|
|
4236
4507
|
const tracker = this.sessionTrackers.get(ctx.sessionId);
|
|
4237
4508
|
if (tracker) {
|
|
4238
4509
|
tracker.destroy();
|
|
@@ -4266,17 +4537,21 @@ Task completed.
|
|
|
4266
4537
|
};
|
|
4267
4538
|
// --- ChannelAdapter implementations ---
|
|
4268
4539
|
async sendMessage(sessionId, content) {
|
|
4269
|
-
if (this.assistantInitializing && sessionId === this.assistantSession?.id)
|
|
4540
|
+
if (this.assistantInitializing && sessionId === this.assistantSession?.id)
|
|
4541
|
+
return;
|
|
4270
4542
|
const session = this.core.sessionManager.getSession(sessionId);
|
|
4271
4543
|
if (!session) return;
|
|
4272
4544
|
if (session.archiving) return;
|
|
4273
4545
|
const threadId = Number(session.threadId);
|
|
4274
4546
|
if (!threadId || isNaN(threadId)) {
|
|
4275
|
-
log13.warn(
|
|
4547
|
+
log13.warn(
|
|
4548
|
+
{ sessionId, threadId: session.threadId },
|
|
4549
|
+
"Session has no valid threadId, skipping message"
|
|
4550
|
+
);
|
|
4276
4551
|
return;
|
|
4277
4552
|
}
|
|
4278
4553
|
const ctx = { sessionId, threadId };
|
|
4279
|
-
await dispatchMessage(this.messageHandlers, ctx, content);
|
|
4554
|
+
await dispatchMessage(this.messageHandlers, ctx, content, this.verbosity);
|
|
4280
4555
|
}
|
|
4281
4556
|
async sendPermissionRequest(sessionId, request) {
|
|
4282
4557
|
log13.info({ sessionId, requestId: request.id }, "Permission request sent");
|
|
@@ -4303,7 +4578,9 @@ Task completed.
|
|
|
4303
4578
|
`;
|
|
4304
4579
|
text += escapeHtml(notification.summary);
|
|
4305
4580
|
const deepLink = notification.deepLink ?? (() => {
|
|
4306
|
-
const session = this.core.sessionManager.getSession(
|
|
4581
|
+
const session = this.core.sessionManager.getSession(
|
|
4582
|
+
notification.sessionId
|
|
4583
|
+
);
|
|
4307
4584
|
const threadId = session?.threadId;
|
|
4308
4585
|
if (!threadId) return void 0;
|
|
4309
4586
|
const chatIdStr = String(this.telegramConfig.chatId);
|
|
@@ -4315,11 +4592,13 @@ Task completed.
|
|
|
4315
4592
|
|
|
4316
4593
|
<a href="${deepLink}">\u2192 Go to topic</a>`;
|
|
4317
4594
|
}
|
|
4595
|
+
const replyMarkup = notification.type === "completed" ? { inline_keyboard: [[{ text: "\u{1F4CB} Summary", callback_data: `sm:summary:${notification.sessionId}` }]] } : void 0;
|
|
4318
4596
|
await this.sendQueue.enqueue(
|
|
4319
4597
|
() => this.bot.api.sendMessage(this.telegramConfig.chatId, text, {
|
|
4320
4598
|
message_thread_id: this.notificationTopicId,
|
|
4321
4599
|
parse_mode: "HTML",
|
|
4322
|
-
disable_notification: false
|
|
4600
|
+
disable_notification: false,
|
|
4601
|
+
reply_markup: replyMarkup
|
|
4323
4602
|
})
|
|
4324
4603
|
);
|
|
4325
4604
|
}
|
|
@@ -4348,7 +4627,10 @@ Task completed.
|
|
|
4348
4627
|
try {
|
|
4349
4628
|
await this.bot.api.deleteForumTopic(this.telegramConfig.chatId, topicId);
|
|
4350
4629
|
} catch (err) {
|
|
4351
|
-
log13.warn(
|
|
4630
|
+
log13.warn(
|
|
4631
|
+
{ err, sessionId, topicId },
|
|
4632
|
+
"Failed to delete forum topic (may already be deleted)"
|
|
4633
|
+
);
|
|
4352
4634
|
}
|
|
4353
4635
|
}
|
|
4354
4636
|
async sendSkillCommands(sessionId, commands) {
|
|
@@ -4360,7 +4642,10 @@ Task completed.
|
|
|
4360
4642
|
await this.skillManager.send(sessionId, threadId, commands);
|
|
4361
4643
|
}
|
|
4362
4644
|
resolveSessionId(threadId) {
|
|
4363
|
-
return this.core.sessionManager.getSessionByThread(
|
|
4645
|
+
return this.core.sessionManager.getSessionByThread(
|
|
4646
|
+
"telegram",
|
|
4647
|
+
String(threadId)
|
|
4648
|
+
)?.id;
|
|
4364
4649
|
}
|
|
4365
4650
|
async downloadTelegramFile(fileId) {
|
|
4366
4651
|
try {
|
|
@@ -4383,7 +4668,12 @@ Task completed.
|
|
|
4383
4668
|
let originalFilePath;
|
|
4384
4669
|
const sessionId = this.resolveSessionId(threadId) || "unknown";
|
|
4385
4670
|
if (convertOggToWav) {
|
|
4386
|
-
const oggAtt = await this.fileService.saveFile(
|
|
4671
|
+
const oggAtt = await this.fileService.saveFile(
|
|
4672
|
+
sessionId,
|
|
4673
|
+
"voice.ogg",
|
|
4674
|
+
downloaded.buffer,
|
|
4675
|
+
"audio/ogg"
|
|
4676
|
+
);
|
|
4387
4677
|
originalFilePath = oggAtt.filePath;
|
|
4388
4678
|
try {
|
|
4389
4679
|
buffer = await this.fileService.convertOggToWav(buffer);
|
|
@@ -4394,7 +4684,12 @@ Task completed.
|
|
|
4394
4684
|
originalFilePath = void 0;
|
|
4395
4685
|
}
|
|
4396
4686
|
}
|
|
4397
|
-
const att = await this.fileService.saveFile(
|
|
4687
|
+
const att = await this.fileService.saveFile(
|
|
4688
|
+
sessionId,
|
|
4689
|
+
fileName,
|
|
4690
|
+
buffer,
|
|
4691
|
+
mimeType
|
|
4692
|
+
);
|
|
4398
4693
|
if (originalFilePath) {
|
|
4399
4694
|
att.originalFilePath = originalFilePath;
|
|
4400
4695
|
}
|
|
@@ -4422,10 +4717,9 @@ Task completed.
|
|
|
4422
4717
|
async archiveSessionTopic(sessionId) {
|
|
4423
4718
|
const core = this.core;
|
|
4424
4719
|
const session = core.sessionManager.getSession(sessionId);
|
|
4425
|
-
if (!session) return
|
|
4720
|
+
if (!session) return;
|
|
4426
4721
|
const chatId = this.telegramConfig.chatId;
|
|
4427
4722
|
const oldTopicId = Number(session.threadId);
|
|
4428
|
-
const rawName = (session.name || `Session ${session.id.slice(0, 6)}`).replace(/^🔄\s*/, "");
|
|
4429
4723
|
session.archiving = true;
|
|
4430
4724
|
await this.draftManager.finalize(session.id, this.assistantSession?.id);
|
|
4431
4725
|
this.draftManager.cleanup(session.id);
|
|
@@ -4437,32 +4731,10 @@ Task completed.
|
|
|
4437
4731
|
this.sessionTrackers.delete(session.id);
|
|
4438
4732
|
}
|
|
4439
4733
|
await deleteSessionTopic(this.bot, chatId, oldTopicId);
|
|
4440
|
-
let newTopicId;
|
|
4441
|
-
try {
|
|
4442
|
-
newTopicId = await createSessionTopic(this.bot, chatId, `\u{1F504} ${rawName}`);
|
|
4443
|
-
} catch (createErr) {
|
|
4444
|
-
session.archiving = false;
|
|
4445
|
-
core.notificationManager.notifyAll({
|
|
4446
|
-
sessionId: session.id,
|
|
4447
|
-
sessionName: session.name,
|
|
4448
|
-
type: "error",
|
|
4449
|
-
summary: `Topic recreation failed for session "${rawName}". Session is orphaned. Error: ${createErr.message}`
|
|
4450
|
-
});
|
|
4451
|
-
throw createErr;
|
|
4452
|
-
}
|
|
4453
|
-
session.threadId = String(newTopicId);
|
|
4454
|
-
const existingRecord = core.sessionManager.getSessionRecord(session.id);
|
|
4455
|
-
const existingPlatform = { ...existingRecord?.platform ?? {} };
|
|
4456
|
-
delete existingPlatform.skillMsgId;
|
|
4457
|
-
await core.sessionManager.patchRecord(session.id, {
|
|
4458
|
-
platform: { ...existingPlatform, topicId: newTopicId }
|
|
4459
|
-
});
|
|
4460
|
-
session.archiving = false;
|
|
4461
|
-
return { newThreadId: String(newTopicId) };
|
|
4462
4734
|
}
|
|
4463
4735
|
};
|
|
4464
4736
|
|
|
4465
4737
|
export {
|
|
4466
4738
|
TelegramAdapter
|
|
4467
4739
|
};
|
|
4468
|
-
//# sourceMappingURL=chunk-
|
|
4740
|
+
//# sourceMappingURL=chunk-5SXG7X5D.js.map
|