@llblab/pi-telegram 0.51.5 → 0.52.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 +10 -8
- package/BACKLOG.md +1 -8
- package/CHANGELOG.md +23 -0
- package/LICENSE +21 -0
- package/README.md +16 -6
- package/dist/lib/activity-verbosity.d.ts +1 -5
- package/dist/lib/activity-verbosity.js +5 -7
- package/dist/lib/bindings.d.ts +9 -2
- package/dist/lib/bindings.js +22 -13
- package/dist/lib/bus-api.js +4 -2
- package/dist/lib/bus-follower.d.ts +55 -57
- package/dist/lib/bus-follower.js +213 -140
- package/dist/lib/bus-leader.d.ts +21 -2
- package/dist/lib/bus-leader.js +181 -25
- package/dist/lib/bus-transport.d.ts +4 -1
- package/dist/lib/bus-transport.js +28 -4
- package/dist/lib/bus.d.ts +52 -56
- package/dist/lib/bus.js +78 -246
- package/dist/lib/channel-posts.d.ts +1 -3
- package/dist/lib/channel-posts.js +23 -26
- package/dist/lib/command-templates.d.ts +0 -5
- package/dist/lib/command-templates.js +5 -5
- package/dist/lib/commands.d.ts +12 -26
- package/dist/lib/commands.js +152 -98
- package/dist/lib/config.d.ts +0 -17
- package/dist/lib/config.js +12 -14
- package/dist/lib/delivery.d.ts +0 -4
- package/dist/lib/delivery.js +2 -5
- package/dist/lib/extension.js +281 -61
- package/dist/lib/generative-apps.d.ts +0 -19
- package/dist/lib/inbound.d.ts +0 -2
- package/dist/lib/inbound.js +2 -2
- package/dist/lib/journal.d.ts +177 -16
- package/dist/lib/journal.js +1115 -249
- package/dist/lib/keyboard.d.ts +0 -2
- package/dist/lib/keyboard.js +2 -2
- package/dist/lib/lifecycle.d.ts +57 -2
- package/dist/lib/lifecycle.js +110 -5
- package/dist/lib/locks.d.ts +100 -12
- package/dist/lib/locks.js +380 -14
- package/dist/lib/logging.d.ts +30 -12
- package/dist/lib/logging.js +129 -72
- package/dist/lib/media.d.ts +28 -5
- package/dist/lib/media.js +26 -8
- package/dist/lib/menu-model.d.ts +0 -11
- package/dist/lib/menu-model.js +8 -8
- package/dist/lib/menu-settings.d.ts +0 -18
- package/dist/lib/menu-settings.js +18 -18
- package/dist/lib/menu-status.d.ts +4 -4
- package/dist/lib/menu-status.js +12 -7
- package/dist/lib/menu-thinking.d.ts +1 -1
- package/dist/lib/menu-thinking.js +1 -1
- package/dist/lib/menu.d.ts +1 -0
- package/dist/lib/menu.js +4 -3
- package/dist/lib/model.js +2 -4
- package/dist/lib/outbound-attachments.d.ts +0 -1
- package/dist/lib/outbound-attachments.js +1 -1
- package/dist/lib/outbound-buttons.js +1 -8
- package/dist/lib/outbound-markup.d.ts +1 -6
- package/dist/lib/outbound-markup.js +4 -21
- package/dist/lib/outbound.d.ts +0 -8
- package/dist/lib/outbound.js +5 -5
- package/dist/lib/paths.d.ts +50 -7
- package/dist/lib/paths.js +155 -17
- package/dist/lib/pi.d.ts +1 -0
- package/dist/lib/pi.js +2 -1
- package/dist/lib/polling.d.ts +0 -5
- package/dist/lib/polling.js +5 -5
- package/dist/lib/preview.d.ts +0 -3
- package/dist/lib/preview.js +3 -3
- package/dist/lib/prompt-templates.d.ts +0 -1
- package/dist/lib/prompt-templates.js +1 -1
- package/dist/lib/queue.d.ts +3 -15
- package/dist/lib/queue.js +69 -8
- package/dist/lib/recovery.d.ts +29 -9
- package/dist/lib/recovery.js +104 -33
- package/dist/lib/replies.d.ts +0 -4
- package/dist/lib/replies.js +1 -1
- package/dist/lib/routing.d.ts +73 -8
- package/dist/lib/routing.js +2206 -307
- package/dist/lib/sections.d.ts +0 -2
- package/dist/lib/sections.js +1 -1
- package/dist/lib/status.d.ts +46 -9
- package/dist/lib/status.js +179 -27
- package/dist/lib/sync.d.ts +0 -5
- package/dist/lib/sync.js +9 -8
- package/dist/lib/telegram-api.d.ts +11 -3
- package/dist/lib/telegram-api.js +34 -23
- package/dist/lib/thread-cleanup-manager.d.ts +1 -0
- package/dist/lib/thread-cleanup-manager.js +18 -21
- package/dist/lib/thread-naming.d.ts +32 -5
- package/dist/lib/thread-naming.js +191 -7
- package/dist/lib/thread-reconciler.d.ts +2 -0
- package/dist/lib/thread-reconciler.js +1 -1
- package/dist/lib/threads.d.ts +292 -59
- package/dist/lib/threads.js +1664 -373
- package/dist/lib/turns.d.ts +0 -1
- package/dist/lib/turns.js +1 -1
- package/dist/lib/updates.d.ts +184 -28
- package/dist/lib/updates.js +1032 -114
- package/dist/lib/wire.d.ts +12 -0
- package/dist/lib/wire.js +21 -0
- package/dist/lib/workspace-admission.d.ts +25 -17
- package/dist/lib/workspace-admission.js +95 -20
- package/dist/lib/workspace-identity.d.ts +20 -0
- package/dist/lib/workspace-identity.js +103 -0
- package/dist/lib/workspace-retirement.d.ts +45 -10
- package/dist/lib/workspace-retirement.js +196 -64
- package/dist/package.json +6 -6
- package/dist/skills/generated-control-surface/SKILL.md +3 -3
- package/dist/skills/telegram-bridge/references/diagnosis.md +3 -3
- package/docs/README.md +1 -1
- package/docs/activity.md +1 -1
- package/docs/architecture.md +158 -39
- package/docs/callback-namespaces.md +1 -1
- package/docs/delivery.md +1 -1
- package/docs/generative-apps.md +2 -2
- package/docs/inbound.md +1 -1
- package/docs/multi-instance-bus.md +127 -19
- package/docs/public-api.md +5 -3
- package/docs/ui-style.md +26 -8
- package/docs/updates.md +1 -1
- package/lib/activity-verbosity.ts +5 -9
- package/lib/bindings.ts +23 -10
- package/lib/bus-api.ts +5 -2
- package/lib/bus-follower.ts +251 -226
- package/lib/bus-leader.ts +178 -31
- package/lib/bus-transport.ts +30 -8
- package/lib/bus.ts +110 -334
- package/lib/channel-posts.ts +29 -29
- package/lib/command-templates.ts +5 -5
- package/lib/commands.ts +150 -112
- package/lib/config.ts +12 -17
- package/lib/delivery.ts +2 -8
- package/lib/extension.ts +282 -72
- package/lib/generative-apps.ts +0 -22
- package/lib/inbound.ts +2 -2
- package/lib/journal.ts +1182 -326
- package/lib/keyboard.ts +2 -2
- package/lib/lifecycle.ts +141 -5
- package/lib/locks.ts +402 -23
- package/lib/logging.ts +151 -101
- package/lib/media.ts +51 -9
- package/lib/menu-model.ts +8 -8
- package/lib/menu-settings.ts +18 -18
- package/lib/menu-status.ts +11 -0
- package/lib/menu-thinking.ts +2 -2
- package/lib/menu.ts +5 -1
- package/lib/model.ts +2 -4
- package/lib/outbound-attachments.ts +1 -1
- package/lib/outbound-buttons.ts +1 -10
- package/lib/outbound-markup.ts +5 -24
- package/lib/outbound.ts +5 -5
- package/lib/paths.ts +177 -17
- package/lib/pi.ts +5 -2
- package/lib/polling.ts +5 -5
- package/lib/preview.ts +3 -3
- package/lib/prompt-templates.ts +1 -1
- package/lib/queue.ts +67 -9
- package/lib/recovery.ts +104 -44
- package/lib/replies.ts +1 -1
- package/lib/routing.ts +1955 -375
- package/lib/sections.ts +1 -1
- package/lib/status.ts +185 -36
- package/lib/sync.ts +8 -8
- package/lib/telegram-api.ts +48 -33
- package/lib/thread-cleanup-manager.ts +24 -21
- package/lib/thread-naming.ts +267 -9
- package/lib/thread-reconciler.ts +3 -1
- package/lib/threads.ts +1718 -491
- package/lib/turns.ts +1 -1
- package/lib/updates.ts +1072 -151
- package/lib/wire.ts +28 -0
- package/lib/workspace-admission.ts +97 -47
- package/lib/workspace-identity.ts +147 -0
- package/lib/workspace-retirement.ts +234 -102
- package/package.json +6 -6
- package/scripts/audit-exports.mjs +100 -0
- package/scripts/check-downgrade.mjs +80 -43
- package/skills/generated-control-surface/SKILL.md +3 -3
- package/skills/telegram-bridge/references/diagnosis.md +3 -3
package/docs/ui-style.md
CHANGED
|
@@ -54,6 +54,7 @@ Use emoji as stable semantic markers, not decoration. Emoji carry transportable
|
|
|
54
54
|
| `🔁` | Replace/restore mode | Thread replace/restore chooser entrypoints | Opens a second step for moving a Pi instance binding to the current source thread. |
|
|
55
55
|
| `➡️` | Choose replacement target | Thread replace/restore target buttons that select which Pi instance should move to the current thread | Use inside the second replace/restore chooser, not for ordinary reroutes. |
|
|
56
56
|
| `☑️` | Activate / choose this item | Model detail activation action, generated button-only choice heading | Positive selection cue; use `🟢 Active` for already-current state. |
|
|
57
|
+
| `⛔️` | Cancel source routing | `⛔️ Cancel routing` chooser action and confirmed `⛔️ Routing cancelled.` feedback | Not an abort of active Pi work. Private retention remains mandatory; disposable-tab removal must be stated in the chooser and bound to exact eligible target authority. |
|
|
57
58
|
| `❌` | No / cancel / terminal failure | Confirmation cancel buttons and terminal failure notices | Do not use for a recoverable operation failure that leaves session state intact. |
|
|
58
59
|
| `🗑` | Delete / defer removal | Destructive confirmations and removal reaction | In the queue menu, reversible Keep/Skip selectors replace immediate deletion. |
|
|
59
60
|
|
|
@@ -70,7 +71,7 @@ Use emoji as stable semantic markers, not decoration. Emoji carry transportable
|
|
|
70
71
|
|
|
71
72
|
| Emoji | Meaning | Canonical surfaces | Notes |
|
|
72
73
|
| --- | --- | --- | --- |
|
|
73
|
-
| `🟢` | Current/active/enabled `On` | Current option in vertical lists, active state rows, active `On` toggle | One
|
|
74
|
+
| `🟢` | Current/active/enabled `On` | Current option in vertical lists, active state rows, active `On` toggle | One marker per selected list value; inactive list values stay unmarked. |
|
|
74
75
|
| `🟡` | Active `Off` or elevated/filter state | Active `Off` toggle, Priority/Scoped active tab | Yellow means intentionally not-normal or off/default-caution, not error. |
|
|
75
76
|
| `🔴` | Active destructive/deferred disposition | Active queue `Skip` selector | Red distinguishes a prompt that will be discarded at dispatch from reversible neutral or elevated state. |
|
|
76
77
|
| `🟣` | Normal/default active tab | Normal priority tab, All/default scope tab, active page picker | Use for neutral active tabs. |
|
|
@@ -109,6 +110,18 @@ Some emoji are intentionally local examples or decorative variants, not global s
|
|
|
109
110
|
|
|
110
111
|
Thread UI rule: when a message heading, chooser, or status line is specifically about Telegram/Pi threads or target thread selection, start the heading with `🧵`. Button labels for concrete thread targets should stay clean (`threadName` or slot fallback) and should not add `🧵` to every target button unless the row would otherwise be ambiguous.
|
|
111
112
|
|
|
113
|
+
## Button Control Hierarchy
|
|
114
|
+
|
|
115
|
+
All inline controls are buttons at the transport level. The local UI kit gives them three visual roles:
|
|
116
|
+
|
|
117
|
+
- **Action button:** Performs an action or navigation, using its semantic emoji and Capitalized action text.
|
|
118
|
+
- **List-item button:** Represents a value in a collection. Use lowercase value labels; only selected values carry a state-circle emoji, while unselected values have no emoji. A list may support single or multiple selection.
|
|
119
|
+
- **Radio-style button:** Represents a labelled state choice. Use Capitalized labels and an indicator on every value: a semantic colored circle for active values, `⚫️` for inactive values. A radio group normally selects one value; checkbox-like binary controls and tabs reuse this same visual family rather than introducing separate label grammars.
|
|
120
|
+
|
|
121
|
+
Selection cardinality belongs to the control's domain, not to the visual family. Independent checkbox dimensions or tab groups may each have an active value. Do not confuse list and radio-style controls merely because both can select one item. Canonical names, identifiers and numeric/spatial tokens keep their own spelling; casing rules apply to authored value words.
|
|
122
|
+
|
|
123
|
+
These are button-based visual grammars, not claims that Telegram exposes native list, radio, checkbox or tab widgets. Selection markers project actual state; they never grant callback, mutation or routing authority. The specialized rules below define each reuse.
|
|
124
|
+
|
|
112
125
|
## Action Buttons
|
|
113
126
|
|
|
114
127
|
Action buttons perform an operation.
|
|
@@ -143,7 +156,7 @@ Examples:
|
|
|
143
156
|
|
|
144
157
|
## Boolean Toggles
|
|
145
158
|
|
|
146
|
-
Boolean settings
|
|
159
|
+
Boolean settings are checkbox-like binary controls rendered with the radio-style grammar as a horizontal `On` / `Off` pair.
|
|
147
160
|
|
|
148
161
|
Rules:
|
|
149
162
|
|
|
@@ -161,7 +174,7 @@ Examples:
|
|
|
161
174
|
|
|
162
175
|
## Horizontal Tabs
|
|
163
176
|
|
|
164
|
-
Tabs or small mutually-exclusive scopes
|
|
177
|
+
Tabs or small mutually-exclusive scopes reuse the radio-style grammar in a horizontal row.
|
|
165
178
|
|
|
166
179
|
Rules:
|
|
167
180
|
|
|
@@ -177,25 +190,25 @@ Examples:
|
|
|
177
190
|
|
|
178
191
|
- `🟡 Scoped` / `⚫️ All`
|
|
179
192
|
- `⚫️ Priority` / `🟣 Normal`
|
|
180
|
-
- `1` / `🟣 2` / `3`
|
|
181
193
|
|
|
182
194
|
## Option Lists
|
|
183
195
|
|
|
184
|
-
Option lists
|
|
196
|
+
Option lists represent values from a collection and may allow single or multiple selection. Current model selection, thinking level, voice reply mode and time injection mode are single-choice examples.
|
|
185
197
|
|
|
186
198
|
Rules:
|
|
187
199
|
|
|
188
200
|
- Put each option on its own row when labels are long, the set may grow, or scanning benefits from full width.
|
|
189
201
|
- A fixed set of short, ordered peer values may use compact rows of up to three buttons.
|
|
190
202
|
- Keep a semantically distinct value such as thinking `off` on its own full-width row before grouped intensity values.
|
|
191
|
-
- Mark only the
|
|
192
|
-
- Leave
|
|
193
|
-
- Use lowercase labels
|
|
203
|
+
- Mark only selected values with the appropriate state circle (`🟢` by default); a multi-select list marks each selected value.
|
|
204
|
+
- Leave unselected values without emoji, never with the radio family's `⚫️` placeholder.
|
|
205
|
+
- Use lowercase authored value labels; preserve canonical names, identifiers and numeric/spatial tokens.
|
|
194
206
|
|
|
195
207
|
Examples:
|
|
196
208
|
|
|
197
209
|
- Vertical: `hidden`, `🟢 mirror`, `always`.
|
|
198
210
|
- Thinking: full-width `off`, then `minimal` / `low` / `🟢 medium`, then `high` / `xhigh` / `max`.
|
|
211
|
+
- Numeric page picker (list grammar, not radio-style tabs): `1` / `🟣 2` / `3`.
|
|
199
212
|
|
|
200
213
|
## Generated Prompt Buttons
|
|
201
214
|
|
|
@@ -211,6 +224,7 @@ Rules:
|
|
|
211
224
|
- First-level submenus opened from the main inline menu start with `⬆️ Main menu`.
|
|
212
225
|
- Deeper submenus start with `⬆️ Back`.
|
|
213
226
|
- `Main menu` returns to the root inline menu.
|
|
227
|
+
- Choosing a Thinking level refreshes the same chooser and its current marker without leaving the submenu; only the top `Main menu` button returns to the root.
|
|
214
228
|
- `Back` returns one level up, never directly to the root unless the parent is the root.
|
|
215
229
|
|
|
216
230
|
Examples:
|
|
@@ -218,6 +232,10 @@ Examples:
|
|
|
218
232
|
- Main menu → Settings: first row is `⬆️ Main menu`.
|
|
219
233
|
- Settings → Voice reply mode: first row is `⬆️ Back`.
|
|
220
234
|
|
|
235
|
+
## Pi Connection Notices
|
|
236
|
+
|
|
237
|
+
Pi TUI connection notices use plain text: a short known cause and one recovery action. Unknown failures use a generic connection-failed notice with `/telegram-status --debug`; never interpolate raw exceptions, credentials, stack traces or Pi lifecycle guidance. Technical evidence belongs in the redacted runtime recorder. Failed disconnect must retain the instruction to keep Pi open; do not also rethrow the same error as a second Pi banner. These TUI notices are distinct from Telegram bot message cards below.
|
|
238
|
+
|
|
221
239
|
## Message Cards
|
|
222
240
|
|
|
223
241
|
Message cards and standalone informational notices sent by the bot should start with a strong heading.
|
package/docs/updates.md
CHANGED
|
@@ -156,7 +156,7 @@ This means:
|
|
|
156
156
|
|
|
157
157
|
## Ownership semantics
|
|
158
158
|
|
|
159
|
-
The handler registry is ownership-agnostic and does not interact with the extension-local transport owner slots documented in [Architecture](./architecture.md#configuration-and-ownership). When the polling runtime loses its
|
|
159
|
+
The handler registry is ownership-agnostic and does not interact with the extension-local transport owner slots documented in [Architecture](./architecture.md#configuration-and-ownership). When the polling runtime loses its transport ownership and stops `getUpdates`, handlers stop receiving updates because no updates are being fetched; they are not unregistered.
|
|
160
160
|
|
|
161
161
|
If a layered extension needs to react to ownership changes, it should observe `pi-telegram` lifecycle events through the standard pi extension hooks rather than through the handler registry.
|
|
162
162
|
|
|
@@ -17,16 +17,16 @@ import type {
|
|
|
17
17
|
TelegramSendRichMessageBody,
|
|
18
18
|
TelegramSentMessage,
|
|
19
19
|
} from "./telegram-api.ts";
|
|
20
|
-
import type
|
|
20
|
+
import { areTelegramTargetsEqual as targetEquals, type TelegramTarget } from "./target.ts";
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const TELEGRAM_ACTIVITY_DETAIL_MAX_CHARS = 1_200;
|
|
23
|
+
const TELEGRAM_ACTIVITY_MESSAGE_MAX_CHARS = 3_900;
|
|
24
24
|
export const TELEGRAM_ACTIVITY_MESSAGE_MAX_TOOLS = 6;
|
|
25
|
-
|
|
25
|
+
const TELEGRAM_REASONING_MESSAGE_MAX_FRAMES = 24;
|
|
26
26
|
export const TELEGRAM_REASONING_BUFFER_MAX_CHARS = 1_200;
|
|
27
27
|
// Match native answer drafts: accumulate the opening frame for one full
|
|
28
28
|
// interval, then publish at most one updated frame per interval.
|
|
29
|
-
|
|
29
|
+
const TELEGRAM_REASONING_MIN_INTERVAL_MS = 2_000;
|
|
30
30
|
export const TELEGRAM_TOOL_UPDATE_MAX_ENTRIES = 4;
|
|
31
31
|
|
|
32
32
|
interface ToolActivity {
|
|
@@ -52,10 +52,6 @@ interface ReasoningMessage {
|
|
|
52
52
|
target: TelegramTarget;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
function targetEquals(left: TelegramTarget, right: TelegramTarget): boolean {
|
|
56
|
-
return left.chatId === right.chatId && left.threadId === right.threadId;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
55
|
function redactActivityText(text: string): string {
|
|
60
56
|
return text
|
|
61
57
|
.replace(/\b\d{8,12}:[A-Za-z0-9_-]{30,}\b/g, "[REDACTED_BOT_TOKEN]")
|
package/lib/bindings.ts
CHANGED
|
@@ -602,6 +602,9 @@ interface TelegramCommandsAndToolsBindingDeps {
|
|
|
602
602
|
| undefined,
|
|
603
603
|
) => void;
|
|
604
604
|
updateStatus: TelegramBridgeStatusUpdater;
|
|
605
|
+
isContextCurrent: (ctx: Pi.ExtensionContext) => boolean;
|
|
606
|
+
getSessionGeneration: () => number;
|
|
607
|
+
connectionIntent: NonNullable<Commands.TelegramBridgeCommandRegistrationDeps["connectionIntent"]>;
|
|
605
608
|
recordRuntimeEvent: TelegramRuntimeEventRecorder;
|
|
606
609
|
}
|
|
607
610
|
|
|
@@ -633,6 +636,9 @@ export function registerTelegramCommandsAndTools({
|
|
|
633
636
|
setGenerativeAppLiveSurfaceRuntime,
|
|
634
637
|
recordRuntimeEvent,
|
|
635
638
|
updateStatus,
|
|
639
|
+
isContextCurrent,
|
|
640
|
+
getSessionGeneration,
|
|
641
|
+
connectionIntent,
|
|
636
642
|
}: TelegramCommandsAndToolsBindingDeps): void {
|
|
637
643
|
GenerativeApps.registerTelegramBindTool(pi, {
|
|
638
644
|
agentDir,
|
|
@@ -783,38 +789,39 @@ export function registerTelegramCommandsAndTools({
|
|
|
783
789
|
reloadConfig: configStore.load,
|
|
784
790
|
hasBotToken: configStore.hasBotToken,
|
|
785
791
|
getBotTokenDiagnostic: configStore.getBotTokenDiagnostic,
|
|
786
|
-
startPolling:
|
|
787
|
-
|
|
788
|
-
return await lockedPollingRuntime.start(ctx, options);
|
|
789
|
-
} catch (error) {
|
|
790
|
-
recordRuntimeEvent("recovery", error, { phase: "polling-start" });
|
|
791
|
-
throw error;
|
|
792
|
-
}
|
|
793
|
-
},
|
|
792
|
+
startPolling: lockedPollingRuntime.start,
|
|
793
|
+
recordConnectionEvent: (error, phase) => recordRuntimeEvent("connection", error, { phase }),
|
|
794
794
|
stopPolling: stopPolling ?? lockedPollingRuntime.stop,
|
|
795
795
|
recoverPollingStart,
|
|
796
796
|
getDisconnectThreadName,
|
|
797
797
|
queueAgentConnectionContext,
|
|
798
798
|
updateStatus,
|
|
799
|
+
isContextCurrent,
|
|
800
|
+
getSessionGeneration,
|
|
801
|
+
connectionIntent,
|
|
799
802
|
getProfileNames: () =>
|
|
800
803
|
Config.getTelegramProfileNames(configStore.getStoredConfig()),
|
|
801
|
-
activateDefaultProfileConfig: async () => {
|
|
804
|
+
activateDefaultProfileConfig: async (_ctx, isCurrent) => {
|
|
802
805
|
const previousProfileName = configStore.getActiveProfileName();
|
|
803
806
|
await configStore.load();
|
|
807
|
+
if (!isCurrent()) return;
|
|
804
808
|
if (previousProfileName) {
|
|
805
809
|
await (stopPolling ?? lockedPollingRuntime.stop)();
|
|
810
|
+
if (!isCurrent()) return;
|
|
806
811
|
}
|
|
807
812
|
configStore.activateProfile(undefined);
|
|
808
813
|
await onTransportChanged?.();
|
|
809
814
|
},
|
|
810
|
-
activateProfileConfig: async (_ctx, profileName) => {
|
|
815
|
+
activateProfileConfig: async (_ctx, profileName, isCurrent) => {
|
|
811
816
|
const previousProfileName = configStore.getActiveProfileName();
|
|
812
817
|
await configStore.load();
|
|
818
|
+
if (!isCurrent()) return false;
|
|
813
819
|
if (!Config.isValidTelegramProfileName(profileName)) return false;
|
|
814
820
|
const storedConfig = configStore.getStoredConfig();
|
|
815
821
|
if (!storedConfig.profiles?.[profileName]) return false;
|
|
816
822
|
if (previousProfileName !== profileName) {
|
|
817
823
|
await (stopPolling ?? lockedPollingRuntime.stop)();
|
|
824
|
+
if (!isCurrent()) return false;
|
|
818
825
|
}
|
|
819
826
|
if (!configStore.activateProfile(profileName)) return false;
|
|
820
827
|
await onTransportChanged?.();
|
|
@@ -828,6 +835,7 @@ interface TelegramLifecycleBindingDeps {
|
|
|
828
835
|
publicationRuntime: TelegramBridgePublicationRuntime;
|
|
829
836
|
activityRuntime: Activity.TelegramActivityRuntime;
|
|
830
837
|
activityVerbosityRuntime?: ActivityVerbosity.TelegramActivityVerbosityRuntime;
|
|
838
|
+
diagnostics?: { onSessionStart(): void; onSessionShutdown(): Promise<void> };
|
|
831
839
|
assistantOutputRuntime: Pick<
|
|
832
840
|
Activity.TelegramAssistantOutputRuntime,
|
|
833
841
|
"start" | "beginTurn" | "hasAdmittedTelegramIntermediate" | "waitForIdle" | "stop"
|
|
@@ -934,6 +942,7 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
934
942
|
publicationRuntime,
|
|
935
943
|
activityRuntime,
|
|
936
944
|
activityVerbosityRuntime,
|
|
945
|
+
diagnostics,
|
|
937
946
|
assistantOutputRuntime,
|
|
938
947
|
sessionLifecycleRuntime,
|
|
939
948
|
configStore,
|
|
@@ -1271,6 +1280,7 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
1271
1280
|
activityRuntime.recordInputSource(event.source ?? "unknown");
|
|
1272
1281
|
},
|
|
1273
1282
|
async onSessionStart(event, ctx) {
|
|
1283
|
+
diagnostics?.onSessionStart();
|
|
1274
1284
|
cancelPendingFinalPublication();
|
|
1275
1285
|
previewRuntime.invalidate();
|
|
1276
1286
|
assistantOutputRuntime.start();
|
|
@@ -1282,6 +1292,7 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
1282
1292
|
},
|
|
1283
1293
|
async onSessionShutdown(event, ctx) {
|
|
1284
1294
|
if (!isSessionContextActive(ctx)) return;
|
|
1295
|
+
const diagnosticsStopped = diagnostics?.onSessionShutdown();
|
|
1285
1296
|
shutdownGenerativeAppLiveSurfaces?.();
|
|
1286
1297
|
agentLifecycleHooks.clearRetainedAgentEnd();
|
|
1287
1298
|
activityRuntime.onSessionShutdown();
|
|
@@ -1292,6 +1303,8 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
1292
1303
|
cancelPendingFinalPublication();
|
|
1293
1304
|
uiPromptActive = false;
|
|
1294
1305
|
compactionObserver.onSessionShutdown();
|
|
1306
|
+
await diagnosticsStopped;
|
|
1307
|
+
if (!isSessionContextActive(ctx)) return;
|
|
1295
1308
|
if (event.reason === "quit" && disconnectOnQuit) {
|
|
1296
1309
|
try {
|
|
1297
1310
|
const automaticCleanupEnabled =
|
package/lib/bus-api.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
buildTelegramAnswerGuestQueryBody,
|
|
13
13
|
isTelegramMessageNotModifiedError,
|
|
14
14
|
} from "./telegram-api.ts";
|
|
15
|
+
import type { TelegramAttachmentSource } from "./media.ts";
|
|
15
16
|
import type {
|
|
16
17
|
TelegramAnswerGuestQueryOptions,
|
|
17
18
|
TelegramApiCallOptions,
|
|
@@ -125,12 +126,14 @@ export function createTelegramBusAwareApiRuntime(
|
|
|
125
126
|
options,
|
|
126
127
|
]) as Promise<TResponse>);
|
|
127
128
|
},
|
|
128
|
-
downloadFile(fileId: string, suggestedName: string): Promise<string> {
|
|
129
|
+
downloadFile(fileId: string, suggestedName: string, source?: TelegramAttachmentSource): Promise<string> {
|
|
130
|
+
// The source names the file (kind-scope-message); dropping it falls back to the bare generated name.
|
|
129
131
|
return deps.ownsDirect()
|
|
130
|
-
? deps.directRuntime.downloadFile(fileId, suggestedName)
|
|
132
|
+
? deps.directRuntime.downloadFile(fileId, suggestedName, source)
|
|
131
133
|
: (deps.callFollowerApi("downloadFile", [
|
|
132
134
|
fileId,
|
|
133
135
|
suggestedName,
|
|
136
|
+
...(source ? [source] : []),
|
|
134
137
|
]) as Promise<string>);
|
|
135
138
|
},
|
|
136
139
|
deleteWebhook(signal?: AbortSignal): Promise<boolean> {
|