@llblab/pi-kit 0.1.12 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +2 -2
- package/node_modules/@llblab/pi-actors/AGENTS.md +5 -3
- package/node_modules/@llblab/pi-actors/BACKLOG.md +1 -1
- package/node_modules/@llblab/pi-actors/CHANGELOG.md +15 -0
- package/node_modules/@llblab/pi-actors/README.md +5 -3
- package/node_modules/@llblab/pi-actors/dist/index.js +4 -1
- package/node_modules/@llblab/pi-actors/dist/lib/async-runs.d.ts +2 -2
- package/node_modules/@llblab/pi-actors/dist/lib/async-runs.js +42 -19
- package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.d.ts +2 -1
- package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.js +7 -2
- package/node_modules/@llblab/pi-actors/dist/lib/limits.d.ts +9 -0
- package/node_modules/@llblab/pi-actors/dist/lib/limits.js +9 -0
- package/node_modules/@llblab/pi-actors/dist/lib/observability.d.ts +10 -11
- package/node_modules/@llblab/pi-actors/dist/lib/observability.js +81 -56
- package/node_modules/@llblab/pi-actors/dist/lib/pi.d.ts +31 -0
- package/node_modules/@llblab/pi-actors/dist/lib/pi.js +180 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.d.ts +115 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.js +623 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.d.ts +3 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.js +341 -13
- package/node_modules/@llblab/pi-actors/dist/lib/runs-trace.d.ts +1 -1
- package/node_modules/@llblab/pi-actors/dist/lib/runs-trace.js +5 -3
- package/node_modules/@llblab/pi-actors/dist/lib/session-evidence.d.ts +16 -0
- package/node_modules/@llblab/pi-actors/dist/lib/session-evidence.js +143 -0
- package/node_modules/@llblab/pi-actors/dist/lib/temp.js +1 -1
- package/node_modules/@llblab/pi-actors/dist/lib/tools-inspect.js +3 -1
- package/node_modules/@llblab/pi-actors/dist/scripts/async-runner.mjs +5 -19
- package/node_modules/@llblab/pi-actors/dist/skills/actors/SKILL.md +2 -2
- package/node_modules/@llblab/pi-actors/dist/skills/actors/references/runs.md +1 -1
- package/node_modules/@llblab/pi-actors/dist/skills/swarm/SKILL.md +1 -1
- package/node_modules/@llblab/pi-actors/docs/README.md +1 -0
- package/node_modules/@llblab/pi-actors/docs/async-runs.md +8 -4
- package/node_modules/@llblab/pi-actors/docs/coordinator-delivery.md +207 -0
- package/node_modules/@llblab/pi-actors/index.ts +4 -1
- package/node_modules/@llblab/pi-actors/lib/async-runs.ts +42 -21
- package/node_modules/@llblab/pi-actors/lib/extension-runtime.ts +8 -3
- package/node_modules/@llblab/pi-actors/lib/limits.ts +9 -0
- package/node_modules/@llblab/pi-actors/lib/observability.ts +97 -78
- package/node_modules/@llblab/pi-actors/lib/pi.ts +210 -0
- package/node_modules/@llblab/pi-actors/lib/run-delivery.ts +800 -0
- package/node_modules/@llblab/pi-actors/lib/run-ui-runtime.ts +370 -18
- package/node_modules/@llblab/pi-actors/lib/runs-trace.ts +6 -4
- package/node_modules/@llblab/pi-actors/lib/session-evidence.ts +153 -0
- package/node_modules/@llblab/pi-actors/lib/temp.ts +1 -1
- package/node_modules/@llblab/pi-actors/lib/tools-inspect.ts +4 -1
- package/node_modules/@llblab/pi-actors/package.json +3 -3
- package/node_modules/@llblab/pi-actors/scripts/async-runner.mjs +5 -19
- package/node_modules/@llblab/pi-actors/skills/actors/SKILL.md +2 -2
- package/node_modules/@llblab/pi-actors/skills/actors/references/runs.md +1 -1
- package/node_modules/@llblab/pi-actors/skills/swarm/SKILL.md +1 -1
- package/node_modules/@llblab/pi-telegram/AGENTS.md +4 -4
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +19 -0
- package/node_modules/@llblab/pi-telegram/README.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/activity.md +12 -5
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +7 -6
- package/node_modules/@llblab/pi-telegram/docs/outbound.md +2 -2
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +3 -4
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +4 -5
- package/node_modules/@llblab/pi-telegram/docs/voice.md +12 -2
- package/node_modules/@llblab/pi-telegram/index.ts +0 -1
- package/node_modules/@llblab/pi-telegram/lib/activity.ts +32 -5
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +59 -12
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/config.ts +25 -25
- package/node_modules/@llblab/pi-telegram/lib/inbound.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +50 -0
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +10 -73
- package/node_modules/@llblab/pi-telegram/lib/pi.ts +15 -0
- package/node_modules/@llblab/pi-telegram/lib/status.ts +11 -1
- package/node_modules/@llblab/pi-telegram/package.json +4 -4
- package/node_modules/@llblab/pi-telegram/skills/generated-control-surface/SKILL.md +5 -3
- package/package.json +3 -3
|
@@ -337,7 +337,6 @@ export interface TelegramAssistantOutputBindingRuntime<TTransportStamp> {
|
|
|
337
337
|
export function createTelegramAssistantOutputBindingRuntime<
|
|
338
338
|
TTransportStamp,
|
|
339
339
|
>(deps: {
|
|
340
|
-
isEnabled: () => boolean;
|
|
341
340
|
authority: {
|
|
342
341
|
getPreferredTarget: () =>
|
|
343
342
|
| OutboundAttachments.TelegramQueuedOutboundAttachmentTurnView["target"]
|
|
@@ -364,7 +363,6 @@ export function createTelegramAssistantOutputBindingRuntime<
|
|
|
364
363
|
deps.sender,
|
|
365
364
|
);
|
|
366
365
|
const runtime = Activity.createTelegramAssistantOutputRuntime({
|
|
367
|
-
isEnabled: deps.isEnabled,
|
|
368
366
|
...authority,
|
|
369
367
|
async send(event, authority, isAuthorityActive) {
|
|
370
368
|
await deps.waitForActivityIdle?.();
|
|
@@ -1012,8 +1010,9 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
1012
1010
|
const agentStartWithDedupReset = Lifecycle.createAgentStartDedupHook(
|
|
1013
1011
|
agentLifecycleHooks.onAgentStart,
|
|
1014
1012
|
);
|
|
1013
|
+
let uiPromptActive = false;
|
|
1015
1014
|
const startAgentActivityTypingLoop = (ctx: Pi.ExtensionContext): boolean => {
|
|
1016
|
-
if (!canSendAgentActivity(ctx)) return false;
|
|
1015
|
+
if (uiPromptActive || !canSendAgentActivity(ctx)) return false;
|
|
1017
1016
|
const turn = activeTurnRuntime.get();
|
|
1018
1017
|
const target = turn?.target ?? proactivePushTargetGetter();
|
|
1019
1018
|
promptDispatchRuntime.startTypingLoop(ctx, turn?.chatId ?? target?.chatId, {
|
|
@@ -1022,12 +1021,15 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
1022
1021
|
return true;
|
|
1023
1022
|
};
|
|
1024
1023
|
const startActiveTurnTypingLoop = (ctx: Pi.ExtensionContext): void => {
|
|
1024
|
+
if (uiPromptActive) return;
|
|
1025
1025
|
const turn = activeTurnRuntime.get();
|
|
1026
1026
|
promptDispatchRuntime.startTypingLoop(ctx, turn?.chatId, {
|
|
1027
1027
|
target: turn?.target,
|
|
1028
1028
|
});
|
|
1029
1029
|
};
|
|
1030
1030
|
let observedAutomaticCompaction = false;
|
|
1031
|
+
let agentWorkActive = false;
|
|
1032
|
+
let terminalAssistantMessagePendingDelivery = false;
|
|
1031
1033
|
const deferredAutomaticCompactionNotices: string[] = [];
|
|
1032
1034
|
const sendCompactionNotice = async (text: string): Promise<void> => {
|
|
1033
1035
|
const turn = activeTurnRuntime.get();
|
|
@@ -1094,6 +1096,9 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
1094
1096
|
activityVerbosityRuntime?.reset();
|
|
1095
1097
|
assistantOutputRuntime.stop();
|
|
1096
1098
|
observedAutomaticCompaction = false;
|
|
1099
|
+
agentWorkActive = false;
|
|
1100
|
+
terminalAssistantMessagePendingDelivery = false;
|
|
1101
|
+
uiPromptActive = false;
|
|
1097
1102
|
deferredAutomaticCompactionNotices.length = 0;
|
|
1098
1103
|
compactionObserver.onSessionShutdown();
|
|
1099
1104
|
if (event.reason === "quit" && disconnectOnQuit) {
|
|
@@ -1116,7 +1121,7 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
1116
1121
|
activityRuntime.onCompactionStart(Pi.getSessionCompactionReason(event));
|
|
1117
1122
|
compactionObserver.onSessionBeforeCompact(event, ctx);
|
|
1118
1123
|
if (shouldNotify) {
|
|
1119
|
-
if (
|
|
1124
|
+
if (terminalAssistantMessagePendingDelivery) {
|
|
1120
1125
|
deferredAutomaticCompactionNotices.push(
|
|
1121
1126
|
Commands.TELEGRAM_COMPACTION_STARTED_MARKDOWN,
|
|
1122
1127
|
);
|
|
@@ -1135,10 +1140,7 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
1135
1140
|
compactionObserver.onSessionCompact(event, ctx);
|
|
1136
1141
|
if (observedAutomaticCompaction) {
|
|
1137
1142
|
observedAutomaticCompaction = false;
|
|
1138
|
-
if (
|
|
1139
|
-
activeTurnRuntime.has() ||
|
|
1140
|
-
deferredAutomaticCompactionNotices.length > 0
|
|
1141
|
-
) {
|
|
1143
|
+
if (deferredAutomaticCompactionNotices.length > 0) {
|
|
1142
1144
|
deferredAutomaticCompactionNotices.push(
|
|
1143
1145
|
Commands.TELEGRAM_COMPACTION_COMPLETED_MARKDOWN,
|
|
1144
1146
|
);
|
|
@@ -1149,8 +1151,27 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
1149
1151
|
}
|
|
1150
1152
|
}
|
|
1151
1153
|
},
|
|
1154
|
+
async onSessionCompactFailed(event, ctx) {
|
|
1155
|
+
if (!isSessionContextActive(ctx)) return;
|
|
1156
|
+
const shouldNotify = observedAutomaticCompaction;
|
|
1157
|
+
const deferredNotices = deferredAutomaticCompactionNotices.splice(0);
|
|
1158
|
+
const shouldDefer =
|
|
1159
|
+
deferredNotices.length > 0 || terminalAssistantMessagePendingDelivery;
|
|
1160
|
+
compactionObserver.onSessionCompactFailed(event, ctx);
|
|
1161
|
+
if (!shouldNotify) return;
|
|
1162
|
+
const notice = event.aborted
|
|
1163
|
+
? "**⚠️ Compaction cancelled.**"
|
|
1164
|
+
: "**⚠️ Compaction failed.**";
|
|
1165
|
+
if (shouldDefer) {
|
|
1166
|
+
deferredAutomaticCompactionNotices.push(...deferredNotices, notice);
|
|
1167
|
+
} else {
|
|
1168
|
+
await sendCompactionNotice(notice);
|
|
1169
|
+
}
|
|
1170
|
+
},
|
|
1152
1171
|
async onAgentStart(event, ctx) {
|
|
1153
1172
|
if (!isSessionContextActive(ctx)) return;
|
|
1173
|
+
agentWorkActive = true;
|
|
1174
|
+
terminalAssistantMessagePendingDelivery = false;
|
|
1154
1175
|
await agentStartWithDedupReset(event, ctx);
|
|
1155
1176
|
activityRuntime.onAgentStart(activeTurnRuntime.get()?.target);
|
|
1156
1177
|
startAgentActivityTypingLoop(ctx);
|
|
@@ -1195,19 +1216,45 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
1195
1216
|
}
|
|
1196
1217
|
await messageActivityHooks.onMessageUpdate(event, ctx);
|
|
1197
1218
|
},
|
|
1219
|
+
onMessageEnd(event, ctx) {
|
|
1220
|
+
if (!isSessionContextActive(ctx)) return;
|
|
1221
|
+
terminalAssistantMessagePendingDelivery =
|
|
1222
|
+
event.message.role === "assistant" &&
|
|
1223
|
+
event.message.stopReason !== "toolUse" &&
|
|
1224
|
+
event.message.stopReason !== "error" &&
|
|
1225
|
+
event.message.stopReason !== "aborted";
|
|
1226
|
+
},
|
|
1227
|
+
onUiPromptStart(event, ctx) {
|
|
1228
|
+
if (!isSessionContextActive(ctx)) return;
|
|
1229
|
+
uiPromptActive = true;
|
|
1230
|
+
typing.stop();
|
|
1231
|
+
activityRuntime.onUiPromptStart(event.kind, event.title);
|
|
1232
|
+
updateStatus(ctx);
|
|
1233
|
+
},
|
|
1234
|
+
onUiPromptEnd(_event, ctx) {
|
|
1235
|
+
if (!isSessionContextActive(ctx)) return;
|
|
1236
|
+
uiPromptActive = false;
|
|
1237
|
+
activityRuntime.onUiPromptEnd();
|
|
1238
|
+
if (agentWorkActive || lifecycle.isCompactionInProgress()) {
|
|
1239
|
+
startAgentActivityTypingLoop(ctx);
|
|
1240
|
+
}
|
|
1241
|
+
updateStatus(ctx);
|
|
1242
|
+
},
|
|
1198
1243
|
async onAgentEnd(event, ctx) {
|
|
1199
1244
|
if (!isSessionContextActive(ctx)) return;
|
|
1200
1245
|
activityRuntime.onAgentEnd();
|
|
1201
1246
|
await agentLifecycleHooks.onAgentEnd(event, ctx);
|
|
1247
|
+
},
|
|
1248
|
+
async onAgentSettled(event, ctx) {
|
|
1249
|
+
if (!isSessionContextActive(ctx)) return;
|
|
1250
|
+
await agentLifecycleHooks.onAgentSettled(event, ctx);
|
|
1202
1251
|
if (deferredAutomaticCompactionNotices.length > 0) {
|
|
1203
1252
|
await waitForActiveTurnDelivery();
|
|
1204
1253
|
if (!isSessionContextActive(ctx)) return;
|
|
1205
1254
|
await flushDeferredAutomaticCompactionNotices();
|
|
1206
1255
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
if (!isSessionContextActive(ctx)) return;
|
|
1210
|
-
await agentLifecycleHooks.onAgentSettled(event, ctx);
|
|
1256
|
+
terminalAssistantMessagePendingDelivery = false;
|
|
1257
|
+
agentWorkActive = false;
|
|
1211
1258
|
activityRuntime.onAgentSettled();
|
|
1212
1259
|
modelContextAvailabilityRuntime.reconcile();
|
|
1213
1260
|
},
|
|
@@ -335,7 +335,7 @@ export function createTelegramBusInstanceLifecycleAnnouncement(input: {
|
|
|
335
335
|
}): TelegramBusFollowerLifecycleAnnouncement {
|
|
336
336
|
return {
|
|
337
337
|
target: { ...input.target },
|
|
338
|
-
text:
|
|
338
|
+
text: `<b>📡 Instance <i>${formatTelegramBusInstanceLabel(input)}</i> ${input.state}.</b>`,
|
|
339
339
|
parseMode: "HTML",
|
|
340
340
|
};
|
|
341
341
|
}
|
|
@@ -105,7 +105,6 @@ export interface TelegramConfig {
|
|
|
105
105
|
assistant?: {
|
|
106
106
|
draftPreviews?: boolean;
|
|
107
107
|
rendering?: TelegramAssistantRenderingMode;
|
|
108
|
-
proactivePush?: boolean;
|
|
109
108
|
activity?: TelegramActivityVerbosity;
|
|
110
109
|
timeInjection?: TelegramTimeMode;
|
|
111
110
|
/** @deprecated use activity */
|
|
@@ -454,10 +453,32 @@ function omitTelegramRootProfileFields(config: TelegramConfig): TelegramConfig {
|
|
|
454
453
|
return sharedConfig;
|
|
455
454
|
}
|
|
456
455
|
|
|
456
|
+
function omitRetiredProactivePush(config: TelegramConfig): {
|
|
457
|
+
config: TelegramConfig;
|
|
458
|
+
changed: boolean;
|
|
459
|
+
} {
|
|
460
|
+
const assistant = config.assistant as
|
|
461
|
+
| (NonNullable<TelegramConfig["assistant"]> & { proactivePush?: unknown })
|
|
462
|
+
| undefined;
|
|
463
|
+
if (!assistant || !Object.hasOwn(assistant, "proactivePush")) {
|
|
464
|
+
return { config, changed: false };
|
|
465
|
+
}
|
|
466
|
+
const { proactivePush: _proactivePush, ...remainingAssistant } = assistant;
|
|
467
|
+
const next = { ...config };
|
|
468
|
+
if (Object.keys(remainingAssistant).length > 0) {
|
|
469
|
+
next.assistant = remainingAssistant;
|
|
470
|
+
} else {
|
|
471
|
+
delete next.assistant;
|
|
472
|
+
}
|
|
473
|
+
return { config: next, changed: true };
|
|
474
|
+
}
|
|
475
|
+
|
|
457
476
|
export function normalizeTelegramDefaultProfileConfig(config: TelegramConfig): {
|
|
458
477
|
config: TelegramConfig;
|
|
459
478
|
changed: boolean;
|
|
460
479
|
} {
|
|
480
|
+
const retiredProactivePush = omitRetiredProactivePush(config);
|
|
481
|
+
config = retiredProactivePush.config;
|
|
461
482
|
const hasLegacyRootProfile = [
|
|
462
483
|
"botToken",
|
|
463
484
|
"botUsername",
|
|
@@ -465,7 +486,9 @@ export function normalizeTelegramDefaultProfileConfig(config: TelegramConfig): {
|
|
|
465
486
|
"allowedUserId",
|
|
466
487
|
"lastUpdateId",
|
|
467
488
|
].some((field) => Object.hasOwn(config, field));
|
|
468
|
-
if (!hasLegacyRootProfile)
|
|
489
|
+
if (!hasLegacyRootProfile) {
|
|
490
|
+
return { config, changed: retiredProactivePush.changed };
|
|
491
|
+
}
|
|
469
492
|
const canonicalProfile = config.profiles?.[TELEGRAM_DEFAULT_PROFILE_NAME];
|
|
470
493
|
const legacyToken = config.botToken?.trim();
|
|
471
494
|
if (Object.hasOwn(config, "botToken") && !legacyToken) {
|
|
@@ -712,27 +735,6 @@ export function createTelegramConfigStore(
|
|
|
712
735
|
};
|
|
713
736
|
}
|
|
714
737
|
|
|
715
|
-
export function createTelegramProactivePushChecker(
|
|
716
|
-
configStore: Pick<TelegramConfigStore, "get">,
|
|
717
|
-
): () => boolean {
|
|
718
|
-
return () => configStore.get().assistant?.proactivePush ?? true;
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
export function createTelegramProactivePushSetter(
|
|
722
|
-
configStore: TelegramMutableConfigStore,
|
|
723
|
-
): (enabled: boolean) => Promise<void> {
|
|
724
|
-
return async (enabled) => {
|
|
725
|
-
await loadLatestTelegramConfig(configStore);
|
|
726
|
-
const current = configStore.get();
|
|
727
|
-
const config: TelegramConfig = {
|
|
728
|
-
...current,
|
|
729
|
-
assistant: { ...current.assistant, proactivePush: enabled },
|
|
730
|
-
};
|
|
731
|
-
configStore.set(config);
|
|
732
|
-
await configStore.persist(config);
|
|
733
|
-
};
|
|
734
|
-
}
|
|
735
|
-
|
|
736
738
|
export function createTelegramDraftPreviewsChecker(
|
|
737
739
|
configStore: Pick<TelegramConfigStore, "get">,
|
|
738
740
|
): () => boolean {
|
|
@@ -1019,8 +1021,6 @@ export function createTelegramConfigControls(
|
|
|
1019
1021
|
configStore: TelegramMutableConfigStore,
|
|
1020
1022
|
) {
|
|
1021
1023
|
return {
|
|
1022
|
-
isProactivePushEnabled: createTelegramProactivePushChecker(configStore),
|
|
1023
|
-
setProactivePushEnabled: createTelegramProactivePushSetter(configStore),
|
|
1024
1024
|
areDraftPreviewsEnabled: createTelegramDraftPreviewsChecker(configStore),
|
|
1025
1025
|
setDraftPreviewsEnabled: createTelegramDraftPreviewsSetter(configStore),
|
|
1026
1026
|
getAssistantRenderingMode:
|
|
@@ -19,7 +19,7 @@ import { getTelegramVoiceTranscriptionProviders } from "./voice.ts";
|
|
|
19
19
|
|
|
20
20
|
const DEFAULT_INBOUND_HANDLER_TIMEOUT_MS = 120_000;
|
|
21
21
|
const INBOUND_HANDLER_REGISTRY_KEY = "__piTelegramInboundHandlers__";
|
|
22
|
-
const MAX_INBOUND_HANDLER_OUTPUT_LENGTH =
|
|
22
|
+
const MAX_INBOUND_HANDLER_OUTPUT_LENGTH = 24_000;
|
|
23
23
|
const MAX_INBOUND_HANDLER_FAILURE_STREAM_LENGTH = 4_000;
|
|
24
24
|
|
|
25
25
|
type TelegramInboundCommandTemplateConfig =
|
|
@@ -16,13 +16,17 @@ import type {
|
|
|
16
16
|
ExtensionAPI,
|
|
17
17
|
ExtensionContext,
|
|
18
18
|
InputEvent,
|
|
19
|
+
MessageEndEvent,
|
|
19
20
|
SessionBeforeCompactEvent,
|
|
20
21
|
SessionCompactEvent,
|
|
22
|
+
SessionCompactFailedEvent,
|
|
21
23
|
SessionShutdownEvent,
|
|
22
24
|
SessionStartEvent,
|
|
23
25
|
ToolExecutionEndEvent,
|
|
24
26
|
ToolExecutionStartEvent,
|
|
25
27
|
ToolExecutionUpdateEvent,
|
|
28
|
+
UIPromptEndEvent,
|
|
29
|
+
UIPromptStartEvent,
|
|
26
30
|
} from "./pi.ts";
|
|
27
31
|
|
|
28
32
|
let resetTransportReplyDedupFn: (() => void) | undefined;
|
|
@@ -78,6 +82,10 @@ export interface TelegramLifecycleRegistrationDeps {
|
|
|
78
82
|
event: SessionCompactEvent,
|
|
79
83
|
ctx: ExtensionContext,
|
|
80
84
|
) => Promise<void> | void;
|
|
85
|
+
onSessionCompactFailed?: (
|
|
86
|
+
event: SessionCompactFailedEvent,
|
|
87
|
+
ctx: ExtensionContext,
|
|
88
|
+
) => Promise<void> | void;
|
|
81
89
|
onBeforeAgentStart: (
|
|
82
90
|
event: TelegramBeforeAgentStartEvent,
|
|
83
91
|
ctx: ExtensionContext,
|
|
@@ -113,6 +121,18 @@ export interface TelegramLifecycleRegistrationDeps {
|
|
|
113
121
|
},
|
|
114
122
|
ctx: ExtensionContext,
|
|
115
123
|
) => Promise<void>;
|
|
124
|
+
onMessageEnd?: (
|
|
125
|
+
event: MessageEndEvent,
|
|
126
|
+
ctx: ExtensionContext,
|
|
127
|
+
) => Promise<void> | void;
|
|
128
|
+
onUiPromptStart?: (
|
|
129
|
+
event: UIPromptStartEvent,
|
|
130
|
+
ctx: ExtensionContext,
|
|
131
|
+
) => Promise<void> | void;
|
|
132
|
+
onUiPromptEnd?: (
|
|
133
|
+
event: UIPromptEndEvent,
|
|
134
|
+
ctx: ExtensionContext,
|
|
135
|
+
) => Promise<void> | void;
|
|
116
136
|
onAgentEnd: (event: AgentEndEvent, ctx: ExtensionContext) => Promise<void>;
|
|
117
137
|
onAgentSettled?: (
|
|
118
138
|
event: AgentSettledEvent,
|
|
@@ -416,6 +436,10 @@ export interface TelegramCompactionObserverRuntime<TContext> {
|
|
|
416
436
|
ctx: TContext,
|
|
417
437
|
) => void;
|
|
418
438
|
onSessionCompact: (event: SessionCompactEvent, ctx: TContext) => void;
|
|
439
|
+
onSessionCompactFailed: (
|
|
440
|
+
event: SessionCompactFailedEvent,
|
|
441
|
+
ctx: TContext,
|
|
442
|
+
) => void;
|
|
419
443
|
onSessionShutdown: () => void;
|
|
420
444
|
}
|
|
421
445
|
|
|
@@ -471,6 +495,16 @@ export function createTelegramCompactionObserverRuntime<TContext>(
|
|
|
471
495
|
deps.updateStatus(ctx);
|
|
472
496
|
requestDispatch();
|
|
473
497
|
},
|
|
498
|
+
onSessionCompactFailed: (_event, ctx) => {
|
|
499
|
+
clearFallbackTimer();
|
|
500
|
+
if (deps.isContextActive && !deps.isContextActive(ctx)) return;
|
|
501
|
+
deps.setCompactionInProgress(false);
|
|
502
|
+
if (typingStartedByObserver) deps.stopTypingLoop?.();
|
|
503
|
+
typingStartedByObserver = false;
|
|
504
|
+
deps.updateStatus(ctx);
|
|
505
|
+
deps.onCompactionAbandoned?.();
|
|
506
|
+
requestDispatch();
|
|
507
|
+
},
|
|
474
508
|
onSessionShutdown: () => {
|
|
475
509
|
clearFallbackTimer();
|
|
476
510
|
if (typingStartedByObserver) deps.stopTypingLoop?.();
|
|
@@ -590,6 +624,10 @@ export function registerTelegramLifecycleHooks(
|
|
|
590
624
|
if (!isActive(ctx)) return;
|
|
591
625
|
await deps.onSessionCompact?.(event, ctx);
|
|
592
626
|
});
|
|
627
|
+
pi.on("session_compact_failed", async (event, ctx) => {
|
|
628
|
+
if (!isActive(ctx)) return;
|
|
629
|
+
await deps.onSessionCompactFailed?.(event, ctx);
|
|
630
|
+
});
|
|
593
631
|
// The Pi SDK still types this result as a string; compatible runtimes may
|
|
594
632
|
// preserve ordered system prompt blocks through the same public hook.
|
|
595
633
|
const registerBeforeAgentStart = pi.on.bind(pi) as unknown as (
|
|
@@ -630,6 +668,18 @@ export function registerTelegramLifecycleHooks(
|
|
|
630
668
|
if (!isActive(ctx)) return;
|
|
631
669
|
await deps.onMessageUpdate(event, ctx);
|
|
632
670
|
});
|
|
671
|
+
pi.on("message_end", async (event, ctx) => {
|
|
672
|
+
if (!isActive(ctx)) return;
|
|
673
|
+
await deps.onMessageEnd?.(event, ctx);
|
|
674
|
+
});
|
|
675
|
+
pi.on("ui_prompt_start", async (event, ctx) => {
|
|
676
|
+
if (!isActive(ctx)) return;
|
|
677
|
+
await deps.onUiPromptStart?.(event, ctx);
|
|
678
|
+
});
|
|
679
|
+
pi.on("ui_prompt_end", async (event, ctx) => {
|
|
680
|
+
if (!isActive(ctx)) return;
|
|
681
|
+
await deps.onUiPromptEnd?.(event, ctx);
|
|
682
|
+
});
|
|
633
683
|
pi.on("agent_end", async (event, ctx) => {
|
|
634
684
|
if (!isActive(ctx)) return;
|
|
635
685
|
await deps.onAgentEnd(event, ctx);
|
|
@@ -21,7 +21,6 @@ import type { TelegramVoiceReplyMode } from "./voice.ts";
|
|
|
21
21
|
export type TelegramSettingsMenuReplyMarkup = TelegramInlineKeyboardMarkup;
|
|
22
22
|
|
|
23
23
|
export interface TelegramSettingsStateDeps {
|
|
24
|
-
isProactivePushEnabled: () => boolean;
|
|
25
24
|
areDraftPreviewsEnabled: () => boolean;
|
|
26
25
|
getAssistantRenderingMode: () => TelegramAssistantRenderingMode;
|
|
27
26
|
getActivityVerbosity: () => TelegramActivityVerbosity;
|
|
@@ -32,7 +31,6 @@ export interface TelegramSettingsStateDeps {
|
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
export interface TelegramSettingsMutationDeps extends TelegramSettingsStateDeps {
|
|
35
|
-
setProactivePushEnabled: (enabled: boolean) => Promise<void>;
|
|
36
34
|
setDraftPreviewsEnabled: (enabled: boolean) => Promise<void>;
|
|
37
35
|
setAssistantRenderingMode: (
|
|
38
36
|
mode: TelegramAssistantRenderingMode,
|
|
@@ -139,7 +137,6 @@ export interface TelegramSettingsMenuRuntimeDeps<
|
|
|
139
137
|
export const SETTINGS_MENU_TITLE = "<b>⚙️ Settings:</b>";
|
|
140
138
|
export const AUTOMATIC_THREAD_CLEANUP_SETTINGS_TITLE =
|
|
141
139
|
"<b>🧹 Thread cleanup:</b>";
|
|
142
|
-
export const PROACTIVE_PUSH_SETTINGS_TITLE = "<b>📌 Proactive push:</b>";
|
|
143
140
|
export const DRAFT_PREVIEWS_SETTINGS_TITLE = "<b>📝 Draft previews:</b>";
|
|
144
141
|
export const ASSISTANT_RENDERING_SETTINGS_TITLE =
|
|
145
142
|
"<b>🧾 Assistant rendering:</b>";
|
|
@@ -181,19 +178,6 @@ export function buildAutomaticThreadCleanupSettingsText(
|
|
|
181
178
|
].join("\n");
|
|
182
179
|
}
|
|
183
180
|
|
|
184
|
-
export function buildProactivePushSettingsText(
|
|
185
|
-
proactivePushEnabled: boolean,
|
|
186
|
-
): string {
|
|
187
|
-
return [
|
|
188
|
-
`${PROACTIVE_PUSH_SETTINGS_TITLE} <code>${proactivePushEnabled ? "on" : "off"}</code>`,
|
|
189
|
-
"",
|
|
190
|
-
"Control whether public assistant output from local/autonomous work is projected to Telegram.",
|
|
191
|
-
"",
|
|
192
|
-
"<code>-</code> <code>on</code> (default): send each completed public block, including visible checkpoints and the final answer, while connected.",
|
|
193
|
-
"<code>-</code> <code>off</code>: keep local/autonomous assistant blocks in Pi; Telegram-originated replies still use their normal delivery path.",
|
|
194
|
-
].join("\n");
|
|
195
|
-
}
|
|
196
|
-
|
|
197
181
|
export function buildDraftPreviewsSettingsText(enabled: boolean): string {
|
|
198
182
|
return [
|
|
199
183
|
`${DRAFT_PREVIEWS_SETTINGS_TITLE} <code>${enabled ? "on" : "off"}</code>`,
|
|
@@ -265,7 +249,6 @@ export function buildTimeInjectionModeSettingsText(
|
|
|
265
249
|
}
|
|
266
250
|
|
|
267
251
|
export function buildTelegramSettingsMenuReplyMarkup(
|
|
268
|
-
proactivePushEnabled: boolean,
|
|
269
252
|
draftPreviewsEnabled: boolean,
|
|
270
253
|
assistantRenderingModeOrVoiceReplyMode:
|
|
271
254
|
TelegramAssistantRenderingMode | TelegramVoiceReplyMode,
|
|
@@ -325,10 +308,6 @@ export function buildTelegramSettingsMenuReplyMarkup(
|
|
|
325
308
|
text: `🔬 Activity: ${activityVerbosity}`,
|
|
326
309
|
callback_data: "settings:open:activity-verbosity",
|
|
327
310
|
},
|
|
328
|
-
{
|
|
329
|
-
text: `📌 Proactive push: ${proactivePushEnabled ? "on" : "off"}`,
|
|
330
|
-
callback_data: "settings:open:proactive",
|
|
331
|
-
},
|
|
332
311
|
{
|
|
333
312
|
text: `🕒 Time injection: ${getTelegramSettingsStateValueLabel(timeInjectionMode)}`,
|
|
334
313
|
callback_data: "settings:open:time-injection",
|
|
@@ -362,7 +341,6 @@ export async function openTelegramSettingsMenu<
|
|
|
362
341
|
state,
|
|
363
342
|
buildTelegramSettingsMenuText(),
|
|
364
343
|
buildTelegramSettingsMenuReplyMarkup(
|
|
365
|
-
deps.isProactivePushEnabled(),
|
|
366
344
|
deps.areDraftPreviewsEnabled(),
|
|
367
345
|
deps.getAssistantRenderingMode(),
|
|
368
346
|
deps.getVoiceReplyMode(),
|
|
@@ -399,26 +377,6 @@ export function buildAutomaticThreadCleanupSettingsReplyMarkup(
|
|
|
399
377
|
};
|
|
400
378
|
}
|
|
401
379
|
|
|
402
|
-
export function buildProactivePushSettingsReplyMarkup(
|
|
403
|
-
proactivePushEnabled: boolean,
|
|
404
|
-
): TelegramSettingsMenuReplyMarkup {
|
|
405
|
-
return {
|
|
406
|
-
inline_keyboard: [
|
|
407
|
-
[{ text: "⬆️ Back", callback_data: "settings:list" }],
|
|
408
|
-
[
|
|
409
|
-
{
|
|
410
|
-
text: proactivePushEnabled ? "🟢 On" : "⚫️ On",
|
|
411
|
-
callback_data: "settings:set:proactive:on",
|
|
412
|
-
},
|
|
413
|
-
{
|
|
414
|
-
text: proactivePushEnabled ? "⚫️ Off" : "🟡 Off",
|
|
415
|
-
callback_data: "settings:set:proactive:off",
|
|
416
|
-
},
|
|
417
|
-
],
|
|
418
|
-
],
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
|
|
422
380
|
export function buildDraftPreviewsSettingsReplyMarkup(
|
|
423
381
|
enabled: boolean,
|
|
424
382
|
): TelegramSettingsMenuReplyMarkup {
|
|
@@ -521,7 +479,6 @@ export async function updateTelegramSettingsMenuMessage(
|
|
|
521
479
|
await deps.updateSettingsMessage(
|
|
522
480
|
buildTelegramSettingsMenuText(),
|
|
523
481
|
buildTelegramSettingsMenuReplyMarkup(
|
|
524
|
-
deps.isProactivePushEnabled(),
|
|
525
482
|
deps.areDraftPreviewsEnabled(),
|
|
526
483
|
deps.getAssistantRenderingMode(),
|
|
527
484
|
deps.getVoiceReplyMode(),
|
|
@@ -544,16 +501,6 @@ export async function updateAutomaticThreadCleanupSettingsMessage(
|
|
|
544
501
|
);
|
|
545
502
|
}
|
|
546
503
|
|
|
547
|
-
export async function updateProactivePushSettingsMessage(
|
|
548
|
-
deps: TelegramSettingsMenuCallbackDeps,
|
|
549
|
-
): Promise<void> {
|
|
550
|
-
const proactivePushEnabled = deps.isProactivePushEnabled();
|
|
551
|
-
await deps.updateSettingsMessage(
|
|
552
|
-
buildProactivePushSettingsText(proactivePushEnabled),
|
|
553
|
-
buildProactivePushSettingsReplyMarkup(proactivePushEnabled),
|
|
554
|
-
);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
504
|
export async function updateDraftPreviewsSettingsMessage(
|
|
558
505
|
deps: TelegramSettingsMenuCallbackDeps,
|
|
559
506
|
): Promise<void> {
|
|
@@ -621,9 +568,16 @@ export async function handleTelegramSettingsMenuCallbackAction(
|
|
|
621
568
|
await deps.answerCallbackQuery(callbackQueryId);
|
|
622
569
|
return true;
|
|
623
570
|
}
|
|
624
|
-
if (
|
|
625
|
-
|
|
626
|
-
|
|
571
|
+
if (
|
|
572
|
+
data === "settings:open:proactive" ||
|
|
573
|
+
data === "settings:set:proactive:on" ||
|
|
574
|
+
data === "settings:set:proactive:off"
|
|
575
|
+
) {
|
|
576
|
+
await updateTelegramSettingsMenuMessage(deps, deps.sectionRegistry);
|
|
577
|
+
await deps.answerCallbackQuery(
|
|
578
|
+
callbackQueryId,
|
|
579
|
+
"Public assistant output is always delivered while Telegram is connected.",
|
|
580
|
+
);
|
|
627
581
|
return true;
|
|
628
582
|
}
|
|
629
583
|
if (
|
|
@@ -751,19 +705,6 @@ export async function handleTelegramSettingsMenuCallbackAction(
|
|
|
751
705
|
);
|
|
752
706
|
return true;
|
|
753
707
|
}
|
|
754
|
-
if (
|
|
755
|
-
data === "settings:set:proactive:on" ||
|
|
756
|
-
data === "settings:set:proactive:off"
|
|
757
|
-
) {
|
|
758
|
-
const enabled = data.endsWith(":on");
|
|
759
|
-
await deps.setProactivePushEnabled(enabled);
|
|
760
|
-
await updateProactivePushSettingsMessage(deps);
|
|
761
|
-
await deps.answerCallbackQuery(
|
|
762
|
-
callbackQueryId,
|
|
763
|
-
`Proactive push ${enabled ? "enabled" : "disabled"}`,
|
|
764
|
-
);
|
|
765
|
-
return true;
|
|
766
|
-
}
|
|
767
708
|
await deps.answerCallbackQuery(callbackQueryId);
|
|
768
709
|
return true;
|
|
769
710
|
}
|
|
@@ -781,7 +722,6 @@ export function createTelegramSettingsMenuRuntime<
|
|
|
781
722
|
return openTelegramSettingsMenu(
|
|
782
723
|
{
|
|
783
724
|
getModelMenuState: () => deps.getModelMenuState(chatId, ctx),
|
|
784
|
-
isProactivePushEnabled: deps.isProactivePushEnabled,
|
|
785
725
|
areDraftPreviewsEnabled: deps.areDraftPreviewsEnabled,
|
|
786
726
|
getAssistantRenderingMode: deps.getAssistantRenderingMode,
|
|
787
727
|
getActivityVerbosity: deps.getActivityVerbosity,
|
|
@@ -805,7 +745,6 @@ export function createTelegramSettingsMenuRuntime<
|
|
|
805
745
|
await deps.reloadConfig?.();
|
|
806
746
|
return updateTelegramSettingsMenuMessage(
|
|
807
747
|
{
|
|
808
|
-
isProactivePushEnabled: deps.isProactivePushEnabled,
|
|
809
748
|
areDraftPreviewsEnabled: deps.areDraftPreviewsEnabled,
|
|
810
749
|
getAssistantRenderingMode: deps.getAssistantRenderingMode,
|
|
811
750
|
getActivityVerbosity: deps.getActivityVerbosity,
|
|
@@ -849,7 +788,6 @@ export function createTelegramSettingsMenuRuntime<
|
|
|
849
788
|
deps.storeModelMenuState(state);
|
|
850
789
|
}
|
|
851
790
|
return handleTelegramSettingsMenuCallbackAction(query.id, query.data, {
|
|
852
|
-
isProactivePushEnabled: deps.isProactivePushEnabled,
|
|
853
791
|
areDraftPreviewsEnabled: deps.areDraftPreviewsEnabled,
|
|
854
792
|
getAssistantRenderingMode: deps.getAssistantRenderingMode,
|
|
855
793
|
getActivityVerbosity: deps.getActivityVerbosity,
|
|
@@ -857,7 +795,6 @@ export function createTelegramSettingsMenuRuntime<
|
|
|
857
795
|
isVoiceReplyModeConfigured: deps.isVoiceReplyModeConfigured,
|
|
858
796
|
getTimeInjectionMode: deps.getTimeInjectionMode,
|
|
859
797
|
isAutomaticThreadCleanupEnabled: deps.isAutomaticThreadCleanupEnabled,
|
|
860
|
-
setProactivePushEnabled: deps.setProactivePushEnabled,
|
|
861
798
|
setDraftPreviewsEnabled: deps.setDraftPreviewsEnabled,
|
|
862
799
|
setAssistantRenderingMode: deps.setAssistantRenderingMode,
|
|
863
800
|
setActivityVerbosity: deps.setActivityVerbosity,
|
|
@@ -14,11 +14,14 @@ import {
|
|
|
14
14
|
type ExtensionCommandContext,
|
|
15
15
|
type ExtensionContext,
|
|
16
16
|
type InputEvent,
|
|
17
|
+
type MessageEndEvent,
|
|
17
18
|
type SessionBeforeCompactEvent,
|
|
18
19
|
type SessionCompactEvent,
|
|
19
20
|
type SessionShutdownEvent,
|
|
20
21
|
type SessionStartEvent,
|
|
21
22
|
type SlashCommandInfo,
|
|
23
|
+
type UIPromptEndEvent,
|
|
24
|
+
type UIPromptStartEvent,
|
|
22
25
|
SettingsManager,
|
|
23
26
|
} from "@earendil-works/pi-coding-agent";
|
|
24
27
|
|
|
@@ -32,13 +35,25 @@ export type {
|
|
|
32
35
|
ExtensionCommandContext,
|
|
33
36
|
ExtensionContext,
|
|
34
37
|
InputEvent,
|
|
38
|
+
MessageEndEvent,
|
|
35
39
|
SessionBeforeCompactEvent,
|
|
36
40
|
SessionCompactEvent,
|
|
37
41
|
SessionShutdownEvent,
|
|
38
42
|
SessionStartEvent,
|
|
39
43
|
SlashCommandInfo,
|
|
44
|
+
UIPromptEndEvent,
|
|
45
|
+
UIPromptStartEvent,
|
|
40
46
|
};
|
|
41
47
|
|
|
48
|
+
export interface SessionCompactFailedEvent {
|
|
49
|
+
type: "session_compact_failed";
|
|
50
|
+
reason: "manual" | "threshold" | "overflow";
|
|
51
|
+
errorMessage?: string;
|
|
52
|
+
aborted: boolean;
|
|
53
|
+
willRetry: boolean;
|
|
54
|
+
fromExtension: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
42
57
|
export interface ToolExecutionStartEvent {
|
|
43
58
|
type: "tool_execution_start";
|
|
44
59
|
toolCallId: string;
|
|
@@ -14,6 +14,7 @@ export interface TelegramUsageStats {
|
|
|
14
14
|
totalCacheRead: number;
|
|
15
15
|
totalCacheWrite: number;
|
|
16
16
|
totalCost: number;
|
|
17
|
+
latestCacheHitRate?: number;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
interface TelegramUsageMessage {
|
|
@@ -1473,6 +1474,9 @@ function collectUsageStats(ctx: TelegramStatusContext): TelegramUsageStats {
|
|
|
1473
1474
|
stats.totalCacheRead += usage.cacheRead;
|
|
1474
1475
|
stats.totalCacheWrite += usage.cacheWrite;
|
|
1475
1476
|
stats.totalCost += usage.cost.total;
|
|
1477
|
+
const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
1478
|
+
stats.latestCacheHitRate =
|
|
1479
|
+
promptTokens > 0 ? (usage.cacheRead / promptTokens) * 100 : undefined;
|
|
1476
1480
|
}
|
|
1477
1481
|
return stats;
|
|
1478
1482
|
}
|
|
@@ -1494,6 +1498,12 @@ function buildUsageSummary(stats: TelegramUsageStats): string | undefined {
|
|
|
1494
1498
|
tokenParts.push(`R${formatTokens(stats.totalCacheRead)}`);
|
|
1495
1499
|
if (stats.totalCacheWrite)
|
|
1496
1500
|
tokenParts.push(`W${formatTokens(stats.totalCacheWrite)}`);
|
|
1501
|
+
if (
|
|
1502
|
+
(stats.totalCacheRead > 0 || stats.totalCacheWrite > 0) &&
|
|
1503
|
+
stats.latestCacheHitRate !== undefined
|
|
1504
|
+
) {
|
|
1505
|
+
tokenParts.push(`CH${stats.latestCacheHitRate.toFixed(1)}%`);
|
|
1506
|
+
}
|
|
1497
1507
|
return tokenParts.length > 0 ? tokenParts.join(" ") : undefined;
|
|
1498
1508
|
}
|
|
1499
1509
|
|
|
@@ -1549,7 +1559,7 @@ export function buildStatusHtml(
|
|
|
1549
1559
|
const usageSummary = buildUsageSummary(stats);
|
|
1550
1560
|
const costSummary = buildCostSummary(stats, usesSubscription);
|
|
1551
1561
|
if (usageSummary) {
|
|
1552
|
-
lines.push(buildStatusRow("
|
|
1562
|
+
lines.push(buildStatusRow("Tokens", usageSummary));
|
|
1553
1563
|
}
|
|
1554
1564
|
if (costSummary) {
|
|
1555
1565
|
lines.push(buildStatusRow("Cost", costSummary));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-telegram",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -71,9 +71,9 @@
|
|
|
71
71
|
"image": "https://raw.githubusercontent.com/llblab/pi-telegram/main/screenshot.png"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
|
-
"@earendil-works/pi-agent-core": ">=0.
|
|
75
|
-
"@earendil-works/pi-ai": ">=0.
|
|
76
|
-
"@earendil-works/pi-coding-agent": ">=0.
|
|
74
|
+
"@earendil-works/pi-agent-core": ">=0.84.4",
|
|
75
|
+
"@earendil-works/pi-ai": ">=0.84.4",
|
|
76
|
+
"@earendil-works/pi-coding-agent": ">=0.84.4",
|
|
77
77
|
"@sinclair/typebox": "*"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|