@llblab/pi-telegram 0.20.1 → 0.20.3
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 +5 -3
- package/BACKLOG.md +1 -1
- package/CHANGELOG.md +24 -0
- package/README.md +3 -2
- package/docs/architecture.md +5 -5
- package/docs/multi-instance-bus.md +22 -21
- package/index.ts +133 -219
- package/lib/bindings.ts +55 -14
- package/lib/bus-follower.ts +161 -32
- package/lib/bus-leader.ts +213 -42
- package/lib/bus.ts +34 -0
- package/lib/paths.ts +11 -0
- package/lib/prompts.ts +19 -7
- package/lib/setup.ts +27 -10
- package/lib/status.ts +9 -2
- package/lib/threads.ts +64 -26
- package/lib/turns.ts +0 -2
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -57,41 +57,31 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
57
57
|
setThinkingLevel,
|
|
58
58
|
} = piRuntime;
|
|
59
59
|
const bridgeRuntime = Runtime.createTelegramBridgeRuntime();
|
|
60
|
-
const telegramInstanceId = `${process.pid}:${Date.now()}`;
|
|
61
|
-
// Manual follower identity must survive a Pi process reload in the same
|
|
62
|
-
// terminal. The process id changes on reload, but the parent shell/terminal id
|
|
63
|
-
// is stable enough to keep the follower bound to its existing Telegram thread.
|
|
64
|
-
const telegramManualFollowerOwnerId = String(process.ppid || process.pid);
|
|
65
60
|
const getActiveTelegramThreadProfile = function (): string | undefined {
|
|
66
61
|
return configStore.getActiveProfileName();
|
|
67
62
|
};
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
const busProcessRuntime = Bus.createTelegramBusProcessRuntime({
|
|
64
|
+
getActiveProfileName: getActiveTelegramThreadProfile,
|
|
65
|
+
pid: process.pid,
|
|
66
|
+
parentPid: process.ppid,
|
|
67
|
+
createdAtMs: Date.now(),
|
|
68
|
+
});
|
|
69
|
+
const {
|
|
70
|
+
instanceId: telegramInstanceId,
|
|
71
|
+
manualFollowerOwnerId: telegramManualFollowerOwnerId,
|
|
72
|
+
getLeaderSocketPath: getTelegramBusSocketPath,
|
|
73
|
+
getFollowerSocketPath: getTelegramBusFollowerSocketPath,
|
|
74
|
+
} = busProcessRuntime;
|
|
75
|
+
const getTelegramManualFollowerProfileKey =
|
|
76
|
+
BusFollower.createTelegramManualFollowerProfileKeyResolver({
|
|
77
|
+
getActiveProfileName: getActiveTelegramThreadProfile,
|
|
78
|
+
manualFollowerOwnerId: telegramManualFollowerOwnerId,
|
|
73
79
|
});
|
|
74
|
-
};
|
|
75
80
|
const telegramBusAuthSecret = Bus.createTelegramBusAuthSecret();
|
|
76
81
|
let telegramActiveBusAuthSecret: string | undefined;
|
|
77
82
|
let telegramBusLifecycleOverridePhase:
|
|
78
83
|
| Status.TelegramBridgeBusLifecyclePhase
|
|
79
84
|
| undefined;
|
|
80
|
-
const getTelegramBusSocketPath = function (): string {
|
|
81
|
-
return Bus.getTelegramBusSocketPath(
|
|
82
|
-
undefined,
|
|
83
|
-
undefined,
|
|
84
|
-
getActiveTelegramThreadProfile(),
|
|
85
|
-
);
|
|
86
|
-
};
|
|
87
|
-
const getTelegramBusFollowerSocketPath = function (): string {
|
|
88
|
-
return Bus.getTelegramBusFollowerSocketPath(
|
|
89
|
-
telegramInstanceId,
|
|
90
|
-
undefined,
|
|
91
|
-
undefined,
|
|
92
|
-
getActiveTelegramThreadProfile(),
|
|
93
|
-
);
|
|
94
|
-
};
|
|
95
85
|
let telegramBusRequestSequence = 0;
|
|
96
86
|
const telegramBusFollowerRegistry = Bus.createTelegramBusFollowerRegistry();
|
|
97
87
|
const telegramBusFollowerRegistrationState =
|
|
@@ -817,68 +807,72 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
817
807
|
compact,
|
|
818
808
|
recordRuntimeEvent,
|
|
819
809
|
});
|
|
820
|
-
const
|
|
821
|
-
BusFollower.
|
|
810
|
+
const promoteTelegramBusFollowerToLeader: BusFollower.TelegramBusFollowerPromotionHandler<Pi.ExtensionContext> =
|
|
811
|
+
BusFollower.createTelegramBusFollowerPromotionHandler<Pi.ExtensionContext>({
|
|
812
|
+
topicTargetStore: threadStore,
|
|
813
|
+
instanceId: telegramInstanceId,
|
|
814
|
+
getActiveProfileName: getActiveTelegramThreadProfile,
|
|
815
|
+
async startLeader(ctx): Promise<void> {
|
|
816
|
+
await lockedPollingRuntime.start(ctx, { force: true });
|
|
817
|
+
},
|
|
818
|
+
recordRuntimeEvent,
|
|
819
|
+
});
|
|
820
|
+
const telegramBusFollowerAssembly: BusFollower.TelegramBusFollowerRuntimeAssembly<Pi.ExtensionContext> =
|
|
821
|
+
BusFollower.createTelegramBusFollowerRuntimeAssembly<
|
|
822
822
|
Pi.ExtensionContext,
|
|
823
823
|
Updates.TelegramMessageReactionUpdated,
|
|
824
824
|
Routing.TelegramRoutedCallbackQuery,
|
|
825
825
|
Routing.TelegramRoutedMessage
|
|
826
826
|
>({
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
827
|
+
receiver: {
|
|
828
|
+
socketPath: getTelegramBusFollowerSocketPath,
|
|
829
|
+
instanceId: telegramInstanceId,
|
|
830
|
+
getContext() {
|
|
831
|
+
return telegramSessionContextStore.get();
|
|
832
|
+
},
|
|
833
|
+
getAuthSecret() {
|
|
834
|
+
return telegramActiveBusAuthSecret;
|
|
835
|
+
},
|
|
836
|
+
handleForwardedCallback(query, ctx) {
|
|
837
|
+
return inboundRouteRuntime.handleUpdate({ callback_query: query }, ctx);
|
|
838
|
+
},
|
|
839
|
+
handleForwardedReaction(reactionUpdate, ctx) {
|
|
840
|
+
return inboundRouteRuntime.handleAuthorizedReactionUpdate(
|
|
841
|
+
reactionUpdate,
|
|
842
|
+
ctx,
|
|
843
|
+
);
|
|
844
|
+
},
|
|
845
|
+
handleForwardedMessage(message, ctx) {
|
|
846
|
+
return inboundRouteRuntime.handleUpdate(
|
|
847
|
+
{ message: message as never },
|
|
848
|
+
ctx,
|
|
849
|
+
);
|
|
850
|
+
},
|
|
851
|
+
async handleForwardedEditedMessage(message, ctx) {
|
|
852
|
+
return inboundRouteRuntime.handleUpdate(
|
|
853
|
+
{ edited_message: message as never },
|
|
854
|
+
ctx,
|
|
855
|
+
);
|
|
856
|
+
},
|
|
857
|
+
recordRuntimeEvent,
|
|
855
858
|
},
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
topicTargetStore: threadStore,
|
|
859
|
-
registrationState: telegramBusFollowerRegistrationState,
|
|
860
|
-
instanceId: telegramInstanceId,
|
|
861
|
-
manualFollowerProfileKey: getTelegramManualFollowerProfileKey(),
|
|
862
|
-
manualFollowerOwnerId: telegramManualFollowerOwnerId,
|
|
863
|
-
getSyncState() {
|
|
864
|
-
return telegramSyncState;
|
|
865
|
-
},
|
|
866
|
-
setSyncState(state) {
|
|
867
|
-
telegramSyncState = state;
|
|
868
|
-
},
|
|
869
|
-
updateStatus,
|
|
870
|
-
recordRuntimeEvent,
|
|
871
|
-
}),
|
|
872
|
-
recordRuntimeEvent,
|
|
873
|
-
});
|
|
874
|
-
let telegramBusFollowerRegistration: BusFollower.TelegramBusFollowerRegistrationRuntime<Pi.ExtensionContext>;
|
|
875
|
-
const telegramFollowerHeartbeatRecovery =
|
|
876
|
-
BusFollower.createTelegramBusFollowerHeartbeatRecoveryHandler<Pi.ExtensionContext>(
|
|
877
|
-
{
|
|
859
|
+
targetReplacement: {
|
|
860
|
+
topicTargetStore: threadStore,
|
|
878
861
|
registrationState: telegramBusFollowerRegistrationState,
|
|
879
|
-
|
|
880
|
-
|
|
862
|
+
instanceId: telegramInstanceId,
|
|
863
|
+
getManualFollowerProfileKey: getTelegramManualFollowerProfileKey,
|
|
864
|
+
manualFollowerOwnerId: telegramManualFollowerOwnerId,
|
|
865
|
+
getSyncState() {
|
|
866
|
+
return telegramSyncState;
|
|
867
|
+
},
|
|
868
|
+
setSyncState(state) {
|
|
869
|
+
telegramSyncState = state;
|
|
881
870
|
},
|
|
871
|
+
updateStatus,
|
|
872
|
+
recordRuntimeEvent,
|
|
873
|
+
},
|
|
874
|
+
recovery: {
|
|
875
|
+
registrationState: telegramBusFollowerRegistrationState,
|
|
882
876
|
getLeaderState() {
|
|
883
877
|
return lockRuntime.getState();
|
|
884
878
|
},
|
|
@@ -886,47 +880,17 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
886
880
|
telegramBusLifecycleOverridePhase = phase;
|
|
887
881
|
},
|
|
888
882
|
updateStatus,
|
|
889
|
-
|
|
890
|
-
const promotedRecord =
|
|
891
|
-
await Threads.promoteTelegramFollowerBindingToLeader({
|
|
892
|
-
store: threadStore,
|
|
893
|
-
instanceId: telegramInstanceId,
|
|
894
|
-
cwd: ctx.cwd,
|
|
895
|
-
telegramProfile: getActiveTelegramThreadProfile(),
|
|
896
|
-
target: binding.target,
|
|
897
|
-
slot: binding.slot,
|
|
898
|
-
threadName: binding.threadName,
|
|
899
|
-
});
|
|
900
|
-
if (promotedRecord) {
|
|
901
|
-
recordRuntimeEvent(
|
|
902
|
-
"bus",
|
|
903
|
-
"Follower thread binding promoted to leader",
|
|
904
|
-
{
|
|
905
|
-
phase: "follower-promoted-binding",
|
|
906
|
-
chatId: promotedRecord.target.chatId,
|
|
907
|
-
threadId: promotedRecord.target.threadId,
|
|
908
|
-
slot: promotedRecord.slot,
|
|
909
|
-
threadName: promotedRecord.threadName,
|
|
910
|
-
},
|
|
911
|
-
);
|
|
912
|
-
}
|
|
913
|
-
await lockedPollingRuntime.start(ctx, { force: true });
|
|
914
|
-
},
|
|
883
|
+
promoteToLeader: promoteTelegramBusFollowerToLeader,
|
|
915
884
|
sleep(ms) {
|
|
916
885
|
return Polling.sleepTelegramPollingRetry(ms);
|
|
917
886
|
},
|
|
918
887
|
promotionGraceMs: BusFollower.TELEGRAM_BUS_FOLLOWER_PROMOTION_GRACE_MS,
|
|
919
888
|
recordRuntimeEvent,
|
|
920
889
|
},
|
|
921
|
-
|
|
922
|
-
telegramBusFollowerRegistration =
|
|
923
|
-
BusFollower.createTelegramBusFollowerRegistrationRuntime<Pi.ExtensionContext>(
|
|
924
|
-
{
|
|
890
|
+
registration: {
|
|
925
891
|
instanceId: telegramInstanceId,
|
|
926
892
|
getFollowerBusSocketPath: getTelegramBusFollowerSocketPath,
|
|
927
893
|
getLeaderSocketPath: getTelegramBusSocketPath,
|
|
928
|
-
startReceiving: telegramBusForwardedUpdateReceiver.start,
|
|
929
|
-
stopReceiving: telegramBusForwardedUpdateReceiver.stop,
|
|
930
894
|
registrationState: telegramBusFollowerRegistrationState,
|
|
931
895
|
createRequestId() {
|
|
932
896
|
telegramBusRequestSequence += 1;
|
|
@@ -947,10 +911,11 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
947
911
|
getProfileKey() {
|
|
948
912
|
return getTelegramManualFollowerProfileKey();
|
|
949
913
|
},
|
|
950
|
-
onHeartbeatFailure: telegramFollowerHeartbeatRecovery,
|
|
951
914
|
recordRuntimeEvent,
|
|
952
915
|
},
|
|
953
|
-
);
|
|
916
|
+
});
|
|
917
|
+
const telegramBusFollowerRegistration =
|
|
918
|
+
telegramBusFollowerAssembly.registration;
|
|
954
919
|
const pollingRuntime = Polling.createTelegramPollingControllerRuntime({
|
|
955
920
|
state: pollingControllerState,
|
|
956
921
|
getConfig: configStore.get,
|
|
@@ -980,116 +945,67 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
980
945
|
recordEvent: recordRuntimeEvent,
|
|
981
946
|
});
|
|
982
947
|
};
|
|
983
|
-
const telegramBusLeaderRuntime =
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
BusLeader.createTelegramBusLeaderTargetProvisioner<Pi.ExtensionContext>({
|
|
1000
|
-
getAllowedUserId: configStore.getAllowedUserId,
|
|
1001
|
-
instanceId: telegramInstanceId,
|
|
1002
|
-
getCwd(ctx) {
|
|
1003
|
-
return typeof ctx.cwd === "string" ? ctx.cwd : undefined;
|
|
1004
|
-
},
|
|
1005
|
-
getTelegramProfile: getActiveTelegramThreadProfile,
|
|
1006
|
-
shouldForceFreshUnnamed() {
|
|
1007
|
-
return forceFreshLeaderThreadOnNextStart;
|
|
1008
|
-
},
|
|
1009
|
-
topicTargetStore: threadStore,
|
|
1010
|
-
callApi(method, body) {
|
|
1011
|
-
return directTelegramApiRuntime.call(method, body);
|
|
1012
|
-
},
|
|
1013
|
-
getCurrentLeaderEpoch,
|
|
1014
|
-
getThreadReconciliationMachineState() {
|
|
1015
|
-
return threadReconciliationRuntime.getState();
|
|
1016
|
-
},
|
|
1017
|
-
recordThreadReconciliationPlan,
|
|
1018
|
-
getSyncState() {
|
|
1019
|
-
return telegramSyncState;
|
|
1020
|
-
},
|
|
1021
|
-
setSyncState(state) {
|
|
1022
|
-
telegramSyncState = state;
|
|
1023
|
-
},
|
|
1024
|
-
setLeaderTarget(input) {
|
|
1025
|
-
telegramBusLeaderTarget = input.target;
|
|
1026
|
-
telegramBusLeaderSlot = input.slot;
|
|
1027
|
-
telegramBusLeaderThreadName = input.threadName;
|
|
1028
|
-
},
|
|
1029
|
-
onProvisioningStart() {
|
|
1030
|
-
telegramTopicProvisioningCount += 1;
|
|
1031
|
-
},
|
|
1032
|
-
onProvisioningEnd() {
|
|
1033
|
-
telegramTopicProvisioningCount = Math.max(
|
|
1034
|
-
0,
|
|
1035
|
-
telegramTopicProvisioningCount - 1,
|
|
1036
|
-
);
|
|
948
|
+
const telegramBusLeaderRuntime =
|
|
949
|
+
BusLeader.createTelegramBusLeaderRuntimeAssembly<Pi.ExtensionContext>({
|
|
950
|
+
runtime: {
|
|
951
|
+
socketPath: getTelegramBusSocketPath,
|
|
952
|
+
followerRegistry: telegramBusFollowerRegistry,
|
|
953
|
+
authSecret: telegramBusAuthSecret,
|
|
954
|
+
startPolling: pollingRuntime.start,
|
|
955
|
+
stopPolling: pollingRuntime.stop,
|
|
956
|
+
authorizeFollowerApiCall: Bus.isTelegramFollowerApiCallAllowed,
|
|
957
|
+
recordFollowerMessageOwnership(record) {
|
|
958
|
+
messageOwnershipStore.record({
|
|
959
|
+
chatId: record.chatId,
|
|
960
|
+
messageId: record.messageId,
|
|
961
|
+
target: record.target,
|
|
962
|
+
instanceId: record.follower.instanceId,
|
|
963
|
+
});
|
|
1037
964
|
},
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
965
|
+
},
|
|
966
|
+
getAllowedUserId: configStore.getAllowedUserId,
|
|
967
|
+
instanceId: telegramInstanceId,
|
|
968
|
+
getCwd(ctx) {
|
|
969
|
+
return typeof ctx.cwd === "string" ? ctx.cwd : undefined;
|
|
970
|
+
},
|
|
971
|
+
getTelegramProfile: getActiveTelegramThreadProfile,
|
|
972
|
+
shouldForceFreshUnnamed() {
|
|
973
|
+
return forceFreshLeaderThreadOnNextStart;
|
|
974
|
+
},
|
|
1041
975
|
topicTargetStore: threadStore,
|
|
1042
976
|
callApi(method, body) {
|
|
1043
977
|
return directTelegramApiRuntime.call(method, body);
|
|
1044
978
|
},
|
|
979
|
+
callMultipart: directTelegramApiRuntime.callMultipart,
|
|
980
|
+
downloadFile: directTelegramApiRuntime.downloadFile,
|
|
981
|
+
recoverStaleTargetError: recoverStaleTelegramTopicApiError,
|
|
1045
982
|
getCurrentLeaderEpoch,
|
|
983
|
+
getThreadReconciliationMachineState() {
|
|
984
|
+
return threadReconciliationRuntime.getState();
|
|
985
|
+
},
|
|
986
|
+
recordThreadReconciliationPlan,
|
|
1046
987
|
getSyncState() {
|
|
1047
988
|
return telegramSyncState;
|
|
1048
989
|
},
|
|
1049
990
|
setSyncState(state) {
|
|
1050
991
|
telegramSyncState = state;
|
|
1051
992
|
},
|
|
993
|
+
setLeaderTarget(input) {
|
|
994
|
+
telegramBusLeaderTarget = input.target;
|
|
995
|
+
telegramBusLeaderSlot = input.slot;
|
|
996
|
+
telegramBusLeaderThreadName = input.threadName;
|
|
997
|
+
},
|
|
998
|
+
onProvisioningStart() {
|
|
999
|
+
telegramTopicProvisioningCount += 1;
|
|
1000
|
+
},
|
|
1001
|
+
onProvisioningEnd() {
|
|
1002
|
+
telegramTopicProvisioningCount = Math.max(
|
|
1003
|
+
0,
|
|
1004
|
+
telegramTopicProvisioningCount - 1,
|
|
1005
|
+
);
|
|
1006
|
+
},
|
|
1052
1007
|
recordRuntimeEvent,
|
|
1053
|
-
})
|
|
1054
|
-
provisionFollowerTarget:
|
|
1055
|
-
BusLeader.createTelegramBusFollowerTargetProvisioner({
|
|
1056
|
-
getAllowedUserId: configStore.getAllowedUserId,
|
|
1057
|
-
topicTargetStore: threadStore,
|
|
1058
|
-
callApi(method, body) {
|
|
1059
|
-
return directTelegramApiRuntime.call(method, body);
|
|
1060
|
-
},
|
|
1061
|
-
getCurrentLeaderEpoch,
|
|
1062
|
-
getSyncState() {
|
|
1063
|
-
return telegramSyncState;
|
|
1064
|
-
},
|
|
1065
|
-
setSyncState(state) {
|
|
1066
|
-
telegramSyncState = state;
|
|
1067
|
-
},
|
|
1068
|
-
onProvisioningStart() {
|
|
1069
|
-
telegramTopicProvisioningCount += 1;
|
|
1070
|
-
},
|
|
1071
|
-
onProvisioningEnd() {
|
|
1072
|
-
telegramTopicProvisioningCount = Math.max(
|
|
1073
|
-
0,
|
|
1074
|
-
telegramTopicProvisioningCount - 1,
|
|
1075
|
-
);
|
|
1076
|
-
},
|
|
1077
|
-
recordRuntimeEvent,
|
|
1078
|
-
}),
|
|
1079
|
-
restoreFollowerRegistry:
|
|
1080
|
-
BusLeader.createTelegramBusFollowerRegistryRestoreHandler({
|
|
1081
|
-
topicTargetStore: threadStore,
|
|
1082
|
-
followerRegistry: telegramBusFollowerRegistry,
|
|
1083
|
-
recordRuntimeEvent,
|
|
1084
|
-
}),
|
|
1085
|
-
callApi: BusLeader.createTelegramBusLeaderApiProxy({
|
|
1086
|
-
call: directTelegramApiRuntime.call,
|
|
1087
|
-
callMultipart: directTelegramApiRuntime.callMultipart,
|
|
1088
|
-
downloadFile: directTelegramApiRuntime.downloadFile,
|
|
1089
|
-
recoverStaleTargetError: recoverStaleTelegramTopicApiError,
|
|
1090
|
-
}),
|
|
1091
|
-
recordRuntimeEvent,
|
|
1092
|
-
});
|
|
1008
|
+
});
|
|
1093
1009
|
let pollingStartedWithTelegramBus = false;
|
|
1094
1010
|
let forceFreshLeaderThreadOnNextStart = false;
|
|
1095
1011
|
const telegramLeaderHealthRuntime = Sync.createTelegramLeaderHealthRuntime({
|
|
@@ -1260,14 +1176,6 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
1260
1176
|
registrationState: telegramBusFollowerRegistrationState,
|
|
1261
1177
|
instanceId: telegramInstanceId,
|
|
1262
1178
|
suspendPolling: lockedPollingRuntime.suspend,
|
|
1263
|
-
onFollowerSessionDisconnect() {
|
|
1264
|
-
const target = telegramBusFollowerRegistrationState.getTarget();
|
|
1265
|
-
if (!target) return undefined;
|
|
1266
|
-
return BusFollower.markTelegramFollowerThreadStaleForSessionDisconnect({
|
|
1267
|
-
topicTargetStore: threadStore,
|
|
1268
|
-
target,
|
|
1269
|
-
});
|
|
1270
|
-
},
|
|
1271
1179
|
recordRuntimeEvent,
|
|
1272
1180
|
});
|
|
1273
1181
|
const queueSessionLifecycle = Queue.createTelegramSessionLifecycleRuntime({
|
|
@@ -1392,6 +1300,12 @@ export default function (pi: Pi.ExtensionAPI) {
|
|
|
1392
1300
|
telegramBusFollowerRegistrationState.isRegistered()
|
|
1393
1301
|
);
|
|
1394
1302
|
},
|
|
1303
|
+
canSendAgentActivity(ctx) {
|
|
1304
|
+
return (
|
|
1305
|
+
lockOwnershipGuard.ownsContext(ctx) ||
|
|
1306
|
+
telegramBusFollowerRegistrationState.isRegistered()
|
|
1307
|
+
);
|
|
1308
|
+
},
|
|
1395
1309
|
updateStatus,
|
|
1396
1310
|
recordRuntimeEvent,
|
|
1397
1311
|
});
|
package/lib/bindings.ts
CHANGED
|
@@ -94,7 +94,9 @@ export function registerTelegramCommandsAndTools({
|
|
|
94
94
|
sendMarkdownReply(chatId, undefined, markdown, options),
|
|
95
95
|
recordRuntimeEvent,
|
|
96
96
|
});
|
|
97
|
-
Prompts.registerTelegramHelpTool(pi
|
|
97
|
+
Prompts.registerTelegramHelpTool(pi, {
|
|
98
|
+
getActiveProfileName: configStore.getActiveProfileName,
|
|
99
|
+
});
|
|
98
100
|
Commands.registerTelegramBridgeCommands(pi, {
|
|
99
101
|
promptForConfig: async (ctx, profileName) => {
|
|
100
102
|
const nextProfileName = profileName ?? undefined;
|
|
@@ -103,36 +105,58 @@ export function registerTelegramCommandsAndTools({
|
|
|
103
105
|
return;
|
|
104
106
|
}
|
|
105
107
|
const previousProfileName = configStore.getActiveProfileName();
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
108
|
+
let setupConfigStore = configStore;
|
|
109
|
+
let persistSetupConfig = persistConfig;
|
|
109
110
|
if (!profileName) {
|
|
111
|
+
if (previousProfileName !== nextProfileName) {
|
|
112
|
+
await (stopPolling ?? lockedPollingRuntime.stop)();
|
|
113
|
+
}
|
|
110
114
|
configStore.activateProfile(undefined);
|
|
111
115
|
} else {
|
|
112
116
|
const storedConfig = configStore.getStoredConfig();
|
|
113
|
-
|
|
117
|
+
setupConfigStore = Config.createTelegramConfigStore({
|
|
118
|
+
initialConfig: {
|
|
119
|
+
...storedConfig,
|
|
120
|
+
profiles: {
|
|
121
|
+
...(storedConfig.profiles ?? {}),
|
|
122
|
+
[profileName]: storedConfig.profiles?.[profileName] ?? {
|
|
123
|
+
botToken: "",
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
setupConfigStore.activateProfile(profileName);
|
|
129
|
+
persistSetupConfig = async () => {
|
|
130
|
+
if (previousProfileName !== profileName) {
|
|
131
|
+
await (stopPolling ?? lockedPollingRuntime.stop)();
|
|
132
|
+
}
|
|
133
|
+
configStore.activateProfile(undefined);
|
|
114
134
|
configStore.set({
|
|
115
135
|
...storedConfig,
|
|
116
136
|
profiles: {
|
|
117
137
|
...(storedConfig.profiles ?? {}),
|
|
118
|
-
[profileName]:
|
|
138
|
+
[profileName]: storedConfig.profiles?.[profileName] ?? {
|
|
139
|
+
botToken: "",
|
|
140
|
+
},
|
|
119
141
|
},
|
|
120
142
|
});
|
|
121
|
-
|
|
122
|
-
|
|
143
|
+
configStore.activateProfile(profileName);
|
|
144
|
+
configStore.set(setupConfigStore.get());
|
|
145
|
+
await persistConfig();
|
|
146
|
+
};
|
|
123
147
|
}
|
|
124
148
|
const runSetup = Setup.createTelegramSetupPromptRuntime({
|
|
125
|
-
getConfig:
|
|
126
|
-
setConfig:
|
|
149
|
+
getConfig: setupConfigStore.get,
|
|
150
|
+
setConfig: setupConfigStore.set,
|
|
127
151
|
setupGuard: setup,
|
|
128
152
|
getMe: TelegramApi.fetchTelegramBotIdentity,
|
|
129
|
-
persistConfig,
|
|
153
|
+
persistConfig: persistSetupConfig,
|
|
130
154
|
startPolling: lockedPollingRuntime.start,
|
|
131
155
|
updateStatus,
|
|
132
156
|
recordRuntimeEvent,
|
|
133
157
|
});
|
|
134
|
-
await runSetup(ctx);
|
|
135
|
-
if (profileName) {
|
|
158
|
+
const completion = await runSetup(ctx);
|
|
159
|
+
if (profileName && completion.status === "success") {
|
|
136
160
|
ctx.ui.notify(`Profile "${profileName}" saved and connected.`, "info");
|
|
137
161
|
}
|
|
138
162
|
},
|
|
@@ -155,6 +179,8 @@ export function registerTelegramCommandsAndTools({
|
|
|
155
179
|
activateProfileConfig: async (_ctx, profileName) => {
|
|
156
180
|
await configStore.load();
|
|
157
181
|
if (!Config.isValidTelegramProfileName(profileName)) return false;
|
|
182
|
+
const storedConfig = configStore.getStoredConfig();
|
|
183
|
+
if (!storedConfig.profiles?.[profileName]) return false;
|
|
158
184
|
const previousProfileName = configStore.getActiveProfileName();
|
|
159
185
|
if (previousProfileName !== profileName) {
|
|
160
186
|
await (stopPolling ?? lockedPollingRuntime.stop)();
|
|
@@ -242,6 +268,7 @@ interface TelegramLifecycleBindingDeps {
|
|
|
242
268
|
proactivePushTargetGetter: () => Queue.TelegramQueueTarget | undefined;
|
|
243
269
|
isProactivePushEnabled: () => boolean;
|
|
244
270
|
canSendProactivePush: (ctx: Pi.ExtensionContext) => boolean;
|
|
271
|
+
canSendAgentActivity: (ctx: Pi.ExtensionContext) => boolean;
|
|
245
272
|
updateStatus: TelegramBridgeStatusUpdater;
|
|
246
273
|
recordRuntimeEvent: TelegramRuntimeEventRecorder;
|
|
247
274
|
}
|
|
@@ -274,6 +301,7 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
274
301
|
proactivePushTargetGetter,
|
|
275
302
|
isProactivePushEnabled,
|
|
276
303
|
canSendProactivePush,
|
|
304
|
+
canSendAgentActivity,
|
|
277
305
|
updateStatus,
|
|
278
306
|
recordRuntimeEvent,
|
|
279
307
|
}: TelegramLifecycleBindingDeps): void {
|
|
@@ -370,6 +398,16 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
370
398
|
const agentStartWithDedupReset = Lifecycle.createAgentStartDedupHook(
|
|
371
399
|
agentLifecycleHooks.onAgentStart,
|
|
372
400
|
);
|
|
401
|
+
const startAgentActivityTypingLoop = (ctx: Pi.ExtensionContext): void => {
|
|
402
|
+
if (!canSendAgentActivity(ctx)) return;
|
|
403
|
+
const turn = activeTurnRuntime.get();
|
|
404
|
+
const target = turn?.target ?? proactivePushTargetGetter();
|
|
405
|
+
promptDispatchRuntime.startTypingLoop(
|
|
406
|
+
ctx,
|
|
407
|
+
turn?.chatId ?? target?.chatId ?? proactivePushChatIdGetter(),
|
|
408
|
+
{ target },
|
|
409
|
+
);
|
|
410
|
+
};
|
|
373
411
|
const startActiveTurnTypingLoop = (ctx: Pi.ExtensionContext): void => {
|
|
374
412
|
const turn = activeTurnRuntime.get();
|
|
375
413
|
promptDispatchRuntime.startTypingLoop(ctx, turn?.chatId, {
|
|
@@ -405,7 +443,10 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
405
443
|
},
|
|
406
444
|
onSessionBeforeCompact: compactionObserver.onSessionBeforeCompact,
|
|
407
445
|
onSessionCompact: compactionObserver.onSessionCompact,
|
|
408
|
-
onAgentStart
|
|
446
|
+
async onAgentStart(event, ctx) {
|
|
447
|
+
await agentStartWithDedupReset(event, ctx);
|
|
448
|
+
startAgentActivityTypingLoop(ctx);
|
|
449
|
+
},
|
|
409
450
|
async onToolExecutionStart(_event, _ctx) {
|
|
410
451
|
agentLifecycleHooks.onToolExecutionStart();
|
|
411
452
|
},
|