@llblab/pi-kit 0.14.1 → 0.16.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/CHANGELOG.md +11 -0
- package/README.md +3 -3
- package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +5 -0
- package/node_modules/@llblab/pi-codex-usage/README.md +6 -0
- package/node_modules/@llblab/pi-codex-usage/index.ts +81 -7
- package/node_modules/@llblab/pi-codex-usage/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/AGENTS.md +9 -9
- package/node_modules/@llblab/pi-state-flow/BACKLOG.md +0 -13
- package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +15 -0
- package/node_modules/@llblab/pi-state-flow/README.md +7 -6
- package/node_modules/@llblab/pi-state-flow/dist/lib/config.d.ts +5 -2
- package/node_modules/@llblab/pi-state-flow/dist/lib/config.js +17 -16
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +8 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +24 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.js +4 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/durable.d.ts +1 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/durable.js +8 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/episode.d.ts +2 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/episode.js +4 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.d.ts +5 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +93 -35
- package/node_modules/@llblab/pi-state-flow/dist/lib/git.js +20 -23
- package/node_modules/@llblab/pi-state-flow/dist/lib/history.js +8 -4
- package/node_modules/@llblab/pi-state-flow/dist/lib/json.js +29 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/migration.js +34 -18
- package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +14 -16
- package/node_modules/@llblab/pi-state-flow/dist/lib/query.d.ts +27 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/query.js +182 -10
- package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.d.ts +2 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.js +34 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +5 -5
- package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +20 -24
- package/node_modules/@llblab/pi-state-flow/dist/lib/state.d.ts +6 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/state.js +5 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/lib/storage.d.ts +2 -0
- package/node_modules/@llblab/pi-state-flow/dist/lib/storage.js +55 -20
- package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.d.ts +8 -6
- package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.js +10 -3
- package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +7 -3
- package/node_modules/@llblab/pi-state-flow/dist/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-memory/SKILL.md +11 -3
- package/node_modules/@llblab/pi-state-flow/docs/README.md +1 -0
- package/node_modules/@llblab/pi-state-flow/docs/architecture.md +5 -3
- package/node_modules/@llblab/pi-state-flow/docs/filesystem-recovery.md +3 -2
- package/node_modules/@llblab/pi-state-flow/docs/lazy-state.md +504 -0
- package/node_modules/@llblab/pi-state-flow/docs/usage.md +11 -8
- package/node_modules/@llblab/pi-state-flow/lib/config.ts +18 -15
- package/node_modules/@llblab/pi-state-flow/lib/context.ts +24 -0
- package/node_modules/@llblab/pi-state-flow/lib/continuation.ts +4 -3
- package/node_modules/@llblab/pi-state-flow/lib/durable.ts +8 -4
- package/node_modules/@llblab/pi-state-flow/lib/episode.ts +5 -0
- package/node_modules/@llblab/pi-state-flow/lib/extension.ts +86 -34
- package/node_modules/@llblab/pi-state-flow/lib/git.ts +23 -22
- package/node_modules/@llblab/pi-state-flow/lib/history.ts +8 -4
- package/node_modules/@llblab/pi-state-flow/lib/json.ts +31 -3
- package/node_modules/@llblab/pi-state-flow/lib/migration.ts +33 -16
- package/node_modules/@llblab/pi-state-flow/lib/protocol.ts +14 -16
- package/node_modules/@llblab/pi-state-flow/lib/query.ts +173 -9
- package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +32 -4
- package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +22 -25
- package/node_modules/@llblab/pi-state-flow/lib/state.ts +11 -6
- package/node_modules/@llblab/pi-state-flow/lib/status.ts +1 -1
- package/node_modules/@llblab/pi-state-flow/lib/storage.ts +46 -18
- package/node_modules/@llblab/pi-state-flow/lib/telegram.ts +19 -6
- package/node_modules/@llblab/pi-state-flow/lib/transition.ts +7 -3
- package/node_modules/@llblab/pi-state-flow/package.json +1 -1
- package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +11 -3
- package/node_modules/@llblab/pi-telegram/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -0
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +12 -0
- package/node_modules/@llblab/pi-telegram/README.md +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/activity.d.ts +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/activity.js +12 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +3 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +7 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +134 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +297 -16
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +11 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +68 -8
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +4 -3
- package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +17 -13
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +2 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +2 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +5 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +59 -7
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.d.ts +23 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +20 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +18 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +152 -6
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +1 -0
- package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +5 -3
- package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +3 -3
- package/node_modules/@llblab/pi-telegram/docs/callback-namespaces.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +4 -3
- package/node_modules/@llblab/pi-telegram/docs/sections.md +2 -2
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +2 -1
- package/node_modules/@llblab/pi-telegram/docs/updates.md +1 -1
- package/node_modules/@llblab/pi-telegram/lib/activity.ts +14 -0
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +10 -2
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +466 -21
- package/node_modules/@llblab/pi-telegram/lib/delivery.ts +15 -0
- package/node_modules/@llblab/pi-telegram/lib/extension.ts +77 -9
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +25 -10
- package/node_modules/@llblab/pi-telegram/lib/pi.ts +3 -0
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +7 -1
- package/node_modules/@llblab/pi-telegram/lib/replies.ts +2 -0
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +90 -19
- package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +30 -0
- package/node_modules/@llblab/pi-telegram/lib/threads.ts +199 -6
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +5 -2
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/package.json +4 -4
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Telegram command routing helpers
|
|
3
3
|
* Zones: telegram controls, pi agent commands, queue controls
|
|
4
|
-
* Owns Telegram slash-command normalization, bot command metadata,
|
|
4
|
+
* Owns Telegram slash-command normalization, bot command metadata, pi-side command registration, and command-initiated session replacement orchestration behind runtime ports
|
|
5
5
|
*/
|
|
6
6
|
import { type TelegramConfigStore } from "./config.ts";
|
|
7
|
+
import type * as Pi from "./pi.ts";
|
|
7
8
|
import type { ExtensionAPI, ExtensionCommandContext } from "./pi.ts";
|
|
8
9
|
import type { TelegramBridgeStatusLineOptions } from "./status.ts";
|
|
10
|
+
import type { TelegramSessionReplacementIntent } from "./threads.ts";
|
|
9
11
|
import { type PendingTelegramControlItem, type TelegramQueueAdmissionReceipt } from "./queue.ts";
|
|
10
12
|
export interface ParsedTelegramCommand {
|
|
11
13
|
name: string;
|
|
@@ -60,6 +62,7 @@ export declare const TELEGRAM_COMMAND_EMOJI: {
|
|
|
60
62
|
readonly abort: "⏹️";
|
|
61
63
|
readonly stop: "🟥";
|
|
62
64
|
readonly name: "🏷️";
|
|
65
|
+
readonly new: "🆕";
|
|
63
66
|
};
|
|
64
67
|
export type TelegramCommandEmojiName = keyof typeof TELEGRAM_COMMAND_EMOJI;
|
|
65
68
|
export declare function getTelegramCommandEmoji(command: TelegramCommandEmojiName): string;
|
|
@@ -144,7 +147,7 @@ export declare function createTelegramThreadDisplayNameRenameBinding(): {
|
|
|
144
147
|
};
|
|
145
148
|
export declare function parseTelegramRequestedThreadName(args: string): string | undefined;
|
|
146
149
|
export declare function registerTelegramBridgeCommands(pi: ExtensionAPI, deps: TelegramBridgeCommandRegistrationDeps): void;
|
|
147
|
-
export declare const TELEGRAM_RESERVED_COMMAND_NAMES: readonly ["stop", "name", "abort", "next", "continue", "status", "queue", "compact", "model", "thinking", "settings", "help", "start"];
|
|
150
|
+
export declare const TELEGRAM_RESERVED_COMMAND_NAMES: readonly ["stop", "name", "new", "abort", "next", "continue", "status", "queue", "compact", "model", "thinking", "settings", "help", "start"];
|
|
148
151
|
export type TelegramReservedCommandName = (typeof TELEGRAM_RESERVED_COMMAND_NAMES)[number];
|
|
149
152
|
export declare function isTelegramReservedCommandName(commandName: string | undefined): commandName is TelegramReservedCommandName;
|
|
150
153
|
export type TelegramCommandAction = {
|
|
@@ -156,6 +159,9 @@ export type TelegramCommandAction = {
|
|
|
156
159
|
} | {
|
|
157
160
|
kind: "name";
|
|
158
161
|
executionMode: "immediate";
|
|
162
|
+
} | {
|
|
163
|
+
kind: "new";
|
|
164
|
+
executionMode: "immediate";
|
|
159
165
|
} | {
|
|
160
166
|
kind: "abort";
|
|
161
167
|
executionMode: "immediate";
|
|
@@ -192,6 +198,7 @@ export type TelegramCommandExecutionMode = "ignored" | "immediate";
|
|
|
192
198
|
export interface TelegramCommandActionDeps<TMessage, TContext> {
|
|
193
199
|
handleStop: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
194
200
|
handleName: (message: TMessage, ctx: TContext, name: string) => Promise<void>;
|
|
201
|
+
handleNew: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
195
202
|
handleAbort: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
196
203
|
handleNext: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
197
204
|
handleContinue: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
@@ -264,6 +271,13 @@ export interface TelegramCompactConfirmationCallbackQuery {
|
|
|
264
271
|
message_thread_id?: number;
|
|
265
272
|
};
|
|
266
273
|
}
|
|
274
|
+
export interface TelegramNewConfirmationCallbackDeps<TContext> {
|
|
275
|
+
ctx: TContext;
|
|
276
|
+
answerCallbackQuery: (callbackQueryId: string, text?: string) => Promise<void>;
|
|
277
|
+
editInteractiveMessage: (chatId: number, messageId: number, text: string, mode: "markdown" | "html" | "plain", replyMarkup: TelegramCompactConfirmationReplyMarkup) => Promise<void>;
|
|
278
|
+
deleteMessage: (chatId: number, messageId: number) => Promise<void>;
|
|
279
|
+
runNew: (ctx: TContext) => Promise<void>;
|
|
280
|
+
}
|
|
267
281
|
export interface TelegramCompactConfirmationCallbackDeps<TContext> {
|
|
268
282
|
ctx: TContext;
|
|
269
283
|
answerCallbackQuery: (callbackQueryId: string, text?: string) => Promise<void>;
|
|
@@ -390,6 +404,7 @@ export interface TelegramCommandRuntimeDeps<TMessage extends TelegramCommandRunt
|
|
|
390
404
|
}) => void;
|
|
391
405
|
stopTypingLoop?: () => void;
|
|
392
406
|
enqueueContinueTurn: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
407
|
+
requestNewSession?: (message: TMessage) => void;
|
|
393
408
|
compact: (ctx: TContext, callbacks: {
|
|
394
409
|
onComplete: () => void;
|
|
395
410
|
onError: (error: unknown) => void;
|
|
@@ -434,6 +449,10 @@ export declare const TELEGRAM_COMMAND_ACTIONS: {
|
|
|
434
449
|
readonly kind: "name";
|
|
435
450
|
readonly executionMode: "immediate";
|
|
436
451
|
};
|
|
452
|
+
readonly new: {
|
|
453
|
+
readonly kind: "new";
|
|
454
|
+
readonly executionMode: "immediate";
|
|
455
|
+
};
|
|
437
456
|
readonly abort: {
|
|
438
457
|
readonly kind: "abort";
|
|
439
458
|
readonly executionMode: "immediate";
|
|
@@ -515,10 +534,27 @@ export declare function handleTelegramNextCommand(deps: {
|
|
|
515
534
|
export declare function handleTelegramContinueCommand<TMessage, TContext>(message: TMessage, ctx: TContext, deps: {
|
|
516
535
|
enqueueContinueTurn: (message: TMessage, ctx: TContext) => Promise<void>;
|
|
517
536
|
}): Promise<void>;
|
|
537
|
+
export declare function buildTelegramNewConfirmationReplyMarkup(): TelegramCompactConfirmationReplyMarkup;
|
|
538
|
+
export declare function getTelegramNewConfirmationHtml(): string;
|
|
539
|
+
export declare function openTelegramNewConfirmation(target: TelegramCommandMessageTarget, deps: TelegramCompactConfirmationDeps): Promise<void>;
|
|
540
|
+
export declare function handleTelegramNewConfirmationCallback<TContext>(query: TelegramCompactConfirmationCallbackQuery, deps: TelegramNewConfirmationCallbackDeps<TContext>): Promise<boolean>;
|
|
518
541
|
export declare function buildTelegramCompactConfirmationReplyMarkup(): TelegramCompactConfirmationReplyMarkup;
|
|
519
542
|
export declare function getTelegramCompactConfirmationHtml(): string;
|
|
520
543
|
export declare function openTelegramCompactConfirmation(target: TelegramCommandMessageTarget, deps: TelegramCompactConfirmationDeps): Promise<void>;
|
|
521
544
|
export declare function handleTelegramCompactConfirmationCallback<TContext>(query: TelegramCompactConfirmationCallbackQuery, deps: TelegramCompactConfirmationCallbackDeps<TContext>): Promise<boolean>;
|
|
545
|
+
export interface TelegramNewCommandDeps extends TelegramRuntimeEventRecorderPort {
|
|
546
|
+
isIdle: () => boolean;
|
|
547
|
+
hasPendingMessages: () => boolean;
|
|
548
|
+
hasActiveTelegramTurn: () => boolean;
|
|
549
|
+
hasDispatchPending: () => boolean;
|
|
550
|
+
hasQueuedTelegramItems: () => boolean;
|
|
551
|
+
isCompactionInProgress: () => boolean;
|
|
552
|
+
requestNewSession?: () => void;
|
|
553
|
+
sendTextReply: (text: string, options?: {
|
|
554
|
+
parseMode?: "HTML";
|
|
555
|
+
}) => Promise<void>;
|
|
556
|
+
}
|
|
557
|
+
export declare function handleTelegramNewCommand(deps: TelegramNewCommandDeps): Promise<void>;
|
|
522
558
|
export declare function handleTelegramCompactCommand(deps: TelegramCompactCommandDeps): Promise<void>;
|
|
523
559
|
export declare function handleTelegramStatusCommand<TContext>(deps: {
|
|
524
560
|
ctx: TContext;
|
|
@@ -538,4 +574,100 @@ export declare function createTelegramCommandHandler<TMessage extends TelegramCo
|
|
|
538
574
|
export declare function createTelegramCommandOrPromptRuntime<TMessage, TContext>(deps: TelegramCommandOrPromptRuntimeDeps<TMessage, TContext>): {
|
|
539
575
|
dispatchMessages: (messages: TMessage[], ctx: TContext) => Promise<void>;
|
|
540
576
|
};
|
|
577
|
+
export declare const TELEGRAM_SESSION_ACTION_COMMAND_NAME = "telegram-session-action";
|
|
578
|
+
export declare const TELEGRAM_SESSION_ACTION_COMMAND_DESCRIPTION = "(internal) replace the current Pi session after Telegram settlement";
|
|
579
|
+
export declare function delayTelegramSessionAction(delayMs: number): Promise<void>;
|
|
580
|
+
export interface TelegramSessionActionRuntimeDeps {
|
|
581
|
+
registerCommand: Pi.ExtensionAPI["registerCommand"];
|
|
582
|
+
sendUserMessage: Pi.ExtensionAPI["sendUserMessage"];
|
|
583
|
+
notifyResult: (target: {
|
|
584
|
+
chatId: number;
|
|
585
|
+
threadId?: number;
|
|
586
|
+
messageId: number;
|
|
587
|
+
}, result: "success" | "cancelled" | "failure") => Promise<void>;
|
|
588
|
+
prepareReplacement?: (ctx: Pi.ExtensionCommandContext, updateId: number, target: {
|
|
589
|
+
chatId: number;
|
|
590
|
+
threadId?: number;
|
|
591
|
+
messageId: number;
|
|
592
|
+
}) => Promise<void>;
|
|
593
|
+
recordRuntimeEvent?: (category: string, error: unknown) => void;
|
|
594
|
+
}
|
|
595
|
+
export interface TelegramSessionReplacementSettlementDeps {
|
|
596
|
+
getIntent: () => Promise<TelegramSessionReplacementIntent | undefined>;
|
|
597
|
+
hasSuccessorContinuity: (intent: TelegramSessionReplacementIntent) => boolean;
|
|
598
|
+
editSuccess: (intent: TelegramSessionReplacementIntent) => Promise<{
|
|
599
|
+
ok: boolean;
|
|
600
|
+
retryable?: boolean;
|
|
601
|
+
message?: string;
|
|
602
|
+
}>;
|
|
603
|
+
clearIntent: (intent: TelegramSessionReplacementIntent) => Promise<boolean>;
|
|
604
|
+
profileName: string | undefined;
|
|
605
|
+
cwd: string;
|
|
606
|
+
sessionId: string;
|
|
607
|
+
now?: () => number;
|
|
608
|
+
sleep?: (delayMs: number) => Promise<void>;
|
|
609
|
+
isCurrent?: () => boolean;
|
|
610
|
+
}
|
|
611
|
+
export declare function settleTelegramSessionReplacement(deps: TelegramSessionReplacementSettlementDeps): Promise<"none" | "settled" | "expired" | "failed" | "stale">;
|
|
612
|
+
export declare function createTelegramSessionReplacementSettlementRuntime<TContext>(deps: {
|
|
613
|
+
resolve: (ctx: TContext) => TelegramSessionReplacementSettlementDeps | undefined;
|
|
614
|
+
onResult?: (result: "none" | "settled" | "expired" | "failed" | "stale") => void;
|
|
615
|
+
onError?: (error: unknown) => void;
|
|
616
|
+
}): {
|
|
617
|
+
onSessionStart: (ctx: TContext) => void;
|
|
618
|
+
};
|
|
619
|
+
export interface TelegramSessionActionAssemblyDeps {
|
|
620
|
+
registerCommand: Pi.ExtensionAPI["registerCommand"];
|
|
621
|
+
sendUserMessage: Pi.ExtensionAPI["sendUserMessage"];
|
|
622
|
+
store: {
|
|
623
|
+
load: () => Promise<void>;
|
|
624
|
+
refresh?: () => Promise<void>;
|
|
625
|
+
getWorkspaceBindingByTarget: (target: {
|
|
626
|
+
chatId: number;
|
|
627
|
+
threadId?: number;
|
|
628
|
+
}, sessionId?: string) => {
|
|
629
|
+
cwd: string;
|
|
630
|
+
sessionId?: string;
|
|
631
|
+
slot?: string;
|
|
632
|
+
threadName?: string;
|
|
633
|
+
manualThreadName?: string;
|
|
634
|
+
target: {
|
|
635
|
+
chatId: number;
|
|
636
|
+
threadId: number;
|
|
637
|
+
};
|
|
638
|
+
} | undefined;
|
|
639
|
+
getSessionReplacementIntent: () => TelegramSessionReplacementIntent | undefined;
|
|
640
|
+
commitSessionReplacementIntent: (intent: TelegramSessionReplacementIntent, isCurrent: () => boolean) => Promise<boolean>;
|
|
641
|
+
removeSessionReplacementIntent: (intent: TelegramSessionReplacementIntent, isCurrent: () => boolean) => Promise<boolean>;
|
|
642
|
+
};
|
|
643
|
+
getProfileName: () => string | undefined;
|
|
644
|
+
ownsPersistence: () => boolean;
|
|
645
|
+
sendResult: (target: {
|
|
646
|
+
chatId: number;
|
|
647
|
+
threadId?: number;
|
|
648
|
+
}, html: string) => Promise<{
|
|
649
|
+
ok: boolean;
|
|
650
|
+
retryable?: boolean;
|
|
651
|
+
}>;
|
|
652
|
+
handoffTtlMs: number;
|
|
653
|
+
now?: () => number;
|
|
654
|
+
recordRuntimeEvent?: (category: string, error: unknown) => void;
|
|
655
|
+
}
|
|
656
|
+
export declare function createTelegramSessionActionAssembly(deps: TelegramSessionActionAssemblyDeps): {
|
|
657
|
+
action: TelegramSessionActionRuntime;
|
|
658
|
+
settlement: {
|
|
659
|
+
onSessionStart: (ctx: Pi.ExtensionContext) => void;
|
|
660
|
+
};
|
|
661
|
+
};
|
|
662
|
+
export interface TelegramSessionActionRuntime {
|
|
663
|
+
register: () => void;
|
|
664
|
+
scheduleAfterUpdate: (updateId: number, target: {
|
|
665
|
+
chatId: number;
|
|
666
|
+
threadId?: number;
|
|
667
|
+
messageId: number;
|
|
668
|
+
}) => boolean;
|
|
669
|
+
onUpdateCompleted: (updateId: number) => void;
|
|
670
|
+
hasPending: () => boolean;
|
|
671
|
+
}
|
|
672
|
+
export declare function createTelegramSessionActionRuntime(deps: TelegramSessionActionRuntimeDeps): TelegramSessionActionRuntime;
|
|
541
673
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Telegram command routing helpers
|
|
3
3
|
* Zones: telegram controls, pi agent commands, queue controls
|
|
4
|
-
* Owns Telegram slash-command normalization, bot command metadata,
|
|
4
|
+
* Owns Telegram slash-command normalization, bot command metadata, pi-side command registration, and command-initiated session replacement orchestration behind runtime ports
|
|
5
5
|
*/
|
|
6
6
|
import { pairTelegramUserIfNeeded, TELEGRAM_DEFAULT_PROFILE_NAME, } from "./config.js";
|
|
7
7
|
import { escapeHtml } from "./rendering.js";
|
|
@@ -89,6 +89,7 @@ export const TELEGRAM_COMMAND_EMOJI = {
|
|
|
89
89
|
abort: "⏹️",
|
|
90
90
|
stop: "🟥",
|
|
91
91
|
name: "🏷️",
|
|
92
|
+
new: "🆕",
|
|
92
93
|
};
|
|
93
94
|
export function getTelegramCommandEmoji(command) {
|
|
94
95
|
return TELEGRAM_COMMAND_EMOJI[command];
|
|
@@ -133,22 +134,22 @@ export const TELEGRAM_BUILTIN_BOT_COMMANDS = [
|
|
|
133
134
|
command: "start",
|
|
134
135
|
description: formatTelegramBotCommandDescription("start", "Open menu / Pair bridge"),
|
|
135
136
|
},
|
|
136
|
-
{
|
|
137
|
-
command: "name",
|
|
138
|
-
description: formatTelegramBotCommandDescription("name", "Rename this thread"),
|
|
139
|
-
},
|
|
140
137
|
{
|
|
141
138
|
command: "compact",
|
|
142
139
|
description: formatTelegramBotCommandDescription("compact", "Compact current session"),
|
|
143
140
|
},
|
|
144
141
|
{
|
|
145
|
-
command: "
|
|
146
|
-
description: formatTelegramBotCommandDescription("
|
|
142
|
+
command: "new",
|
|
143
|
+
description: formatTelegramBotCommandDescription("new", "Start a new session"),
|
|
147
144
|
},
|
|
148
145
|
{
|
|
149
146
|
command: "continue",
|
|
150
147
|
description: formatTelegramBotCommandDescription("continue", "Queue continue prompt"),
|
|
151
148
|
},
|
|
149
|
+
{
|
|
150
|
+
command: "next",
|
|
151
|
+
description: formatTelegramBotCommandDescription("next", "Force next turn"),
|
|
152
|
+
},
|
|
152
153
|
{
|
|
153
154
|
command: "abort",
|
|
154
155
|
description: formatTelegramBotCommandDescription("abort", "Abort Pi"),
|
|
@@ -179,15 +180,15 @@ export async function registerTelegramBotCommands(deps) {
|
|
|
179
180
|
await deps.setMyCommands(TELEGRAM_BOT_COMMANDS);
|
|
180
181
|
return;
|
|
181
182
|
}
|
|
182
|
-
const
|
|
183
|
-
if (
|
|
183
|
+
const nextCommandIndex = TELEGRAM_BOT_COMMANDS.findIndex((command) => command.command === "next");
|
|
184
|
+
if (nextCommandIndex === -1) {
|
|
184
185
|
await deps.setMyCommands([...TELEGRAM_BOT_COMMANDS, ...extensionCommands]);
|
|
185
186
|
return;
|
|
186
187
|
}
|
|
187
188
|
await deps.setMyCommands([
|
|
188
|
-
...TELEGRAM_BOT_COMMANDS.slice(0,
|
|
189
|
+
...TELEGRAM_BOT_COMMANDS.slice(0, nextCommandIndex + 1),
|
|
189
190
|
...extensionCommands,
|
|
190
|
-
...TELEGRAM_BOT_COMMANDS.slice(
|
|
191
|
+
...TELEGRAM_BOT_COMMANDS.slice(nextCommandIndex + 1),
|
|
191
192
|
]);
|
|
192
193
|
}
|
|
193
194
|
export function createTelegramBotCommandRegistrar(deps) {
|
|
@@ -412,6 +413,7 @@ export function registerTelegramBridgeCommands(pi, deps) {
|
|
|
412
413
|
export const TELEGRAM_RESERVED_COMMAND_NAMES = [
|
|
413
414
|
"stop",
|
|
414
415
|
"name",
|
|
416
|
+
"new",
|
|
415
417
|
"abort",
|
|
416
418
|
"next",
|
|
417
419
|
"continue",
|
|
@@ -529,10 +531,10 @@ export const TELEGRAM_APP_MENU_INTRO_HTML = [
|
|
|
529
531
|
"<b>Pi Telegram</b>",
|
|
530
532
|
"",
|
|
531
533
|
`${formatTelegramCommandEmojiPrefix("start")}/start — Open menu / Pair bridge`,
|
|
532
|
-
`${formatTelegramCommandEmojiPrefix("name")}/name — Rename this thread`,
|
|
533
534
|
`${formatTelegramCommandEmojiPrefix("compact")}/compact — Compact current session`,
|
|
534
|
-
`${formatTelegramCommandEmojiPrefix("
|
|
535
|
+
`${formatTelegramCommandEmojiPrefix("new")}/new — Start a new session`,
|
|
535
536
|
`${formatTelegramCommandEmojiPrefix("continue")}/continue — Queue continue prompt`,
|
|
537
|
+
`${formatTelegramCommandEmojiPrefix("next")}/next — Force next turn`,
|
|
536
538
|
`${formatTelegramCommandEmojiPrefix("abort")}/abort — Abort Pi`,
|
|
537
539
|
`${formatTelegramCommandEmojiPrefix("stop")}/stop — Abort Pi & Clear queue`,
|
|
538
540
|
].join("\n");
|
|
@@ -567,11 +569,11 @@ function buildTelegramAppMenuIntroHtml() {
|
|
|
567
569
|
"<b>Pi Telegram</b>",
|
|
568
570
|
"",
|
|
569
571
|
`${formatTelegramCommandEmojiPrefix("start")}/start — Open menu / Pair bridge`,
|
|
570
|
-
`${formatTelegramCommandEmojiPrefix("name")}/name — Rename this thread`,
|
|
571
572
|
`${formatTelegramCommandEmojiPrefix("compact")}/compact — Compact current session`,
|
|
572
|
-
|
|
573
|
-
`${formatTelegramCommandEmojiPrefix("next")}/next — Force next turn`,
|
|
573
|
+
`${formatTelegramCommandEmojiPrefix("new")}/new — Start a new session`,
|
|
574
574
|
`${formatTelegramCommandEmojiPrefix("continue")}/continue — Queue continue prompt`,
|
|
575
|
+
`${formatTelegramCommandEmojiPrefix("next")}/next — Force next turn`,
|
|
576
|
+
...extensionLines,
|
|
575
577
|
`${formatTelegramCommandEmojiPrefix("abort")}/abort — Abort Pi`,
|
|
576
578
|
`${formatTelegramCommandEmojiPrefix("stop")}/stop — Abort Pi & Clear queue`,
|
|
577
579
|
].join("\n");
|
|
@@ -623,6 +625,7 @@ export function parseTelegramCommand(text) {
|
|
|
623
625
|
export const TELEGRAM_COMMAND_ACTIONS = {
|
|
624
626
|
stop: { kind: "stop", executionMode: "immediate" },
|
|
625
627
|
name: { kind: "name", executionMode: "immediate" },
|
|
628
|
+
new: { kind: "new", executionMode: "immediate" },
|
|
626
629
|
abort: { kind: "abort", executionMode: "immediate" },
|
|
627
630
|
next: { kind: "next", executionMode: "immediate" },
|
|
628
631
|
continue: { kind: "continue", executionMode: "immediate" },
|
|
@@ -709,6 +712,43 @@ function dispatchNextQueuedTelegramTurnAfterCompact(deps) {
|
|
|
709
712
|
}
|
|
710
713
|
deps.dispatchNextQueuedTelegramTurn();
|
|
711
714
|
}
|
|
715
|
+
export function buildTelegramNewConfirmationReplyMarkup() {
|
|
716
|
+
return {
|
|
717
|
+
inline_keyboard: [
|
|
718
|
+
[
|
|
719
|
+
{ text: "🆕 Yes, start new", callback_data: "new:confirm" },
|
|
720
|
+
{ text: "❌ No", callback_data: "new:cancel" },
|
|
721
|
+
],
|
|
722
|
+
],
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
export function getTelegramNewConfirmationHtml() {
|
|
726
|
+
return "<b>Start a new session?</b>";
|
|
727
|
+
}
|
|
728
|
+
export async function openTelegramNewConfirmation(target, deps) {
|
|
729
|
+
await deps.sendInteractiveMessage(target.chatId, getTelegramNewConfirmationHtml(), "html", buildTelegramNewConfirmationReplyMarkup(), target.threadId !== undefined
|
|
730
|
+
? { target: { chatId: target.chatId, threadId: target.threadId } }
|
|
731
|
+
: undefined);
|
|
732
|
+
}
|
|
733
|
+
export async function handleTelegramNewConfirmationCallback(query, deps) {
|
|
734
|
+
if (query.data !== "new:confirm" && query.data !== "new:cancel")
|
|
735
|
+
return false;
|
|
736
|
+
const chatId = query.message?.chat?.id;
|
|
737
|
+
const messageId = query.message?.message_id;
|
|
738
|
+
if (typeof chatId !== "number" || typeof messageId !== "number") {
|
|
739
|
+
await deps.answerCallbackQuery(query.id, "⌛ Interactive message expired.");
|
|
740
|
+
return true;
|
|
741
|
+
}
|
|
742
|
+
if (query.data === "new:cancel") {
|
|
743
|
+
await deps.editInteractiveMessage(chatId, messageId, "<b>🚫 New session cancelled.</b>", "html", { inline_keyboard: [] });
|
|
744
|
+
await deps.answerCallbackQuery(query.id);
|
|
745
|
+
return true;
|
|
746
|
+
}
|
|
747
|
+
await deps.answerCallbackQuery(query.id);
|
|
748
|
+
await deps.deleteMessage(chatId, messageId);
|
|
749
|
+
await deps.runNew(deps.ctx);
|
|
750
|
+
return true;
|
|
751
|
+
}
|
|
712
752
|
export function buildTelegramCompactConfirmationReplyMarkup() {
|
|
713
753
|
return {
|
|
714
754
|
inline_keyboard: [
|
|
@@ -749,6 +789,22 @@ export async function handleTelegramCompactConfirmationCallback(query, deps) {
|
|
|
749
789
|
await deps.runCompact(deps.ctx, chatId, messageId, typeof threadId === "number" ? { chatId, threadId } : { chatId });
|
|
750
790
|
return true;
|
|
751
791
|
}
|
|
792
|
+
export async function handleTelegramNewCommand(deps) {
|
|
793
|
+
if (!deps.isIdle() ||
|
|
794
|
+
deps.hasPendingMessages() ||
|
|
795
|
+
deps.hasActiveTelegramTurn() ||
|
|
796
|
+
deps.hasDispatchPending() ||
|
|
797
|
+
deps.hasQueuedTelegramItems() ||
|
|
798
|
+
deps.isCompactionInProgress()) {
|
|
799
|
+
await deps.sendTextReply(formatTelegramInformationHeading("⏳", "Cannot start a new session while Pi or the Telegram queue is busy. Wait for queued turns to finish or send /abort first."), { parseMode: "HTML" });
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
if (!deps.requestNewSession) {
|
|
803
|
+
await deps.sendTextReply(formatTelegramInformationHeading("🚫", "Session replacement is unavailable in this Pi runtime."), { parseMode: "HTML" });
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
deps.requestNewSession();
|
|
807
|
+
}
|
|
752
808
|
export async function handleTelegramCompactCommand(deps) {
|
|
753
809
|
if (!deps.isIdle() ||
|
|
754
810
|
deps.hasPendingMessages() ||
|
|
@@ -830,6 +886,9 @@ export async function executeTelegramCommandAction(action, message, ctx, deps, c
|
|
|
830
886
|
case "name":
|
|
831
887
|
await deps.handleName(message, ctx, commandArgs);
|
|
832
888
|
return true;
|
|
889
|
+
case "new":
|
|
890
|
+
await deps.handleNew(message, ctx);
|
|
891
|
+
return true;
|
|
833
892
|
case "abort":
|
|
834
893
|
await deps.handleAbort(message, ctx);
|
|
835
894
|
return true;
|
|
@@ -900,6 +959,7 @@ export function createTelegramCommandHandlerTargetRuntime(deps) {
|
|
|
900
959
|
stopTypingLoop: deps.stopTypingLoop,
|
|
901
960
|
enqueueContinueTurn: deps.enqueueContinueTurn,
|
|
902
961
|
compact: deps.compact,
|
|
962
|
+
requestNewSession: deps.requestNewSession,
|
|
903
963
|
sendInteractiveMessage: deps.sendInteractiveMessage,
|
|
904
964
|
enqueueControlItem: commandTargetRuntime.enqueueControlItem,
|
|
905
965
|
showStatus: commandTargetRuntime.showStatus,
|
|
@@ -1075,6 +1135,25 @@ async function handleTelegramCommandRuntime(commandName, message, ctx, deps, com
|
|
|
1075
1135
|
handleQueue: async (nextMessage, commandCtx) => {
|
|
1076
1136
|
scheduleTelegramCommandEffect(commandCtx, "queue", "menu-render", deps, () => deps.openQueueMenu(nextMessage, commandCtx), assertExecutionCurrentFor(nextMessage));
|
|
1077
1137
|
},
|
|
1138
|
+
handleNew: async (nextMessage, commandCtx) => {
|
|
1139
|
+
if (deps.sendInteractiveMessage) {
|
|
1140
|
+
await openTelegramNewConfirmation(getTelegramCommandMessageTarget(nextMessage), { sendInteractiveMessage: deps.sendInteractiveMessage });
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
await handleTelegramNewCommand({
|
|
1144
|
+
isIdle: () => deps.isIdle(commandCtx),
|
|
1145
|
+
hasPendingMessages: () => deps.hasPendingMessages(commandCtx),
|
|
1146
|
+
hasActiveTelegramTurn: deps.hasActiveTelegramTurn,
|
|
1147
|
+
hasDispatchPending: deps.hasDispatchPending,
|
|
1148
|
+
hasQueuedTelegramItems: deps.hasQueuedTelegramItems,
|
|
1149
|
+
isCompactionInProgress: deps.isCompactionInProgress,
|
|
1150
|
+
requestNewSession: deps.requestNewSession
|
|
1151
|
+
? () => deps.requestNewSession(nextMessage)
|
|
1152
|
+
: undefined,
|
|
1153
|
+
sendTextReply: sendReplyFor(nextMessage),
|
|
1154
|
+
recordRuntimeEvent: deps.recordRuntimeEvent,
|
|
1155
|
+
});
|
|
1156
|
+
},
|
|
1078
1157
|
handleCompact: async (nextMessage, commandCtx) => {
|
|
1079
1158
|
if (deps.sendInteractiveMessage) {
|
|
1080
1159
|
await openTelegramCompactConfirmation(getTelegramCommandMessageTarget(nextMessage), { sendInteractiveMessage: deps.sendInteractiveMessage });
|
|
@@ -1153,3 +1232,205 @@ async function handleTelegramCommandRuntime(commandName, message, ctx, deps, com
|
|
|
1153
1232
|
},
|
|
1154
1233
|
}, commandArgs);
|
|
1155
1234
|
}
|
|
1235
|
+
export const TELEGRAM_SESSION_ACTION_COMMAND_NAME = "telegram-session-action";
|
|
1236
|
+
export const TELEGRAM_SESSION_ACTION_COMMAND_DESCRIPTION = "(internal) replace the current Pi session after Telegram settlement";
|
|
1237
|
+
export function delayTelegramSessionAction(delayMs) {
|
|
1238
|
+
return new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1239
|
+
}
|
|
1240
|
+
export async function settleTelegramSessionReplacement(deps) {
|
|
1241
|
+
const now = deps.now ?? Date.now;
|
|
1242
|
+
const sleep = deps.sleep ?? ((delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs)));
|
|
1243
|
+
while (deps.isCurrent?.() !== false) {
|
|
1244
|
+
const intent = await deps.getIntent();
|
|
1245
|
+
if (!intent || intent.sourceSessionId === deps.sessionId)
|
|
1246
|
+
return "none";
|
|
1247
|
+
if (intent.profileName !== deps.profileName || intent.cwd !== deps.cwd)
|
|
1248
|
+
return "stale";
|
|
1249
|
+
if (now() >= intent.expiresAtMs)
|
|
1250
|
+
return "expired";
|
|
1251
|
+
if (!deps.hasSuccessorContinuity(intent)) {
|
|
1252
|
+
await sleep(100);
|
|
1253
|
+
continue;
|
|
1254
|
+
}
|
|
1255
|
+
if (!await deps.clearIntent(intent))
|
|
1256
|
+
return "failed";
|
|
1257
|
+
do {
|
|
1258
|
+
const delivered = await deps.editSuccess(intent);
|
|
1259
|
+
if (delivered.ok)
|
|
1260
|
+
return "settled";
|
|
1261
|
+
if (!delivered.retryable)
|
|
1262
|
+
return "failed";
|
|
1263
|
+
await sleep(100);
|
|
1264
|
+
} while (deps.isCurrent?.() !== false && now() < intent.expiresAtMs);
|
|
1265
|
+
return "failed";
|
|
1266
|
+
}
|
|
1267
|
+
return "stale";
|
|
1268
|
+
}
|
|
1269
|
+
export function createTelegramSessionReplacementSettlementRuntime(deps) {
|
|
1270
|
+
let generation = 0;
|
|
1271
|
+
return {
|
|
1272
|
+
onSessionStart(ctx) {
|
|
1273
|
+
const currentGeneration = ++generation;
|
|
1274
|
+
const resolved = deps.resolve(ctx);
|
|
1275
|
+
if (!resolved)
|
|
1276
|
+
return;
|
|
1277
|
+
void settleTelegramSessionReplacement({
|
|
1278
|
+
...resolved,
|
|
1279
|
+
isCurrent: () => currentGeneration === generation &&
|
|
1280
|
+
resolved.isCurrent?.() !== false,
|
|
1281
|
+
}).then(deps.onResult, deps.onError);
|
|
1282
|
+
},
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
export function createTelegramSessionActionAssembly(deps) {
|
|
1286
|
+
const now = deps.now ?? Date.now;
|
|
1287
|
+
const report = (error) => deps.recordRuntimeEvent?.("new-session", error);
|
|
1288
|
+
const sendTerminalResult = async (target, result) => {
|
|
1289
|
+
const text = result === "success" ? "<b>🆕 New session started.</b>"
|
|
1290
|
+
: result === "cancelled" ? "<b>🚫 New session cancelled.</b>"
|
|
1291
|
+
: "<b>⚠️ New session failed.</b>";
|
|
1292
|
+
const deadline = now() + 10_000;
|
|
1293
|
+
do {
|
|
1294
|
+
const delivery = await deps.sendResult(target, text);
|
|
1295
|
+
if (delivery.ok)
|
|
1296
|
+
return;
|
|
1297
|
+
if (!delivery.retryable)
|
|
1298
|
+
break;
|
|
1299
|
+
await delayTelegramSessionAction(100);
|
|
1300
|
+
} while (now() < deadline);
|
|
1301
|
+
report(new Error("Telegram new-session result delivery failed."));
|
|
1302
|
+
};
|
|
1303
|
+
const action = createTelegramSessionActionRuntime({
|
|
1304
|
+
registerCommand: deps.registerCommand,
|
|
1305
|
+
sendUserMessage: deps.sendUserMessage,
|
|
1306
|
+
notifyResult(target, result) { return sendTerminalResult(target, result); },
|
|
1307
|
+
async prepareReplacement(ctx, updateId, target) {
|
|
1308
|
+
await deps.store.load();
|
|
1309
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
1310
|
+
const binding = typeof target.threadId === "number"
|
|
1311
|
+
? deps.store.getWorkspaceBindingByTarget(target)
|
|
1312
|
+
: undefined;
|
|
1313
|
+
if (typeof target.threadId === "number" &&
|
|
1314
|
+
(!binding || binding.cwd !== ctx.cwd || binding.sessionId !== sessionId)) {
|
|
1315
|
+
throw new Error("Telegram session replacement binding is unavailable.");
|
|
1316
|
+
}
|
|
1317
|
+
const createdAtMs = now();
|
|
1318
|
+
if (!await deps.store.commitSessionReplacementIntent({
|
|
1319
|
+
continuity: binding ? "workspace-thread" : "classic-chat",
|
|
1320
|
+
cwd: binding?.cwd ?? ctx.cwd,
|
|
1321
|
+
profileName: deps.getProfileName() ?? "default",
|
|
1322
|
+
sourceSessionId: sessionId,
|
|
1323
|
+
sourceUpdateId: updateId,
|
|
1324
|
+
target: binding ? { ...binding.target } : { chatId: target.chatId },
|
|
1325
|
+
messageId: target.messageId,
|
|
1326
|
+
...(binding?.slot ? { slot: binding.slot } : {}),
|
|
1327
|
+
...(binding?.manualThreadName ?? binding?.threadName
|
|
1328
|
+
? { threadName: binding.manualThreadName ?? binding.threadName } : {}),
|
|
1329
|
+
createdAtMs,
|
|
1330
|
+
expiresAtMs: createdAtMs + deps.handoffTtlMs,
|
|
1331
|
+
}, deps.ownsPersistence)) {
|
|
1332
|
+
throw new Error("Telegram session replacement intent was not persisted.");
|
|
1333
|
+
}
|
|
1334
|
+
},
|
|
1335
|
+
recordRuntimeEvent: deps.recordRuntimeEvent,
|
|
1336
|
+
});
|
|
1337
|
+
const settlement = createTelegramSessionReplacementSettlementRuntime({
|
|
1338
|
+
resolve(ctx) {
|
|
1339
|
+
const sessionId = ctx.sessionManager?.getSessionId?.();
|
|
1340
|
+
if (!sessionId)
|
|
1341
|
+
return undefined;
|
|
1342
|
+
return {
|
|
1343
|
+
async getIntent() { await deps.store.refresh?.(); return deps.store.getSessionReplacementIntent(); },
|
|
1344
|
+
hasSuccessorContinuity(intent) {
|
|
1345
|
+
return intent.continuity === "classic-chat" ||
|
|
1346
|
+
deps.store.getWorkspaceBindingByTarget(intent.target, sessionId)?.cwd === intent.cwd;
|
|
1347
|
+
},
|
|
1348
|
+
editSuccess(intent) { return deps.sendResult(intent.target, "<b>🆕 New session started.</b>"); },
|
|
1349
|
+
clearIntent(intent) { return deps.store.removeSessionReplacementIntent(intent, deps.ownsPersistence); },
|
|
1350
|
+
profileName: deps.getProfileName() ?? "default",
|
|
1351
|
+
cwd: ctx.cwd,
|
|
1352
|
+
sessionId,
|
|
1353
|
+
};
|
|
1354
|
+
},
|
|
1355
|
+
onResult(result) {
|
|
1356
|
+
if (result === "expired" || result === "failed") {
|
|
1357
|
+
report(new Error(`Telegram session replacement successor settlement ${result}.`));
|
|
1358
|
+
}
|
|
1359
|
+
},
|
|
1360
|
+
onError: report,
|
|
1361
|
+
});
|
|
1362
|
+
return { action, settlement };
|
|
1363
|
+
}
|
|
1364
|
+
export function createTelegramSessionActionRuntime(deps) {
|
|
1365
|
+
let pendingUpdateId;
|
|
1366
|
+
let pendingTarget;
|
|
1367
|
+
let commandPending = false;
|
|
1368
|
+
let commandUpdateId;
|
|
1369
|
+
let registered = false;
|
|
1370
|
+
const reportFailure = (error) => {
|
|
1371
|
+
try {
|
|
1372
|
+
deps.recordRuntimeEvent?.("new-session", error);
|
|
1373
|
+
}
|
|
1374
|
+
catch {
|
|
1375
|
+
// Diagnostics cannot make a completed durable update retryable.
|
|
1376
|
+
}
|
|
1377
|
+
};
|
|
1378
|
+
return {
|
|
1379
|
+
register() {
|
|
1380
|
+
if (registered)
|
|
1381
|
+
return;
|
|
1382
|
+
registered = true;
|
|
1383
|
+
deps.registerCommand(TELEGRAM_SESSION_ACTION_COMMAND_NAME, {
|
|
1384
|
+
description: TELEGRAM_SESSION_ACTION_COMMAND_DESCRIPTION,
|
|
1385
|
+
handler: async (_args, ctx) => {
|
|
1386
|
+
if (!commandPending)
|
|
1387
|
+
return;
|
|
1388
|
+
commandPending = false;
|
|
1389
|
+
const target = pendingTarget;
|
|
1390
|
+
const updateId = commandUpdateId;
|
|
1391
|
+
pendingTarget = undefined;
|
|
1392
|
+
commandUpdateId = undefined;
|
|
1393
|
+
if (!target || updateId === undefined)
|
|
1394
|
+
return;
|
|
1395
|
+
try {
|
|
1396
|
+
await deps.prepareReplacement?.(ctx, updateId, target);
|
|
1397
|
+
const result = await ctx.newSession();
|
|
1398
|
+
if (result.cancelled)
|
|
1399
|
+
await deps.notifyResult(target, "cancelled");
|
|
1400
|
+
}
|
|
1401
|
+
catch (error) {
|
|
1402
|
+
reportFailure(error);
|
|
1403
|
+
await deps.notifyResult(target, "failure");
|
|
1404
|
+
}
|
|
1405
|
+
},
|
|
1406
|
+
});
|
|
1407
|
+
},
|
|
1408
|
+
scheduleAfterUpdate(updateId, target) {
|
|
1409
|
+
if (pendingUpdateId !== undefined || commandPending)
|
|
1410
|
+
return false;
|
|
1411
|
+
pendingUpdateId = updateId;
|
|
1412
|
+
pendingTarget = { ...target };
|
|
1413
|
+
return true;
|
|
1414
|
+
},
|
|
1415
|
+
onUpdateCompleted(updateId) {
|
|
1416
|
+
if (pendingUpdateId !== updateId)
|
|
1417
|
+
return;
|
|
1418
|
+
pendingUpdateId = undefined;
|
|
1419
|
+
commandUpdateId = updateId;
|
|
1420
|
+
commandPending = true;
|
|
1421
|
+
void Promise.resolve()
|
|
1422
|
+
.then(() => deps.sendUserMessage(`/${TELEGRAM_SESSION_ACTION_COMMAND_NAME}`, {
|
|
1423
|
+
expandPromptTemplates: true,
|
|
1424
|
+
}))
|
|
1425
|
+
.catch((error) => {
|
|
1426
|
+
commandPending = false;
|
|
1427
|
+
commandUpdateId = undefined;
|
|
1428
|
+
pendingTarget = undefined;
|
|
1429
|
+
reportFailure(error);
|
|
1430
|
+
});
|
|
1431
|
+
},
|
|
1432
|
+
hasPending() {
|
|
1433
|
+
return pendingUpdateId !== undefined || commandPending;
|
|
1434
|
+
},
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
@@ -156,6 +156,8 @@ export declare function clearTelegramDeliveryRuntime(): void;
|
|
|
156
156
|
/** @internal */
|
|
157
157
|
export declare function isTelegramDeliveryHandleCurrent(handle: TelegramDeliveryHandle): boolean;
|
|
158
158
|
export declare function sendTelegramView(view: TelegramDeliveryView, options: SendTelegramViewOptions): Promise<TelegramDeliveryResult<TelegramDeliveryHandle>>;
|
|
159
|
+
/** @internal Edit an exact Telegram message through the currently bound runtime generation. */
|
|
160
|
+
export declare function editTelegramTargetView(target: TelegramDeliveryTarget, messageId: number, view: TelegramDeliveryView): Promise<TelegramDeliveryResult<TelegramDeliveryHandle>>;
|
|
159
161
|
export declare function editTelegramView(handle: TelegramDeliveryHandle, view: TelegramDeliveryView): Promise<TelegramDeliveryResult<TelegramDeliveryHandle>>;
|
|
160
162
|
export declare function deleteTelegramView(handle: TelegramDeliveryHandle): Promise<TelegramDeliveryResult<void>>;
|
|
161
163
|
export declare function sendTelegramChatAction(action: TelegramDeliveryChatAction, options: {
|
|
@@ -518,6 +518,17 @@ export async function sendTelegramView(view, options) {
|
|
|
518
518
|
return invalid;
|
|
519
519
|
return runDeliveryOperation((runtime) => runtime.sendView(view, options));
|
|
520
520
|
}
|
|
521
|
+
/** @internal Edit an exact Telegram message through the currently bound runtime generation. */
|
|
522
|
+
export async function editTelegramTargetView(target, messageId, view) {
|
|
523
|
+
const invalid = validateView(view);
|
|
524
|
+
if (invalid)
|
|
525
|
+
return invalid;
|
|
526
|
+
return runDeliveryOperation((runtime) => runtime.editView({
|
|
527
|
+
target: { ...target },
|
|
528
|
+
messageIds: [messageId],
|
|
529
|
+
generation: runtime.generation,
|
|
530
|
+
}, view));
|
|
531
|
+
}
|
|
521
532
|
export async function editTelegramView(handle, view) {
|
|
522
533
|
const invalid = validateView(view);
|
|
523
534
|
if (invalid)
|