@nordbyte/nordrelay 0.5.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +80 -11
- package/README.md +154 -22
- package/dist/access-control.js +7 -1
- package/dist/activity-events.js +44 -0
- package/dist/audit-log.js +40 -2
- package/dist/bot-preferences.js +1 -0
- package/dist/bot-rendering.js +10 -7
- package/dist/bot.js +535 -11
- package/dist/channel-actions.js +7 -2
- package/dist/channel-adapter.js +40 -7
- package/dist/channel-command-catalog.js +88 -0
- package/dist/channel-command-service.js +369 -0
- package/dist/channel-mirror-registry.js +77 -0
- package/dist/channel-peer-prompt.js +95 -0
- package/dist/channel-runtime.js +12 -5
- package/dist/channel-turn-service.js +237 -0
- package/dist/codex-state.js +114 -78
- package/dist/config-metadata.js +93 -13
- package/dist/config.js +103 -8
- package/dist/context-key.js +87 -5
- package/dist/discord-artifacts.js +165 -0
- package/dist/discord-bot.js +2073 -0
- package/dist/discord-channel-runtime.js +133 -0
- package/dist/discord-command-surface.js +57 -0
- package/dist/discord-rate-limit.js +141 -0
- package/dist/index.js +36 -5
- package/dist/job-store.js +127 -0
- package/dist/metrics.js +87 -0
- package/dist/peer-auth.js +85 -0
- package/dist/peer-client.js +256 -0
- package/dist/peer-context.js +21 -0
- package/dist/peer-identity.js +127 -0
- package/dist/peer-runtime-service.js +636 -0
- package/dist/peer-server.js +220 -0
- package/dist/peer-store.js +294 -0
- package/dist/peer-types.js +52 -0
- package/dist/relay-external-activity-monitor.js +47 -6
- package/dist/relay-runtime-helpers.js +208 -0
- package/dist/relay-runtime.js +897 -394
- package/dist/remote-prompt.js +98 -0
- package/dist/runtime-cache.js +57 -0
- package/dist/session-locks.js +10 -7
- package/dist/support-bundle.js +1 -0
- package/dist/telegram-access-commands.js +15 -2
- package/dist/telegram-access-middleware.js +16 -3
- package/dist/telegram-agent-commands.js +25 -0
- package/dist/telegram-artifact-commands.js +46 -0
- package/dist/telegram-command-menu.js +3 -53
- package/dist/telegram-diagnostics-command.js +5 -50
- package/dist/telegram-general-commands.js +16 -6
- package/dist/telegram-operational-commands.js +14 -6
- package/dist/telegram-preference-commands.js +23 -127
- package/dist/telegram-queue-commands.js +74 -4
- package/dist/telegram-support-command.js +7 -0
- package/dist/telegram-update-commands.js +27 -0
- package/dist/user-management.js +208 -0
- package/dist/web-api-contract.js +17 -0
- package/dist/web-dashboard-access-routes.js +74 -1
- package/dist/web-dashboard-artifact-routes.js +3 -3
- package/dist/web-dashboard-assets.js +2 -0
- package/dist/web-dashboard-pages.js +109 -13
- package/dist/web-dashboard-peer-routes.js +204 -0
- package/dist/web-dashboard-runtime-routes.js +53 -8
- package/dist/web-dashboard-session-routes.js +27 -20
- package/dist/web-dashboard-ui.js +2 -0
- package/dist/web-dashboard.js +160 -6
- package/dist/web-state.js +33 -2
- package/dist/webui-assets/dashboard.css +75 -1
- package/dist/webui-assets/dashboard.js +779 -55
- package/package.json +5 -2
- package/plugins/nordrelay/scripts/nordrelay.mjs +578 -19
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { capabilitiesOf, idOf, labelOf, parseToggle, } from "./bot-rendering.js";
|
|
3
|
-
import { friendlyErrorText } from "./error-messages.js";
|
|
1
|
+
import { capabilitiesOf, labelOf, } from "./bot-rendering.js";
|
|
4
2
|
import { escapeHTML } from "./format.js";
|
|
5
|
-
import { getAvailableBackends } from "./voice.js";
|
|
6
3
|
import { evaluateWorkspacePolicy, filterAllowedWorkspaces, renderWorkspacePolicyLine, } from "./workspace-policy.js";
|
|
7
4
|
import { safeReply } from "./telegram-output.js";
|
|
8
5
|
export function registerTelegramPreferenceCommands(options) {
|
|
@@ -18,28 +15,15 @@ export function registerTelegramPreferenceCommands(options) {
|
|
|
18
15
|
return;
|
|
19
16
|
}
|
|
20
17
|
const argument = (ctx.message?.text ?? "").replace(/^\/mirror(?:@\w+)?\s*/i, "").trim();
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
const mode = options.getEffectiveMirrorMode(contextKey);
|
|
32
|
-
const plain = [
|
|
33
|
-
`CLI mirroring: ${mode}`,
|
|
34
|
-
`Minimum update interval: ${options.config.telegramMirrorMinUpdateMs} ms`,
|
|
35
|
-
"Modes: off, status, final, full",
|
|
36
|
-
].join("\n");
|
|
37
|
-
const html = [
|
|
38
|
-
`<b>CLI mirroring:</b> <code>${escapeHTML(mode)}</code>`,
|
|
39
|
-
`<b>Minimum update interval:</b> <code>${options.config.telegramMirrorMinUpdateMs} ms</code>`,
|
|
40
|
-
"<b>Modes:</b> <code>off</code>, <code>status</code>, <code>final</code>, <code>full</code>",
|
|
41
|
-
].join("\n");
|
|
42
|
-
await safeReply(ctx, html, { fallbackText: plain });
|
|
18
|
+
const response = options.commandService.renderMirrorPreference({
|
|
19
|
+
source: "telegram",
|
|
20
|
+
contextKey,
|
|
21
|
+
argument,
|
|
22
|
+
preferencesStore: options.preferencesStore,
|
|
23
|
+
cliMirrorSupported: capabilitiesOf(session.getInfo()).cliMirror,
|
|
24
|
+
agentLabel: labelOf(session.getInfo()),
|
|
25
|
+
});
|
|
26
|
+
await safeReply(ctx, response.html, { fallbackText: response.plain });
|
|
43
27
|
});
|
|
44
28
|
options.bot.command("notify", async (ctx) => {
|
|
45
29
|
const contextSession = await options.getContextSession(ctx, { deferThreadStart: true });
|
|
@@ -48,45 +32,13 @@ export function registerTelegramPreferenceCommands(options) {
|
|
|
48
32
|
}
|
|
49
33
|
const { contextKey } = contextSession;
|
|
50
34
|
const argument = (ctx.message?.text ?? "").replace(/^\/notify(?:@\w+)?\s*/i, "").trim();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
catch (error) {
|
|
59
|
-
await safeReply(ctx, escapeHTML(`Invalid quiet hours: ${friendlyErrorText(error)}`), {
|
|
60
|
-
fallbackText: `Invalid quiet hours: ${friendlyErrorText(error)}`,
|
|
61
|
-
});
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
options.preferencesStore.update(contextKey, { quietHours });
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
const mode = parseNotifyMode(argument, options.getEffectiveNotifyMode(contextKey));
|
|
68
|
-
if (!["off", "minimal", "all"].includes(argument.toLowerCase())) {
|
|
69
|
-
await safeReply(ctx, escapeHTML("Usage: /notify [off|minimal|all] or /notify quiet HH-HH"), {
|
|
70
|
-
fallbackText: "Usage: /notify [off|minimal|all] or /notify quiet HH-HH",
|
|
71
|
-
});
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
options.preferencesStore.update(contextKey, { notifyMode: mode });
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
const mode = options.getEffectiveNotifyMode(contextKey);
|
|
78
|
-
const quietHours = options.getEffectiveQuietHours(contextKey);
|
|
79
|
-
const plain = [
|
|
80
|
-
`Notifications: ${mode}`,
|
|
81
|
-
`Quiet hours: ${formatQuietHours(quietHours)}`,
|
|
82
|
-
`Currently quiet: ${isQuietNow(quietHours) ? "yes" : "no"}`,
|
|
83
|
-
].join("\n");
|
|
84
|
-
const html = [
|
|
85
|
-
`<b>Notifications:</b> <code>${escapeHTML(mode)}</code>`,
|
|
86
|
-
`<b>Quiet hours:</b> <code>${escapeHTML(formatQuietHours(quietHours))}</code>`,
|
|
87
|
-
`<b>Currently quiet:</b> <code>${isQuietNow(quietHours) ? "yes" : "no"}</code>`,
|
|
88
|
-
].join("\n");
|
|
89
|
-
await safeReply(ctx, html, { fallbackText: plain });
|
|
35
|
+
const response = options.commandService.renderNotifyPreference({
|
|
36
|
+
source: "telegram",
|
|
37
|
+
contextKey,
|
|
38
|
+
argument,
|
|
39
|
+
preferencesStore: options.preferencesStore,
|
|
40
|
+
});
|
|
41
|
+
await safeReply(ctx, response.html, { fallbackText: response.plain });
|
|
90
42
|
});
|
|
91
43
|
options.bot.command("workspaces", async (ctx) => {
|
|
92
44
|
const contextSession = await options.getContextSession(ctx, { deferThreadStart: true });
|
|
@@ -131,68 +83,12 @@ export function registerTelegramPreferenceCommands(options) {
|
|
|
131
83
|
}
|
|
132
84
|
const { contextKey } = contextSession;
|
|
133
85
|
const argument = (ctx.message?.text ?? "").replace(/^\/voice(?:@\w+)?\s*/i, "").trim();
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
options.preferencesStore.update(contextKey, { voiceBackend: parseVoiceBackendPreference(value) });
|
|
140
|
-
}
|
|
141
|
-
else if (key === "language") {
|
|
142
|
-
options.preferencesStore.update(contextKey, { voiceLanguage: value && value.toLowerCase() !== "auto" ? value : null });
|
|
143
|
-
}
|
|
144
|
-
else if (key === "transcribe_only" || key === "transcribe-only") {
|
|
145
|
-
const enabled = parseToggle(value);
|
|
146
|
-
if (enabled === undefined) {
|
|
147
|
-
await safeReply(ctx, escapeHTML("Usage: /voice transcribe_only on|off"), {
|
|
148
|
-
fallbackText: "Usage: /voice transcribe_only on|off",
|
|
149
|
-
});
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
options.preferencesStore.update(contextKey, { voiceTranscribeOnly: enabled });
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
await safeReply(ctx, escapeHTML("Usage: /voice, /voice backend auto|parakeet|faster-whisper|openai, /voice language auto|<code>, /voice transcribe_only on|off"), {
|
|
156
|
-
fallbackText: "Usage: /voice, /voice backend auto|parakeet|faster-whisper|openai, /voice language auto|<code>, /voice transcribe_only on|off",
|
|
157
|
-
});
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
const backends = await getAvailableBackends().catch(() => []);
|
|
162
|
-
if (backends.length === 0) {
|
|
163
|
-
await safeReply(ctx, [
|
|
164
|
-
"<b>Voice transcription is not available.</b>",
|
|
165
|
-
"",
|
|
166
|
-
"Install <code>faster-whisper</code> + ffmpeg, install <code>parakeet-coreml</code> on macOS Apple Silicon, or set <code>OPENAI_API_KEY</code>.",
|
|
167
|
-
"<i>Cloud transcription uses OPENAI_API_KEY, not CODEX_API_KEY.</i>",
|
|
168
|
-
].join("\n"), {
|
|
169
|
-
fallbackText: [
|
|
170
|
-
"Voice transcription is not available.",
|
|
171
|
-
"",
|
|
172
|
-
"Install faster-whisper + ffmpeg, install parakeet-coreml on macOS Apple Silicon, or set OPENAI_API_KEY.",
|
|
173
|
-
"Cloud transcription uses OPENAI_API_KEY, not CODEX_API_KEY.",
|
|
174
|
-
].join("\n"),
|
|
175
|
-
});
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
const joined = backends.join(" + ");
|
|
179
|
-
const backendPreference = options.getEffectiveVoiceBackend(contextKey);
|
|
180
|
-
const language = options.getEffectiveVoiceLanguage(contextKey);
|
|
181
|
-
const transcribeOnly = options.isVoiceTranscribeOnly(contextKey);
|
|
182
|
-
const plain = [
|
|
183
|
-
`Voice backends: ${joined}`,
|
|
184
|
-
`Preferred backend: ${backendPreference}`,
|
|
185
|
-
`Language: ${language ?? "auto"}`,
|
|
186
|
-
`Transcribe only: ${transcribeOnly ? "on" : "off"}`,
|
|
187
|
-
].join("\n");
|
|
188
|
-
const html = [
|
|
189
|
-
`<b>Voice backends:</b> <code>${escapeHTML(joined)}</code>`,
|
|
190
|
-
`<b>Preferred backend:</b> <code>${escapeHTML(backendPreference)}</code>`,
|
|
191
|
-
`<b>Language:</b> <code>${escapeHTML(language ?? "auto")}</code>`,
|
|
192
|
-
`<b>Transcribe only:</b> <code>${transcribeOnly ? "on" : "off"}</code>`,
|
|
193
|
-
].join("\n");
|
|
194
|
-
await safeReply(ctx, html, {
|
|
195
|
-
fallbackText: plain,
|
|
86
|
+
const response = await options.commandService.renderVoicePreference({
|
|
87
|
+
source: "telegram",
|
|
88
|
+
contextKey,
|
|
89
|
+
argument,
|
|
90
|
+
preferencesStore: options.preferencesStore,
|
|
196
91
|
});
|
|
92
|
+
await safeReply(ctx, response.html, { fallbackText: response.plain });
|
|
197
93
|
});
|
|
198
94
|
}
|
|
@@ -48,12 +48,21 @@ export function registerTelegramQueueCommands(options) {
|
|
|
48
48
|
const minutes = Math.min(7 * 24 * 60, Math.max(1, Number(laterMatch[1])));
|
|
49
49
|
const text = laterMatch[2].trim();
|
|
50
50
|
const notBefore = Date.now() + minutes * 60 * 1000;
|
|
51
|
-
const item = promptStore.enqueue(contextKey,
|
|
51
|
+
const item = promptStore.enqueue(contextKey, {
|
|
52
|
+
...toPromptEnvelope(text),
|
|
53
|
+
activityActor: options.activityActor?.(ctx),
|
|
54
|
+
}, { notBefore });
|
|
52
55
|
const message = `Queued prompt ${item.id} for ${formatLocalDateTime(new Date(notBefore))}.`;
|
|
53
56
|
await safeReply(ctx, escapeHTML(message), {
|
|
54
57
|
fallbackText: message,
|
|
55
58
|
replyMarkup: createQueuedPromptCancelKeyboard(contextKey, item.id),
|
|
56
59
|
});
|
|
60
|
+
options.appendActivity?.(ctx, contextKey, session, {
|
|
61
|
+
status: "queued",
|
|
62
|
+
type: "prompt_queued",
|
|
63
|
+
prompt: item.description,
|
|
64
|
+
detail: `Queued prompt ${item.id} for ${formatLocalDateTime(new Date(notBefore))}.`,
|
|
65
|
+
});
|
|
57
66
|
options.auditContext(ctx, contextKey, session, {
|
|
58
67
|
action: "prompt_queued",
|
|
59
68
|
status: "ok",
|
|
@@ -81,12 +90,22 @@ export function registerTelegramQueueCommands(options) {
|
|
|
81
90
|
const message = `Queue paused. ${promptStore.list(contextKey).length} queued.`;
|
|
82
91
|
await safeReply(ctx, escapeHTML(message), { fallbackText: message });
|
|
83
92
|
await options.updateQueueStatusMessage(contextKey, message);
|
|
93
|
+
options.appendActivity?.(ctx, contextKey, session, {
|
|
94
|
+
status: "info",
|
|
95
|
+
type: "queue_pause",
|
|
96
|
+
detail: message,
|
|
97
|
+
});
|
|
84
98
|
return;
|
|
85
99
|
}
|
|
86
100
|
if (/^resume$/i.test(argument)) {
|
|
87
101
|
promptStore.resume(contextKey);
|
|
88
102
|
const message = `Queue resumed. ${promptStore.list(contextKey).length} queued.`;
|
|
89
103
|
await safeReply(ctx, escapeHTML(message), { fallbackText: message });
|
|
104
|
+
options.appendActivity?.(ctx, contextKey, session, {
|
|
105
|
+
status: "info",
|
|
106
|
+
type: "queue_resume",
|
|
107
|
+
detail: message,
|
|
108
|
+
});
|
|
90
109
|
if (chatId) {
|
|
91
110
|
void options.drainQueuedPrompts(ctx, contextKey, chatId, session).catch((error) => {
|
|
92
111
|
console.error("Failed to drain queue after resume:", error);
|
|
@@ -110,6 +129,12 @@ export function registerTelegramQueueCommands(options) {
|
|
|
110
129
|
}
|
|
111
130
|
const message = `Moved queued prompt ${item.id} ${direction}.`;
|
|
112
131
|
await safeReply(ctx, escapeHTML(message), { fallbackText: message });
|
|
132
|
+
options.appendActivity?.(ctx, contextKey, session, {
|
|
133
|
+
status: "info",
|
|
134
|
+
type: "queue_move",
|
|
135
|
+
prompt: item.description,
|
|
136
|
+
detail: message,
|
|
137
|
+
});
|
|
113
138
|
return;
|
|
114
139
|
}
|
|
115
140
|
const runMatch = argument.match(/^run\s+([a-z0-9]+)$/i);
|
|
@@ -123,6 +148,12 @@ export function registerTelegramQueueCommands(options) {
|
|
|
123
148
|
}
|
|
124
149
|
promptStore.enqueueFront(contextKey, item);
|
|
125
150
|
promptStore.resume(contextKey);
|
|
151
|
+
options.appendActivity?.(ctx, contextKey, session, {
|
|
152
|
+
status: "info",
|
|
153
|
+
type: "queue_run",
|
|
154
|
+
prompt: item.description,
|
|
155
|
+
detail: `Queued prompt ${item.id} moved to next.`,
|
|
156
|
+
});
|
|
126
157
|
if (!chatId) {
|
|
127
158
|
return;
|
|
128
159
|
}
|
|
@@ -159,9 +190,15 @@ export function registerTelegramQueueCommands(options) {
|
|
|
159
190
|
if (!contextSession) {
|
|
160
191
|
return;
|
|
161
192
|
}
|
|
162
|
-
const
|
|
193
|
+
const { contextKey, session } = contextSession;
|
|
194
|
+
const count = promptStore.clear(contextKey);
|
|
163
195
|
const message = `Cleared ${count} queued prompt${count === 1 ? "" : "s"}.`;
|
|
164
196
|
await safeReply(ctx, escapeHTML(message), { fallbackText: message });
|
|
197
|
+
options.appendActivity?.(ctx, contextKey, session, {
|
|
198
|
+
status: "info",
|
|
199
|
+
type: "queue_clear",
|
|
200
|
+
detail: message,
|
|
201
|
+
});
|
|
165
202
|
});
|
|
166
203
|
bot.command("cancel", async (ctx) => {
|
|
167
204
|
const contextSession = await options.getContextSession(ctx, { deferThreadStart: true });
|
|
@@ -176,7 +213,8 @@ export function registerTelegramQueueCommands(options) {
|
|
|
176
213
|
});
|
|
177
214
|
return;
|
|
178
215
|
}
|
|
179
|
-
const
|
|
216
|
+
const { contextKey, session } = contextSession;
|
|
217
|
+
const removed = promptStore.remove(contextKey, id);
|
|
180
218
|
if (!removed) {
|
|
181
219
|
await safeReply(ctx, escapeHTML(`No queued prompt found with id ${id}.`), {
|
|
182
220
|
fallbackText: `No queued prompt found with id ${id}.`,
|
|
@@ -186,6 +224,12 @@ export function registerTelegramQueueCommands(options) {
|
|
|
186
224
|
await safeReply(ctx, escapeHTML(`Cancelled queued prompt ${removed.id}.`), {
|
|
187
225
|
fallbackText: `Cancelled queued prompt ${removed.id}.`,
|
|
188
226
|
});
|
|
227
|
+
options.appendActivity?.(ctx, contextKey, session, {
|
|
228
|
+
status: "aborted",
|
|
229
|
+
type: "queue_cancel",
|
|
230
|
+
prompt: removed.description,
|
|
231
|
+
detail: `Cancelled queued prompt ${removed.id}.`,
|
|
232
|
+
});
|
|
189
233
|
});
|
|
190
234
|
bot.callbackQuery(/^queue_(cancel|remove|top|up|down|run):(-?\d+(?::\d+)?):([a-z0-9]+)$/, async (ctx) => {
|
|
191
235
|
const action = ctx.match?.[1];
|
|
@@ -209,6 +253,15 @@ export function registerTelegramQueueCommands(options) {
|
|
|
209
253
|
? promptStore.moveUp(contextKey, queueId)
|
|
210
254
|
: promptStore.moveDown(contextKey, queueId);
|
|
211
255
|
await ctx.answerCallbackQuery({ text: item ? `Moved ${queueId} ${action}.` : "Queued prompt not found." });
|
|
256
|
+
const session = item ? options.getSession(contextKey) : undefined;
|
|
257
|
+
if (item && session) {
|
|
258
|
+
options.appendActivity?.(ctx, contextKey, session, {
|
|
259
|
+
status: "info",
|
|
260
|
+
type: "queue_move",
|
|
261
|
+
prompt: item.description,
|
|
262
|
+
detail: `Moved queued prompt ${item.id} ${action}.`,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
212
265
|
if (chatId && messageId) {
|
|
213
266
|
const rendered = renderQueueList(promptStore, contextKey, promptStore.list(contextKey));
|
|
214
267
|
await safeEditMessage(bot, chatId, messageId, rendered.html, {
|
|
@@ -227,6 +280,15 @@ export function registerTelegramQueueCommands(options) {
|
|
|
227
280
|
promptStore.enqueueFront(contextKey, item);
|
|
228
281
|
promptStore.resume(contextKey);
|
|
229
282
|
await ctx.answerCallbackQuery({ text: `Queued prompt ${queueId} moved to next.` });
|
|
283
|
+
const session = options.getSession(contextKey);
|
|
284
|
+
if (session) {
|
|
285
|
+
options.appendActivity?.(ctx, contextKey, session, {
|
|
286
|
+
status: "info",
|
|
287
|
+
type: "queue_run",
|
|
288
|
+
prompt: item.description,
|
|
289
|
+
detail: `Queued prompt ${item.id} moved to next.`,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
230
292
|
if (chatId && messageId) {
|
|
231
293
|
const rendered = renderQueueList(promptStore, contextKey, promptStore.list(contextKey));
|
|
232
294
|
await safeEditMessage(bot, chatId, messageId, rendered.html, {
|
|
@@ -234,7 +296,6 @@ export function registerTelegramQueueCommands(options) {
|
|
|
234
296
|
replyMarkup: rendered.keyboard,
|
|
235
297
|
});
|
|
236
298
|
}
|
|
237
|
-
const session = options.getSession(contextKey);
|
|
238
299
|
if (chatId && session && !options.getBusyReason(contextKey).busy) {
|
|
239
300
|
void options.drainQueuedPrompts(ctx, contextKey, chatId, session).catch((error) => {
|
|
240
301
|
console.error("Failed to drain queue after run-now callback:", error);
|
|
@@ -262,6 +323,15 @@ export function registerTelegramQueueCommands(options) {
|
|
|
262
323
|
}
|
|
263
324
|
const message = `Cancelled queued prompt ${removed.id}.`;
|
|
264
325
|
await ctx.answerCallbackQuery({ text: message });
|
|
326
|
+
const session = options.getSession(contextKey);
|
|
327
|
+
if (session) {
|
|
328
|
+
options.appendActivity?.(ctx, contextKey, session, {
|
|
329
|
+
status: "aborted",
|
|
330
|
+
type: "queue_cancel",
|
|
331
|
+
prompt: removed.description,
|
|
332
|
+
detail: message,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
265
335
|
if (!chatId || !messageId) {
|
|
266
336
|
return;
|
|
267
337
|
}
|
|
@@ -26,6 +26,13 @@ export function registerTelegramSupportCommands(options) {
|
|
|
26
26
|
action: "command",
|
|
27
27
|
status: "ok",
|
|
28
28
|
contextKey,
|
|
29
|
+
actor: {
|
|
30
|
+
channel: "telegram",
|
|
31
|
+
id: ctx.from?.id !== undefined ? `telegram:${ctx.from.id}` : undefined,
|
|
32
|
+
label: ctx.from?.username || ctx.from?.first_name || (ctx.from?.id !== undefined ? String(ctx.from.id) : undefined),
|
|
33
|
+
username: ctx.from?.username,
|
|
34
|
+
channelUserId: ctx.from?.id !== undefined ? String(ctx.from.id) : undefined,
|
|
35
|
+
},
|
|
29
36
|
actorId: ctx.from?.id,
|
|
30
37
|
actorRole: options.getUserRole(ctx),
|
|
31
38
|
description: "export diagnostics bundle",
|
|
@@ -33,12 +33,26 @@ export function registerTelegramUpdateCommands(deps) {
|
|
|
33
33
|
}
|
|
34
34
|
if (subcommand === "cancel" && tokens[1]) {
|
|
35
35
|
const job = agentUpdates.cancel(tokens[1]);
|
|
36
|
+
deps.appendActivity?.(ctx, {
|
|
37
|
+
status: "aborted",
|
|
38
|
+
type: "agent_update_cancel_requested",
|
|
39
|
+
threadId: null,
|
|
40
|
+
agentId: job.agentId,
|
|
41
|
+
detail: `${job.agentLabel} ${job.operation} cancellation requested.`,
|
|
42
|
+
});
|
|
36
43
|
const rendered = renderAgentUpdateJobAction(job);
|
|
37
44
|
await replyChannelAction(ctx, rendered);
|
|
38
45
|
return;
|
|
39
46
|
}
|
|
40
47
|
if ((subcommand === "input" || subcommand === "send") && tokens[1] && tokens.slice(2).join(" ").trim()) {
|
|
41
48
|
const job = agentUpdates.sendInput(tokens[1], tokens.slice(2).join(" "));
|
|
49
|
+
deps.appendActivity?.(ctx, {
|
|
50
|
+
status: "info",
|
|
51
|
+
type: "agent_update_input_sent",
|
|
52
|
+
threadId: null,
|
|
53
|
+
agentId: job.agentId,
|
|
54
|
+
detail: `Input sent to ${job.agentLabel} ${job.operation}.`,
|
|
55
|
+
});
|
|
42
56
|
const rendered = renderAgentUpdateJobAction(job);
|
|
43
57
|
await replyChannelAction(ctx, rendered);
|
|
44
58
|
return;
|
|
@@ -54,6 +68,12 @@ export function registerTelegramUpdateCommands(deps) {
|
|
|
54
68
|
return;
|
|
55
69
|
}
|
|
56
70
|
const update = spawnSelfUpdate();
|
|
71
|
+
deps.appendActivity?.(ctx, {
|
|
72
|
+
status: "info",
|
|
73
|
+
type: "update_started",
|
|
74
|
+
threadId: null,
|
|
75
|
+
detail: `${update.method}: ${update.summary}`,
|
|
76
|
+
});
|
|
57
77
|
const rendered = renderSelfUpdateStartedAction(update);
|
|
58
78
|
await replyChannelAction(ctx, rendered);
|
|
59
79
|
});
|
|
@@ -87,6 +107,13 @@ export function registerTelegramUpdateCommands(deps) {
|
|
|
87
107
|
return;
|
|
88
108
|
}
|
|
89
109
|
const job = agentUpdates.cancel(id);
|
|
110
|
+
deps.appendActivity?.(ctx, {
|
|
111
|
+
status: "aborted",
|
|
112
|
+
type: "agent_update_cancel_requested",
|
|
113
|
+
threadId: null,
|
|
114
|
+
agentId: job.agentId,
|
|
115
|
+
detail: `${job.agentLabel} ${job.operation} cancellation requested.`,
|
|
116
|
+
});
|
|
90
117
|
const rendered = renderAgentUpdateJobAction(job);
|
|
91
118
|
await replyChannelAction(ctx, rendered);
|
|
92
119
|
});
|