@llblab/pi-telegram 0.4.0 → 0.5.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.
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Telegram lifecycle hook registration helpers
3
+ * Owns binding prepared Telegram lifecycle runtimes to pi extension lifecycle events
4
+ */
5
+
6
+ import type {
7
+ AgentEndEvent,
8
+ AgentStartEvent,
9
+ BeforeAgentStartEvent,
10
+ ExtensionAPI,
11
+ ExtensionContext,
12
+ SessionShutdownEvent,
13
+ SessionStartEvent,
14
+ } from "./pi.ts";
15
+
16
+ export interface TelegramBeforeAgentStartResult {
17
+ systemPrompt?: string;
18
+ }
19
+
20
+ type TelegramBeforeAgentStartReturn =
21
+ | Promise<TelegramBeforeAgentStartResult | undefined>
22
+ | TelegramBeforeAgentStartResult
23
+ | undefined;
24
+
25
+ type TelegramLifecycleModel = ExtensionContext["model"];
26
+ type TelegramLifecycleMessage = AgentEndEvent["messages"][number];
27
+
28
+ export interface TelegramLifecycleRegistrationDeps {
29
+ onSessionStart: (
30
+ event: SessionStartEvent,
31
+ ctx: ExtensionContext,
32
+ ) => Promise<void>;
33
+ onSessionShutdown: (
34
+ event: SessionShutdownEvent,
35
+ ctx: ExtensionContext,
36
+ ) => Promise<void>;
37
+ onBeforeAgentStart: (
38
+ event: BeforeAgentStartEvent,
39
+ ctx: ExtensionContext,
40
+ ) => TelegramBeforeAgentStartReturn;
41
+ onModelSelect: (
42
+ event: { model: TelegramLifecycleModel },
43
+ ctx: ExtensionContext,
44
+ ) => Promise<void> | void;
45
+ onAgentStart: (
46
+ event: AgentStartEvent,
47
+ ctx: ExtensionContext,
48
+ ) => Promise<void>;
49
+ onToolExecutionStart: (
50
+ event: unknown,
51
+ ctx: ExtensionContext,
52
+ ) => Promise<void> | void;
53
+ onToolExecutionEnd: (
54
+ event: unknown,
55
+ ctx: ExtensionContext,
56
+ ) => Promise<void> | void;
57
+ onMessageStart: (
58
+ event: { message: TelegramLifecycleMessage },
59
+ ctx: ExtensionContext,
60
+ ) => Promise<void>;
61
+ onMessageUpdate: (
62
+ event: { message: TelegramLifecycleMessage },
63
+ ctx: ExtensionContext,
64
+ ) => Promise<void>;
65
+ onAgentEnd: (event: AgentEndEvent, ctx: ExtensionContext) => Promise<void>;
66
+ }
67
+
68
+ export interface TelegramSessionLifecycleHooks {
69
+ onSessionStart: (
70
+ event: SessionStartEvent,
71
+ ctx: ExtensionContext,
72
+ ) => Promise<void>;
73
+ onSessionShutdown: (
74
+ event: SessionShutdownEvent,
75
+ ctx: ExtensionContext,
76
+ ) => Promise<void>;
77
+ }
78
+
79
+ export interface TelegramExtraLifecycleHooks {
80
+ onSessionStart?: (
81
+ event: SessionStartEvent,
82
+ ctx: ExtensionContext,
83
+ ) => Promise<void>;
84
+ onSessionShutdown?: (
85
+ event: SessionShutdownEvent,
86
+ ctx: ExtensionContext,
87
+ ) => Promise<void>;
88
+ }
89
+
90
+ export function appendTelegramLifecycleHooks(
91
+ base: TelegramSessionLifecycleHooks,
92
+ extra: TelegramExtraLifecycleHooks,
93
+ ): TelegramSessionLifecycleHooks {
94
+ return {
95
+ onSessionStart: async (event, ctx) => {
96
+ await base.onSessionStart(event, ctx);
97
+ await extra.onSessionStart?.(event, ctx);
98
+ },
99
+ onSessionShutdown: async (event, ctx) => {
100
+ await base.onSessionShutdown(event, ctx);
101
+ await extra.onSessionShutdown?.(event, ctx);
102
+ },
103
+ };
104
+ }
105
+
106
+ export function registerTelegramLifecycleHooks(
107
+ pi: ExtensionAPI,
108
+ deps: TelegramLifecycleRegistrationDeps,
109
+ ): void {
110
+ pi.on("session_start", async (event, ctx) => {
111
+ await deps.onSessionStart(event, ctx);
112
+ });
113
+ pi.on("session_shutdown", async (event, ctx) => {
114
+ await deps.onSessionShutdown(event, ctx);
115
+ });
116
+ pi.on("before_agent_start", async (event, ctx) => {
117
+ return deps.onBeforeAgentStart(event, ctx);
118
+ });
119
+ pi.on("model_select", async (event, ctx) => {
120
+ await deps.onModelSelect(event, ctx);
121
+ });
122
+ pi.on("agent_start", async (event, ctx) => {
123
+ await deps.onAgentStart(event, ctx);
124
+ });
125
+ pi.on("tool_execution_start", async (event, ctx) => {
126
+ await deps.onToolExecutionStart(event, ctx);
127
+ });
128
+ pi.on("tool_execution_end", async (event, ctx) => {
129
+ await deps.onToolExecutionEnd(event, ctx);
130
+ });
131
+ pi.on("message_start", async (event, ctx) => {
132
+ await deps.onMessageStart(event, ctx);
133
+ });
134
+ pi.on("message_update", async (event, ctx) => {
135
+ await deps.onMessageUpdate(event, ctx);
136
+ });
137
+ pi.on("agent_end", async (event, ctx) => {
138
+ await deps.onAgentEnd(event, ctx);
139
+ });
140
+ }
package/lib/locks.ts CHANGED
@@ -3,7 +3,14 @@
3
3
  * Owns shared locks.json access and Telegram bridge ownership semantics
4
4
  */
5
5
 
6
- import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
6
+ import {
7
+ existsSync,
8
+ mkdirSync,
9
+ readFileSync,
10
+ renameSync,
11
+ unlinkSync,
12
+ writeFileSync,
13
+ } from "node:fs";
7
14
  import { homedir } from "node:os";
8
15
  import { dirname, join, resolve } from "node:path";
9
16
 
@@ -68,7 +75,9 @@ export type TelegramLockedPollingStartResult =
68
75
  | { ok: true; message: string; canTakeover?: false }
69
76
  | { ok: false; message: string; canTakeover?: boolean; owner?: string };
70
77
 
71
- export interface TelegramLockedPollingRuntime<TContext extends TelegramLockContext> {
78
+ export interface TelegramLockedPollingRuntime<
79
+ TContext extends TelegramLockContext,
80
+ > {
72
81
  start: (
73
82
  ctx: TContext,
74
83
  options?: TelegramLockedPollingStartOptions,
@@ -78,13 +87,19 @@ export interface TelegramLockedPollingRuntime<TContext extends TelegramLockConte
78
87
  onSessionStart: (_event: unknown, ctx: TContext) => Promise<void>;
79
88
  }
80
89
 
81
- export interface TelegramLockedPollingRuntimeDeps<TContext extends TelegramLockContext> {
90
+ export interface TelegramLockedPollingRuntimeDeps<
91
+ TContext extends TelegramLockContext,
92
+ > {
82
93
  lock: TelegramLockRuntime<TContext>;
83
94
  hasBotToken: () => boolean;
84
95
  startPolling: (ctx: TContext) => void | Promise<void>;
85
96
  stopPolling: () => Promise<void>;
86
97
  updateStatus: (ctx: TContext) => void;
87
- recordRuntimeEvent?: (category: string, error: unknown, details?: Record<string, unknown>) => void;
98
+ recordRuntimeEvent?: (
99
+ category: string,
100
+ error: unknown,
101
+ details?: Record<string, unknown>,
102
+ ) => void;
88
103
  ownershipCheckMs?: number;
89
104
  }
90
105
 
@@ -116,8 +131,11 @@ export function writeLocks(path: string, locks: Record<string, unknown>): void {
116
131
  }
117
132
  }
118
133
 
119
- export function parseTelegramLockEntry(value: unknown): TelegramLockEntry | undefined {
120
- if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
134
+ export function parseTelegramLockEntry(
135
+ value: unknown,
136
+ ): TelegramLockEntry | undefined {
137
+ if (!value || typeof value !== "object" || Array.isArray(value))
138
+ return undefined;
121
139
  const record = value as Record<string, unknown>;
122
140
  if (typeof record.pid !== "number") return undefined;
123
141
  return {
@@ -140,7 +158,11 @@ function formatLock(lock: TelegramLockEntry): string {
140
158
  return lock.cwd ? `pid ${lock.pid}, cwd ${lock.cwd}` : `pid ${lock.pid}`;
141
159
  }
142
160
 
143
- function getLockState(lock: TelegramLockEntry | undefined, pid: number, isAlive: (pid: number) => boolean): TelegramLockState {
161
+ function getLockState(
162
+ lock: TelegramLockEntry | undefined,
163
+ pid: number,
164
+ isAlive: (pid: number) => boolean,
165
+ ): TelegramLockState {
144
166
  if (!lock) return { kind: "inactive" };
145
167
  if (lock.pid === pid) return { kind: "active-here", lock };
146
168
  if (isAlive(lock.pid)) return { kind: "active-elsewhere", lock };
@@ -205,12 +227,15 @@ export function createTelegramLockRuntime<TContext extends TelegramLockContext>(
205
227
  return state;
206
228
  },
207
229
  getState: () => getLockState(readLock(), pid, isAlive),
208
- getStatusLabel: () => formatLockState(getLockState(readLock(), pid, isAlive)),
230
+ getStatusLabel: () =>
231
+ formatLockState(getLockState(readLock(), pid, isAlive)),
209
232
  owns: (ctx) => ownsLockContext(readLock(), pid, ctx),
210
233
  };
211
234
  }
212
235
 
213
- export function createTelegramLockedPollingRuntime<TContext extends TelegramLockContext>(
236
+ export function createTelegramLockedPollingRuntime<
237
+ TContext extends TelegramLockContext,
238
+ >(
214
239
  deps: TelegramLockedPollingRuntimeDeps<TContext>,
215
240
  ): TelegramLockedPollingRuntime<TContext> {
216
241
  let ownershipInterval: ReturnType<typeof setInterval> | undefined;
@@ -239,8 +264,11 @@ export function createTelegramLockedPollingRuntime<TContext extends TelegramLock
239
264
  const stopAfterOwnershipLoss = (ctx: TContext) => {
240
265
  if (ownershipStop) return;
241
266
  stopOwnershipWatcher();
242
- ownershipStop = deps.stopPolling()
243
- .catch((error) => deps.recordRuntimeEvent?.("lock", error, { phase: "ownership-loss" }))
267
+ ownershipStop = deps
268
+ .stopPolling()
269
+ .catch((error) =>
270
+ deps.recordRuntimeEvent?.("lock", error, { phase: "ownership-loss" }),
271
+ )
244
272
  .finally(() => {
245
273
  ownershipStop = undefined;
246
274
  updateStatusSafely(ctx, "ownership-loss-status");
@@ -257,7 +285,8 @@ export function createTelegramLockedPollingRuntime<TContext extends TelegramLock
257
285
  };
258
286
  return {
259
287
  start: async (ctx, options = {}) => {
260
- if (!deps.hasBotToken()) return { ok: false, message: "Telegram bot is not configured." };
288
+ if (!deps.hasBotToken())
289
+ return { ok: false, message: "Telegram bot is not configured." };
261
290
  const acquired = deps.lock.acquire(ctx, options);
262
291
  if (!acquired.ok) {
263
292
  return {
@@ -279,7 +308,8 @@ export function createTelegramLockedPollingRuntime<TContext extends TelegramLock
279
308
  if (state.kind === "active-elsewhere") {
280
309
  return `Telegram bridge is active in another pi instance (${formatLock(state.lock)}).`;
281
310
  }
282
- if (state.kind === "stale") return `Removed stale Telegram bridge lock (${formatLock(state.lock)}).`;
311
+ if (state.kind === "stale")
312
+ return `Removed stale Telegram bridge lock (${formatLock(state.lock)}).`;
283
313
  return "Telegram bridge disconnected.";
284
314
  },
285
315
  suspend: suspendPolling,
package/lib/menu.ts CHANGED
@@ -807,10 +807,6 @@ export function buildTelegramModelCallbackPlan<
807
807
  export async function openTelegramStatusMenu<
808
808
  TModel extends MenuModel = MenuModel,
809
809
  >(deps: TelegramStatusMenuOpenDeps<TModel>): Promise<void> {
810
- if (!deps.isIdle()) {
811
- await deps.sendBusyMessage();
812
- return;
813
- }
814
810
  const state = await deps.getModelMenuState();
815
811
  const messageId = await deps.sendStatusMenu(
816
812
  state,
package/lib/prompts.ts ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Telegram prompt injection helpers
3
+ * Owns Telegram-specific system prompt suffixes injected into pi agent turns
4
+ */
5
+
6
+ import type { BeforeAgentStartEvent } from "./pi.ts";
7
+ import { TELEGRAM_PREFIX } from "./turns.ts";
8
+
9
+ const SYSTEM_PROMPT_SUFFIX = `
10
+
11
+ Telegram bridge extension is active.
12
+ - Messages forwarded from Telegram are prefixed with "[telegram]".
13
+ - [telegram] messages may include [attachments] sections with a base directory plus relative local file entries. Resolve and read those files as needed.
14
+ - Telegram is often read on narrow phone screens, so prefer narrow table columns when presenting tabular data; wide monospace tables can become unreadable.
15
+ - If a [telegram] user asked for a file or generated artifact, use telegram_attach with the local path instead of only mentioning the path in text.
16
+ - Do not assume mentioning a local file path in plain text will send it to Telegram. Use telegram_attach.`;
17
+
18
+ export function buildTelegramBridgeSystemPrompt(options: {
19
+ prompt: string;
20
+ systemPrompt: string;
21
+ telegramPrefix?: string;
22
+ systemPromptSuffix: string;
23
+ }): { systemPrompt: string } {
24
+ const telegramPrefix = options.telegramPrefix ?? TELEGRAM_PREFIX;
25
+ const suffix = options.prompt.trimStart().startsWith(telegramPrefix)
26
+ ? `${options.systemPromptSuffix}\n- The current user message came from Telegram.`
27
+ : options.systemPromptSuffix;
28
+ return { systemPrompt: options.systemPrompt + suffix };
29
+ }
30
+
31
+ export function createTelegramBeforeAgentStartHook(
32
+ options: {
33
+ telegramPrefix?: string;
34
+ systemPromptSuffix?: string;
35
+ } = {},
36
+ ): (event: BeforeAgentStartEvent) => { systemPrompt: string } {
37
+ return (event) =>
38
+ buildTelegramBridgeSystemPrompt({
39
+ prompt: event.prompt,
40
+ systemPrompt: event.systemPrompt,
41
+ telegramPrefix: options.telegramPrefix,
42
+ systemPromptSuffix: options.systemPromptSuffix ?? SYSTEM_PROMPT_SUFFIX,
43
+ });
44
+ }
package/lib/queue.ts CHANGED
@@ -856,8 +856,9 @@ export function createTelegramAgentEndHook<
856
856
  preserveQueuedTurnsAsHistory: deps.getPreserveQueuedTurnsAsHistory(),
857
857
  resetRuntimeState: deps.resetRuntimeState,
858
858
  updateStatus: () => deps.updateStatus(ctx),
859
- dispatchNextQueuedTelegramTurn: () =>
860
- deps.dispatchNextQueuedTelegramTurn(ctx),
859
+ dispatchNextQueuedTelegramTurn: () => {
860
+ setTimeout(() => deps.dispatchNextQueuedTelegramTurn(ctx), 0);
861
+ },
861
862
  clearPreview: deps.clearPreview,
862
863
  setPreviewPendingText: deps.setPreviewPendingText,
863
864
  finalizeMarkdownPreview: deps.finalizeMarkdownPreview,
@@ -1400,8 +1401,9 @@ export interface TelegramRuntimeEventRecorderPort {
1400
1401
  ) => void;
1401
1402
  }
1402
1403
 
1403
- export interface TelegramControlRuntimeDeps<TContext>
1404
- extends TelegramRuntimeEventRecorderPort {
1404
+ export interface TelegramControlRuntimeDeps<
1405
+ TContext,
1406
+ > extends TelegramRuntimeEventRecorderPort {
1405
1407
  ctx: TContext;
1406
1408
  sendTextReply: (
1407
1409
  chatId: number,
@@ -1454,8 +1456,9 @@ export interface TelegramDispatchRuntimeDeps<TContext = unknown> {
1454
1456
  onIdle: () => void;
1455
1457
  }
1456
1458
 
1457
- export interface TelegramQueueDispatchControllerDeps<TContext = unknown>
1458
- extends TelegramRuntimeEventRecorderPort {
1459
+ export interface TelegramQueueDispatchControllerDeps<
1460
+ TContext = unknown,
1461
+ > extends TelegramRuntimeEventRecorderPort {
1459
1462
  getQueuedItems: () => TelegramQueueItem<TContext>[];
1460
1463
  setQueuedItems: (items: TelegramQueueItem<TContext>[]) => void;
1461
1464
  canDispatch: (ctx: TContext) => boolean;
package/lib/routing.ts CHANGED
@@ -116,7 +116,8 @@ export function createTelegramInboundRouteRuntime<
116
116
  isIdle: deps.isIdle,
117
117
  hasActiveTelegramTurn: deps.activeTurnRuntime.has,
118
118
  hasAbortHandler: deps.bridgeRuntime.abort.hasHandler,
119
- getActiveToolExecutions: deps.bridgeRuntime.lifecycle.getActiveToolExecutions,
119
+ getActiveToolExecutions:
120
+ deps.bridgeRuntime.lifecycle.getActiveToolExecutions,
120
121
  setModel: deps.setModel,
121
122
  setCurrentModel: deps.currentModelRuntime.setCurrentModel,
122
123
  stagePendingModelSwitch: deps.modelSwitchController.stagePendingSwitch,
@@ -138,7 +139,8 @@ export function createTelegramInboundRouteRuntime<
138
139
  hasActiveTelegramTurn: deps.activeTurnRuntime.has,
139
140
  hasDispatchPending: deps.bridgeRuntime.lifecycle.hasDispatchPending,
140
141
  isCompactionInProgress: deps.bridgeRuntime.lifecycle.isCompactionInProgress,
141
- setCompactionInProgress: deps.bridgeRuntime.lifecycle.setCompactionInProgress,
142
+ setCompactionInProgress:
143
+ deps.bridgeRuntime.lifecycle.setCompactionInProgress,
142
144
  updateStatus: deps.updateStatus,
143
145
  dispatchNextQueuedTelegramTurn: deps.dispatchNextQueuedTelegramTurn,
144
146
  compact: deps.compact,
package/lib/runtime.ts CHANGED
@@ -327,8 +327,9 @@ export interface TelegramRuntimeEventRecorderPort {
327
327
  ) => void;
328
328
  }
329
329
 
330
- export interface TelegramTypingLoopStarterDeps<TContext>
331
- extends TelegramRuntimeEventRecorderPort {
330
+ export interface TelegramTypingLoopStarterDeps<
331
+ TContext,
332
+ > extends TelegramRuntimeEventRecorderPort {
332
333
  typing: TelegramRuntimeTypingPort;
333
334
  getDefaultChatId: () => number | undefined;
334
335
  sendTypingAction: (chatId: number) => Promise<unknown>;
@@ -413,8 +414,9 @@ export function createTelegramAgentEndResetter(
413
414
  };
414
415
  }
415
416
 
416
- export interface TelegramPromptDispatchLifecycleDeps<TContext>
417
- extends TelegramRuntimeEventRecorderPort {
417
+ export interface TelegramPromptDispatchLifecycleDeps<
418
+ TContext,
419
+ > extends TelegramRuntimeEventRecorderPort {
418
420
  lifecycle: Pick<
419
421
  TelegramRuntimeLifecyclePort,
420
422
  "setDispatchPending" | "clearDispatchPending"
@@ -424,8 +426,9 @@ export interface TelegramPromptDispatchLifecycleDeps<TContext>
424
426
  updateStatus: (ctx: TContext, error?: string) => void;
425
427
  }
426
428
 
427
- export interface TelegramPromptDispatchRuntimeDeps<TContext>
428
- extends TelegramRuntimeEventRecorderPort {
429
+ export interface TelegramPromptDispatchRuntimeDeps<
430
+ TContext,
431
+ > extends TelegramRuntimeEventRecorderPort {
429
432
  lifecycle: TelegramPromptDispatchLifecycleDeps<TContext>["lifecycle"];
430
433
  typing: TelegramRuntimeTypingPort;
431
434
  getDefaultChatId: () => number | undefined;
package/lib/setup.ts CHANGED
@@ -86,7 +86,11 @@ const TELEGRAM_BOT_TOKEN_ENV_VARS = [
86
86
  function isTelegramPollingStartResult(
87
87
  value: unknown,
88
88
  ): value is TelegramPollingStartResult {
89
- return !!value && typeof value === "object" && typeof (value as { ok?: unknown }).ok === "boolean";
89
+ return (
90
+ !!value &&
91
+ typeof value === "object" &&
92
+ typeof (value as { ok?: unknown }).ok === "boolean"
93
+ );
90
94
  }
91
95
 
92
96
  export function getTelegramBotTokenInputDefault(
package/lib/status.ts CHANGED
@@ -108,6 +108,7 @@ export interface TelegramStatusBarState {
108
108
  paired: boolean;
109
109
  compactionInProgress: boolean;
110
110
  processing: boolean;
111
+ processingStatus?: string;
111
112
  queuedStatus: string;
112
113
  error?: string;
113
114
  }
@@ -333,6 +334,10 @@ export function createTelegramBridgeStatusRuntime<
333
334
  getStatusBarState: (_ctx, error) => {
334
335
  const config = deps.getConfig();
335
336
  const queuedItems = deps.getQueuedItems();
337
+ const hasActiveTurn = deps.hasActiveTurn();
338
+ const hasPendingDispatch = deps.hasDispatchPending();
339
+ const hasPendingModelSwitch = deps.hasPendingModelSwitch();
340
+ const activeToolExecutions = deps.getActiveToolExecutions();
336
341
  const compactionInProgress = deps.isCompactionInProgress();
337
342
  return {
338
343
  hasBotToken: !!config.botToken,
@@ -340,9 +345,14 @@ export function createTelegramBridgeStatusRuntime<
340
345
  paired: !!config.allowedUserId,
341
346
  compactionInProgress,
342
347
  processing:
343
- deps.hasActiveTurn() ||
344
- deps.hasDispatchPending() ||
345
- queuedItems.length > 0,
348
+ hasActiveTurn || hasPendingDispatch || queuedItems.length > 0,
349
+ processingStatus: getTelegramStatusBarProcessingStatus({
350
+ hasActiveTurn,
351
+ hasPendingDispatch,
352
+ hasPendingModelSwitch,
353
+ activeToolExecutions,
354
+ queuedItems: queuedItems.length,
355
+ }),
346
356
  queuedStatus: deps.formatQueuedStatus(queuedItems),
347
357
  error,
348
358
  };
@@ -367,6 +377,21 @@ export function createTelegramBridgeStatusRuntime<
367
377
  });
368
378
  }
369
379
 
380
+ export function getTelegramStatusBarProcessingStatus(state: {
381
+ hasActiveTurn: boolean;
382
+ hasPendingDispatch: boolean;
383
+ hasPendingModelSwitch: boolean;
384
+ activeToolExecutions: number;
385
+ queuedItems: number;
386
+ }): string | undefined {
387
+ if (state.hasPendingModelSwitch) return "model";
388
+ if (state.activeToolExecutions > 0) return "tool running";
389
+ if (state.hasActiveTurn) return "active";
390
+ if (state.hasPendingDispatch) return "dispatching";
391
+ if (state.queuedItems > 0) return "queued";
392
+ return undefined;
393
+ }
394
+
370
395
  export function buildTelegramStatusBarText(
371
396
  theme: TelegramStatusBarTheme,
372
397
  state: TelegramStatusBarState,
@@ -386,7 +411,7 @@ export function buildTelegramStatusBarText(
386
411
  return `${label} ${theme.fg("accent", "compacting")}${queued}`;
387
412
  }
388
413
  if (state.processing) {
389
- return `${label} ${theme.fg("accent", "processing")}${queued}`;
414
+ return `${label} ${theme.fg("accent", state.processingStatus ?? "processing")}${queued}`;
390
415
  }
391
416
  return `${label} ${theme.fg("success", "connected")}`;
392
417
  }
package/lib/turns.ts CHANGED
@@ -57,9 +57,7 @@ export function formatTelegramTurnStatusSummary(
57
57
  ): string {
58
58
  const textSummary = truncateTelegramQueueSummary(rawText);
59
59
  if (textSummary) return textSummary;
60
- const handlerSummary = truncateTelegramQueueSummary(
61
- handlerOutputs.join(" "),
62
- );
60
+ const handlerSummary = truncateTelegramQueueSummary(handlerOutputs.join(" "));
63
61
  if (handlerSummary) return handlerSummary;
64
62
  if (files.length === 1) {
65
63
  const fileName = basename(
@@ -121,7 +119,11 @@ export function buildTelegramTurnPrompt(options: {
121
119
  }
122
120
  const promptFiles = options.promptFiles ?? options.files;
123
121
  prompt = appendTelegramAttachmentSection(prompt, promptFiles);
124
- prompt = appendTelegramListSection(prompt, "outputs", options.handlerOutputs ?? []);
122
+ prompt = appendTelegramListSection(
123
+ prompt,
124
+ "outputs",
125
+ options.handlerOutputs ?? [],
126
+ );
125
127
  return prompt;
126
128
  }
127
129
 
@@ -158,7 +160,9 @@ function splitTelegramPromptAttachmentSuffix(prompt: string): {
158
160
  const attachmentFiles = attachmentLines
159
161
  .map((line) => line.match(/^- (.+)$/)?.[1]?.trim())
160
162
  .filter((path): path is string => !!path)
161
- .map((path) => (attachmentDir ? join(attachmentDir, path.replace(/^\/+/, "")) : path))
163
+ .map((path) =>
164
+ attachmentDir ? join(attachmentDir, path.replace(/^\/+/, "")) : path,
165
+ )
162
166
  .map((path) => ({
163
167
  path,
164
168
  fileName: basename(path),
@@ -301,8 +305,9 @@ export type BuildTelegramPromptTurnRuntimeOptions = Omit<
301
305
  "readBinaryFile"
302
306
  >;
303
307
 
304
- export interface TelegramPromptTurnRuntimeBuilderDeps<TContext = unknown>
305
- extends DownloadTelegramMessageFilesDeps {
308
+ export interface TelegramPromptTurnRuntimeBuilderDeps<
309
+ TContext = unknown,
310
+ > extends DownloadTelegramMessageFilesDeps {
306
311
  allocateQueueOrder: () => number;
307
312
  processAttachments?: (
308
313
  files: DownloadedTelegramTurnFile[],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-telegram",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "private": false,
5
5
  "description": "Better Telegram DM bridge extension for pi",
6
6
  "type": "module",