@llblab/pi-telegram 0.46.0 → 0.48.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 +4 -2
- package/BACKLOG.md +0 -6
- package/CHANGELOG.md +14 -0
- package/README.md +5 -2
- package/dist/api/activity.d.ts +6 -0
- package/dist/api/activity.js +6 -0
- package/dist/api/commands.d.ts +6 -0
- package/dist/api/commands.js +6 -0
- package/dist/api/delivery.d.ts +6 -0
- package/dist/api/delivery.js +6 -0
- package/dist/api/inbound.d.ts +6 -0
- package/dist/api/inbound.js +6 -0
- package/dist/api/keyboard.d.ts +6 -0
- package/dist/api/keyboard.js +6 -0
- package/dist/api/outbound.d.ts +6 -0
- package/dist/api/outbound.js +6 -0
- package/dist/api/sections.d.ts +7 -0
- package/dist/api/sections.js +6 -0
- package/dist/api/status.d.ts +6 -0
- package/dist/api/status.js +6 -0
- package/dist/api/updates.d.ts +6 -0
- package/dist/api/updates.js +6 -0
- package/dist/api/voice.d.ts +6 -0
- package/dist/api/voice.js +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/lib/activity-verbosity.d.ts +52 -0
- package/dist/lib/activity-verbosity.js +596 -0
- package/dist/lib/activity.d.ts +220 -0
- package/dist/lib/activity.js +574 -0
- package/dist/lib/agent-messages.d.ts +28 -0
- package/dist/lib/agent-messages.js +86 -0
- package/dist/lib/bindings.d.ts +250 -0
- package/dist/lib/bindings.js +936 -0
- package/dist/lib/bus-api.d.ts +18 -0
- package/dist/lib/bus-api.js +254 -0
- package/dist/lib/bus-follower.d.ts +464 -0
- package/dist/lib/bus-follower.js +1686 -0
- package/dist/lib/bus-leader.d.ts +292 -0
- package/dist/lib/bus-leader.js +2242 -0
- package/dist/lib/bus-transport.d.ts +64 -0
- package/dist/lib/bus-transport.js +140 -0
- package/dist/lib/bus.d.ts +518 -0
- package/dist/lib/bus.js +2055 -0
- package/dist/lib/channel-posts.d.ts +170 -0
- package/dist/lib/channel-posts.js +611 -0
- package/dist/lib/command-templates.d.ts +70 -0
- package/dist/lib/command-templates.js +744 -0
- package/dist/lib/commands.d.ts +541 -0
- package/dist/lib/commands.js +1155 -0
- package/dist/lib/config.d.ts +252 -0
- package/dist/lib/config.js +889 -0
- package/dist/lib/delivery.d.ts +163 -0
- package/dist/lib/delivery.js +542 -0
- package/dist/lib/extension.d.ts +7 -0
- package/dist/lib/extension.js +1604 -0
- package/dist/lib/generative-app-worker.mjs +104 -0
- package/dist/lib/generative-apps.d.ts +212 -0
- package/dist/lib/generative-apps.js +1006 -0
- package/dist/lib/inbound.d.ts +91 -0
- package/dist/lib/inbound.js +502 -0
- package/dist/lib/journal.d.ts +665 -0
- package/dist/lib/journal.js +3701 -0
- package/dist/lib/keyboard.d.ts +23 -0
- package/dist/lib/keyboard.js +37 -0
- package/dist/lib/lifecycle.d.ts +157 -0
- package/dist/lib/lifecycle.js +395 -0
- package/dist/lib/locks.d.ts +164 -0
- package/dist/lib/locks.js +1208 -0
- package/dist/lib/logging.d.ts +50 -0
- package/dist/lib/logging.js +274 -0
- package/dist/lib/media.d.ts +181 -0
- package/dist/lib/media.js +602 -0
- package/dist/lib/menu-model.d.ts +217 -0
- package/dist/lib/menu-model.js +663 -0
- package/dist/lib/menu-queue.d.ts +37 -0
- package/dist/lib/menu-queue.js +408 -0
- package/dist/lib/menu-settings.d.ts +115 -0
- package/dist/lib/menu-settings.js +595 -0
- package/dist/lib/menu-status.d.ts +32 -0
- package/dist/lib/menu-status.js +112 -0
- package/dist/lib/menu-thinking.d.ts +29 -0
- package/dist/lib/menu-thinking.js +82 -0
- package/dist/lib/menu.d.ts +171 -0
- package/dist/lib/menu.js +323 -0
- package/dist/lib/model.d.ts +127 -0
- package/dist/lib/model.js +409 -0
- package/dist/lib/outbound-attachments.d.ts +241 -0
- package/dist/lib/outbound-attachments.js +639 -0
- package/dist/lib/outbound-buttons.d.ts +69 -0
- package/dist/lib/outbound-buttons.js +248 -0
- package/dist/lib/outbound-markup.d.ts +42 -0
- package/dist/lib/outbound-markup.js +678 -0
- package/dist/lib/outbound-voice.d.ts +55 -0
- package/dist/lib/outbound-voice.js +152 -0
- package/dist/lib/outbound.d.ts +185 -0
- package/dist/lib/outbound.js +516 -0
- package/dist/lib/ownership.d.ts +77 -0
- package/dist/lib/ownership.js +174 -0
- package/dist/lib/paths.d.ts +40 -0
- package/dist/lib/paths.js +94 -0
- package/dist/lib/pi.d.ts +72 -0
- package/dist/lib/pi.js +121 -0
- package/dist/lib/polling.d.ts +351 -0
- package/dist/lib/polling.js +1196 -0
- package/dist/lib/preview.d.ts +192 -0
- package/dist/lib/preview.js +614 -0
- package/dist/lib/prompt-templates.d.ts +24 -0
- package/dist/lib/prompt-templates.js +118 -0
- package/dist/lib/prompts.d.ts +57 -0
- package/dist/lib/prompts.js +167 -0
- package/dist/lib/queue.d.ts +766 -0
- package/dist/lib/queue.js +1965 -0
- package/dist/lib/recovery.d.ts +86 -0
- package/dist/lib/recovery.js +285 -0
- package/dist/lib/rendering.d.ts +20 -0
- package/dist/lib/rendering.js +983 -0
- package/dist/lib/replies.d.ts +214 -0
- package/dist/lib/replies.js +737 -0
- package/dist/lib/routing.d.ts +207 -0
- package/dist/lib/routing.js +2282 -0
- package/dist/lib/runtime.d.ts +172 -0
- package/dist/lib/runtime.js +402 -0
- package/dist/lib/sections.d.ts +165 -0
- package/dist/lib/sections.js +327 -0
- package/dist/lib/setup.d.ts +82 -0
- package/dist/lib/setup.js +150 -0
- package/dist/lib/skills.d.ts +8 -0
- package/dist/lib/skills.js +12 -0
- package/dist/lib/status.d.ts +442 -0
- package/dist/lib/status.js +1008 -0
- package/dist/lib/sync.d.ts +179 -0
- package/dist/lib/sync.js +782 -0
- package/dist/lib/target.d.ts +20 -0
- package/dist/lib/target.js +27 -0
- package/dist/lib/telegram-api.d.ts +541 -0
- package/dist/lib/telegram-api.js +1159 -0
- package/dist/lib/text-groups.d.ts +89 -0
- package/dist/lib/text-groups.js +317 -0
- package/dist/lib/thread-cleanup-manager.d.ts +288 -0
- package/dist/lib/thread-cleanup-manager.js +560 -0
- package/dist/lib/thread-display.d.ts +46 -0
- package/dist/lib/thread-display.js +257 -0
- package/dist/lib/thread-naming.d.ts +46 -0
- package/dist/lib/thread-naming.js +78 -0
- package/dist/lib/thread-reconciler.d.ts +239 -0
- package/dist/lib/thread-reconciler.js +644 -0
- package/dist/lib/threads.d.ts +621 -0
- package/dist/lib/threads.js +3679 -0
- package/dist/lib/time-injection.d.ts +15 -0
- package/dist/lib/time-injection.js +56 -0
- package/dist/lib/turns.d.ts +109 -0
- package/dist/lib/turns.js +500 -0
- package/dist/lib/updates.d.ts +1290 -0
- package/dist/lib/updates.js +3634 -0
- package/dist/lib/voice.d.ts +117 -0
- package/dist/lib/voice.js +174 -0
- package/dist/lib/workspace-admission.d.ts +264 -0
- package/dist/lib/workspace-admission.js +1136 -0
- package/dist/lib/workspace-retirement.d.ts +219 -0
- package/dist/lib/workspace-retirement.js +587 -0
- package/dist/lib/workspace-slots.d.ts +30 -0
- package/dist/lib/workspace-slots.js +54 -0
- package/dist/package.json +126 -0
- package/dist/pi-telegram/index.js +1 -0
- package/dist/skills/generated-control-surface/SKILL.md +107 -0
- package/dist/skills/generated-control-surface/references/capability-adapters.md +27 -0
- package/dist/skills/generated-control-surface/references/layout-and-state.md +37 -0
- package/dist/skills/generative-apps/SKILL.md +115 -0
- package/dist/skills/show-me/SKILL.md +166 -0
- package/dist/skills/show-me/references/telegram-surfaces.md +43 -0
- package/dist/skills/telegram-bridge/SKILL.md +129 -0
- package/dist/skills/telegram-bridge/references/configuration.md +15 -0
- package/dist/skills/telegram-bridge/references/delivery-and-threads.md +27 -0
- package/dist/skills/telegram-bridge/references/diagnosis.md +18 -0
- package/docs/README.md +2 -0
- package/docs/architecture.md +1 -1
- package/docs/compact-matrix-literal.md +10 -3
- package/docs/generative-apps.md +15 -13
- package/docs/multi-instance-bus.md +6 -4
- package/docs/outbound.md +1 -1
- package/docs/public-api.md +3 -3
- package/lib/bindings.ts +89 -6
- package/lib/bus-follower.ts +7 -3
- package/lib/bus-leader.ts +44 -19
- package/lib/bus.ts +4 -1
- package/lib/commands.ts +2 -2
- package/lib/config.ts +14 -7
- package/lib/delivery.ts +38 -6
- package/lib/extension.ts +7 -0
- package/lib/generative-apps.ts +379 -13
- package/lib/menu-settings.ts +20 -6
- package/lib/outbound-markup.ts +16 -7
- package/lib/status.ts +15 -12
- package/lib/telegram-api.ts +12 -1
- package/lib/thread-display.ts +96 -18
- package/package.json +56 -13
- package/scripts/build-dist.mjs +44 -0
- package/scripts/measure-bus.mjs +8 -1
- package/scripts/measure-workspace.mjs +8 -1
- package/skills/generative-apps/SKILL.md +1 -1
- package/skills/show-me/SKILL.md +1 -1
- package/skills/show-me/references/telegram-surfaces.md +1 -1
- package/skills/telegram-bridge/SKILL.md +1 -1
package/lib/bindings.ts
CHANGED
|
@@ -10,6 +10,7 @@ import * as ChannelPosts from "./channel-posts.ts";
|
|
|
10
10
|
import * as CommandTemplates from "./command-templates.ts";
|
|
11
11
|
import * as Commands from "./commands.ts";
|
|
12
12
|
import * as Config from "./config.ts";
|
|
13
|
+
import * as Delivery from "./delivery.ts";
|
|
13
14
|
import * as Keyboard from "./keyboard.ts";
|
|
14
15
|
import * as Lifecycle from "./lifecycle.ts";
|
|
15
16
|
import * as Locks from "./locks.ts";
|
|
@@ -176,14 +177,47 @@ export function createTelegramQueueBindingRuntime<TContext>(deps: {
|
|
|
176
177
|
};
|
|
177
178
|
}
|
|
178
179
|
|
|
180
|
+
export interface TelegramGenerativeAppLiveSurfaceBinding {
|
|
181
|
+
get: () =>
|
|
182
|
+
| GenerativeApps.GenerativeAppLiveSurfaceRuntime<GenerativeApps.TelegramBindLiveHandle>
|
|
183
|
+
| undefined;
|
|
184
|
+
set: (
|
|
185
|
+
runtime: GenerativeApps.GenerativeAppLiveSurfaceRuntime<GenerativeApps.TelegramBindLiveHandle>
|
|
186
|
+
| undefined,
|
|
187
|
+
) => void;
|
|
188
|
+
shutdown: () => void;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function createTelegramGenerativeAppLiveSurfaceBinding():
|
|
192
|
+
TelegramGenerativeAppLiveSurfaceBinding {
|
|
193
|
+
let current:
|
|
194
|
+
| GenerativeApps.GenerativeAppLiveSurfaceRuntime<GenerativeApps.TelegramBindLiveHandle>
|
|
195
|
+
| undefined;
|
|
196
|
+
return {
|
|
197
|
+
get() { return current; },
|
|
198
|
+
set(runtime) {
|
|
199
|
+
current?.shutdown();
|
|
200
|
+
current = runtime;
|
|
201
|
+
},
|
|
202
|
+
shutdown() {
|
|
203
|
+
current?.shutdown();
|
|
204
|
+
current = undefined;
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
179
209
|
export function createTelegramGenerativeAppBoundButtonActionInvoker<
|
|
180
210
|
TQuery extends {
|
|
181
|
-
message?: { chat?: { id?: number }; message_id?: number };
|
|
211
|
+
message?: { chat?: { id?: number }; message_id?: number; message_thread_id?: number };
|
|
182
212
|
},
|
|
183
213
|
>(deps: {
|
|
184
214
|
agentDir: string;
|
|
185
215
|
assertExecutionCurrent: (query: TQuery) => void;
|
|
186
216
|
getExecutionFence: (query: TQuery) => GenerativeApps.GenerativeAppExecutionFence | undefined;
|
|
217
|
+
getActiveProfileName?: () => string | undefined;
|
|
218
|
+
getLiveSurfaceRuntime?: () =>
|
|
219
|
+
| GenerativeApps.GenerativeAppLiveSurfaceRuntime<GenerativeApps.TelegramBindLiveHandle>
|
|
220
|
+
| undefined;
|
|
187
221
|
planOutput: ReturnType<typeof OutboundHandlers.createTelegramOutboundReplyPlanner>;
|
|
188
222
|
sendMarkdownReply: (
|
|
189
223
|
chatId: number,
|
|
@@ -205,10 +239,29 @@ export function createTelegramGenerativeAppBoundButtonActionInvoker<
|
|
|
205
239
|
) => Promise<false | "new" | "edit"> {
|
|
206
240
|
return async (action, query) => {
|
|
207
241
|
let boundAction: GenerativeApps.GenerativeAppBoundAction | undefined;
|
|
242
|
+
let handedOff:
|
|
243
|
+
| GenerativeApps.GenerativeAppLiveSurface<GenerativeApps.TelegramBindLiveHandle>
|
|
244
|
+
| undefined;
|
|
208
245
|
try {
|
|
209
246
|
boundAction = GenerativeApps.parseGenerativeAppBoundAction(action.prompt);
|
|
210
247
|
if (!boundAction) return false;
|
|
211
248
|
deps.assertExecutionCurrent(query);
|
|
249
|
+
const chatId = query.message?.chat?.id;
|
|
250
|
+
const messageId = query.message?.message_id;
|
|
251
|
+
if (typeof chatId !== "number" || typeof messageId !== "number") {
|
|
252
|
+
throw new Error("Generative App callback target is unavailable.");
|
|
253
|
+
}
|
|
254
|
+
const liveSurfaces = deps.getLiveSurfaceRuntime?.();
|
|
255
|
+
handedOff = liveSurfaces?.take(GenerativeApps.getTelegramBindLiveSurfaceKey(
|
|
256
|
+
boundAction.app,
|
|
257
|
+
deps.getActiveProfileName?.() ?? "default",
|
|
258
|
+
{
|
|
259
|
+
chatId,
|
|
260
|
+
...(query.message?.message_thread_id !== undefined
|
|
261
|
+
? { threadId: query.message.message_thread_id }
|
|
262
|
+
: {}),
|
|
263
|
+
},
|
|
264
|
+
));
|
|
212
265
|
const result = await GenerativeApps.invokeGenerativeApp({
|
|
213
266
|
agentDir: deps.agentDir,
|
|
214
267
|
...(deps.getExecutionFence(query)
|
|
@@ -227,11 +280,6 @@ export function createTelegramGenerativeAppBoundButtonActionInvoker<
|
|
|
227
280
|
app: boundAction.app,
|
|
228
281
|
});
|
|
229
282
|
deps.assertExecutionCurrent(query);
|
|
230
|
-
const chatId = query.message?.chat?.id;
|
|
231
|
-
const messageId = query.message?.message_id;
|
|
232
|
-
if (typeof chatId !== "number" || typeof messageId !== "number") {
|
|
233
|
-
throw new Error("Generative App callback target is unavailable.");
|
|
234
|
-
}
|
|
235
283
|
const reply = deps.planOutput(result.output, {
|
|
236
284
|
binding: {
|
|
237
285
|
generation: result.generation,
|
|
@@ -239,6 +287,19 @@ export function createTelegramGenerativeAppBoundButtonActionInvoker<
|
|
|
239
287
|
revision: result.revision,
|
|
240
288
|
},
|
|
241
289
|
});
|
|
290
|
+
if (handedOff && liveSurfaces) {
|
|
291
|
+
try {
|
|
292
|
+
await liveSurfaces.resume(handedOff, result);
|
|
293
|
+
deps.assertExecutionCurrent(query);
|
|
294
|
+
return "edit";
|
|
295
|
+
} catch (error) {
|
|
296
|
+
deps.recordRuntimeEvent("generative-app", error, {
|
|
297
|
+
phase: "bound-action-live-edit-fallback",
|
|
298
|
+
app: boundAction.app,
|
|
299
|
+
method: boundAction.method,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
242
303
|
if (result.viewMode === "edit" && deps.editInteractiveMessage) {
|
|
243
304
|
let editFailed = false;
|
|
244
305
|
try {
|
|
@@ -267,6 +328,7 @@ export function createTelegramGenerativeAppBoundButtonActionInvoker<
|
|
|
267
328
|
deps.assertExecutionCurrent(query);
|
|
268
329
|
return "new";
|
|
269
330
|
} catch (error) {
|
|
331
|
+
if (handedOff) deps.getLiveSurfaceRuntime?.()?.open(handedOff);
|
|
270
332
|
deps.recordRuntimeEvent("generative-app", error, {
|
|
271
333
|
phase: "bound-action",
|
|
272
334
|
...(boundAction
|
|
@@ -534,6 +596,10 @@ interface TelegramCommandsAndToolsBindingDeps {
|
|
|
534
596
|
resolveAgentTarget?: OutboundAttachments.TelegramOutboundMessageToolRegistrationDeps["resolveAgentTarget"];
|
|
535
597
|
routeAgentMessage?: OutboundAttachments.TelegramOutboundMessageToolRegistrationDeps["routeAgentMessage"];
|
|
536
598
|
canSendDirect: () => boolean;
|
|
599
|
+
setGenerativeAppLiveSurfaceRuntime?: (
|
|
600
|
+
runtime: GenerativeApps.GenerativeAppLiveSurfaceRuntime<GenerativeApps.TelegramBindLiveHandle>
|
|
601
|
+
| undefined,
|
|
602
|
+
) => void;
|
|
537
603
|
updateStatus: TelegramBridgeStatusUpdater;
|
|
538
604
|
recordRuntimeEvent: TelegramRuntimeEventRecorder;
|
|
539
605
|
}
|
|
@@ -565,17 +631,31 @@ export function registerTelegramCommandsAndTools({
|
|
|
565
631
|
resolveAgentTarget,
|
|
566
632
|
routeAgentMessage,
|
|
567
633
|
canSendDirect,
|
|
634
|
+
setGenerativeAppLiveSurfaceRuntime,
|
|
568
635
|
recordRuntimeEvent,
|
|
569
636
|
updateStatus,
|
|
570
637
|
}: TelegramCommandsAndToolsBindingDeps): void {
|
|
571
638
|
GenerativeApps.registerTelegramBindTool(pi, {
|
|
572
639
|
agentDir,
|
|
640
|
+
getActiveProfileName: configStore.getActiveProfileName,
|
|
573
641
|
getActiveTurn: activeTurnRuntime.get,
|
|
642
|
+
...(setGenerativeAppLiveSurfaceRuntime
|
|
643
|
+
? { setLiveSurfaceRuntime: setGenerativeAppLiveSurfaceRuntime }
|
|
644
|
+
: {}),
|
|
645
|
+
isDeliveryHandleCurrent: Delivery.isTelegramDeliveryHandleCurrent,
|
|
646
|
+
editView: (handle, view) => Delivery.editTelegramView(
|
|
647
|
+
handle as Delivery.TelegramDeliveryHandle,
|
|
648
|
+
view as Delivery.TelegramDeliveryView,
|
|
649
|
+
),
|
|
574
650
|
planOutput: OutboundHandlers.createTelegramOutboundReplyPlanner(
|
|
575
651
|
buttonActionStore,
|
|
576
652
|
Config.createTelegramConfigControls(configStore).getAssistantRenderingMode,
|
|
577
653
|
),
|
|
578
654
|
sendMarkdownReply,
|
|
655
|
+
sendView: (view, options) => Delivery.sendTelegramView(
|
|
656
|
+
view as Delivery.TelegramDeliveryView,
|
|
657
|
+
options,
|
|
658
|
+
),
|
|
579
659
|
recordRuntimeEvent,
|
|
580
660
|
});
|
|
581
661
|
ChannelPosts.registerTelegramChannelPostMutationTool(pi, { mutate: mutateChannelPost });
|
|
@@ -782,6 +862,7 @@ interface TelegramLifecycleBindingDeps {
|
|
|
782
862
|
deferredQueueDispatchRuntime: Queue.TelegramDeferredQueueDispatchRuntime<Pi.ExtensionContext>;
|
|
783
863
|
modelContextAvailabilityRuntime: Prompts.TelegramModelContextAvailabilityRuntime;
|
|
784
864
|
disconnectOnQuit?: () => Promise<unknown>;
|
|
865
|
+
shutdownGenerativeAppLiveSurfaces?: () => void;
|
|
785
866
|
resolveAutomaticThreadCleanupEnabled?: () => boolean | Promise<boolean>;
|
|
786
867
|
buttonActionStore: OutboundHandlers.TelegramButtonActionStore;
|
|
787
868
|
callMultipart: OutboundHandlers.TelegramVoiceReplySenderDeps["sendMultipart"];
|
|
@@ -871,6 +952,7 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
871
952
|
deferredQueueDispatchRuntime,
|
|
872
953
|
modelContextAvailabilityRuntime,
|
|
873
954
|
disconnectOnQuit,
|
|
955
|
+
shutdownGenerativeAppLiveSurfaces,
|
|
874
956
|
resolveAutomaticThreadCleanupEnabled,
|
|
875
957
|
buttonActionStore,
|
|
876
958
|
callMultipart,
|
|
@@ -1194,6 +1276,7 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
1194
1276
|
},
|
|
1195
1277
|
async onSessionShutdown(event, ctx) {
|
|
1196
1278
|
if (!isSessionContextActive(ctx)) return;
|
|
1279
|
+
shutdownGenerativeAppLiveSurfaces?.();
|
|
1197
1280
|
agentLifecycleHooks.clearRetainedAgentEnd();
|
|
1198
1281
|
activityRuntime.onSessionShutdown();
|
|
1199
1282
|
activityVerbosityRuntime?.reset();
|
package/lib/bus-follower.ts
CHANGED
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
type TelegramBusSocketPathSource,
|
|
44
44
|
TELEGRAM_BUS_CAPABILITY_WORKSPACE_THREAD_RENAME,
|
|
45
45
|
TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE,
|
|
46
|
+
TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT,
|
|
46
47
|
} from "./bus.ts";
|
|
47
48
|
import type { TelegramConfigStore, TelegramThreadDisplayMode } from "./config.ts";
|
|
48
49
|
import {
|
|
@@ -1914,9 +1915,12 @@ export function createTelegramBusFollowerRegistrationRuntime<
|
|
|
1914
1915
|
if (!socketPath || !generation || !deps.registrationState?.isRegistered()) {
|
|
1915
1916
|
throw new Error("Telegram follower is not registered with the leader.");
|
|
1916
1917
|
}
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1918
|
+
const requiredCapability = mode === "directory-snake" || mode === "directory-title"
|
|
1919
|
+
? TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT
|
|
1920
|
+
: TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE;
|
|
1921
|
+
if (!hasTelegramBusCapability(deps.protocolIdentity, requiredCapability) ||
|
|
1922
|
+
!hasTelegramBusCapability(deps.registrationState.getLeaderProtocol(), requiredCapability)) {
|
|
1923
|
+
throw new Error("The Telegram peers do not support this Thread display setting. Update or restart both instances.");
|
|
1920
1924
|
}
|
|
1921
1925
|
const requestId = deps.createRequestId();
|
|
1922
1926
|
const response = await sendTelegramBusLocalEnvelope({
|
package/lib/bus-leader.ts
CHANGED
|
@@ -9,6 +9,7 @@ import * as Sync from "./sync.ts";
|
|
|
9
9
|
import {
|
|
10
10
|
createTelegramThreadDisplayReconciler,
|
|
11
11
|
resolveTelegramInitialWorkspaceDisplayName,
|
|
12
|
+
resolveTelegramLiveWorkspaceBindingKeys,
|
|
12
13
|
} from "./thread-display.ts";
|
|
13
14
|
import type { TelegramThreadDisplayMode } from "./config.ts";
|
|
14
15
|
import * as ThreadReconciler from "./thread-reconciler.ts";
|
|
@@ -40,6 +41,7 @@ import {
|
|
|
40
41
|
TELEGRAM_BUS_CAPABILITY_WORKSPACE_FOLLOWER_AUTO_CONNECT,
|
|
41
42
|
TELEGRAM_BUS_CAPABILITY_WORKSPACE_THREAD_RENAME,
|
|
42
43
|
TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE,
|
|
44
|
+
TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT,
|
|
43
45
|
} from "./bus.ts";
|
|
44
46
|
import { getTelegramBusTransportRetryPolicy } from "./bus-transport.ts";
|
|
45
47
|
import type { TelegramQueueHandoffPayload } from "./queue.ts";
|
|
@@ -309,6 +311,13 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
|
|
|
309
311
|
});
|
|
310
312
|
},
|
|
311
313
|
}).run;
|
|
314
|
+
const captureLiveBindingKeys = (
|
|
315
|
+
bindings: readonly Threads.TelegramWorkspaceThreadBinding[],
|
|
316
|
+
): ReadonlySet<string> => resolveTelegramLiveWorkspaceBindingKeys(
|
|
317
|
+
bindings,
|
|
318
|
+
deps.topicTargetStore.getActiveByInstanceId(deps.instanceId)?.target,
|
|
319
|
+
deps.runtime.followerRegistry.list(),
|
|
320
|
+
);
|
|
312
321
|
const provisionerPorts = {
|
|
313
322
|
getAllowedUserId: deps.getAllowedUserId,
|
|
314
323
|
topicTargetStore: deps.topicTargetStore,
|
|
@@ -327,6 +336,9 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
|
|
|
327
336
|
bindings: deps.topicTargetStore.listWorkspaceBindings(),
|
|
328
337
|
binding,
|
|
329
338
|
mode: deps.getThreadDisplayMode!(),
|
|
339
|
+
liveBindingKeys: captureLiveBindingKeys(
|
|
340
|
+
deps.topicTargetStore.listWorkspaceBindings(),
|
|
341
|
+
),
|
|
330
342
|
});
|
|
331
343
|
},
|
|
332
344
|
}
|
|
@@ -339,6 +351,7 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
|
|
|
339
351
|
getMode: deps.getThreadDisplayMode,
|
|
340
352
|
getProfileKey: () => deps.getTelegramProfile?.() ?? "default",
|
|
341
353
|
getLeaderEpoch: () => deps.getCurrentLeaderEpoch?.(),
|
|
354
|
+
captureLiveBindingKeys,
|
|
342
355
|
captureBindingAuthority(binding) {
|
|
343
356
|
const matches = (target: TelegramTarget | undefined) =>
|
|
344
357
|
target?.chatId === binding.target.chatId && target?.threadId === binding.target.threadId;
|
|
@@ -392,8 +405,11 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
|
|
|
392
405
|
throw new Error("Telegram Thread display setting requires current leader authority.");
|
|
393
406
|
}
|
|
394
407
|
const assertDisplayPeers = () => {
|
|
408
|
+
const requiredCapability = mode === "directory-snake" || mode === "directory-title"
|
|
409
|
+
? TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT
|
|
410
|
+
: TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE;
|
|
395
411
|
if (mode !== "names" && deps.runtime.followerRegistry.list().some((follower) =>
|
|
396
|
-
!hasTelegramBusCapability(follower.protocol,
|
|
412
|
+
!hasTelegramBusCapability(follower.protocol, requiredCapability),
|
|
397
413
|
)) throw new Error("Update or restart all connected followers before changing Thread display mode.");
|
|
398
414
|
};
|
|
399
415
|
assertDisplayPeers();
|
|
@@ -597,14 +613,17 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
|
|
|
597
613
|
);
|
|
598
614
|
return binding?.displayTitle ?? binding?.threadName;
|
|
599
615
|
},
|
|
600
|
-
onFollowerDisconnected: (follower) =>
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
616
|
+
onFollowerDisconnected: async (follower) => {
|
|
617
|
+
await runWorkspaceOperation(
|
|
618
|
+
{
|
|
619
|
+
operationId: createTelegramWorkspaceAdmissionOperationId(),
|
|
620
|
+
operationKind: "workspace.disconnect-follower",
|
|
621
|
+
scopes: [{ kind: "profile" }],
|
|
622
|
+
},
|
|
623
|
+
() => disconnectFollower(follower),
|
|
624
|
+
);
|
|
625
|
+
scheduleDisplay();
|
|
626
|
+
},
|
|
608
627
|
async renameFollowerThread(follower, threadName) {
|
|
609
628
|
return runWorkspaceOperation({
|
|
610
629
|
operationId: createTelegramWorkspaceAdmissionOperationId(),
|
|
@@ -692,14 +711,17 @@ export function createTelegramBusLeaderRuntimeAssembly<TContext>(
|
|
|
692
711
|
});
|
|
693
712
|
},
|
|
694
713
|
),
|
|
695
|
-
onFollowerConfirmedDead: (follower) =>
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
714
|
+
onFollowerConfirmedDead: async (follower) => {
|
|
715
|
+
await runWorkspaceOperation(
|
|
716
|
+
{
|
|
717
|
+
operationId: createTelegramWorkspaceAdmissionOperationId(),
|
|
718
|
+
operationKind: "workspace.cleanup-dead-follower",
|
|
719
|
+
scopes: [{ kind: "profile" }],
|
|
720
|
+
},
|
|
721
|
+
() => cleanupConfirmedDeadFollower(follower),
|
|
722
|
+
);
|
|
723
|
+
scheduleDisplay();
|
|
724
|
+
},
|
|
703
725
|
provisionFollowerTarget: (registration, options) => runWorkspaceOperation(
|
|
704
726
|
{
|
|
705
727
|
operationId: `follower-provision:${registration.instanceId}:${registration.registrationGeneration}`,
|
|
@@ -2243,9 +2265,12 @@ export function createTelegramBusLeaderEnvelopeHandler(deps: {
|
|
|
2243
2265
|
const current = () => epoch !== undefined && deps.getCurrentLeaderEpoch?.() === epoch &&
|
|
2244
2266
|
deps.followerRegistry.get(envelope.instanceId)?.registrationGeneration === envelope.registrationGeneration;
|
|
2245
2267
|
const follower = deps.followerRegistry.get(envelope.instanceId);
|
|
2268
|
+
const requiredCapability = envelope.mode === "directory-snake" || envelope.mode === "directory-title"
|
|
2269
|
+
? TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT
|
|
2270
|
+
: TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE;
|
|
2246
2271
|
if (!current() || !follower?.registrationGeneration || !deps.applyThreadDisplayMode ||
|
|
2247
|
-
!hasTelegramBusCapability(deps.protocolIdentity,
|
|
2248
|
-
!hasTelegramBusCapability(follower.protocol,
|
|
2272
|
+
!hasTelegramBusCapability(deps.protocolIdentity, requiredCapability) ||
|
|
2273
|
+
!hasTelegramBusCapability(follower.protocol, requiredCapability)) {
|
|
2249
2274
|
return { kind: "bus.ack", requestId: envelope.requestId, ok: false,
|
|
2250
2275
|
message: "Thread display settings require current registration and compatible leader authority." };
|
|
2251
2276
|
}
|
package/lib/bus.ts
CHANGED
|
@@ -230,6 +230,8 @@ export const TELEGRAM_BUS_CAPABILITY_INPUT_CUSTODY_REFERENCE =
|
|
|
230
230
|
export const TELEGRAM_BUS_CAPABILITY_WORKSPACE_THREAD_RENAME =
|
|
231
231
|
"workspace-thread-rename-v1" as const;
|
|
232
232
|
export const TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE = "thread-display-mode-v1" as const;
|
|
233
|
+
export const TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT =
|
|
234
|
+
"directory-display-format-v1" as const;
|
|
233
235
|
export const TELEGRAM_BUS_CAPABILITY_WORKSPACE_FOLLOWER_AUTO_CONNECT =
|
|
234
236
|
"workspace-follower-auto-connect-v1" as const;
|
|
235
237
|
|
|
@@ -1027,7 +1029,8 @@ export function parseTelegramBusEnvelope(
|
|
|
1027
1029
|
case "follower.setThreadDisplayMode":
|
|
1028
1030
|
if (typeof value.instanceId === "string" &&
|
|
1029
1031
|
typeof value.registrationGeneration === "string" &&
|
|
1030
|
-
(value.mode === "letters" || value.mode === "names" ||
|
|
1032
|
+
(value.mode === "letters" || value.mode === "names" ||
|
|
1033
|
+
value.mode === "directory-snake" || value.mode === "directory-title")) {
|
|
1031
1034
|
envelope = { kind, requestId, instanceId: value.instanceId,
|
|
1032
1035
|
registrationGeneration: value.registrationGeneration, mode: value.mode };
|
|
1033
1036
|
}
|
package/lib/commands.ts
CHANGED
|
@@ -1205,7 +1205,7 @@ export const TELEGRAM_APP_MENU_INTRO_HTML = [
|
|
|
1205
1205
|
"<b>Pi Telegram</b>",
|
|
1206
1206
|
"",
|
|
1207
1207
|
`${formatTelegramCommandEmojiPrefix("start")}/start — Open menu / Pair bridge`,
|
|
1208
|
-
`${formatTelegramCommandEmojiPrefix("name")}/name
|
|
1208
|
+
`${formatTelegramCommandEmojiPrefix("name")}/name — Rename this thread`,
|
|
1209
1209
|
`${formatTelegramCommandEmojiPrefix("compact")}/compact — Compact current session`,
|
|
1210
1210
|
`${formatTelegramCommandEmojiPrefix("next")}/next — Force next turn`,
|
|
1211
1211
|
`${formatTelegramCommandEmojiPrefix("continue")}/continue — Queue continue prompt`,
|
|
@@ -1246,7 +1246,7 @@ function buildTelegramAppMenuIntroHtml(): string {
|
|
|
1246
1246
|
"<b>Pi Telegram</b>",
|
|
1247
1247
|
"",
|
|
1248
1248
|
`${formatTelegramCommandEmojiPrefix("start")}/start — Open menu / Pair bridge`,
|
|
1249
|
-
`${formatTelegramCommandEmojiPrefix("name")}/name
|
|
1249
|
+
`${formatTelegramCommandEmojiPrefix("name")}/name — Rename this thread`,
|
|
1250
1250
|
`${formatTelegramCommandEmojiPrefix("compact")}/compact — Compact current session`,
|
|
1251
1251
|
...extensionLines,
|
|
1252
1252
|
`${formatTelegramCommandEmojiPrefix("next")}/next — Force next turn`,
|
package/lib/config.ts
CHANGED
|
@@ -136,16 +136,23 @@ export interface ResolvedTelegramTimeConfig {
|
|
|
136
136
|
timezone: string;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
export type TelegramThreadDisplayMode =
|
|
139
|
+
export type TelegramThreadDisplayMode =
|
|
140
|
+
| "letters"
|
|
141
|
+
| "names"
|
|
142
|
+
| "directories"
|
|
143
|
+
| "directory-snake"
|
|
144
|
+
| "directory-title";
|
|
145
|
+
|
|
146
|
+
const TELEGRAM_THREAD_DISPLAY_MODES: readonly TelegramThreadDisplayMode[] = [
|
|
147
|
+
"letters", "names", "directory-snake", "directory-title",
|
|
148
|
+
];
|
|
140
149
|
|
|
141
150
|
export function resolveTelegramThreadDisplayMode(
|
|
142
151
|
config: Pick<TelegramConfig, "threadDisplayMode">,
|
|
143
152
|
): TelegramThreadDisplayMode {
|
|
144
|
-
return config.threadDisplayMode
|
|
145
|
-
?
|
|
146
|
-
:
|
|
147
|
-
? "directories"
|
|
148
|
-
: "letters";
|
|
153
|
+
return TELEGRAM_THREAD_DISPLAY_MODES.includes(config.threadDisplayMode as TelegramThreadDisplayMode)
|
|
154
|
+
? config.threadDisplayMode as TelegramThreadDisplayMode
|
|
155
|
+
: "letters";
|
|
149
156
|
}
|
|
150
157
|
|
|
151
158
|
export async function setTelegramThreadDisplayMode(
|
|
@@ -153,7 +160,7 @@ export async function setTelegramThreadDisplayMode(
|
|
|
153
160
|
mode: TelegramThreadDisplayMode,
|
|
154
161
|
isCurrent: () => boolean,
|
|
155
162
|
): Promise<void> {
|
|
156
|
-
if (!
|
|
163
|
+
if (!TELEGRAM_THREAD_DISPLAY_MODES.includes(mode)) {
|
|
157
164
|
throw new Error("Invalid Telegram Thread display mode.");
|
|
158
165
|
}
|
|
159
166
|
const profile = store.getActiveProfileName();
|
package/lib/delivery.ts
CHANGED
|
@@ -18,7 +18,10 @@ import {
|
|
|
18
18
|
type TelegramTarget,
|
|
19
19
|
} from "./target.ts";
|
|
20
20
|
import {
|
|
21
|
+
getTelegramApiRetryAfterMs,
|
|
22
|
+
isRetryableTelegramApiError,
|
|
21
23
|
isTelegramApiCommitUnknownError,
|
|
24
|
+
isTelegramMessageUnavailableError,
|
|
22
25
|
type TelegramBridgeApiRuntime,
|
|
23
26
|
} from "./telegram-api.ts";
|
|
24
27
|
|
|
@@ -60,6 +63,9 @@ export type TelegramDeliveryFailureReason =
|
|
|
60
63
|
| "stale-handle"
|
|
61
64
|
| "invalid-view"
|
|
62
65
|
| "commit-unknown"
|
|
66
|
+
| "message-unavailable"
|
|
67
|
+
| "rate-limited"
|
|
68
|
+
| "transport-retryable"
|
|
63
69
|
| "transport-failed";
|
|
64
70
|
|
|
65
71
|
export type TelegramDeliveryResult<T> =
|
|
@@ -68,6 +74,8 @@ export type TelegramDeliveryResult<T> =
|
|
|
68
74
|
ok: false;
|
|
69
75
|
reason: TelegramDeliveryFailureReason;
|
|
70
76
|
message: string;
|
|
77
|
+
/** Exact Telegram flood-control delay when supplied by the API. */
|
|
78
|
+
retryAfterMs?: number;
|
|
71
79
|
/** Successfully materialized state that callers may edit or delete to recover. */
|
|
72
80
|
partial?: T;
|
|
73
81
|
};
|
|
@@ -246,10 +254,26 @@ function failure<T>(
|
|
|
246
254
|
reason: TelegramDeliveryFailureReason,
|
|
247
255
|
message: string,
|
|
248
256
|
partial?: T,
|
|
257
|
+
retryAfterMs?: number,
|
|
249
258
|
): TelegramDeliveryResult<T> {
|
|
259
|
+
const retry = retryAfterMs === undefined ? {} : { retryAfterMs };
|
|
250
260
|
return partial === undefined
|
|
251
|
-
? { ok: false, reason, message }
|
|
252
|
-
: { ok: false, reason, message, partial };
|
|
261
|
+
? { ok: false, reason, message, ...retry }
|
|
262
|
+
: { ok: false, reason, message, partial, ...retry };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function classifyTelegramDeliveryTransportError(error: unknown): {
|
|
266
|
+
reason: Extract<TelegramDeliveryFailureReason,
|
|
267
|
+
"commit-unknown" | "message-unavailable" | "rate-limited" |
|
|
268
|
+
"transport-retryable" | "transport-failed">;
|
|
269
|
+
retryAfterMs?: number;
|
|
270
|
+
} {
|
|
271
|
+
if (isTelegramApiCommitUnknownError(error)) return { reason: "commit-unknown" };
|
|
272
|
+
if (isTelegramMessageUnavailableError(error)) return { reason: "message-unavailable" };
|
|
273
|
+
const retryAfterMs = getTelegramApiRetryAfterMs(error);
|
|
274
|
+
if (retryAfterMs !== undefined) return { reason: "rate-limited", retryAfterMs };
|
|
275
|
+
if (isRetryableTelegramApiError(error)) return { reason: "transport-retryable" };
|
|
276
|
+
return { reason: "transport-failed" };
|
|
253
277
|
}
|
|
254
278
|
|
|
255
279
|
/** @internal */
|
|
@@ -479,14 +503,14 @@ export function createTelegramDeliveryRuntime(
|
|
|
479
503
|
if (error instanceof TelegramDeliveryTransportGenerationError) {
|
|
480
504
|
return inactive();
|
|
481
505
|
}
|
|
506
|
+
const classified = classifyTelegramDeliveryTransportError(error);
|
|
482
507
|
return failure(
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
: "transport-failed",
|
|
486
|
-
isTelegramApiCommitUnknownError(error)
|
|
508
|
+
classified.reason,
|
|
509
|
+
classified.reason === "commit-unknown"
|
|
487
510
|
? `Telegram delivery ${operation} may have committed before transport failed.`
|
|
488
511
|
: `Telegram delivery ${operation} failed.`,
|
|
489
512
|
partial,
|
|
513
|
+
classified.retryAfterMs,
|
|
490
514
|
);
|
|
491
515
|
};
|
|
492
516
|
const createHandle = (
|
|
@@ -837,6 +861,14 @@ export function clearTelegramDeliveryRuntime(): void {
|
|
|
837
861
|
registry.runtime = undefined;
|
|
838
862
|
}
|
|
839
863
|
|
|
864
|
+
/** @internal */
|
|
865
|
+
export function isTelegramDeliveryHandleCurrent(
|
|
866
|
+
handle: TelegramDeliveryHandle,
|
|
867
|
+
): boolean {
|
|
868
|
+
const runtime = getTelegramDeliveryRuntimeRegistry().runtime;
|
|
869
|
+
return runtime !== undefined && runtime.generation === handle.generation;
|
|
870
|
+
}
|
|
871
|
+
|
|
840
872
|
export async function sendTelegramView(
|
|
841
873
|
view: TelegramDeliveryView,
|
|
842
874
|
options: SendTelegramViewOptions,
|
package/lib/extension.ts
CHANGED
|
@@ -64,6 +64,7 @@ const telegramBusProtocolIdentity =
|
|
|
64
64
|
Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_FOLLOWER_AUTO_CONNECT,
|
|
65
65
|
Bus.TELEGRAM_BUS_CAPABILITY_WORKSPACE_THREAD_RENAME,
|
|
66
66
|
Bus.TELEGRAM_BUS_CAPABILITY_THREAD_DISPLAY_MODE,
|
|
67
|
+
Bus.TELEGRAM_BUS_CAPABILITY_DIRECTORY_DISPLAY_FORMAT,
|
|
67
68
|
]);
|
|
68
69
|
|
|
69
70
|
// --- Extension Runtime ---
|
|
@@ -672,11 +673,15 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
672
673
|
getHandlers: configStore.getOutboundHandlers,
|
|
673
674
|
recordRuntimeEvent,
|
|
674
675
|
});
|
|
676
|
+
const generativeAppLiveSurfaceBinding =
|
|
677
|
+
Bindings.createTelegramGenerativeAppLiveSurfaceBinding();
|
|
675
678
|
const invokeGenerativeAppBoundButtonAction =
|
|
676
679
|
Bindings.createTelegramGenerativeAppBoundButtonActionInvoker({
|
|
677
680
|
agentDir: Paths.resolveAgentDir(),
|
|
678
681
|
assertExecutionCurrent: Updates.assertTelegramUpdateExecutionCurrent,
|
|
679
682
|
getExecutionFence: Updates.getTelegramUpdateExecutionFence,
|
|
683
|
+
getActiveProfileName: configStore.getActiveProfileName,
|
|
684
|
+
getLiveSurfaceRuntime: generativeAppLiveSurfaceBinding.get,
|
|
680
685
|
planOutput: planGenerativeAppOutput,
|
|
681
686
|
sendMarkdownReply,
|
|
682
687
|
editInteractiveMessage,
|
|
@@ -1803,6 +1808,7 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
1803
1808
|
getDefaultChatId: proactivePushChatIdGetter,
|
|
1804
1809
|
getDefaultTarget: proactivePushTargetGetter,
|
|
1805
1810
|
...agentMessageToolRoutingRuntime,
|
|
1811
|
+
setGenerativeAppLiveSurfaceRuntime: generativeAppLiveSurfaceBinding.set,
|
|
1806
1812
|
updateStatus,
|
|
1807
1813
|
recordRuntimeEvent,
|
|
1808
1814
|
});
|
|
@@ -1831,6 +1837,7 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
1831
1837
|
deferredQueueDispatchRuntime,
|
|
1832
1838
|
modelContextAvailabilityRuntime,
|
|
1833
1839
|
disconnectOnQuit: cleanupTelegramThreadForSessionRestart,
|
|
1840
|
+
shutdownGenerativeAppLiveSurfaces: generativeAppLiveSurfaceBinding.shutdown,
|
|
1834
1841
|
resolveAutomaticThreadCleanupEnabled:
|
|
1835
1842
|
configControls.resolveAutomaticThreadCleanupEnabled,
|
|
1836
1843
|
buttonActionStore,
|