@llblab/pi-kit 0.1.12 → 0.1.13

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 CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  All notable changes to `@llblab/pi-kit` are documented here.
4
4
 
5
+ ## 0.1.13 - 2026-08-30
6
+
7
+ - `Telegram Minor Release`: Advances `@llblab/pi-telegram` to `0.40.0`, requiring Pi 0.84.4 and adopting native compaction-failure, mid-run compaction, terminal-message, and local UI-prompt lifecycle contracts while increasing bounded inbound text output to 24,000 characters.
8
+
5
9
  ## 0.1.12 - 2026-08-28
6
10
 
7
11
  - `Codex Usage Release`: Advances `@llblab/pi-codex-usage` to `0.9.4`, reducing automatic OpenAI quota polling by increasing the refresh interval from 30 to 60 seconds while preserving the local countdown responsiveness.
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  | `@llblab/pi-actors` | `0.50.0` | Extension and Skills |
10
10
  | `@llblab/pi-codex-usage` | `0.9.4` | Extension |
11
11
  | `@llblab/pi-grow-loop` | `0.7.3` | Extension and Skills |
12
- | `@llblab/pi-telegram` | `0.39.5` | Extension and Skills |
12
+ | `@llblab/pi-telegram` | `0.40.0` | Extension and Skills |
13
13
 
14
14
  Versions are exact by design. Updating an extension does not change an installed kit until this repository explicitly advances that dependency and publishes a new kit version.
15
15
 
@@ -2,6 +2,14 @@
2
2
 
3
3
  > Each release keeps at most 8 outcome records of at most 512 characters.
4
4
 
5
+ ## 0.40.0: Pi 0.84.4 Lifecycle Alignment
6
+
7
+ - `Pi Compatibility`: Requires `@earendil-works/pi-coding-agent`, `pi-agent-core`, and `pi-ai` 0.84.4 or newer, aligning the bridge and its validation runtime with native compaction-failure, mid-run compaction, message-finalization, and UI-prompt lifecycle contracts.
8
+ - `Compaction Failure`: Handles `session_compact_failed` immediately by clearing compacting state, stopping observer-owned typing, releasing deferred queue work, abandoning stale activity, and reporting automatic failure or cancellation without duplicating manual `/compact` errors.
9
+ - `Compaction Chronology`: Distinguishes terminal assistant output awaiting Telegram delivery from mid-run tool continuation. Post-answer notices remain ordered after the final reply, while tool-result threshold compaction is reported in place before the next assistant response.
10
+ - `Local UI Waiting`: Pauses Telegram typing while Pi waits on extension-owned local select, confirm, input, editor, or custom prompts and emits coalesced `ui-prompt-start` / `ui-prompt-end` Activity boundaries before resuming active-turn typing.
11
+ - `Inbound Context`: Raises successful inbound handler and built-in text attachment output from 12,000 to 24,000 characters while retaining the 1 MB built-in file admission ceiling and explicit truncation evidence.
12
+
5
13
  ## 0.39.5: Auto-Compaction Notice Chronology Hotfix
6
14
 
7
15
  - `Turn Chronology`: Defers observed automatic-compaction notices while a Telegram turn is still active, preserving the same causal order shown by the terminal: final answer, compaction started, then compaction completed. Abandoned compactions and session shutdown discard deferred notices instead of leaking them into a later turn.
@@ -96,7 +96,7 @@ Source classification follows evidence, not guesses:
96
96
 
97
97
  Automatic retries, overflow compaction retries, and tool continuations inherit the current activity identity/source until `agent_settled`. A new unrelated `agent_start` after settlement allocates a new activity id.
98
98
 
99
- A standalone compaction owns a temporary activity only until `session_compact`. Pi does not expose a sibling-extension cancellation/failure callback after `session_before_compact`, so pi-telegram abandons that temporary identity at the first provable fallback boundary: the next `agent_start`, a replacement compaction start, session shutdown, or the existing five-minute compaction-observer timeout. A late `session_compact` after abandonment is ignored and cannot attach to the next run. Compaction inside an existing agent activity never clears that agent's identity.
99
+ A standalone compaction owns a temporary activity until `session_compact` or `session_compact_failed`. Native failure or cancellation immediately abandons that identity, clears compacting state, releases deferred queue work, and stops observer-owned typing; the five-minute observer timeout remains a compatibility fallback for a host that never emits a terminal compaction event. A late `session_compact` after abandonment is ignored and cannot attach to the next run. Compaction inside an existing agent activity never clears that agent's identity.
100
100
 
101
101
  ## Event Contract
102
102
 
@@ -151,6 +151,12 @@ export type TelegramActivityEvent = TelegramActivityEnvelope & (
151
151
  type: "compaction-end";
152
152
  reason: "manual" | "threshold" | "overflow" | "unknown";
153
153
  }
154
+ | {
155
+ type: "ui-prompt-start";
156
+ kind: "select" | "confirm" | "input" | "editor" | "custom";
157
+ title?: string;
158
+ }
159
+ | { type: "ui-prompt-end" }
154
160
  | { type: "agent-end" }
155
161
  | { type: "agent-settled" }
156
162
  );
@@ -250,7 +256,8 @@ The bridge maps Pi hooks as follows:
250
256
  - `agent_start`: allocate or reuse activity identity and emit `agent-start` after Telegram queue consumption establishes active-turn ownership.
251
257
  - `message_update.assistantMessageEvent`: normalize text/reasoning/provider boundaries.
252
258
  - `tool_execution_start/update/end`: emit executed tool events.
253
- - `session_before_compact` / `session_compact`: emit compaction boundaries and preserve activity identity across retry compaction; abandon an unterminated standalone compaction at the next lifecycle boundary or observer timeout rather than merging it into another run. A missing or unrecognized reason maps to `unknown` rather than guessing.
259
+ - `session_before_compact` / `session_compact` / `session_compact_failed`: emit successful compaction boundaries, abandon failed or cancelled work immediately, and preserve activity identity across retry compaction. Mid-run threshold compaction stays between tool results and the next assistant response, while terminal assistant output awaiting transport keeps later notices behind its final reply. A missing or unrecognized reason maps to `unknown` rather than guessing.
260
+ - `ui_prompt_start` / `ui_prompt_end`: emit one coalesced waiting span for extension-owned local UI, pause Telegram typing while Pi waits for the operator, and resume active-turn typing when the prompt closes.
254
261
  - `agent_end`: emit low-level run completion but keep identity alive for retry/follow-up work.
255
262
  - `agent_settled`: emit terminal settlement, flush pending terminal segments, and release activity identity.
256
263
  - `session_shutdown`: stop dispatch, clear pending normalization state, and invalidate delivery generation through the existing delivery lifecycle.
@@ -315,14 +315,15 @@ Queue and menu mutations are reachable through Telegram updates handled by the c
315
315
 
316
316
  ### Compaction And Typing Status
317
317
 
318
- Manual `/compact` requires inline confirmation because accidental taps are disruptive. Confirmed manual compaction and auto-compaction both set the bridge compaction flag, block queued prompt dispatch, retain that flag in explicit diagnostics, and clear it on compact completion, timeout fallback, or session shutdown. Pi owns its terminal compaction lifecycle; pi-telegram keeps `Active` scoped to Telegram-owned work and otherwise preserves the stable connected/leader/follower role.
318
+ Manual `/compact` requires inline confirmation because accidental taps are disruptive. Confirmed manual compaction and auto-compaction both set the bridge compaction flag, block queued prompt dispatch, retain that flag in explicit diagnostics, and clear it on native compact completion or failure, timeout fallback, or session shutdown. Pi owns its terminal compaction lifecycle; pi-telegram keeps `Active` scoped to Telegram-owned work and otherwise preserves the stable connected/leader/follower role. Mid-run threshold compaction reports notices in place between tool output and the next assistant response; compaction observed after terminal assistant output waits for final Telegram delivery so transport chronology matches the terminal.
319
319
 
320
320
  Native typing during compaction follows connected-instance activity rather than terminal status:
321
321
 
322
322
  - Confirmed manual `/compact` starts a native `typing` keepalive in the command target and stops it on completion/failure.
323
323
  - Automatic/session compaction with an active Telegram turn reuses that turn's target.
324
324
  - Automatic/session compaction without an active Telegram turn uses the connected instance's assigned target; an unconnected instance sends nothing.
325
- - Thread-targeted typing is sent to the concrete thread and mirrored to `All` as the aggregate activity surface; completion, timeout, and shutdown stop the keyed loop.
325
+ - Thread-targeted typing is sent to the concrete thread and mirrored to `All` as the aggregate activity surface; completion, native failure, timeout, and shutdown stop the keyed loop.
326
+ - Pi `ui_prompt_start` pauses active-turn typing while an extension-owned local prompt waits for the operator; `ui_prompt_end` emits the matching Activity boundary and resumes typing.
326
327
 
327
328
  At every connected instance `agent_start`, the lifecycle binding starts Telegram's native `…typing` indicator in that instance's assigned target, whether the run came from Telegram, the local TUI, or an autonomous continuation such as Grow Loop. Terminal `Active` remains Telegram-turn-specific; the native indicator answers the separate question of whether the instance is doing agent work. Each loop keeps one action in flight, while the leader API runtime coalesces identical chat/thread/action calls across local and follower traffic for two seconds; expired gates prune opportunistically and at most 256 currently active keys are retained. A Telegram 429 response opens the exact action's shared `retry_after` suppression window without scheduling delayed retries or projecting expected activity throttling as a terminal status error. Assistant message start/update hooks still re-arm it during Telegram-owned turns so transient provider/model errors do not leave a continuing run without activity feedback, and agent/session completion stops it.
328
329
 
@@ -85,6 +85,12 @@ export type TelegramActivityPayload =
85
85
  type: "compaction-end";
86
86
  reason: "manual" | "threshold" | "overflow" | "unknown";
87
87
  }
88
+ | {
89
+ type: "ui-prompt-start";
90
+ kind: "select" | "confirm" | "input" | "editor" | "custom";
91
+ title?: string;
92
+ }
93
+ | { type: "ui-prompt-end" }
88
94
  | { type: "agent-end" }
89
95
  | { type: "agent-settled" };
90
96
 
@@ -440,6 +446,12 @@ export function createTelegramActivityBridgeRuntime(deps: {
440
446
  onCompactionAbandoned() {
441
447
  getRuntime()?.onCompactionAbandoned();
442
448
  },
449
+ onUiPromptStart(kind, title) {
450
+ getRuntime()?.onUiPromptStart(kind, title);
451
+ },
452
+ onUiPromptEnd() {
453
+ getRuntime()?.onUiPromptEnd();
454
+ },
443
455
  onAgentEnd() {
444
456
  getRuntime()?.onAgentEnd();
445
457
  },
@@ -502,6 +514,11 @@ export interface TelegramActivityRuntime {
502
514
  reason: "manual" | "threshold" | "overflow" | "unknown",
503
515
  ) => void;
504
516
  onCompactionAbandoned: () => void;
517
+ onUiPromptStart: (
518
+ kind: "select" | "confirm" | "input" | "editor" | "custom",
519
+ title?: string,
520
+ ) => void;
521
+ onUiPromptEnd: () => void;
505
522
  onAgentEnd: () => void;
506
523
  onAgentSettled: () => void;
507
524
  onSessionShutdown: () => void;
@@ -533,6 +550,7 @@ export function createTelegramActivityRuntime(deps: {
533
550
  let pendingAssistantSegment: PendingAssistantSegment | undefined;
534
551
  let compactionInProgress = false;
535
552
  let compactionOwnedActivity = false;
553
+ let uiPromptInProgress = false;
536
554
  const ensureActivity = (
537
555
  activeTelegramTarget?: TelegramActivityTarget,
538
556
  ): string => {
@@ -592,6 +610,7 @@ export function createTelegramActivityRuntime(deps: {
592
610
  pendingAssistantSegment = undefined;
593
611
  compactionInProgress = false;
594
612
  compactionOwnedActivity = false;
613
+ uiPromptInProgress = false;
595
614
  };
596
615
  const abandonCompaction = (): void => {
597
616
  if (!compactionInProgress) return;
@@ -685,6 +704,16 @@ export function createTelegramActivityRuntime(deps: {
685
704
  onCompactionAbandoned() {
686
705
  abandonCompaction();
687
706
  },
707
+ onUiPromptStart(kind, title) {
708
+ if (!activityId || uiPromptInProgress) return;
709
+ uiPromptInProgress = true;
710
+ emit({ type: "ui-prompt-start", kind, title });
711
+ },
712
+ onUiPromptEnd() {
713
+ if (!activityId || !uiPromptInProgress) return;
714
+ uiPromptInProgress = false;
715
+ emit({ type: "ui-prompt-end" });
716
+ },
688
717
  onAgentEnd() {
689
718
  if (activityId) emit({ type: "agent-end" });
690
719
  },
@@ -1012,8 +1012,9 @@ export function registerTelegramLifecycleRuntimeHooks({
1012
1012
  const agentStartWithDedupReset = Lifecycle.createAgentStartDedupHook(
1013
1013
  agentLifecycleHooks.onAgentStart,
1014
1014
  );
1015
+ let uiPromptActive = false;
1015
1016
  const startAgentActivityTypingLoop = (ctx: Pi.ExtensionContext): boolean => {
1016
- if (!canSendAgentActivity(ctx)) return false;
1017
+ if (uiPromptActive || !canSendAgentActivity(ctx)) return false;
1017
1018
  const turn = activeTurnRuntime.get();
1018
1019
  const target = turn?.target ?? proactivePushTargetGetter();
1019
1020
  promptDispatchRuntime.startTypingLoop(ctx, turn?.chatId ?? target?.chatId, {
@@ -1022,12 +1023,15 @@ export function registerTelegramLifecycleRuntimeHooks({
1022
1023
  return true;
1023
1024
  };
1024
1025
  const startActiveTurnTypingLoop = (ctx: Pi.ExtensionContext): void => {
1026
+ if (uiPromptActive) return;
1025
1027
  const turn = activeTurnRuntime.get();
1026
1028
  promptDispatchRuntime.startTypingLoop(ctx, turn?.chatId, {
1027
1029
  target: turn?.target,
1028
1030
  });
1029
1031
  };
1030
1032
  let observedAutomaticCompaction = false;
1033
+ let agentRunActive = false;
1034
+ let terminalAssistantMessagePendingDelivery = false;
1031
1035
  const deferredAutomaticCompactionNotices: string[] = [];
1032
1036
  const sendCompactionNotice = async (text: string): Promise<void> => {
1033
1037
  const turn = activeTurnRuntime.get();
@@ -1094,6 +1098,9 @@ export function registerTelegramLifecycleRuntimeHooks({
1094
1098
  activityVerbosityRuntime?.reset();
1095
1099
  assistantOutputRuntime.stop();
1096
1100
  observedAutomaticCompaction = false;
1101
+ agentRunActive = false;
1102
+ terminalAssistantMessagePendingDelivery = false;
1103
+ uiPromptActive = false;
1097
1104
  deferredAutomaticCompactionNotices.length = 0;
1098
1105
  compactionObserver.onSessionShutdown();
1099
1106
  if (event.reason === "quit" && disconnectOnQuit) {
@@ -1116,7 +1123,10 @@ export function registerTelegramLifecycleRuntimeHooks({
1116
1123
  activityRuntime.onCompactionStart(Pi.getSessionCompactionReason(event));
1117
1124
  compactionObserver.onSessionBeforeCompact(event, ctx);
1118
1125
  if (shouldNotify) {
1119
- if (activeTurnRuntime.has()) {
1126
+ if (
1127
+ activeTurnRuntime.has() &&
1128
+ terminalAssistantMessagePendingDelivery
1129
+ ) {
1120
1130
  deferredAutomaticCompactionNotices.push(
1121
1131
  Commands.TELEGRAM_COMPACTION_STARTED_MARKDOWN,
1122
1132
  );
@@ -1135,10 +1145,7 @@ export function registerTelegramLifecycleRuntimeHooks({
1135
1145
  compactionObserver.onSessionCompact(event, ctx);
1136
1146
  if (observedAutomaticCompaction) {
1137
1147
  observedAutomaticCompaction = false;
1138
- if (
1139
- activeTurnRuntime.has() ||
1140
- deferredAutomaticCompactionNotices.length > 0
1141
- ) {
1148
+ if (deferredAutomaticCompactionNotices.length > 0) {
1142
1149
  deferredAutomaticCompactionNotices.push(
1143
1150
  Commands.TELEGRAM_COMPACTION_COMPLETED_MARKDOWN,
1144
1151
  );
@@ -1149,8 +1156,28 @@ export function registerTelegramLifecycleRuntimeHooks({
1149
1156
  }
1150
1157
  }
1151
1158
  },
1159
+ async onSessionCompactFailed(event, ctx) {
1160
+ if (!isSessionContextActive(ctx)) return;
1161
+ const shouldNotify = observedAutomaticCompaction;
1162
+ const deferredNotices = deferredAutomaticCompactionNotices.splice(0);
1163
+ const shouldDefer =
1164
+ deferredNotices.length > 0 ||
1165
+ (activeTurnRuntime.has() && terminalAssistantMessagePendingDelivery);
1166
+ compactionObserver.onSessionCompactFailed(event, ctx);
1167
+ if (!shouldNotify) return;
1168
+ const notice = event.aborted
1169
+ ? "**⚠️ Compaction cancelled.**"
1170
+ : "**⚠️ Compaction failed.**";
1171
+ if (shouldDefer) {
1172
+ deferredAutomaticCompactionNotices.push(...deferredNotices, notice);
1173
+ } else {
1174
+ await sendCompactionNotice(notice);
1175
+ }
1176
+ },
1152
1177
  async onAgentStart(event, ctx) {
1153
1178
  if (!isSessionContextActive(ctx)) return;
1179
+ agentRunActive = true;
1180
+ terminalAssistantMessagePendingDelivery = false;
1154
1181
  await agentStartWithDedupReset(event, ctx);
1155
1182
  activityRuntime.onAgentStart(activeTurnRuntime.get()?.target);
1156
1183
  startAgentActivityTypingLoop(ctx);
@@ -1195,8 +1222,31 @@ export function registerTelegramLifecycleRuntimeHooks({
1195
1222
  }
1196
1223
  await messageActivityHooks.onMessageUpdate(event, ctx);
1197
1224
  },
1225
+ onMessageEnd(event, ctx) {
1226
+ if (!isSessionContextActive(ctx)) return;
1227
+ terminalAssistantMessagePendingDelivery =
1228
+ event.message.role === "assistant" &&
1229
+ event.message.stopReason !== "toolUse" &&
1230
+ event.message.stopReason !== "error" &&
1231
+ event.message.stopReason !== "aborted";
1232
+ },
1233
+ onUiPromptStart(event, ctx) {
1234
+ if (!isSessionContextActive(ctx)) return;
1235
+ uiPromptActive = true;
1236
+ typing.stop();
1237
+ activityRuntime.onUiPromptStart(event.kind, event.title);
1238
+ updateStatus(ctx);
1239
+ },
1240
+ onUiPromptEnd(_event, ctx) {
1241
+ if (!isSessionContextActive(ctx)) return;
1242
+ uiPromptActive = false;
1243
+ activityRuntime.onUiPromptEnd();
1244
+ if (agentRunActive) startAgentActivityTypingLoop(ctx);
1245
+ updateStatus(ctx);
1246
+ },
1198
1247
  async onAgentEnd(event, ctx) {
1199
1248
  if (!isSessionContextActive(ctx)) return;
1249
+ agentRunActive = false;
1200
1250
  activityRuntime.onAgentEnd();
1201
1251
  await agentLifecycleHooks.onAgentEnd(event, ctx);
1202
1252
  if (deferredAutomaticCompactionNotices.length > 0) {
@@ -1204,6 +1254,7 @@ export function registerTelegramLifecycleRuntimeHooks({
1204
1254
  if (!isSessionContextActive(ctx)) return;
1205
1255
  await flushDeferredAutomaticCompactionNotices();
1206
1256
  }
1257
+ terminalAssistantMessagePendingDelivery = false;
1207
1258
  },
1208
1259
  async onAgentSettled(event, ctx) {
1209
1260
  if (!isSessionContextActive(ctx)) return;
@@ -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 = 12_000;
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);
@@ -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;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-telegram",
3
- "version": "0.39.5",
3
+ "version": "0.40.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.80.6",
75
- "@earendil-works/pi-ai": ">=0.80.6",
76
- "@earendil-works/pi-coding-agent": ">=0.80.6",
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": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-kit",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -43,7 +43,7 @@
43
43
  "@llblab/pi-actors": "0.50.0",
44
44
  "@llblab/pi-codex-usage": "0.9.4",
45
45
  "@llblab/pi-grow-loop": "0.7.3",
46
- "@llblab/pi-telegram": "0.39.5"
46
+ "@llblab/pi-telegram": "0.40.0"
47
47
  },
48
48
  "bundledDependencies": [
49
49
  "@llblab/pi-actors",