@llblab/pi-telegram 0.8.2 → 0.9.1
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 +1 -0
- package/CHANGELOG.md +19 -1
- package/README.md +10 -7
- package/docs/architecture.md +34 -31
- package/index.ts +38 -2
- package/lib/commands.ts +72 -0
- package/lib/config.ts +24 -0
- package/lib/menu-model.ts +302 -18
- package/lib/menu-queue.ts +137 -36
- package/lib/menu-settings.ts +272 -0
- package/lib/menu-status.ts +15 -2
- package/lib/menu-thinking.ts +1 -1
- package/lib/menu.ts +45 -3
- package/lib/pi.ts +16 -0
- package/lib/prompts.ts +24 -1
- package/lib/queue.ts +37 -14
- package/lib/routing.ts +26 -0
- package/lib/status.ts +20 -6
- package/lib/updates.ts +2 -0
- package/package.json +1 -1
package/lib/menu.ts
CHANGED
|
@@ -118,6 +118,7 @@ export interface TelegramMenuEffectPort<TModel extends MenuModel = MenuModel> {
|
|
|
118
118
|
updateModelMenuMessage: () => Promise<void>;
|
|
119
119
|
updateThinkingMenuMessage: () => Promise<void>;
|
|
120
120
|
updateStatusMessage: () => Promise<void>;
|
|
121
|
+
persistScopedModelPatterns?: (patterns: string[]) => Promise<void>;
|
|
121
122
|
setModel: (model: TModel) => Promise<boolean>;
|
|
122
123
|
setCurrentModel: (model: TModel) => void;
|
|
123
124
|
setThinkingLevel: (level: ThinkingLevel) => void;
|
|
@@ -188,6 +189,10 @@ export interface TelegramMenuCallbackRuntimeDeps<
|
|
|
188
189
|
state: TelegramModelMenuState<TModel>,
|
|
189
190
|
ctx: TContext,
|
|
190
191
|
) => Promise<void>;
|
|
192
|
+
updateSettingsMenuMessage?: (
|
|
193
|
+
state: TelegramModelMenuState<TModel>,
|
|
194
|
+
ctx: TContext,
|
|
195
|
+
) => Promise<void>;
|
|
191
196
|
answerCallbackQuery: (
|
|
192
197
|
callbackQueryId: string,
|
|
193
198
|
text?: string,
|
|
@@ -196,6 +201,10 @@ export interface TelegramMenuCallbackRuntimeDeps<
|
|
|
196
201
|
hasActiveTelegramTurn: () => boolean;
|
|
197
202
|
hasAbortHandler: () => boolean;
|
|
198
203
|
hasActiveToolExecutions: () => boolean;
|
|
204
|
+
persistScopedModelPatterns?: (
|
|
205
|
+
patterns: string[],
|
|
206
|
+
ctx: TContext,
|
|
207
|
+
) => Promise<void>;
|
|
199
208
|
setModel: (model: TModel) => Promise<boolean>;
|
|
200
209
|
setCurrentModel: (model: TModel, ctx: TContext) => void;
|
|
201
210
|
stagePendingModelSwitch: (
|
|
@@ -265,11 +274,21 @@ export interface TelegramMenuActionRuntime<
|
|
|
265
274
|
|
|
266
275
|
export type TelegramMenuCallbackAction =
|
|
267
276
|
| { kind: "ignore" }
|
|
268
|
-
| { kind: "status"; action: "model" | "thinking" | "queue" }
|
|
277
|
+
| { kind: "status"; action: "model" | "thinking" | "queue" | "settings" }
|
|
269
278
|
| { kind: "thinking:set"; level: string }
|
|
270
279
|
| {
|
|
271
280
|
kind: "model";
|
|
272
|
-
action:
|
|
281
|
+
action:
|
|
282
|
+
| "noop"
|
|
283
|
+
| "scope"
|
|
284
|
+
| "page"
|
|
285
|
+
| "pages"
|
|
286
|
+
| "open"
|
|
287
|
+
| "pick"
|
|
288
|
+
| "pick-selected"
|
|
289
|
+
| "scope-enable"
|
|
290
|
+
| "scope-disable"
|
|
291
|
+
| "scope-toggle";
|
|
273
292
|
value?: string;
|
|
274
293
|
};
|
|
275
294
|
|
|
@@ -285,6 +304,9 @@ export function parseTelegramMenuCallbackAction(
|
|
|
285
304
|
if (data === "menu:queue" || data === "status:queue") {
|
|
286
305
|
return { kind: "status", action: "queue" };
|
|
287
306
|
}
|
|
307
|
+
if (data === "menu:settings" || data === "status:settings") {
|
|
308
|
+
return { kind: "status", action: "settings" };
|
|
309
|
+
}
|
|
288
310
|
if (data?.startsWith("thinking:set:")) {
|
|
289
311
|
return {
|
|
290
312
|
kind: "thinking:set",
|
|
@@ -298,7 +320,12 @@ export function parseTelegramMenuCallbackAction(
|
|
|
298
320
|
action === "scope" ||
|
|
299
321
|
action === "page" ||
|
|
300
322
|
action === "pages" ||
|
|
301
|
-
action === "
|
|
323
|
+
action === "open" ||
|
|
324
|
+
action === "pick" ||
|
|
325
|
+
action === "pick-selected" ||
|
|
326
|
+
action === "scope-enable" ||
|
|
327
|
+
action === "scope-disable" ||
|
|
328
|
+
action === "scope-toggle"
|
|
302
329
|
) {
|
|
303
330
|
return { kind: "model", action, value };
|
|
304
331
|
}
|
|
@@ -379,6 +406,10 @@ export interface TelegramMenuCallbackRuntimeAdapterDeps<
|
|
|
379
406
|
state: TelegramModelMenuState<TModel>,
|
|
380
407
|
ctx: TContext,
|
|
381
408
|
) => Promise<void>;
|
|
409
|
+
updateSettingsMenuMessage?: (
|
|
410
|
+
state: TelegramModelMenuState<TModel>,
|
|
411
|
+
ctx: TContext,
|
|
412
|
+
) => Promise<void>;
|
|
382
413
|
answerCallbackQuery: (
|
|
383
414
|
callbackQueryId: string,
|
|
384
415
|
text?: string,
|
|
@@ -387,6 +418,10 @@ export interface TelegramMenuCallbackRuntimeAdapterDeps<
|
|
|
387
418
|
hasActiveTelegramTurn: () => boolean;
|
|
388
419
|
hasAbortHandler: () => boolean;
|
|
389
420
|
getActiveToolExecutions: () => number;
|
|
421
|
+
persistScopedModelPatterns?: (
|
|
422
|
+
patterns: string[],
|
|
423
|
+
ctx: TContext,
|
|
424
|
+
) => Promise<void>;
|
|
390
425
|
setModel: (model: TModel) => Promise<boolean>;
|
|
391
426
|
setCurrentModel: (model: TModel, ctx: TContext) => void;
|
|
392
427
|
stagePendingModelSwitch: (
|
|
@@ -425,11 +460,13 @@ export function createTelegramMenuCallbackHandlerForContext<
|
|
|
425
460
|
updateModelMenuMessage: deps.updateModelMenuMessage,
|
|
426
461
|
updateThinkingMenuMessage: deps.updateThinkingMenuMessage,
|
|
427
462
|
updateStatusMessage: deps.updateStatusMessage,
|
|
463
|
+
updateSettingsMenuMessage: deps.updateSettingsMenuMessage,
|
|
428
464
|
answerCallbackQuery: deps.answerCallbackQuery,
|
|
429
465
|
isIdle: deps.isIdle,
|
|
430
466
|
hasActiveTelegramTurn: deps.hasActiveTelegramTurn,
|
|
431
467
|
hasAbortHandler: deps.hasAbortHandler,
|
|
432
468
|
hasActiveToolExecutions: () => deps.getActiveToolExecutions() > 0,
|
|
469
|
+
persistScopedModelPatterns: deps.persistScopedModelPatterns,
|
|
433
470
|
setModel: deps.setModel,
|
|
434
471
|
setCurrentModel: deps.setCurrentModel,
|
|
435
472
|
stagePendingModelSwitch: deps.stagePendingModelSwitch,
|
|
@@ -467,6 +504,8 @@ export async function handleTelegramMenuCallbackRuntime<
|
|
|
467
504
|
updateModelMenuMessage: () => deps.updateModelMenuMessage(state, ctx),
|
|
468
505
|
updateThinkingMenuMessage: () =>
|
|
469
506
|
deps.updateThinkingMenuMessage(state, ctx),
|
|
507
|
+
updateSettingsMenuMessage: () =>
|
|
508
|
+
deps.updateSettingsMenuMessage?.(state, ctx) ?? Promise.resolve(),
|
|
470
509
|
answerCallbackQuery: deps.answerCallbackQuery,
|
|
471
510
|
},
|
|
472
511
|
),
|
|
@@ -504,6 +543,9 @@ export async function handleTelegramMenuCallbackRuntime<
|
|
|
504
543
|
deps.updateModelMenuMessage(state, ctx),
|
|
505
544
|
updateStatusMessage: () => deps.updateStatusMessage(state, ctx),
|
|
506
545
|
answerCallbackQuery: deps.answerCallbackQuery,
|
|
546
|
+
persistScopedModelPatterns: deps.persistScopedModelPatterns
|
|
547
|
+
? (patterns) => deps.persistScopedModelPatterns!(patterns, ctx)
|
|
548
|
+
: undefined,
|
|
507
549
|
setModel: deps.setModel,
|
|
508
550
|
setCurrentModel: (model) => deps.setCurrentModel(model, ctx),
|
|
509
551
|
setThinkingLevel: (level) => {
|
package/lib/pi.ts
CHANGED
|
@@ -31,7 +31,9 @@ export type {
|
|
|
31
31
|
|
|
32
32
|
export interface PiSettingsManager {
|
|
33
33
|
reload: () => Promise<void>;
|
|
34
|
+
flush: () => Promise<void>;
|
|
34
35
|
getEnabledModels: () => string[] | undefined;
|
|
36
|
+
setEnabledModels: (patterns: string[] | undefined) => void;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
export type PiSlashCommandInfo = SlashCommandInfo;
|
|
@@ -70,6 +72,20 @@ export function createSettingsManager(cwd: string): PiSettingsManager {
|
|
|
70
72
|
return SettingsManager.create(cwd);
|
|
71
73
|
}
|
|
72
74
|
|
|
75
|
+
export function createScopedModelPatternPersister(deps: {
|
|
76
|
+
createSettingsManager: (cwd: string) => PiSettingsManager;
|
|
77
|
+
clearCachedModelMenuInputs: () => void;
|
|
78
|
+
}): (patterns: string[], ctx: ExtensionContext) => Promise<void> {
|
|
79
|
+
return async function persistScopedModelPatterns(patterns, ctx) {
|
|
80
|
+
const settingsManager = deps.createSettingsManager(ctx.cwd);
|
|
81
|
+
settingsManager.setEnabledModels(
|
|
82
|
+
patterns.length > 0 ? patterns : undefined,
|
|
83
|
+
);
|
|
84
|
+
await settingsManager.flush();
|
|
85
|
+
deps.clearCachedModelMenuInputs();
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
73
89
|
export function getExtensionContextModel(
|
|
74
90
|
ctx: ExtensionContext,
|
|
75
91
|
): ExtensionContext["model"] {
|
package/lib/prompts.ts
CHANGED
|
@@ -18,7 +18,9 @@ Inbound context:
|
|
|
18
18
|
- Unknown \`[callback] ...\` messages may be intended for another extension; if you see one, say the callback was not handled and the environment may be misconfigured.
|
|
19
19
|
|
|
20
20
|
Telegram-visible output:
|
|
21
|
-
- Telegram is often phone-width;
|
|
21
|
+
- Telegram is often phone-width; keep tables, dense list items, and compact text blocks at or below 37 visible cells when possible.
|
|
22
|
+
- Count display width, not raw characters: emoji and some glyphs are wide, so prefer shorter labels when unsure.
|
|
23
|
+
- Wide monospace blocks can become unreadable on mobile; use them only when structure or literal code requires them.
|
|
22
24
|
- For requested/generated files, call tool \`telegram_attach(local_path)\`; mentioning a local path in text does not send it.
|
|
23
25
|
|
|
24
26
|
Native outbound actions:
|
|
@@ -55,3 +57,24 @@ export function createTelegramBeforeAgentStartHook(
|
|
|
55
57
|
systemPromptSuffix: options.systemPromptSuffix ?? SYSTEM_PROMPT_SUFFIX,
|
|
56
58
|
});
|
|
57
59
|
}
|
|
60
|
+
|
|
61
|
+
export interface TelegramProactivePromptHookDeps<TContext> {
|
|
62
|
+
baseHook?: (event: BeforeAgentStartEvent) => { systemPrompt: string };
|
|
63
|
+
isProactivePushEnabled: () => boolean;
|
|
64
|
+
isCurrentOwner: (ctx: TContext) => boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function createTelegramProactiveBeforeAgentStartHook<TContext>(
|
|
68
|
+
deps: TelegramProactivePromptHookDeps<TContext>,
|
|
69
|
+
): (
|
|
70
|
+
event: BeforeAgentStartEvent,
|
|
71
|
+
ctx: TContext,
|
|
72
|
+
) => Promise<{ systemPrompt: string }> {
|
|
73
|
+
const baseHook = deps.baseHook ?? createTelegramBeforeAgentStartHook();
|
|
74
|
+
return async function onBeforeAgentStart(event, ctx) {
|
|
75
|
+
const result = baseHook(event);
|
|
76
|
+
if (!deps.isProactivePushEnabled()) return result;
|
|
77
|
+
if (!deps.isCurrentOwner(ctx)) return result;
|
|
78
|
+
return result;
|
|
79
|
+
};
|
|
80
|
+
}
|
package/lib/queue.ts
CHANGED
|
@@ -357,7 +357,7 @@ function formatTelegramQueueItemStatusSummary<TContext = unknown>(
|
|
|
357
357
|
item: TelegramQueueItem<TContext>,
|
|
358
358
|
): string {
|
|
359
359
|
if (item.queueLane === "priority") {
|
|
360
|
-
return `${item.kind === "prompt" ? item.priorityEmoji ?? "⚡" : "⚡"} ${item.statusSummary}`;
|
|
360
|
+
return `${item.kind === "prompt" ? (item.priorityEmoji ?? "⚡") : "⚡"} ${item.statusSummary}`;
|
|
361
361
|
}
|
|
362
362
|
return item.statusSummary;
|
|
363
363
|
}
|
|
@@ -365,15 +365,7 @@ function formatTelegramQueueItemStatusSummary<TContext = unknown>(
|
|
|
365
365
|
export function formatQueuedTelegramItemsStatus<TContext = unknown>(
|
|
366
366
|
items: TelegramQueueItem<TContext>[],
|
|
367
367
|
): string {
|
|
368
|
-
|
|
369
|
-
const previewCount = 4;
|
|
370
|
-
const summaries = items
|
|
371
|
-
.slice(0, previewCount)
|
|
372
|
-
.map(formatTelegramQueueItemStatusSummary)
|
|
373
|
-
.filter(Boolean);
|
|
374
|
-
if (summaries.length === 0) return ` +${items.length}`;
|
|
375
|
-
const suffix = items.length > summaries.length ? ", …" : "";
|
|
376
|
-
return ` +${items.length}: [${summaries.join(", ")}${suffix}]`;
|
|
368
|
+
return items.length === 0 ? "" : ` +${items.length}`;
|
|
377
369
|
}
|
|
378
370
|
|
|
379
371
|
export function canDispatchTelegramTurnState(
|
|
@@ -783,7 +775,7 @@ export interface TelegramAgentEndRuntimeDeps<
|
|
|
783
775
|
) => Promise<boolean>;
|
|
784
776
|
sendMarkdownReply: (
|
|
785
777
|
chatId: number,
|
|
786
|
-
replyToMessageId: number,
|
|
778
|
+
replyToMessageId: number | undefined,
|
|
787
779
|
markdown: string,
|
|
788
780
|
options?: { replyMarkup?: TReplyMarkup },
|
|
789
781
|
) => Promise<unknown>;
|
|
@@ -801,6 +793,13 @@ export interface TelegramAgentEndRuntimeDeps<
|
|
|
801
793
|
plan: TelegramAgentEndOutboundReplyPlan,
|
|
802
794
|
options?: { replyToPrompt?: boolean },
|
|
803
795
|
) => Promise<void>;
|
|
796
|
+
getDefaultChatId?: () => number | undefined;
|
|
797
|
+
isProactivePushEnabled?: () => boolean;
|
|
798
|
+
recordRuntimeEvent?: (
|
|
799
|
+
category: string,
|
|
800
|
+
error: unknown,
|
|
801
|
+
details?: Record<string, unknown>,
|
|
802
|
+
) => void;
|
|
804
803
|
}
|
|
805
804
|
|
|
806
805
|
export interface TelegramAgentEndHookRuntimeDeps<
|
|
@@ -838,6 +837,9 @@ export interface TelegramAgentEndHookRuntimeDeps<
|
|
|
838
837
|
TReplyMarkup
|
|
839
838
|
>["planOutboundReply"];
|
|
840
839
|
sendOutboundReplyArtifacts?: TelegramAgentEndRuntimeDeps<TTurn>["sendOutboundReplyArtifacts"];
|
|
840
|
+
getDefaultChatId?: TelegramAgentEndRuntimeDeps<TTurn>["getDefaultChatId"];
|
|
841
|
+
isProactivePushEnabled?: TelegramAgentEndRuntimeDeps<TTurn>["isProactivePushEnabled"];
|
|
842
|
+
recordRuntimeEvent?: TelegramAgentEndRuntimeDeps<TTurn>["recordRuntimeEvent"];
|
|
841
843
|
}
|
|
842
844
|
|
|
843
845
|
export interface TelegramAgentEndHookEvent<TMessage> {
|
|
@@ -928,9 +930,11 @@ export function createTelegramAgentEndHook<
|
|
|
928
930
|
ctx: TContext,
|
|
929
931
|
): Promise<void> {
|
|
930
932
|
const turn = deps.getActiveTurn();
|
|
933
|
+
const proactiveEnabled = deps.isProactivePushEnabled?.() ?? false;
|
|
931
934
|
await handleTelegramAgentEndRuntime({
|
|
932
935
|
turn,
|
|
933
|
-
assistant:
|
|
936
|
+
assistant:
|
|
937
|
+
turn || proactiveEnabled ? deps.extractAssistant(event.messages) : {},
|
|
934
938
|
preserveQueuedTurnsAsHistory: deps.getPreserveQueuedTurnsAsHistory(),
|
|
935
939
|
resetRuntimeState: deps.resetRuntimeState,
|
|
936
940
|
updateStatus: () => deps.updateStatus(ctx),
|
|
@@ -950,6 +954,9 @@ export function createTelegramAgentEndHook<
|
|
|
950
954
|
sendQueuedAttachments: deps.sendQueuedAttachments,
|
|
951
955
|
planOutboundReply: deps.planOutboundReply,
|
|
952
956
|
sendOutboundReplyArtifacts: deps.sendOutboundReplyArtifacts,
|
|
957
|
+
getDefaultChatId: deps.getDefaultChatId,
|
|
958
|
+
isProactivePushEnabled: deps.isProactivePushEnabled,
|
|
959
|
+
recordRuntimeEvent: deps.recordRuntimeEvent,
|
|
953
960
|
});
|
|
954
961
|
};
|
|
955
962
|
}
|
|
@@ -969,8 +976,8 @@ export async function handleTelegramAgentEndRuntime<
|
|
|
969
976
|
const replyMarkup = outboundReply?.replyMarkup;
|
|
970
977
|
deps.resetRuntimeState();
|
|
971
978
|
deps.updateStatus();
|
|
972
|
-
if (
|
|
973
|
-
await deps.clearPreview(turn.chatId);
|
|
979
|
+
if (deps.isCurrentOwner && !deps.isCurrentOwner()) {
|
|
980
|
+
if (turn) await deps.clearPreview(turn.chatId);
|
|
974
981
|
return;
|
|
975
982
|
}
|
|
976
983
|
const endPlan = buildTelegramAgentEndPlan({
|
|
@@ -981,6 +988,22 @@ export async function handleTelegramAgentEndRuntime<
|
|
|
981
988
|
preserveQueuedTurnsAsHistory: deps.preserveQueuedTurnsAsHistory,
|
|
982
989
|
});
|
|
983
990
|
if (!turn) {
|
|
991
|
+
if (
|
|
992
|
+
deps.isProactivePushEnabled?.() &&
|
|
993
|
+
finalText &&
|
|
994
|
+
!assistant.errorMessage
|
|
995
|
+
) {
|
|
996
|
+
const defaultChatId = deps.getDefaultChatId?.();
|
|
997
|
+
if (defaultChatId !== undefined) {
|
|
998
|
+
try {
|
|
999
|
+
await deps.sendMarkdownReply(defaultChatId, undefined, finalText);
|
|
1000
|
+
} catch (error) {
|
|
1001
|
+
deps.recordRuntimeEvent?.("proactive-push", error, {
|
|
1002
|
+
chatId: defaultChatId,
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
984
1007
|
if (endPlan.shouldDispatchNext) deps.dispatchNextQueuedTelegramTurn();
|
|
985
1008
|
return;
|
|
986
1009
|
}
|
package/lib/routing.ts
CHANGED
|
@@ -50,11 +50,24 @@ export interface TelegramInboundRouteRuntimeDeps<
|
|
|
50
50
|
Model.ScopedTelegramModel<TModel>
|
|
51
51
|
>;
|
|
52
52
|
menuActions: Menu.TelegramMenuActionRuntime<TContext, TModel>;
|
|
53
|
+
updateSettingsMenuMessage?: (
|
|
54
|
+
state: Menu.TelegramModelMenuState<TModel>,
|
|
55
|
+
ctx: TContext,
|
|
56
|
+
) => Promise<void>;
|
|
53
57
|
openQueueMenu: (
|
|
54
58
|
chatId: number,
|
|
55
59
|
replyToMessageId: number,
|
|
56
60
|
ctx: TContext,
|
|
57
61
|
) => Promise<void>;
|
|
62
|
+
openSettingsMenu?: (
|
|
63
|
+
chatId: number,
|
|
64
|
+
replyToMessageId: number,
|
|
65
|
+
ctx: TContext,
|
|
66
|
+
) => Promise<void>;
|
|
67
|
+
settingsMenuCallbackHandler?: (
|
|
68
|
+
query: TCallbackQuery,
|
|
69
|
+
ctx: TContext,
|
|
70
|
+
) => Promise<boolean>;
|
|
58
71
|
queueMenuCallbackHandler: (
|
|
59
72
|
query: TCallbackQuery,
|
|
60
73
|
ctx: TContext,
|
|
@@ -79,6 +92,10 @@ export interface TelegramInboundRouteRuntimeDeps<
|
|
|
79
92
|
downloadFile: Media.DownloadTelegramMessageFilesDeps["downloadFile"];
|
|
80
93
|
getThinkingLevel: () => Model.ThinkingLevel;
|
|
81
94
|
setThinkingLevel: (level: Model.ThinkingLevel) => void;
|
|
95
|
+
persistScopedModelPatterns?: (
|
|
96
|
+
patterns: string[],
|
|
97
|
+
ctx: TContext,
|
|
98
|
+
) => Promise<void>;
|
|
82
99
|
setModel: (model: TModel) => Promise<boolean>;
|
|
83
100
|
sendUserMessage?: (message: string) => void;
|
|
84
101
|
isIdle: (ctx: TContext) => boolean;
|
|
@@ -98,6 +115,7 @@ const TELEGRAM_OWNED_CALLBACK_PREFIXES = [
|
|
|
98
115
|
"menu:",
|
|
99
116
|
"model:",
|
|
100
117
|
"queue:",
|
|
118
|
+
"settings:",
|
|
101
119
|
"status:",
|
|
102
120
|
"tgbtn:",
|
|
103
121
|
"thinking:",
|
|
@@ -140,12 +158,14 @@ export function createTelegramInboundRouteRuntime<
|
|
|
140
158
|
updateModelMenuMessage: deps.menuActions.updateModelMenuMessage,
|
|
141
159
|
updateThinkingMenuMessage: deps.menuActions.updateThinkingMenuMessage,
|
|
142
160
|
updateStatusMessage: deps.menuActions.updateStatusMessage,
|
|
161
|
+
updateSettingsMenuMessage: deps.updateSettingsMenuMessage,
|
|
143
162
|
answerCallbackQuery: deps.answerCallbackQuery,
|
|
144
163
|
isIdle: deps.isIdle,
|
|
145
164
|
hasActiveTelegramTurn: deps.activeTurnRuntime.has,
|
|
146
165
|
hasAbortHandler: deps.bridgeRuntime.abort.hasHandler,
|
|
147
166
|
getActiveToolExecutions:
|
|
148
167
|
deps.bridgeRuntime.lifecycle.getActiveToolExecutions,
|
|
168
|
+
persistScopedModelPatterns: deps.persistScopedModelPatterns,
|
|
149
169
|
setModel: deps.setModel,
|
|
150
170
|
setCurrentModel: deps.currentModelRuntime.setCurrentModel,
|
|
151
171
|
stagePendingModelSwitch: deps.modelSwitchController.stagePendingSwitch,
|
|
@@ -187,6 +207,11 @@ export function createTelegramInboundRouteRuntime<
|
|
|
187
207
|
}
|
|
188
208
|
const handledByQueue = await deps.queueMenuCallbackHandler(query, ctx);
|
|
189
209
|
if (handledByQueue) return;
|
|
210
|
+
const handledBySettings = await deps.settingsMenuCallbackHandler?.(
|
|
211
|
+
query,
|
|
212
|
+
ctx,
|
|
213
|
+
);
|
|
214
|
+
if (handledBySettings) return;
|
|
190
215
|
const callbackData = query.data;
|
|
191
216
|
if (
|
|
192
217
|
deps.sendUserMessage &&
|
|
@@ -279,6 +304,7 @@ export function createTelegramInboundRouteRuntime<
|
|
|
279
304
|
const chatId = (message as { chat: { id: number } }).chat.id;
|
|
280
305
|
return deps.openQueueMenu(chatId, message.message_id, ctx);
|
|
281
306
|
},
|
|
307
|
+
openSettingsMenu: deps.openSettingsMenu,
|
|
282
308
|
getAllowedUserId: deps.configStore.getAllowedUserId,
|
|
283
309
|
setAllowedUserId: deps.configStore.setAllowedUserId,
|
|
284
310
|
setMyCommands: deps.setMyCommands,
|
package/lib/status.ts
CHANGED
|
@@ -44,6 +44,7 @@ export interface TelegramStatusContext {
|
|
|
44
44
|
getContextUsage(): TelegramContextUsage | undefined;
|
|
45
45
|
isIdle?: () => boolean;
|
|
46
46
|
hasPendingMessages?: () => boolean;
|
|
47
|
+
isCompactionInProgress?: () => boolean;
|
|
47
48
|
modelRegistry: {
|
|
48
49
|
isUsingOAuth(model: TelegramStatusActiveModel): boolean;
|
|
49
50
|
};
|
|
@@ -303,8 +304,13 @@ export function buildTelegramRuntimeEventLines(
|
|
|
303
304
|
|
|
304
305
|
export function createTelegramStatusHtmlBuilder<TContext>(deps: {
|
|
305
306
|
getActiveModel: (ctx: TContext) => TelegramStatusActiveModel | undefined;
|
|
307
|
+
isCompactionInProgress?: () => boolean;
|
|
306
308
|
}): (ctx: TContext & TelegramStatusContext) => string {
|
|
307
|
-
return (ctx) =>
|
|
309
|
+
return (ctx) =>
|
|
310
|
+
buildStatusHtml(
|
|
311
|
+
{ ...ctx, isCompactionInProgress: deps.isCompactionInProgress },
|
|
312
|
+
deps.getActiveModel(ctx),
|
|
313
|
+
);
|
|
308
314
|
}
|
|
309
315
|
|
|
310
316
|
export function createTelegramStatusRuntime<
|
|
@@ -348,7 +354,11 @@ export function createTelegramBridgeStatusRuntime<
|
|
|
348
354
|
paired: !!config.allowedUserId,
|
|
349
355
|
compactionInProgress,
|
|
350
356
|
processing:
|
|
351
|
-
hasActiveTurn ||
|
|
357
|
+
hasActiveTurn ||
|
|
358
|
+
hasPendingDispatch ||
|
|
359
|
+
hasPendingModelSwitch ||
|
|
360
|
+
activeToolExecutions > 0 ||
|
|
361
|
+
queuedItems.length > 0,
|
|
352
362
|
processingStatus: getTelegramStatusBarProcessingStatus({
|
|
353
363
|
hasActiveTurn,
|
|
354
364
|
hasPendingDispatch,
|
|
@@ -388,8 +398,9 @@ export function getTelegramStatusBarProcessingStatus(state: {
|
|
|
388
398
|
queuedItems: number;
|
|
389
399
|
}): string | undefined {
|
|
390
400
|
if (state.hasPendingModelSwitch) return "model";
|
|
391
|
-
if (state.activeToolExecutions > 0)
|
|
392
|
-
|
|
401
|
+
if (state.hasActiveTurn && state.activeToolExecutions > 0)
|
|
402
|
+
return "tool running";
|
|
403
|
+
if (state.hasActiveTurn || state.activeToolExecutions > 0) return "active";
|
|
393
404
|
if (state.hasPendingDispatch) return "dispatching";
|
|
394
405
|
if (state.queuedItems > 0) return "queued";
|
|
395
406
|
return undefined;
|
|
@@ -410,13 +421,15 @@ export function buildTelegramStatusBarText(
|
|
|
410
421
|
if (!state.paired)
|
|
411
422
|
return `${label} ${theme.fg("warning", "awaiting pairing")}`;
|
|
412
423
|
const queued = state.queuedStatus
|
|
413
|
-
? theme.fg("
|
|
424
|
+
? theme.fg("success", state.queuedStatus)
|
|
414
425
|
: "";
|
|
415
426
|
if (state.compactionInProgress) {
|
|
416
427
|
return `${label} ${theme.fg("accent", "compacting")}${queued}`;
|
|
417
428
|
}
|
|
418
429
|
if (state.processing) {
|
|
419
|
-
const processingStatus = state.
|
|
430
|
+
const processingStatus = state.queuedStatus
|
|
431
|
+
? "active"
|
|
432
|
+
: (state.processingStatus ?? "processing");
|
|
420
433
|
const processingToken =
|
|
421
434
|
processingStatus === "active" ? "warning" : "accent";
|
|
422
435
|
return `${label} ${theme.fg(processingToken, processingStatus)}${queued}`;
|
|
@@ -537,6 +550,7 @@ function buildContextSummary(
|
|
|
537
550
|
}
|
|
538
551
|
|
|
539
552
|
function buildStatusSummary(ctx: TelegramStatusContext): string {
|
|
553
|
+
if (ctx.isCompactionInProgress?.()) return "compacting";
|
|
540
554
|
if (ctx.hasPendingMessages?.()) return "pending";
|
|
541
555
|
if (ctx.isIdle?.() === false) return "active";
|
|
542
556
|
if (ctx.isIdle?.() === true) return "idle";
|
package/lib/updates.ts
CHANGED
|
@@ -31,12 +31,14 @@ export const TELEGRAM_PRIORITY_REACTIONS = [
|
|
|
31
31
|
{ id: 11, name: "lightning", emoji: "⚡" },
|
|
32
32
|
{ id: 12, name: "heart", emoji: "❤" },
|
|
33
33
|
{ id: 13, name: "dove", emoji: "🕊" },
|
|
34
|
+
{ id: 14, name: "fire", emoji: "🔥" },
|
|
34
35
|
] as const;
|
|
35
36
|
export const TELEGRAM_REMOVAL_REACTIONS = [
|
|
36
37
|
{ id: 20, name: "dislike", emoji: "👎" },
|
|
37
38
|
{ id: 21, name: "ghost", emoji: "👻" },
|
|
38
39
|
{ id: 22, name: "broken-heart", emoji: "💔" },
|
|
39
40
|
{ id: 23, name: "poop", emoji: "💩" },
|
|
41
|
+
{ id: 24, name: "wastebasket", emoji: "🗑" },
|
|
40
42
|
] as const;
|
|
41
43
|
export const TELEGRAM_PRIORITY_REACTION_EMOJIS =
|
|
42
44
|
TELEGRAM_PRIORITY_REACTIONS.map((reaction) => reaction.emoji);
|