@llblab/pi-telegram 0.11.1 → 0.12.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/AGENTS.md +17 -12
- package/BACKLOG.md +0 -10
- package/CHANGELOG.md +33 -2
- package/README.md +42 -25
- package/api/inbound.ts +14 -0
- package/api/keyboard.ts +10 -0
- package/api/outbound.ts +11 -0
- package/api/sections.ts +17 -0
- package/api/updates.ts +11 -0
- package/api/voice.ts +24 -0
- package/docs/README.md +7 -5
- package/docs/architecture.md +176 -135
- package/docs/callback-namespaces.md +3 -3
- package/docs/command-templates.md +81 -24
- package/docs/{inbound-handlers.md → inbound.md} +13 -10
- package/docs/locks.md +3 -3
- package/docs/{outbound-handlers.md → outbound.md} +13 -10
- package/docs/public-api.md +266 -0
- package/docs/{extension-sections.md → sections.md} +31 -27
- package/docs/ui-style.md +165 -0
- package/docs/{external-handlers.md → updates.md} +33 -31
- package/docs/voice.md +17 -14
- package/index.ts +86 -261
- package/lib/bindings.ts +301 -0
- package/lib/command-templates.ts +163 -32
- package/lib/commands.ts +114 -1
- package/lib/config.ts +45 -4
- package/lib/{inbound-handlers.ts → inbound.ts} +5 -4
- package/lib/lifecycle.ts +122 -1
- package/lib/menu-model.ts +3 -3
- package/lib/menu-queue.ts +1 -1
- package/lib/menu-settings.ts +63 -32
- package/lib/menu-status.ts +1 -1
- package/lib/menu.ts +1 -1
- package/lib/{outbound-handlers.ts → outbound.ts} +21 -11
- package/lib/pi.ts +4 -0
- package/lib/polling.ts +4 -3
- package/lib/preview.ts +1 -1
- package/lib/routing.ts +45 -13
- package/lib/{extension-sections.ts → sections.ts} +37 -8
- package/lib/time-injection.ts +1 -1
- package/lib/updates.ts +121 -1
- package/lib/voice.ts +33 -14
- package/package.json +11 -1
- package/lib/external-handlers.ts +0 -166
package/lib/commands.ts
CHANGED
|
@@ -307,6 +307,10 @@ export interface TelegramRuntimeEventRecorderPort {
|
|
|
307
307
|
) => void;
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
+
export interface TelegramCompactConfirmationReplyMarkup {
|
|
311
|
+
inline_keyboard: { text: string; callback_data: string }[][];
|
|
312
|
+
}
|
|
313
|
+
|
|
310
314
|
export interface TelegramCompactCommandDeps extends TelegramRuntimeEventRecorderPort {
|
|
311
315
|
isIdle: () => boolean;
|
|
312
316
|
hasPendingMessages: () => boolean;
|
|
@@ -327,6 +331,42 @@ export interface TelegramCompactCommandDeps extends TelegramRuntimeEventRecorder
|
|
|
327
331
|
onError: (error: unknown) => void;
|
|
328
332
|
}) => void;
|
|
329
333
|
sendTextReply: (text: string) => Promise<void>;
|
|
334
|
+
suppressStartNotice?: boolean;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export interface TelegramCompactConfirmationDeps {
|
|
338
|
+
sendInteractiveMessage: (
|
|
339
|
+
chatId: number,
|
|
340
|
+
text: string,
|
|
341
|
+
mode: "html" | "plain",
|
|
342
|
+
replyMarkup: TelegramCompactConfirmationReplyMarkup,
|
|
343
|
+
) => Promise<number | undefined>;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export interface TelegramCompactConfirmationCallbackQuery {
|
|
347
|
+
id: string;
|
|
348
|
+
data?: string;
|
|
349
|
+
message?: { chat?: { id?: number }; message_id?: number };
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export interface TelegramCompactConfirmationCallbackDeps<TContext> {
|
|
353
|
+
ctx: TContext;
|
|
354
|
+
answerCallbackQuery: (
|
|
355
|
+
callbackQueryId: string,
|
|
356
|
+
text?: string,
|
|
357
|
+
) => Promise<void>;
|
|
358
|
+
editInteractiveMessage: (
|
|
359
|
+
chatId: number,
|
|
360
|
+
messageId: number,
|
|
361
|
+
text: string,
|
|
362
|
+
mode: "html" | "plain",
|
|
363
|
+
replyMarkup: TelegramCompactConfirmationReplyMarkup,
|
|
364
|
+
) => Promise<void>;
|
|
365
|
+
runCompact: (
|
|
366
|
+
ctx: TContext,
|
|
367
|
+
chatId: number,
|
|
368
|
+
replyToMessageId: number,
|
|
369
|
+
) => Promise<void>;
|
|
330
370
|
}
|
|
331
371
|
|
|
332
372
|
export type TelegramControlCommandType =
|
|
@@ -580,6 +620,7 @@ export interface TelegramCommandRuntimeDeps<
|
|
|
580
620
|
getPromptTemplateCommands?: () => readonly TelegramPromptTemplateMenuCommand[];
|
|
581
621
|
persistConfig: () => Promise<void>;
|
|
582
622
|
sendTextReply: (message: TMessage, text: string) => Promise<void>;
|
|
623
|
+
sendInteractiveMessage?: TelegramCompactConfirmationDeps["sendInteractiveMessage"];
|
|
583
624
|
}
|
|
584
625
|
|
|
585
626
|
export const TELEGRAM_APP_MENU_INTRO_HTML = [
|
|
@@ -784,6 +825,69 @@ function dispatchNextQueuedTelegramTurnAfterCompact(
|
|
|
784
825
|
deps.dispatchNextQueuedTelegramTurn();
|
|
785
826
|
}
|
|
786
827
|
|
|
828
|
+
export function buildTelegramCompactConfirmationReplyMarkup(): TelegramCompactConfirmationReplyMarkup {
|
|
829
|
+
return {
|
|
830
|
+
inline_keyboard: [
|
|
831
|
+
[
|
|
832
|
+
{ text: "🗜 Yes, compact", callback_data: "compact:confirm" },
|
|
833
|
+
{ text: "❌ No", callback_data: "compact:cancel" },
|
|
834
|
+
],
|
|
835
|
+
],
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
export function getTelegramCompactConfirmationHtml(): string {
|
|
840
|
+
return "<b>Compact session?</b>";
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
export async function openTelegramCompactConfirmation(
|
|
844
|
+
chatId: number,
|
|
845
|
+
deps: TelegramCompactConfirmationDeps,
|
|
846
|
+
): Promise<void> {
|
|
847
|
+
await deps.sendInteractiveMessage(
|
|
848
|
+
chatId,
|
|
849
|
+
getTelegramCompactConfirmationHtml(),
|
|
850
|
+
"html",
|
|
851
|
+
buildTelegramCompactConfirmationReplyMarkup(),
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
export async function handleTelegramCompactConfirmationCallback<TContext>(
|
|
856
|
+
query: TelegramCompactConfirmationCallbackQuery,
|
|
857
|
+
deps: TelegramCompactConfirmationCallbackDeps<TContext>,
|
|
858
|
+
): Promise<boolean> {
|
|
859
|
+
if (query.data !== "compact:confirm" && query.data !== "compact:cancel") {
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
const chatId = query.message?.chat?.id;
|
|
863
|
+
const messageId = query.message?.message_id;
|
|
864
|
+
if (typeof chatId !== "number" || typeof messageId !== "number") {
|
|
865
|
+
await deps.answerCallbackQuery(query.id, "Interactive message expired.");
|
|
866
|
+
return true;
|
|
867
|
+
}
|
|
868
|
+
if (query.data === "compact:cancel") {
|
|
869
|
+
await deps.editInteractiveMessage(
|
|
870
|
+
chatId,
|
|
871
|
+
messageId,
|
|
872
|
+
"Compaction cancelled.",
|
|
873
|
+
"plain",
|
|
874
|
+
{ inline_keyboard: [] },
|
|
875
|
+
);
|
|
876
|
+
await deps.answerCallbackQuery(query.id);
|
|
877
|
+
return true;
|
|
878
|
+
}
|
|
879
|
+
await deps.editInteractiveMessage(
|
|
880
|
+
chatId,
|
|
881
|
+
messageId,
|
|
882
|
+
"Compaction started.",
|
|
883
|
+
"plain",
|
|
884
|
+
{ inline_keyboard: [] },
|
|
885
|
+
);
|
|
886
|
+
await deps.answerCallbackQuery(query.id);
|
|
887
|
+
await deps.runCompact(deps.ctx, chatId, messageId);
|
|
888
|
+
return true;
|
|
889
|
+
}
|
|
890
|
+
|
|
787
891
|
export async function handleTelegramCompactCommand(
|
|
788
892
|
deps: TelegramCompactCommandDeps,
|
|
789
893
|
): Promise<void> {
|
|
@@ -834,7 +938,9 @@ export async function handleTelegramCompactCommand(
|
|
|
834
938
|
await deps.sendTextReply(`Compaction failed: ${errorMessage}`);
|
|
835
939
|
return;
|
|
836
940
|
}
|
|
837
|
-
|
|
941
|
+
if (!deps.suppressStartNotice) {
|
|
942
|
+
await deps.sendTextReply("Compaction started.");
|
|
943
|
+
}
|
|
838
944
|
if (compactionStillInProgress) deps.startTypingLoop?.();
|
|
839
945
|
}
|
|
840
946
|
|
|
@@ -978,6 +1084,7 @@ export function createTelegramCommandHandlerTargetRuntime<
|
|
|
978
1084
|
stopTypingLoop: deps.stopTypingLoop,
|
|
979
1085
|
enqueueContinueTurn: deps.enqueueContinueTurn,
|
|
980
1086
|
compact: deps.compact,
|
|
1087
|
+
sendInteractiveMessage: deps.sendInteractiveMessage,
|
|
981
1088
|
enqueueControlItem: commandTargetRuntime.enqueueControlItem,
|
|
982
1089
|
showStatus: commandTargetRuntime.showStatus,
|
|
983
1090
|
openModelMenu: commandTargetRuntime.openModelMenu,
|
|
@@ -1110,6 +1217,12 @@ async function handleTelegramCommandRuntime<
|
|
|
1110
1217
|
await deps.openQueueMenu(nextMessage, commandCtx);
|
|
1111
1218
|
},
|
|
1112
1219
|
handleCompact: async (nextMessage, commandCtx) => {
|
|
1220
|
+
if (deps.sendInteractiveMessage) {
|
|
1221
|
+
await openTelegramCompactConfirmation(nextMessage.chat.id, {
|
|
1222
|
+
sendInteractiveMessage: deps.sendInteractiveMessage,
|
|
1223
|
+
});
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1113
1226
|
await handleTelegramCompactCommand({
|
|
1114
1227
|
isIdle: () => deps.isIdle(commandCtx),
|
|
1115
1228
|
hasPendingMessages: () => deps.hasPendingMessages(commandCtx),
|
package/lib/config.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Telegram bridge config and pairing helpers
|
|
3
3
|
* Zones: telegram config, pairing, filesystem
|
|
4
|
-
* Owns persisted bot/session pairing state, local config storage, authorization policy, and first-user pairing side effects
|
|
4
|
+
* Owns persisted bot/session pairing state, local config storage, live config controls, authorization policy, and first-user pairing side effects
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { existsSync } from "node:fs";
|
|
@@ -9,7 +9,7 @@ import { chmod, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
10
|
import { join, resolve } from "node:path";
|
|
11
11
|
|
|
12
|
-
import type { TelegramInboundHandlerConfig } from "./inbound
|
|
12
|
+
import type { TelegramInboundHandlerConfig } from "./inbound.ts";
|
|
13
13
|
import type { CommandTemplateObjectConfig } from "./command-templates.ts";
|
|
14
14
|
|
|
15
15
|
const CONFIG_RUNTIME_KEY = "__piTelegramConfigRuntime__";
|
|
@@ -35,7 +35,7 @@ export interface TelegramOutboundHandlerConfig extends CommandTemplateObjectConf
|
|
|
35
35
|
timeout?: number;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export type TelegramTimeMode = "
|
|
38
|
+
export type TelegramTimeMode = "hidden" | "always" | "interval";
|
|
39
39
|
|
|
40
40
|
export interface TelegramTimeConfig {
|
|
41
41
|
injectionMode?: TelegramTimeMode;
|
|
@@ -110,6 +110,22 @@ export function updateTelegramVoiceConfig(
|
|
|
110
110
|
return true;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
export function bindGlobalTelegramConfigRuntime(
|
|
114
|
+
configStore: Pick<TelegramConfigStore, "get" | "set" | "persist">,
|
|
115
|
+
): void {
|
|
116
|
+
setGlobalTelegramConfigRuntime({
|
|
117
|
+
updateVoiceConfig(voice) {
|
|
118
|
+
const current = configStore.get();
|
|
119
|
+
const next = {
|
|
120
|
+
...current,
|
|
121
|
+
voice: { ...(current.voice ?? {}), ...voice },
|
|
122
|
+
};
|
|
123
|
+
configStore.set(next);
|
|
124
|
+
void configStore.persist(next);
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
113
129
|
export async function readTelegramConfig(
|
|
114
130
|
configPath: string,
|
|
115
131
|
): Promise<TelegramConfig> {
|
|
@@ -240,7 +256,7 @@ export function resolveTelegramTimeConfig(
|
|
|
240
256
|
const injectionMode: TelegramTimeMode =
|
|
241
257
|
raw?.injectionMode === "always" || raw?.injectionMode === "interval"
|
|
242
258
|
? raw.injectionMode
|
|
243
|
-
: "
|
|
259
|
+
: "hidden";
|
|
244
260
|
const interval =
|
|
245
261
|
typeof raw?.interval === "number" && raw.interval > 0
|
|
246
262
|
? raw.interval
|
|
@@ -266,6 +282,16 @@ export function createTelegramTimeInjectionModeSetter(
|
|
|
266
282
|
): (injectionMode: TelegramTimeMode) => Promise<void> {
|
|
267
283
|
return async (injectionMode) => {
|
|
268
284
|
const current = configStore.get();
|
|
285
|
+
if (injectionMode === "hidden") {
|
|
286
|
+
const { injectionMode: _injectionMode, ...remainingTime } =
|
|
287
|
+
current.time ?? {};
|
|
288
|
+
const next = { ...current };
|
|
289
|
+
if (Object.keys(remainingTime).length > 0) next.time = remainingTime;
|
|
290
|
+
else delete next.time;
|
|
291
|
+
configStore.set(next);
|
|
292
|
+
await configStore.persist(next);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
269
295
|
const next = {
|
|
270
296
|
...current,
|
|
271
297
|
time: { ...(current.time ?? {}), injectionMode },
|
|
@@ -282,6 +308,21 @@ export function createTelegramProactivePushChatIdGetter(deps: {
|
|
|
282
308
|
return () => deps.getActiveTurnChatId() ?? deps.getAllowedUserId();
|
|
283
309
|
}
|
|
284
310
|
|
|
311
|
+
export function createTelegramConfigControls(
|
|
312
|
+
configStore: Pick<TelegramConfigStore, "get" | "set" | "persist">,
|
|
313
|
+
) {
|
|
314
|
+
return {
|
|
315
|
+
isProactivePushEnabled: createTelegramProactivePushChecker(configStore),
|
|
316
|
+
setProactivePushEnabled: createTelegramProactivePushSetter(configStore),
|
|
317
|
+
getVoiceReplyMode: createTelegramVoiceReplyModeGetter(configStore),
|
|
318
|
+
isVoiceReplyModeConfigured:
|
|
319
|
+
createTelegramVoiceReplyModeConfiguredChecker(configStore),
|
|
320
|
+
setVoiceReplyMode: createTelegramVoiceReplyModeSetter(configStore),
|
|
321
|
+
getTimeInjectionMode: createTelegramTimeInjectionModeGetter(configStore),
|
|
322
|
+
setTimeInjectionMode: createTelegramTimeInjectionModeSetter(configStore),
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
285
326
|
export type TelegramAuthorizationState =
|
|
286
327
|
| { kind: "pair"; userId: number }
|
|
287
328
|
| { kind: "allow" }
|
|
@@ -216,9 +216,7 @@ function matchesWildcard(pattern: string, value: string | undefined): boolean {
|
|
|
216
216
|
return new RegExp(`^${escaped}$`).test(normalizedValue);
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
-
function handlerHasSelectors(
|
|
220
|
-
handler: TelegramInboundHandlerConfig,
|
|
221
|
-
): boolean {
|
|
219
|
+
function handlerHasSelectors(handler: TelegramInboundHandlerConfig): boolean {
|
|
222
220
|
return (
|
|
223
221
|
normalizeStringList(handler.match).length > 0 ||
|
|
224
222
|
normalizeStringList(handler.mime).length > 0 ||
|
|
@@ -642,7 +640,10 @@ async function readBuiltInTelegramTextAttachment(
|
|
|
642
640
|
if (!isTelegramTextMimeType(file.mimeType)) return undefined;
|
|
643
641
|
const content = await readFile(file.path, "utf8");
|
|
644
642
|
const normalized = content.trim();
|
|
645
|
-
if (
|
|
643
|
+
if (
|
|
644
|
+
!normalized ||
|
|
645
|
+
Buffer.byteLength(normalized, "utf8") > BUILT_IN_TEXT_ATTACHMENT_MAX_BYTES
|
|
646
|
+
) {
|
|
646
647
|
return undefined;
|
|
647
648
|
}
|
|
648
649
|
const name = file.fileName || basename(file.path);
|
package/lib/lifecycle.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Telegram lifecycle hook registration helpers
|
|
3
3
|
* Zones: pi agent lifecycle, telegram session
|
|
4
|
-
*
|
|
4
|
+
* Binds prepared Telegram lifecycle runtimes to pi extension lifecycle events
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type {
|
|
@@ -10,6 +10,8 @@ import type {
|
|
|
10
10
|
BeforeAgentStartEvent,
|
|
11
11
|
ExtensionAPI,
|
|
12
12
|
ExtensionContext,
|
|
13
|
+
SessionBeforeCompactEvent,
|
|
14
|
+
SessionCompactEvent,
|
|
13
15
|
SessionShutdownEvent,
|
|
14
16
|
SessionStartEvent,
|
|
15
17
|
} from "./pi.ts";
|
|
@@ -50,6 +52,14 @@ export interface TelegramLifecycleRegistrationDeps {
|
|
|
50
52
|
event: SessionShutdownEvent,
|
|
51
53
|
ctx: ExtensionContext,
|
|
52
54
|
) => Promise<void>;
|
|
55
|
+
onSessionBeforeCompact?: (
|
|
56
|
+
event: SessionBeforeCompactEvent,
|
|
57
|
+
ctx: ExtensionContext,
|
|
58
|
+
) => Promise<void> | void;
|
|
59
|
+
onSessionCompact?: (
|
|
60
|
+
event: SessionCompactEvent,
|
|
61
|
+
ctx: ExtensionContext,
|
|
62
|
+
) => Promise<void> | void;
|
|
53
63
|
onBeforeAgentStart: (
|
|
54
64
|
event: BeforeAgentStartEvent,
|
|
55
65
|
ctx: ExtensionContext,
|
|
@@ -92,6 +102,111 @@ export interface TelegramSessionLifecycleHooks {
|
|
|
92
102
|
) => Promise<void>;
|
|
93
103
|
}
|
|
94
104
|
|
|
105
|
+
type TelegramLifecycleTimer = number | ReturnType<typeof setTimeout>;
|
|
106
|
+
|
|
107
|
+
export interface TelegramCompactionObserverRuntimeDeps<TContext> {
|
|
108
|
+
setCompactionInProgress: (inProgress: boolean) => void;
|
|
109
|
+
updateStatus: (ctx: TContext) => void;
|
|
110
|
+
startTypingLoop?: (ctx: TContext) => void;
|
|
111
|
+
stopTypingLoop?: () => void;
|
|
112
|
+
requestDeferredDispatchNextQueuedTelegramTurn: (
|
|
113
|
+
dispatch: (ctx: TContext) => void,
|
|
114
|
+
) => void;
|
|
115
|
+
dispatchNextQueuedTelegramTurn: (ctx: TContext) => void;
|
|
116
|
+
recordRuntimeEvent?: (category: string, error: unknown) => void;
|
|
117
|
+
timeoutMs?: number;
|
|
118
|
+
setTimer?: (callback: () => void, ms: number) => TelegramLifecycleTimer;
|
|
119
|
+
clearTimer?: (timer: TelegramLifecycleTimer) => void;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface TelegramCompactionObserverRuntime<TContext> {
|
|
123
|
+
onSessionBeforeCompact: (
|
|
124
|
+
event: SessionBeforeCompactEvent,
|
|
125
|
+
ctx: TContext,
|
|
126
|
+
) => void;
|
|
127
|
+
onSessionCompact: (event: SessionCompactEvent, ctx: TContext) => void;
|
|
128
|
+
onSessionShutdown: () => void;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function createTelegramCompactionObserverRuntime<TContext>(
|
|
132
|
+
deps: TelegramCompactionObserverRuntimeDeps<TContext>,
|
|
133
|
+
): TelegramCompactionObserverRuntime<TContext> {
|
|
134
|
+
const timeoutMs = deps.timeoutMs ?? 300_000;
|
|
135
|
+
const setTimer = deps.setTimer ?? setTimeout;
|
|
136
|
+
const clearTimer = deps.clearTimer ?? clearTimeout;
|
|
137
|
+
let fallbackTimer: TelegramLifecycleTimer | undefined;
|
|
138
|
+
const clearFallbackTimer = (): void => {
|
|
139
|
+
if (!fallbackTimer) return;
|
|
140
|
+
clearTimer(fallbackTimer);
|
|
141
|
+
fallbackTimer = undefined;
|
|
142
|
+
};
|
|
143
|
+
const requestDispatch = (): void => {
|
|
144
|
+
deps.requestDeferredDispatchNextQueuedTelegramTurn(
|
|
145
|
+
deps.dispatchNextQueuedTelegramTurn,
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
return {
|
|
149
|
+
onSessionBeforeCompact: (_event, ctx) => {
|
|
150
|
+
deps.setCompactionInProgress(true);
|
|
151
|
+
deps.startTypingLoop?.(ctx);
|
|
152
|
+
deps.updateStatus(ctx);
|
|
153
|
+
clearFallbackTimer();
|
|
154
|
+
fallbackTimer = setTimer(() => {
|
|
155
|
+
fallbackTimer = undefined;
|
|
156
|
+
deps.setCompactionInProgress(false);
|
|
157
|
+
deps.stopTypingLoop?.();
|
|
158
|
+
deps.updateStatus(ctx);
|
|
159
|
+
deps.recordRuntimeEvent?.(
|
|
160
|
+
"compact",
|
|
161
|
+
new Error("Compaction observer timed out"),
|
|
162
|
+
);
|
|
163
|
+
requestDispatch();
|
|
164
|
+
}, timeoutMs);
|
|
165
|
+
},
|
|
166
|
+
onSessionCompact: (_event, ctx) => {
|
|
167
|
+
clearFallbackTimer();
|
|
168
|
+
deps.setCompactionInProgress(false);
|
|
169
|
+
deps.stopTypingLoop?.();
|
|
170
|
+
deps.updateStatus(ctx);
|
|
171
|
+
requestDispatch();
|
|
172
|
+
},
|
|
173
|
+
onSessionShutdown: () => {
|
|
174
|
+
clearFallbackTimer();
|
|
175
|
+
deps.stopTypingLoop?.();
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export interface TelegramMessageActivityTypingDeps<TContext> {
|
|
181
|
+
hasActiveTurn: () => boolean;
|
|
182
|
+
startTypingLoop: (ctx: TContext) => void;
|
|
183
|
+
onMessageStart: TelegramLifecycleRegistrationDeps["onMessageStart"];
|
|
184
|
+
onMessageUpdate: TelegramLifecycleRegistrationDeps["onMessageUpdate"];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function createTelegramMessageActivityTypingHooks<
|
|
188
|
+
TContext extends ExtensionContext,
|
|
189
|
+
>(
|
|
190
|
+
deps: TelegramMessageActivityTypingDeps<TContext>,
|
|
191
|
+
): Pick<
|
|
192
|
+
TelegramLifecycleRegistrationDeps,
|
|
193
|
+
"onMessageStart" | "onMessageUpdate"
|
|
194
|
+
> {
|
|
195
|
+
const ensureTyping = (ctx: TContext): void => {
|
|
196
|
+
if (deps.hasActiveTurn()) deps.startTypingLoop(ctx);
|
|
197
|
+
};
|
|
198
|
+
return {
|
|
199
|
+
onMessageStart: async (event, ctx) => {
|
|
200
|
+
ensureTyping(ctx as TContext);
|
|
201
|
+
await deps.onMessageStart(event, ctx);
|
|
202
|
+
},
|
|
203
|
+
onMessageUpdate: async (event, ctx) => {
|
|
204
|
+
ensureTyping(ctx as TContext);
|
|
205
|
+
await deps.onMessageUpdate(event, ctx);
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
95
210
|
export function createDedupAgentStartHook(
|
|
96
211
|
dedup: { reset(): void },
|
|
97
212
|
inner: (event: AgentStartEvent, ctx: ExtensionContext) => Promise<void>,
|
|
@@ -139,6 +254,12 @@ export function registerTelegramLifecycleHooks(
|
|
|
139
254
|
pi.on("session_shutdown", async (event, ctx) => {
|
|
140
255
|
await deps.onSessionShutdown(event, ctx);
|
|
141
256
|
});
|
|
257
|
+
pi.on("session_before_compact", async (event, ctx) => {
|
|
258
|
+
await deps.onSessionBeforeCompact?.(event, ctx);
|
|
259
|
+
});
|
|
260
|
+
pi.on("session_compact", async (event, ctx) => {
|
|
261
|
+
await deps.onSessionCompact?.(event, ctx);
|
|
262
|
+
});
|
|
142
263
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
143
264
|
return deps.onBeforeAgentStart(event, ctx);
|
|
144
265
|
});
|
package/lib/menu-model.ts
CHANGED
|
@@ -983,7 +983,7 @@ export function buildModelMenuReplyMarkup(
|
|
|
983
983
|
callback_data: "model:scope:scoped",
|
|
984
984
|
},
|
|
985
985
|
{
|
|
986
|
-
text: state.scope === "all" ? "
|
|
986
|
+
text: state.scope === "all" ? "🟣 All" : "⚫️ All",
|
|
987
987
|
callback_data: "model:scope:all",
|
|
988
988
|
},
|
|
989
989
|
]);
|
|
@@ -1050,7 +1050,7 @@ export function buildModelDetailMenuReplyMarkup(
|
|
|
1050
1050
|
callback_data: "model:scope-enable",
|
|
1051
1051
|
},
|
|
1052
1052
|
{
|
|
1053
|
-
text: scoped ? "⚫️ All" : "
|
|
1053
|
+
text: scoped ? "⚫️ All" : "🟣 All",
|
|
1054
1054
|
callback_data: "model:scope-disable",
|
|
1055
1055
|
},
|
|
1056
1056
|
],
|
|
@@ -1091,7 +1091,7 @@ export function buildModelPageMenuReplyMarkup(
|
|
|
1091
1091
|
return {
|
|
1092
1092
|
text:
|
|
1093
1093
|
pageIndex === menuPage.page
|
|
1094
|
-
?
|
|
1094
|
+
? `🟣 ${pageIndex + 1}`
|
|
1095
1095
|
: String(pageIndex + 1),
|
|
1096
1096
|
callback_data: `model:page:${pageIndex}`,
|
|
1097
1097
|
};
|
package/lib/menu-queue.ts
CHANGED
|
@@ -162,7 +162,7 @@ function buildTelegramQueueItemSubmenuReplyMarkup(
|
|
|
162
162
|
callback_data: `queue:prio-set:${chatId}:${replyToMessageId}:priority`,
|
|
163
163
|
},
|
|
164
164
|
{
|
|
165
|
-
text: isPriority ? "⚫️ Normal" : "
|
|
165
|
+
text: isPriority ? "⚫️ Normal" : "🟣 Normal",
|
|
166
166
|
callback_data: `queue:prio-set:${chatId}:${replyToMessageId}:normal`,
|
|
167
167
|
},
|
|
168
168
|
],
|