Fork of upstream llblab/[email protected].0 (SHA afe09c5) repackaged as a drop-in extension for can1357/oh-my-pi (omp >= 16.5.2). Changes vs upstream: - Rename package: @llblab/pi-telegram -> @evandrodevbr/oh-my-pi-telegram - Bump version: 0.22.0 -> 0.22.0-evandro.1 - Update repository/homepage/bugs URLs to evandrodevbr - Add omp field in package.json (displayName + compatibleWith) - README: prepend 'Oh My Pi (omp) Compatibility' section with install commands, verified-components table, upstream lineage, and rationale - CHANGELOG: add '0.22.0-evandro.1' entry under Unreleased - docs/: rename @llblab/pi-telegram imports to @evandrodevbr/oh-my-pi-telegram - tests/public-api.test.ts: rename package import paths Gates re-run on the fork: - npm run typecheck -> tsc --noEmit (success) - npm test -> 1229 pass / 0 fail / 1 platform-only skip - npm run audit -> found 0 vulnerabilities - npm run pack:check -> evandrodevbr-oh-my-pi-telegram-0.22.0-evandro.1.tgz Verified: - omp install --link ./pi-telegram -> Linked OK - omp plugin list -> @evandrodevbr/[email protected].0-evandro.1 Upstream lineage: badlogic/pi-telegram -> llblab/pi-telegram (0.22.0) -> evandrodevbr/oh-my-pi-telegram (this fork)
1076 lines
40 KiB
TypeScript
1076 lines
40 KiB
TypeScript
/**
|
|
* Telegram bridge extension entrypoint and orchestration layer
|
|
* Zones: telegram, pi agent, orchestration
|
|
* Keeps the runtime wiring in one place while delegating reusable domain logic to /lib modules
|
|
*/
|
|
|
|
import * as Activity from "./lib/activity.ts";
|
|
import * as Bindings from "./lib/bindings.ts";
|
|
import * as BusApi from "./lib/bus-api.ts";
|
|
import * as Bus from "./lib/bus.ts";
|
|
import * as BusFollower from "./lib/bus-follower.ts";
|
|
import * as BusLeader from "./lib/bus-leader.ts";
|
|
import * as BusTransport from "./lib/bus-transport.ts";
|
|
import * as CommandTemplates from "./lib/command-templates.ts";
|
|
import * as Commands from "./lib/commands.ts";
|
|
import * as Config from "./lib/config.ts";
|
|
import * as Delivery from "./lib/delivery.ts";
|
|
import * as Threads from "./lib/threads.ts";
|
|
import * as Inbound from "./lib/inbound.ts";
|
|
import * as Lifecycle from "./lib/lifecycle.ts";
|
|
import * as Locks from "./lib/locks.ts";
|
|
import * as Media from "./lib/media.ts";
|
|
import * as MenuQueue from "./lib/menu-queue.ts";
|
|
import * as MenuSettings from "./lib/menu-settings.ts";
|
|
import * as Menu from "./lib/menu.ts";
|
|
import * as Model from "./lib/model.ts";
|
|
import * as Outbound from "./lib/outbound.ts";
|
|
import * as Ownership from "./lib/ownership.ts";
|
|
import * as Paths from "./lib/paths.ts";
|
|
import * as Pi from "./lib/pi.ts";
|
|
import * as Polling from "./lib/polling.ts";
|
|
import * as Preview from "./lib/preview.ts";
|
|
import * as PromptTemplates from "./lib/prompt-templates.ts";
|
|
import * as Queue from "./lib/queue.ts";
|
|
import * as Replies from "./lib/replies.ts";
|
|
import * as Routing from "./lib/routing.ts";
|
|
import * as Runtime from "./lib/runtime.ts";
|
|
import * as Logs from "./lib/logs.ts";
|
|
import * as Sections from "./lib/sections.ts";
|
|
import * as Status from "./lib/status.ts";
|
|
import * as Sync from "./lib/sync.ts";
|
|
import * as TelegramApi from "./lib/telegram-api.ts";
|
|
import * as TextGroups from "./lib/text-groups.ts";
|
|
import * as ThreadReconciler from "./lib/thread-reconciler.ts";
|
|
import * as TimeInjection from "./lib/time-injection.ts";
|
|
import * as Updates from "./lib/updates.ts";
|
|
import * as Voice from "./lib/voice.ts";
|
|
|
|
type ActivePiModel = NonNullable<Pi.ExtensionContext["model"]>;
|
|
|
|
// --- Extension Runtime ---
|
|
|
|
export default function (pi: Pi.ExtensionAPI) {
|
|
const piRuntime = Pi.createExtensionApiRuntimePorts(pi);
|
|
const {
|
|
getCommands,
|
|
getThinkingLevel,
|
|
sendUserMessage,
|
|
setModel,
|
|
setThinkingLevel,
|
|
} = piRuntime;
|
|
const bridgeRuntime = Runtime.createTelegramBridgeRuntime();
|
|
const getActiveTelegramThreadProfile = function (): string | undefined {
|
|
return configStore.getActiveProfileName();
|
|
};
|
|
const busProcessRuntime = Bus.createTelegramBusProcessRuntime({
|
|
getActiveProfileName: getActiveTelegramThreadProfile,
|
|
pid: process.pid,
|
|
parentPid: process.ppid,
|
|
createdAtMs: Date.now(),
|
|
});
|
|
const {
|
|
instanceId: telegramInstanceId,
|
|
manualFollowerOwnerId: telegramManualFollowerOwnerId,
|
|
getLeaderSocketPath: getTelegramBusSocketPath,
|
|
getFollowerSocketPath: getTelegramBusFollowerSocketPath,
|
|
} = busProcessRuntime;
|
|
const getTelegramManualFollowerProfileKey =
|
|
BusFollower.createTelegramManualFollowerProfileKeyResolver({
|
|
getActiveProfileName: getActiveTelegramThreadProfile,
|
|
manualFollowerOwnerId: telegramManualFollowerOwnerId,
|
|
});
|
|
const telegramBusAuthSecret = Bus.createTelegramBusAuthSecret();
|
|
let telegramActiveBusAuthSecret: string | undefined;
|
|
let telegramBusLifecycleOverridePhase:
|
|
Status.TelegramBridgeBusLifecyclePhase | undefined;
|
|
const telegramBusFollowerRegistry = Bus.createTelegramBusFollowerRegistry();
|
|
const telegramBusFollowerRegistrationState =
|
|
BusFollower.createTelegramBusFollowerRegistrationState();
|
|
const telegramBusLeaderState =
|
|
Threads.createTelegramLeaderThreadStateRuntime();
|
|
const telegramThreadCapabilityState =
|
|
Polling.createTelegramThreadCapabilityStateRuntime();
|
|
const telegramProvisioningActivity =
|
|
Sync.createTelegramProvisioningActivityRuntime();
|
|
const messageOwnershipRuntime =
|
|
Ownership.createTelegramBusMessageOwnershipRuntime({
|
|
instanceId: telegramInstanceId,
|
|
getProfileKey() {
|
|
return getActiveTelegramThreadProfile() ?? "default";
|
|
},
|
|
listFollowers: telegramBusFollowerRegistry.list,
|
|
});
|
|
const { abort, lifecycle, queue, setup, typing } = bridgeRuntime;
|
|
const runtimeDiagnostics =
|
|
Logs.createTelegramRuntimeDiagnosticsRuntime<Pi.ExtensionContext>();
|
|
const runtimeEvents = runtimeDiagnostics.events;
|
|
const recordRuntimeEvent = runtimeDiagnostics.recordRuntimeEvent;
|
|
const configStore = Config.createTelegramConfigStore({ recordRuntimeEvent });
|
|
const isTelegramBusConfigured = function (): boolean {
|
|
return true;
|
|
};
|
|
const isTelegramBusRuntimeEnabled = function (): boolean {
|
|
return (
|
|
isTelegramBusConfigured() &&
|
|
!telegramThreadCapabilityState.isTopicModeUnavailable()
|
|
);
|
|
};
|
|
Config.bindGlobalTelegramConfigRuntime(configStore);
|
|
const configControls = Config.createTelegramConfigControls(configStore);
|
|
const lockRuntime = Locks.createTelegramLockRuntime<Pi.ExtensionContext>({
|
|
key: Locks.createTelegramLockKeyResolver(configStore),
|
|
instanceId: telegramInstanceId,
|
|
busSecret: telegramBusAuthSecret,
|
|
staleHeartbeatMs: Locks.TELEGRAM_BUS_LEADER_STALE_HEARTBEAT_MS,
|
|
});
|
|
const threadStore = Threads.createTelegramTopicTargetStore({
|
|
path: function () {
|
|
return Threads.getTelegramTopicTargetsPath(
|
|
undefined,
|
|
configStore.getActiveProfileName(),
|
|
);
|
|
},
|
|
canPersist: lockRuntime.owns,
|
|
commitPersist: lockRuntime.commitIfOwned,
|
|
});
|
|
runtimeDiagnostics.bindStorage({
|
|
getBotToken: configStore.getBotToken,
|
|
getProfileName: configStore.getActiveProfileName,
|
|
canReset: lockRuntime.owns,
|
|
commitReset: lockRuntime.commitIfOwned,
|
|
});
|
|
const lockOwnershipGuard =
|
|
Locks.createTelegramLockOwnershipGuard(lockRuntime);
|
|
const getCurrentLeaderEpoch = lockRuntime.getOwnedLeaderEpoch;
|
|
const telegramSessionContextStore =
|
|
Lifecycle.createTelegramSessionContextStore<Pi.ExtensionContext>({
|
|
getIdentity(ctx) {
|
|
return ctx.sessionManager ?? ctx.cwd;
|
|
},
|
|
});
|
|
const ownsTelegramDirectDelivery =
|
|
Locks.createTelegramDirectDeliveryOwnershipChecker({
|
|
lock: lockRuntime,
|
|
contextStore: telegramSessionContextStore,
|
|
});
|
|
const activeTurnRuntime = Queue.createTelegramActiveTurnStore();
|
|
const proactivePushChatIdGetter =
|
|
Config.createTelegramProactivePushChatIdGetter({
|
|
getActiveTurnChatId: activeTurnRuntime.getChatId,
|
|
getAllowedUserId: configStore.getAllowedUserId,
|
|
});
|
|
const proactivePushTargetGetter =
|
|
Config.createTelegramProactivePushTargetGetter({
|
|
getActiveTurnTarget: activeTurnRuntime.getTarget,
|
|
getAssignedTarget() {
|
|
return (
|
|
telegramBusFollowerRegistrationState.getTarget() ??
|
|
telegramBusLeaderState.getTarget()
|
|
);
|
|
},
|
|
getAllowedUserId: configStore.getAllowedUserId,
|
|
});
|
|
const buttonActionStore = Outbound.createTelegramButtonActionStore();
|
|
const pendingModelSwitchStore =
|
|
Model.createPendingModelSwitchStore<
|
|
Model.ScopedTelegramModel<ActivePiModel>
|
|
>();
|
|
const modelMenuRuntime = Menu.createTelegramModelMenuRuntime<ActivePiModel>();
|
|
const sectionRegistry = Sections.createAndBindTelegramSectionRegistry();
|
|
|
|
const timeInjectionRuntime = TimeInjection.createTimeInjectionRuntime({
|
|
getConfig: Config.createTelegramTimeConfigGetter(configStore),
|
|
recordRuntimeEvent,
|
|
});
|
|
Outbound.bindTelegramRuntimeEventRecorder(recordRuntimeEvent);
|
|
const getContextModel = Pi.getExtensionContextModel;
|
|
const isIdle = Pi.isExtensionContextIdle;
|
|
const hasPendingMessages = Pi.hasExtensionContextPendingMessages;
|
|
const compact = Pi.compactExtensionContext;
|
|
const mediaGroupRuntime = Media.createTelegramMediaGroupController<
|
|
TelegramApi.TelegramMessage,
|
|
Pi.ExtensionContext
|
|
>();
|
|
const textGroupRuntime = TextGroups.createTelegramTextGroupController<
|
|
TelegramApi.TelegramMessage,
|
|
Pi.ExtensionContext
|
|
>();
|
|
const rawTelegramQueueStore =
|
|
Queue.createTelegramQueueStore<Pi.ExtensionContext>();
|
|
const telegramTransportStampRuntime =
|
|
Queue.createTelegramTransportStampRuntime({
|
|
getProfileName: configStore.getActiveProfileName,
|
|
getBotToken: configStore.getBotToken,
|
|
});
|
|
const telegramQueueStore = Queue.createTelegramTransportStampedQueueStore(
|
|
rawTelegramQueueStore,
|
|
telegramTransportStampRuntime.getStamp,
|
|
);
|
|
const deferredQueueDispatchRuntime =
|
|
Queue.createTelegramDeferredQueueDispatchRuntime<Pi.ExtensionContext>({
|
|
delayMs: 50,
|
|
recordRuntimeEvent,
|
|
});
|
|
const pollingControllerState = Polling.createTelegramPollingControllerState();
|
|
const telegramSyncStateRuntime = Sync.createTelegramSyncStateRuntime();
|
|
const threadReconciliationRuntime =
|
|
ThreadReconciler.createThreadReconciliationRuntime({
|
|
recordRuntimeEvent,
|
|
scheduleSnapshotPersist: runtimeDiagnostics.scheduleSnapshotPersist,
|
|
});
|
|
const recordThreadReconciliationPlan = threadReconciliationRuntime.recordPlan;
|
|
const markTelegramConfigSyncChange =
|
|
telegramSyncStateRuntime.markConfigChange;
|
|
const persistTelegramConfigWithSync = async function (
|
|
nextConfig?: Config.TelegramConfig,
|
|
) {
|
|
await configStore.persist(nextConfig);
|
|
markTelegramConfigSyncChange("config-persist");
|
|
};
|
|
const currentInstanceThreadRuntime =
|
|
Threads.createTelegramCurrentInstanceThreadRuntime({
|
|
instanceId: telegramInstanceId,
|
|
listRecords: threadStore.list,
|
|
getPreferredTarget() {
|
|
return (
|
|
activeTurnRuntime.getTarget() ??
|
|
telegramBusFollowerRegistrationState.getTarget() ??
|
|
telegramBusLeaderState.getTarget()
|
|
);
|
|
},
|
|
getFollower() {
|
|
const target = telegramBusFollowerRegistrationState.getTarget();
|
|
if (!target) return undefined;
|
|
return {
|
|
registered: telegramBusFollowerRegistrationState.isRegistered(),
|
|
target,
|
|
slot: telegramBusFollowerRegistrationState.getSlot(),
|
|
threadName: telegramBusFollowerRegistrationState.getThreadName(),
|
|
};
|
|
},
|
|
getLeader: telegramBusLeaderState.getIdentity,
|
|
});
|
|
const findCurrentThreadRecord = currentInstanceThreadRuntime.findRecord;
|
|
const getCurrentInstanceThreadIdentity =
|
|
currentInstanceThreadRuntime.getIdentity;
|
|
const threadStatusProjectionRuntime =
|
|
Threads.createTelegramThreadStatusProjectionRuntime({
|
|
getThreadMode: function () {
|
|
return threadStore.getBotState().threadMode;
|
|
},
|
|
isBusPollingStarted: telegramThreadCapabilityState.isBusPollingStarted,
|
|
isFollowerRegistered: telegramBusFollowerRegistrationState.isRegistered,
|
|
listFollowers: telegramBusFollowerRegistry.list,
|
|
listRecords: threadStore.list,
|
|
listReservations: threadStore.listReservations,
|
|
listSyncObservations: threadStore.listSyncObservations,
|
|
getLeaderSocketPath: getTelegramBusSocketPath,
|
|
getFollowerSocketPath: getTelegramBusFollowerSocketPath,
|
|
getTransportKind: BusTransport.getTelegramBusTransportKind,
|
|
getFollowerTarget: telegramBusFollowerRegistrationState.getTarget,
|
|
getFollowerSlot: telegramBusFollowerRegistrationState.getSlot,
|
|
getFollowerThreadName: telegramBusFollowerRegistrationState.getThreadName,
|
|
getCurrentIdentity: getCurrentInstanceThreadIdentity,
|
|
});
|
|
const statusRuntime = Status.createTelegramBridgeStatusRuntime<
|
|
Pi.ExtensionContext,
|
|
Queue.TelegramQueueItem<Pi.ExtensionContext>
|
|
>({
|
|
getConfig: configStore.get,
|
|
getActiveProfileName: configStore.getActiveProfileName,
|
|
getDiagnosticPaths: Paths.getTelegramDiagnosticsDisplayPaths,
|
|
isPollingActive: Polling.createTelegramPollingActivityReader(
|
|
pollingControllerState,
|
|
),
|
|
getActiveSourceMessageIds: activeTurnRuntime.getSourceMessageIds,
|
|
hasActiveTurn: activeTurnRuntime.has,
|
|
hasDispatchPending: lifecycle.hasDispatchPending,
|
|
isCompactionInProgress: lifecycle.isCompactionInProgress,
|
|
getActiveToolExecutions: lifecycle.getActiveToolExecutions,
|
|
hasPendingModelSwitch: pendingModelSwitchStore.has,
|
|
getQueuedItems: telegramQueueStore.getQueuedItems,
|
|
formatQueuedStatus: Queue.formatQueuedTelegramItemsStatus,
|
|
getRecentRuntimeEvents: runtimeEvents.getEvents,
|
|
getRuntimeLockState: lockRuntime.getStatusLabel,
|
|
...threadStatusProjectionRuntime,
|
|
getBusLifecyclePhase() {
|
|
return telegramBusLifecycleOverridePhase;
|
|
},
|
|
getBotThreadMode() {
|
|
return threadStore.getBotState();
|
|
},
|
|
getSyncState: telegramSyncStateRuntime.getState,
|
|
getThreadReconciliationState() {
|
|
return threadReconciliationRuntime.getState();
|
|
},
|
|
});
|
|
runtimeDiagnostics.bindStatus({
|
|
instanceId: telegramInstanceId,
|
|
updateStatus: statusRuntime.updateStatus,
|
|
getStatusState: statusRuntime.getStatusState,
|
|
async persistSnapshot(snapshot) {
|
|
threadStore.setStatusSnapshot(snapshot);
|
|
await threadStore.persist();
|
|
},
|
|
});
|
|
const updateStatus = runtimeDiagnostics.updateStatus;
|
|
const getStatusLines = runtimeDiagnostics.getStatusLines;
|
|
const inboundHandlerRuntime = Inbound.createTelegramInboundHandlerRuntime({
|
|
getHandlers: configStore.getInboundHandlers,
|
|
execCommand: CommandTemplates.execCommandTemplate,
|
|
getCwd: Pi.getExtensionContextCwd,
|
|
recordRuntimeEvent,
|
|
});
|
|
|
|
// --- Telegram API ---
|
|
|
|
const directTelegramApiRuntime =
|
|
TelegramApi.createDefaultTelegramBridgeApiRuntime({
|
|
getBotToken: configStore.getBotToken,
|
|
recordRuntimeEvent,
|
|
});
|
|
const telegramBusFollowerClients =
|
|
BusFollower.createTelegramBusFollowerClientRuntime<
|
|
Pi.ExtensionContext,
|
|
Updates.TelegramMessageReactionUpdated,
|
|
Routing.TelegramRoutedCallbackQuery,
|
|
Routing.TelegramRoutedMessage
|
|
>({
|
|
socketPath: getTelegramBusSocketPath,
|
|
instanceId: telegramInstanceId,
|
|
getApiAuthSecret() {
|
|
return telegramActiveBusAuthSecret;
|
|
},
|
|
getForwardingAuthSecret() {
|
|
return telegramBusAuthSecret;
|
|
},
|
|
getRegistrationGeneration:
|
|
telegramBusFollowerRegistrationState.getGeneration,
|
|
timeoutMs: 30_000,
|
|
});
|
|
const telegramApiRuntime = BusApi.createTelegramBusAwareApiRuntime({
|
|
directRuntime: directTelegramApiRuntime,
|
|
ownsDirect() {
|
|
return lockRuntime.owns();
|
|
},
|
|
getDefaultTarget: proactivePushTargetGetter,
|
|
callFollowerApi: telegramBusFollowerClients.callApi,
|
|
});
|
|
const {
|
|
call: callTelegramApi,
|
|
callMultipart,
|
|
deleteWebhook,
|
|
getUpdates,
|
|
setMyCommands,
|
|
sendTypingAction,
|
|
sendChatAction,
|
|
sendRecordVoiceAction,
|
|
sendMessageDraft,
|
|
sendMessage,
|
|
sendRichMessage,
|
|
sendRichMessageDraft,
|
|
downloadFile: downloadTelegramBridgeFile,
|
|
editMessageText: editTelegramMessageText,
|
|
answerCallbackQuery,
|
|
answerGuestQuery,
|
|
deleteMessage: deleteTelegramMessage,
|
|
prepareTempDir,
|
|
} = telegramApiRuntime;
|
|
|
|
// --- Message Delivery ---
|
|
|
|
const sendGuestReply = Replies.createGuestMarkdownReplySender({
|
|
answerGuestQuery,
|
|
});
|
|
|
|
const promptDispatchRuntime = Runtime.createTelegramPromptDispatchRuntime({
|
|
lifecycle,
|
|
typing,
|
|
getDefaultChatId: proactivePushChatIdGetter,
|
|
sendTypingAction,
|
|
sendAggregateTypingAction:
|
|
BusApi.createTelegramAggregateTypingActionSender(telegramApiRuntime),
|
|
updateStatus,
|
|
recordRuntimeEvent,
|
|
});
|
|
const currentModelRuntime = Model.createCurrentModelRuntime({
|
|
getContextModel,
|
|
updateStatus,
|
|
});
|
|
const queueMutationRuntime = Queue.createTelegramQueueMutationController({
|
|
...telegramQueueStore,
|
|
getNextPriorityReactionOrder: queue.getNextPriorityReactionOrder,
|
|
incrementNextPriorityReactionOrder:
|
|
queue.incrementNextPriorityReactionOrder,
|
|
updateStatus,
|
|
});
|
|
|
|
// --- Reply Runtime & Preview ---
|
|
|
|
const replyRuntime = Replies.createTelegramRenderedMessageDeliveryRuntime({
|
|
recordOwnership: messageOwnershipRuntime.recordLocal,
|
|
sendMessage,
|
|
sendRichMessage,
|
|
getAssistantRenderingMode: configControls.getAssistantRenderingMode,
|
|
editMessage: editTelegramMessageText,
|
|
});
|
|
const { replyTransport, editInteractiveMessage, sendInteractiveMessage } =
|
|
replyRuntime;
|
|
const deliveryTargetPolicyRuntime =
|
|
Delivery.createTelegramDeliveryTargetPolicyRuntime({
|
|
ownsDirect: lockRuntime.owns,
|
|
isFollowerRegistered: telegramBusFollowerRegistrationState.isRegistered,
|
|
getAllowedChatId: configStore.getAllowedUserId,
|
|
getFollowerTarget: telegramBusFollowerRegistrationState.getTarget,
|
|
getLeaderTarget: telegramBusLeaderState.getTarget,
|
|
listThreadRecords: threadStore.list,
|
|
getActiveTurnTarget: activeTurnRuntime.getTarget,
|
|
getActiveGuestQueryId: activeTurnRuntime.getGuestQueryId,
|
|
});
|
|
const deliveryGenerationSeed = `${telegramInstanceId}:${Date.now()}`;
|
|
const deliveryLifecycleRuntime =
|
|
Delivery.createTelegramBridgeDeliveryLifecycleHooks({
|
|
generationSeed: deliveryGenerationSeed,
|
|
getTargetPolicyView: deliveryTargetPolicyRuntime.getTargetPolicyView,
|
|
getTransportStamp: telegramTransportStampRuntime.getStamp,
|
|
isTransportStampActive: telegramTransportStampRuntime.isActive,
|
|
getActiveTurnTarget: deliveryTargetPolicyRuntime.getActiveTurnTarget,
|
|
api: telegramApiRuntime,
|
|
recordOwnership: messageOwnershipRuntime.recordLocal,
|
|
recordFailure(operation, error, target) {
|
|
recordRuntimeEvent("delivery", error, {
|
|
operation,
|
|
scope: target?.threadId === undefined ? "aggregate" : "thread",
|
|
});
|
|
},
|
|
});
|
|
const activityRuntime = Activity.createTelegramActivityBridgeRuntime({
|
|
generation: deliveryGenerationSeed,
|
|
recordFailure(handlerId, event, error) {
|
|
recordRuntimeEvent("activity", error, {
|
|
handlerId,
|
|
eventType: event.type,
|
|
activityId: event.activityId,
|
|
});
|
|
},
|
|
});
|
|
const { sendTextReply, sendMarkdownReply } =
|
|
Outbound.createTelegramOutboundTextReplyRuntime({
|
|
sendTextReply: replyRuntime.sendTextReply,
|
|
sendMarkdownReply: replyRuntime.sendMarkdownReply,
|
|
execCommand: CommandTemplates.execCommandTemplate,
|
|
getHandlers: configStore.getOutboundHandlers,
|
|
recordRuntimeEvent,
|
|
});
|
|
const dispatchNextQueuedTelegramTurn =
|
|
Queue.createTelegramQueueDispatchRuntime({
|
|
...telegramQueueStore,
|
|
isCompactionInProgress: lifecycle.isCompactionInProgress,
|
|
hasActiveTurn: activeTurnRuntime.has,
|
|
hasDispatchPending: lifecycle.hasDispatchPending,
|
|
isIdle,
|
|
hasPendingMessages,
|
|
hasDispatchContext: deferredQueueDispatchRuntime.isBound,
|
|
isQueueItemTransportActive(item) {
|
|
return telegramTransportStampRuntime.isActive(item.transportStamp);
|
|
},
|
|
updateStatus,
|
|
sendTextReply,
|
|
recordRuntimeEvent,
|
|
...promptDispatchRuntime,
|
|
sendUserMessage,
|
|
}).dispatchNext;
|
|
const queueDispatchWatchdogRuntime =
|
|
Queue.createTelegramQueueDispatchWatchdogRuntime({
|
|
hasQueuedItems: telegramQueueStore.hasQueuedItems,
|
|
dispatchNextQueuedTelegramTurn,
|
|
recordRuntimeEvent,
|
|
});
|
|
const nativeMarkdownDraftSender =
|
|
TelegramApi.createTelegramAssistantDraftSender({
|
|
getAssistantRenderingMode: configControls.getAssistantRenderingMode,
|
|
renderMarkdownToHtmlDraft: Replies.renderTelegramMarkdownToHtmlDraft,
|
|
sendMessageDraft,
|
|
sendRichMessageDraft,
|
|
});
|
|
const previewRuntime = Preview.createTelegramAssistantPreviewRuntime({
|
|
getActiveTurn: activeTurnRuntime.get,
|
|
isAssistantMessage: Replies.isAssistantAgentMessage,
|
|
getMessageText: Replies.getAgentMessageText,
|
|
getDefaultReplyToMessageId: activeTurnRuntime.getReplyToMessageId,
|
|
sendDraft: nativeMarkdownDraftSender,
|
|
canSend: configControls.areDraftPreviewsEnabled,
|
|
sendMarkdownReply,
|
|
recordRuntimeEvent,
|
|
...replyTransport,
|
|
});
|
|
const { finalizeMarkdownPreview } =
|
|
Outbound.createTelegramOutboundTextPreviewRuntime({
|
|
finalizeMarkdownPreview: previewRuntime.finalizeMarkdown,
|
|
execCommand: CommandTemplates.execCommandTemplate,
|
|
getHandlers: configStore.getOutboundHandlers,
|
|
recordRuntimeEvent,
|
|
});
|
|
|
|
// --- Model And Menu Setup ---
|
|
|
|
const modelSwitchController =
|
|
Model.createTelegramModelSwitchControllerRuntime({
|
|
isIdle,
|
|
getPendingModelSwitch: pendingModelSwitchStore.get,
|
|
setPendingModelSwitch: pendingModelSwitchStore.set,
|
|
getActiveTurn: activeTurnRuntime.get,
|
|
getAbortHandler: abort.getHandler,
|
|
hasAbortHandler: abort.hasHandler,
|
|
getActiveToolExecutions: lifecycle.getActiveToolExecutions,
|
|
allocateItemOrder: queue.allocateItemOrder,
|
|
allocateControlOrder: queue.allocateControlOrder,
|
|
appendQueuedItem: queueMutationRuntime.append,
|
|
updateStatus,
|
|
});
|
|
const getQueueItemCount =
|
|
Queue.createTelegramQueueItemCountGetter(telegramQueueStore);
|
|
const getPromptTemplateCommands =
|
|
PromptTemplates.createTelegramPromptTemplateCommandGetter({
|
|
getCommands,
|
|
getReservedCommandNames: Commands.getTelegramReservedCommandNames,
|
|
});
|
|
const menuActions = Menu.createTelegramMenuActionRuntimeWithStateBuilder({
|
|
runtime: modelMenuRuntime,
|
|
createSettingsManager: Pi.createSettingsManager,
|
|
getActiveModel: currentModelRuntime.get,
|
|
getThinkingLevel,
|
|
getQueueItemCount,
|
|
buildStatusHtml: Commands.createTelegramAppMenuHtmlBuilder({
|
|
buildStatusHtml: Status.createTelegramStatusHtmlBuilder({
|
|
getActiveModel: currentModelRuntime.get,
|
|
isCompactionInProgress: lifecycle.isCompactionInProgress,
|
|
getBridgeStatusLineState: statusRuntime.getStatusState,
|
|
}),
|
|
getPromptTemplateCommands,
|
|
}),
|
|
storeModelMenuState: modelMenuRuntime.storeState,
|
|
isIdle,
|
|
canOfferInFlightModelSwitch: modelSwitchController.canOfferInFlightSwitch,
|
|
sendTextReply,
|
|
editInteractiveMessage,
|
|
sendInteractiveMessage,
|
|
sectionRegistry,
|
|
|
|
// Menu/status UI uses this to reflect whether the active Telegram turn expects voice delivery.
|
|
isVoiceReplyActive: function () {
|
|
const turn = activeTurnRuntime.get();
|
|
return Voice.isVoiceTurn(turn);
|
|
},
|
|
});
|
|
|
|
// --- Queue And Settings Menus ---
|
|
|
|
const getQueueMenuState = Menu.createTelegramModelMenuStateBuilder({
|
|
runtime: modelMenuRuntime,
|
|
createSettingsManager: Pi.createSettingsManager,
|
|
getActiveModel: currentModelRuntime.get,
|
|
});
|
|
const queueMenuRuntime = MenuQueue.createTelegramQueueMenuRuntime({
|
|
telegramQueueStore,
|
|
queueMutationRuntime,
|
|
sendInteractiveMessage,
|
|
editInteractiveMessage,
|
|
answerCallbackQuery,
|
|
getModelMenuState: getQueueMenuState,
|
|
getStoredModelMenuState: modelMenuRuntime.getState,
|
|
storeModelMenuState: modelMenuRuntime.storeState,
|
|
updateStatusMessage: menuActions.updateStatusMessage,
|
|
updateStatus,
|
|
});
|
|
const settingsMenuRuntime = MenuSettings.createTelegramSettingsMenuRuntime(
|
|
{
|
|
getModelMenuState: getQueueMenuState,
|
|
getStoredModelMenuState: modelMenuRuntime.getState,
|
|
storeModelMenuState: modelMenuRuntime.storeState,
|
|
editInteractiveMessage,
|
|
sendInteractiveMessage,
|
|
answerCallbackQuery,
|
|
...configControls,
|
|
},
|
|
sectionRegistry,
|
|
);
|
|
|
|
// --- Polling ---
|
|
|
|
const foreignOwnedUpdateForwarder =
|
|
telegramBusFollowerClients.foreignOwnedUpdateForwarder;
|
|
const followerTargetController = telegramBusFollowerClients.targetController;
|
|
const restoreFollowerThreadTarget =
|
|
Bus.createTelegramBusFollowerThreadRestoreHandler({
|
|
followerRegistry: telegramBusFollowerRegistry,
|
|
followerTargetController,
|
|
onRestored() {
|
|
telegramSyncStateRuntime.markSliceFresh("target-bindings", {
|
|
nowMs: Date.now(),
|
|
action: "follower-thread-restore",
|
|
});
|
|
},
|
|
});
|
|
const observedThreadTargetBinding =
|
|
Polling.createTelegramThreadTargetObservationBinding<Pi.ExtensionContext>();
|
|
const topicLifecycleSync =
|
|
Sync.createTelegramObservedTopicLifecycleSyncHandler({
|
|
topicTargetStore: threadStore,
|
|
isBusEnabled: isTelegramBusRuntimeEnabled,
|
|
callApi: callTelegramApi,
|
|
isTopicProvisioningActive: telegramProvisioningActivity.isActive,
|
|
getCurrentLeaderEpoch,
|
|
getThreadReconciliationMachineState() {
|
|
return threadReconciliationRuntime.getState();
|
|
},
|
|
recordThreadReconciliationPlan,
|
|
getSyncState: telegramSyncStateRuntime.getState,
|
|
setSyncState: telegramSyncStateRuntime.setState,
|
|
recordEvent: recordRuntimeEvent,
|
|
});
|
|
const inboundBusProjectionRuntime =
|
|
Routing.createTelegramInboundBusProjectionRuntime({
|
|
instanceId: telegramInstanceId,
|
|
listFollowers: telegramBusFollowerRegistry.list,
|
|
listThreadRecords: threadStore.list,
|
|
getLeaderTarget: telegramBusLeaderState.getTarget,
|
|
isFollowerRegistered: telegramBusFollowerRegistrationState.isRegistered,
|
|
getFollowerTarget: telegramBusFollowerRegistrationState.getTarget,
|
|
getCurrentIdentity: getCurrentInstanceThreadIdentity,
|
|
});
|
|
const inboundRouteRuntime = Routing.createTelegramInboundRouteRuntime({
|
|
configStore,
|
|
callApi: callTelegramApi,
|
|
getCurrentInstanceId() {
|
|
return telegramInstanceId;
|
|
},
|
|
getMessageOwnership: messageOwnershipRuntime.store.get,
|
|
recordMessageOwnership: messageOwnershipRuntime.recordRouted,
|
|
...inboundBusProjectionRuntime,
|
|
getCurrentLeaderEpoch,
|
|
getThreadReconciliationMachineState() {
|
|
return threadReconciliationRuntime.getState();
|
|
},
|
|
recordThreadReconciliationPlan,
|
|
handleTelegramTopicLifecycleUpdate: topicLifecycleSync,
|
|
handleTelegramThreadTargetObserved(_target, ctx) {
|
|
return observedThreadTargetBinding.handle(ctx);
|
|
},
|
|
foreignOwnedUpdateForwarder,
|
|
replaceFollowerThreadTarget: restoreFollowerThreadTarget,
|
|
bridgeRuntime,
|
|
activeTurnRuntime,
|
|
mediaGroupRuntime,
|
|
textGroupRuntime,
|
|
telegramQueueStore,
|
|
queueMutationRuntime,
|
|
modelMenuRuntime,
|
|
currentModelRuntime,
|
|
modelSwitchController,
|
|
menuActions,
|
|
updateSettingsMenuMessage: settingsMenuRuntime.updateSettingsMenuMessage,
|
|
openQueueMenu: queueMenuRuntime.openQueueMenu,
|
|
queueMenuCallbackHandler: queueMenuRuntime.handleCallbackQuery,
|
|
openSettingsMenu: settingsMenuRuntime.openSettingsMenu,
|
|
settingsMenuCallbackHandler: settingsMenuRuntime.handleCallbackQuery,
|
|
sectionRegistry,
|
|
buttonActionStore,
|
|
inboundHandlerRuntime,
|
|
threadStore,
|
|
updateStatus,
|
|
dispatchNextQueuedTelegramTurn,
|
|
requestDeferredDispatchNextQueuedTelegramTurn:
|
|
deferredQueueDispatchRuntime.request,
|
|
hasDeferredDispatchContext: deferredQueueDispatchRuntime.isBound,
|
|
startTypingLoop: promptDispatchRuntime.startTypingLoop,
|
|
stopTypingLoop: typing.stop,
|
|
answerCallbackQuery,
|
|
editInteractiveMessage,
|
|
sendInteractiveMessage,
|
|
deleteMessage: deleteTelegramMessage,
|
|
answerGuestQuery,
|
|
sendTextReply,
|
|
setMyCommands,
|
|
getCommands,
|
|
downloadFile: downloadTelegramBridgeFile,
|
|
resolveTimeLine: timeInjectionRuntime.resolveLine,
|
|
getThinkingLevel,
|
|
setThinkingLevel,
|
|
persistScopedModelPatterns: Pi.createScopedModelPatternPersister({
|
|
createSettingsManager: Pi.createSettingsManager,
|
|
clearCachedModelMenuInputs: modelMenuRuntime.clearCachedInputs,
|
|
}),
|
|
setModel,
|
|
sendUserMessage,
|
|
isIdle,
|
|
hasPendingMessages,
|
|
compact,
|
|
recordRuntimeEvent,
|
|
});
|
|
const promoteTelegramBusFollowerToLeader: BusFollower.TelegramBusFollowerPromotionHandler<Pi.ExtensionContext> =
|
|
BusFollower.createTelegramBusFollowerPromotionHandler<Pi.ExtensionContext>({
|
|
topicTargetStore: threadStore,
|
|
instanceId: telegramInstanceId,
|
|
getActiveProfileName: getActiveTelegramThreadProfile,
|
|
async startLeader(ctx, election, onAcquired): Promise<boolean> {
|
|
const result = await lockedPollingRuntime.start(ctx, {
|
|
election,
|
|
onAcquired,
|
|
});
|
|
return result.ok;
|
|
},
|
|
recordRuntimeEvent,
|
|
});
|
|
const forwardedRouteHandlers =
|
|
BusFollower.createTelegramBusForwardedRouteHandlers<
|
|
Pi.ExtensionContext,
|
|
Updates.TelegramMessageReactionUpdated,
|
|
Routing.TelegramRoutedCallbackQuery,
|
|
Routing.TelegramRoutedMessage
|
|
>({
|
|
handleUpdate: inboundRouteRuntime.handleUpdate,
|
|
handleAuthorizedReactionUpdate:
|
|
inboundRouteRuntime.handleAuthorizedReactionUpdate,
|
|
});
|
|
const telegramBusFollowerAssembly: BusFollower.TelegramBusFollowerRuntimeAssembly<Pi.ExtensionContext> =
|
|
BusFollower.createTelegramBusFollowerRuntimeAssembly<
|
|
Pi.ExtensionContext,
|
|
Updates.TelegramMessageReactionUpdated,
|
|
Routing.TelegramRoutedCallbackQuery,
|
|
Routing.TelegramRoutedMessage
|
|
>({
|
|
receiver: {
|
|
socketPath: getTelegramBusFollowerSocketPath,
|
|
instanceId: telegramInstanceId,
|
|
getContext() {
|
|
return telegramSessionContextStore.get();
|
|
},
|
|
getAuthSecret() {
|
|
return telegramActiveBusAuthSecret;
|
|
},
|
|
...forwardedRouteHandlers,
|
|
recordRuntimeEvent,
|
|
},
|
|
targetReplacement: {
|
|
topicTargetStore: threadStore,
|
|
registrationState: telegramBusFollowerRegistrationState,
|
|
instanceId: telegramInstanceId,
|
|
getManualFollowerProfileKey: getTelegramManualFollowerProfileKey,
|
|
manualFollowerOwnerId: telegramManualFollowerOwnerId,
|
|
getSyncState: telegramSyncStateRuntime.getState,
|
|
setSyncState: telegramSyncStateRuntime.setState,
|
|
updateStatus,
|
|
recordRuntimeEvent,
|
|
},
|
|
recovery: {
|
|
registrationState: telegramBusFollowerRegistrationState,
|
|
getLeaderState() {
|
|
return lockRuntime.getState();
|
|
},
|
|
setLifecyclePhase(phase) {
|
|
telegramBusLifecycleOverridePhase = phase;
|
|
},
|
|
updateStatus,
|
|
promoteToLeader: promoteTelegramBusFollowerToLeader,
|
|
getActiveContext() {
|
|
return telegramSessionContextStore.get();
|
|
},
|
|
recordRuntimeEvent,
|
|
},
|
|
registration: {
|
|
instanceId: telegramInstanceId,
|
|
getFollowerBusSocketPath: getTelegramBusFollowerSocketPath,
|
|
getLeaderSocketPath: getTelegramBusSocketPath,
|
|
registrationState: telegramBusFollowerRegistrationState,
|
|
isContextActive(ctx) {
|
|
return telegramSessionContextStore.isCurrent(ctx);
|
|
},
|
|
createRequestId: telegramBusFollowerClients.createRequestId,
|
|
getLeaderAuthSecret(owner) {
|
|
return owner.busSecret;
|
|
},
|
|
setActiveAuthSecret(secret) {
|
|
telegramActiveBusAuthSecret = secret;
|
|
},
|
|
getThreadName() {
|
|
return undefined;
|
|
},
|
|
getProfileKey() {
|
|
return getTelegramManualFollowerProfileKey();
|
|
},
|
|
recordRuntimeEvent,
|
|
},
|
|
});
|
|
const telegramBusFollowerRegistration =
|
|
telegramBusFollowerAssembly.registration;
|
|
const pollingRuntime = Polling.createTelegramPollingControllerRuntime({
|
|
state: pollingControllerState,
|
|
getConfig: configStore.get,
|
|
hasBotToken: configStore.hasBotToken,
|
|
deleteWebhook,
|
|
getUpdates,
|
|
persistConfig: persistTelegramConfigWithSync,
|
|
handleUpdate: Updates.createTelegramUpdateHandle({
|
|
defaultHandle: inboundRouteRuntime.handleUpdate,
|
|
}),
|
|
stopTypingLoop: typing.stop,
|
|
updateStatus,
|
|
recordRuntimeEvent,
|
|
});
|
|
const recoverStaleTelegramTopicApiError = function (
|
|
apiBody: unknown,
|
|
error: unknown,
|
|
) {
|
|
return Sync.recoverStaleTelegramTopicApiError(apiBody, error, {
|
|
topicTargetStore: threadStore,
|
|
getSyncState: telegramSyncStateRuntime.getState,
|
|
setSyncState: telegramSyncStateRuntime.setState,
|
|
recordEvent: recordRuntimeEvent,
|
|
});
|
|
};
|
|
const authorizeFollowerApiCall = Bus.createTelegramFollowerApiCallAuthorizer({
|
|
isMessageOwned: messageOwnershipRuntime.isOwnedByFollower,
|
|
});
|
|
const telegramBusLeaderRuntime =
|
|
BusLeader.createTelegramBusLeaderRuntimeAssembly<Pi.ExtensionContext>({
|
|
runtime: {
|
|
socketPath: getTelegramBusSocketPath,
|
|
commitEndpointPublication(commit) {
|
|
return lockRuntime.commitIfOwned(commit);
|
|
},
|
|
followerRegistry: telegramBusFollowerRegistry,
|
|
authSecret: telegramBusAuthSecret,
|
|
startPolling: pollingRuntime.start,
|
|
stopPolling: pollingRuntime.stop,
|
|
authorizeFollowerApiCall,
|
|
recordFollowerMessageOwnership(record) {
|
|
messageOwnershipRuntime.recordFollower(record);
|
|
},
|
|
},
|
|
getAllowedUserId: configStore.getAllowedUserId,
|
|
instanceId: telegramInstanceId,
|
|
getCwd(ctx) {
|
|
return typeof ctx.cwd === "string" ? ctx.cwd : undefined;
|
|
},
|
|
getTelegramProfile: getActiveTelegramThreadProfile,
|
|
shouldForceFreshUnnamed:
|
|
telegramThreadCapabilityState.shouldForceFreshLeaderThread,
|
|
topicTargetStore: threadStore,
|
|
callApi(method, body) {
|
|
return directTelegramApiRuntime.call(method, body);
|
|
},
|
|
callMultipart: directTelegramApiRuntime.callMultipart,
|
|
downloadFile: directTelegramApiRuntime.downloadFile,
|
|
recoverStaleTargetError: recoverStaleTelegramTopicApiError,
|
|
getCurrentLeaderEpoch,
|
|
getThreadReconciliationMachineState() {
|
|
return threadReconciliationRuntime.getState();
|
|
},
|
|
recordThreadReconciliationPlan,
|
|
getSyncState: telegramSyncStateRuntime.getState,
|
|
setSyncState: telegramSyncStateRuntime.setState,
|
|
setLeaderTarget: telegramBusLeaderState.set,
|
|
onProvisioningStart: telegramProvisioningActivity.start,
|
|
onProvisioningEnd: telegramProvisioningActivity.end,
|
|
recordRuntimeEvent,
|
|
});
|
|
const telegramLeaderHealthRuntime = Sync.createTelegramLeaderHealthRuntime({
|
|
callGetMe() {
|
|
return directTelegramApiRuntime.call("getMe", {});
|
|
},
|
|
getSyncState: telegramSyncStateRuntime.getState,
|
|
setSyncState: telegramSyncStateRuntime.setState,
|
|
recordEvent: recordRuntimeEvent,
|
|
});
|
|
const telegramThreadCapabilityRuntime =
|
|
Polling.createTelegramThreadCapabilityOrchestration<
|
|
Pi.ExtensionContext,
|
|
Locks.TelegramLockEntry
|
|
>({
|
|
state: telegramThreadCapabilityState,
|
|
getAllowedUserId: configStore.getAllowedUserId,
|
|
callApi: callTelegramApi,
|
|
topicTargetStore: threadStore,
|
|
isBusConfigured: isTelegramBusConfigured,
|
|
isBusRuntimeEnabled: isTelegramBusRuntimeEnabled,
|
|
ownsLock: lockRuntime.owns,
|
|
startClassicPolling: pollingRuntime.start,
|
|
stopClassicPolling: pollingRuntime.stop,
|
|
startBusLeaderPolling: telegramBusLeaderRuntime.startPolling,
|
|
stopBusLeaderPolling: telegramBusLeaderRuntime.stopPolling,
|
|
startLeaderHealth: telegramLeaderHealthRuntime.start,
|
|
stopLeaderHealth: telegramLeaderHealthRuntime.stop,
|
|
registerFollowerWithLeader:
|
|
telegramBusFollowerRegistration.registerWithLeader,
|
|
stopFollowerRegistration: telegramBusFollowerRegistration.stop,
|
|
isTopicModeUnavailableError: Threads.isTelegramTopicModeUnavailableError,
|
|
updateStatus,
|
|
recordEvent: recordRuntimeEvent,
|
|
});
|
|
const telegramThreadCapabilityMonitor =
|
|
telegramThreadCapabilityRuntime.monitor;
|
|
observedThreadTargetBinding.set(
|
|
telegramThreadCapabilityRuntime.observeTarget,
|
|
);
|
|
const threadAwarePollingPorts = telegramThreadCapabilityRuntime.pollingPorts;
|
|
const lockedPollingRuntime = Locks.createTelegramLockedPollingRuntime({
|
|
lock: lockRuntime,
|
|
hasBotToken: configStore.hasBotToken,
|
|
canStartPolling: Pi.canStartPollingInExtensionContext,
|
|
formatStartBlockedMessage: Pi.formatPollingStartBlockedByRunMode,
|
|
startPolling: threadAwarePollingPorts.startPolling,
|
|
stopPolling: threadAwarePollingPorts.stopPolling,
|
|
registerFollowerWithOwner:
|
|
threadAwarePollingPorts.registerFollowerWithOwner,
|
|
stopFollowerRegistration: threadAwarePollingPorts.stopFollowerRegistration,
|
|
updateStatus,
|
|
recordRuntimeEvent,
|
|
});
|
|
const disconnectTelegramAndDeleteCurrentThread =
|
|
Sync.createTelegramManualThreadDisconnectHandler({
|
|
instanceId: telegramInstanceId,
|
|
getCurrentThreadRecord: findCurrentThreadRecord,
|
|
topicTargetStore: threadStore,
|
|
callApi: callTelegramApi,
|
|
getCurrentLeaderEpoch,
|
|
getLeaderTarget: telegramBusLeaderState.getTarget,
|
|
clearLeaderTarget: telegramBusLeaderState.clear,
|
|
getSyncState: telegramSyncStateRuntime.getState,
|
|
setSyncState: telegramSyncStateRuntime.setState,
|
|
stopPolling: lockedPollingRuntime.stop,
|
|
recordRuntimeEvent,
|
|
});
|
|
const sessionLifecycleRuntime =
|
|
Lifecycle.createTelegramBridgeSessionLifecycleAssembly({
|
|
contextStore: telegramSessionContextStore,
|
|
queue: {
|
|
getCurrentModel: getContextModel,
|
|
loadConfig: configStore.load,
|
|
setQueuedItems: telegramQueueStore.setQueuedItems,
|
|
setCurrentModel: currentModelRuntime.set,
|
|
setPendingModelSwitch: pendingModelSwitchStore.set,
|
|
syncCounters: queue.syncCounters,
|
|
syncFlags: lifecycle.syncFlags,
|
|
bindDeferredDispatchContext: deferredQueueDispatchRuntime.bind,
|
|
prepareTempDir,
|
|
updateStatus,
|
|
unbindDeferredDispatchContext: deferredQueueDispatchRuntime.unbind,
|
|
clearModelMenuState: modelMenuRuntime.clear,
|
|
getActiveTurnChatId: activeTurnRuntime.getChatId,
|
|
getActiveTurnTarget: activeTurnRuntime.getTarget,
|
|
clearPreview: previewRuntime.clear,
|
|
clearActiveTurn: activeTurnRuntime.clear,
|
|
clearAbort: abort.clearHandler,
|
|
recordRuntimeEvent,
|
|
},
|
|
follower: {
|
|
registrationState: telegramBusFollowerRegistrationState,
|
|
registrationRuntime: telegramBusFollowerRegistration,
|
|
instanceId: telegramInstanceId,
|
|
suspendPolling: lockedPollingRuntime.suspend,
|
|
getLeaderState: lockRuntime.getState,
|
|
updateStatus,
|
|
recordRuntimeEvent,
|
|
},
|
|
services: {
|
|
resumeGroupedInput(ctx) {
|
|
mediaGroupRuntime.resume(ctx);
|
|
textGroupRuntime.resume(ctx);
|
|
},
|
|
suspendGroupedInput: TextGroups.createTelegramGroupedInputClearer({
|
|
clearMediaGroups: mediaGroupRuntime.suspend,
|
|
clearTextGroups: textGroupRuntime.suspend,
|
|
}),
|
|
delivery: deliveryLifecycleRuntime,
|
|
polling: lockedPollingRuntime,
|
|
capabilityMonitor: telegramThreadCapabilityMonitor,
|
|
queueWatchdog: queueDispatchWatchdogRuntime,
|
|
},
|
|
});
|
|
|
|
// --- Extension API Bindings ---
|
|
|
|
Bindings.registerTelegramCommandsAndTools({
|
|
pi,
|
|
configStore,
|
|
persistConfig: persistTelegramConfigWithSync,
|
|
setup,
|
|
activeTurnRuntime,
|
|
lockedPollingRuntime,
|
|
stopPolling: disconnectTelegramAndDeleteCurrentThread,
|
|
onTransportChanged: deliveryLifecycleRuntime.onSessionStart,
|
|
getStatusLines,
|
|
buttonActionStore,
|
|
sendMarkdownReply,
|
|
callMultipart,
|
|
getDefaultChatId: proactivePushChatIdGetter,
|
|
getDefaultTarget: proactivePushTargetGetter,
|
|
canSendDirect() {
|
|
return (
|
|
ownsTelegramDirectDelivery() ||
|
|
telegramBusFollowerRegistrationState.isRegistered()
|
|
);
|
|
},
|
|
updateStatus,
|
|
recordRuntimeEvent,
|
|
});
|
|
|
|
// --- Lifecycle Hooks ---
|
|
|
|
Bindings.registerTelegramLifecycleRuntimeHooks({
|
|
pi,
|
|
sessionLifecycleRuntime: {
|
|
...sessionLifecycleRuntime,
|
|
onModelSelect: currentModelRuntime.onModelSelect,
|
|
},
|
|
activityRuntime,
|
|
configStore,
|
|
abort,
|
|
typing,
|
|
lifecycle,
|
|
activeTurnRuntime,
|
|
telegramQueueStore,
|
|
modelSwitchController,
|
|
previewRuntime,
|
|
promptDispatchRuntime,
|
|
deferredQueueDispatchRuntime,
|
|
lockOwnershipGuard,
|
|
buttonActionStore,
|
|
callMultipart,
|
|
sendChatAction,
|
|
sendRecordVoiceAction,
|
|
sendMarkdownReply,
|
|
sendTextReply,
|
|
dispatchNextQueuedTelegramTurn,
|
|
answerGuestQuery,
|
|
deleteMessage: deleteTelegramMessage,
|
|
sendGuestReply,
|
|
finalizeMarkdownPreview,
|
|
proactivePushChatIdGetter,
|
|
proactivePushTargetGetter,
|
|
isProactivePushEnabled: configControls.isProactivePushEnabled,
|
|
canSendProactivePush(ctx) {
|
|
return (
|
|
lockOwnershipGuard.ownsContext(ctx) ||
|
|
telegramBusFollowerRegistrationState.isRegistered()
|
|
);
|
|
},
|
|
canSendAgentActivity(ctx) {
|
|
return (
|
|
lockOwnershipGuard.ownsContext(ctx) ||
|
|
telegramBusFollowerRegistrationState.isRegistered()
|
|
);
|
|
},
|
|
isSessionContextActive(ctx) {
|
|
return telegramSessionContextStore.isCurrent(ctx);
|
|
},
|
|
isTurnTransportActive(turn) {
|
|
return telegramTransportStampRuntime.isActive(turn.transportStamp);
|
|
},
|
|
updateStatus,
|
|
recordRuntimeEvent,
|
|
});
|
|
}
|