@llblab/pi-telegram 0.52.2 → 0.53.1

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.
Files changed (204) hide show
  1. package/AGENTS.md +9 -7
  2. package/BACKLOG.md +1 -18
  3. package/CHANGELOG.md +15 -0
  4. package/README.md +7 -11
  5. package/api/commands.ts +3 -0
  6. package/dist/api/commands.d.ts +1 -1
  7. package/dist/lib/activity-verbosity.d.ts +1 -5
  8. package/dist/lib/activity-verbosity.js +15 -42
  9. package/dist/lib/activity.d.ts +9 -0
  10. package/dist/lib/activity.js +39 -10
  11. package/dist/lib/agent-messages.js +7 -3
  12. package/dist/lib/bindings.d.ts +43 -5
  13. package/dist/lib/bindings.js +163 -20
  14. package/dist/lib/bus-api.d.ts +12 -0
  15. package/dist/lib/bus-api.js +182 -79
  16. package/dist/lib/bus-follower.d.ts +111 -31
  17. package/dist/lib/bus-follower.js +1324 -359
  18. package/dist/lib/bus-leader.d.ts +41 -91
  19. package/dist/lib/bus-leader.js +969 -637
  20. package/dist/lib/bus-transport.js +16 -9
  21. package/dist/lib/bus.d.ts +215 -18
  22. package/dist/lib/bus.js +1048 -327
  23. package/dist/lib/channel-posts.d.ts +5 -0
  24. package/dist/lib/channel-posts.js +434 -261
  25. package/dist/lib/command-templates.d.ts +26 -5
  26. package/dist/lib/command-templates.js +92 -176
  27. package/dist/lib/commands.d.ts +168 -82
  28. package/dist/lib/commands.js +1409 -291
  29. package/dist/lib/config.d.ts +1 -8
  30. package/dist/lib/config.js +34 -76
  31. package/dist/lib/delivery.d.ts +2 -2
  32. package/dist/lib/delivery.js +16 -16
  33. package/dist/lib/extension.js +639 -171
  34. package/dist/lib/generative-app-worker.mjs +19 -7
  35. package/dist/lib/generative-apps.d.ts +0 -5
  36. package/dist/lib/generative-apps.js +61 -49
  37. package/dist/lib/inbound.d.ts +5 -0
  38. package/dist/lib/inbound.js +35 -59
  39. package/dist/lib/journal.d.ts +33 -3
  40. package/dist/lib/journal.js +2063 -782
  41. package/dist/lib/lifecycle.d.ts +2 -6
  42. package/dist/lib/lifecycle.js +75 -58
  43. package/dist/lib/locks.d.ts +29 -3
  44. package/dist/lib/locks.js +289 -108
  45. package/dist/lib/logging.js +50 -14
  46. package/dist/lib/media.d.ts +22 -1
  47. package/dist/lib/media.js +46 -28
  48. package/dist/lib/menu-model.d.ts +19 -5
  49. package/dist/lib/menu-model.js +53 -11
  50. package/dist/lib/menu-queue.d.ts +5 -4
  51. package/dist/lib/menu-queue.js +45 -63
  52. package/dist/lib/menu-settings.d.ts +5 -4
  53. package/dist/lib/menu-settings.js +114 -78
  54. package/dist/lib/menu-status.d.ts +1 -1
  55. package/dist/lib/menu-status.js +8 -25
  56. package/dist/lib/menu-thinking.d.ts +6 -1
  57. package/dist/lib/menu-thinking.js +14 -21
  58. package/dist/lib/menu.d.ts +8 -61
  59. package/dist/lib/menu.js +92 -164
  60. package/dist/lib/model.d.ts +1 -1
  61. package/dist/lib/model.js +2 -16
  62. package/dist/lib/outbound-attachments.d.ts +6 -27
  63. package/dist/lib/outbound-attachments.js +45 -38
  64. package/dist/lib/outbound-buttons.js +22 -16
  65. package/dist/lib/outbound-markup.d.ts +0 -2
  66. package/dist/lib/outbound-markup.js +51 -64
  67. package/dist/lib/outbound-voice.js +6 -3
  68. package/dist/lib/outbound.d.ts +6 -6
  69. package/dist/lib/outbound.js +65 -51
  70. package/dist/lib/ownership.js +6 -2
  71. package/dist/lib/paths.d.ts +5 -0
  72. package/dist/lib/paths.js +37 -21
  73. package/dist/lib/pi.d.ts +2 -0
  74. package/dist/lib/pi.js +8 -1
  75. package/dist/lib/polling.d.ts +21 -37
  76. package/dist/lib/polling.js +59 -50
  77. package/dist/lib/preview.js +39 -19
  78. package/dist/lib/process-identity.d.ts +24 -0
  79. package/dist/lib/process-identity.js +133 -0
  80. package/dist/lib/prompts.js +2 -7
  81. package/dist/lib/queue.d.ts +14 -16
  82. package/dist/lib/queue.js +252 -127
  83. package/dist/lib/recovery.d.ts +2 -83
  84. package/dist/lib/recovery.js +20 -274
  85. package/dist/lib/replies.d.ts +16 -24
  86. package/dist/lib/replies.js +99 -116
  87. package/dist/lib/routing.d.ts +120 -7
  88. package/dist/lib/routing.js +4667 -1152
  89. package/dist/lib/runtime.d.ts +1 -11
  90. package/dist/lib/sections.d.ts +4 -29
  91. package/dist/lib/sections.js +7 -20
  92. package/dist/lib/skills.js +4 -3
  93. package/dist/lib/status.js +86 -57
  94. package/dist/lib/sync.d.ts +1 -3
  95. package/dist/lib/sync.js +67 -43
  96. package/dist/lib/target.d.ts +4 -0
  97. package/dist/lib/target.js +18 -0
  98. package/dist/lib/telegram-api.d.ts +18 -13
  99. package/dist/lib/telegram-api.js +148 -53
  100. package/dist/lib/text-groups.js +4 -39
  101. package/dist/lib/thread-cleanup-manager.d.ts +6 -27
  102. package/dist/lib/thread-cleanup-manager.js +369 -186
  103. package/dist/lib/thread-display.d.ts +1 -2
  104. package/dist/lib/thread-display.js +58 -38
  105. package/dist/lib/thread-naming.d.ts +28 -8
  106. package/dist/lib/thread-naming.js +175 -66
  107. package/dist/lib/thread-reconciler.d.ts +42 -16
  108. package/dist/lib/thread-reconciler.js +90 -50
  109. package/dist/lib/threads.d.ts +82 -20
  110. package/dist/lib/threads.js +2247 -855
  111. package/dist/lib/time-injection.js +1 -2
  112. package/dist/lib/turns.js +1 -19
  113. package/dist/lib/updates.d.ts +169 -80
  114. package/dist/lib/updates.js +2418 -641
  115. package/dist/lib/voice.d.ts +7 -22
  116. package/dist/lib/voice.js +7 -22
  117. package/dist/lib/wire.js +1 -1
  118. package/dist/lib/workspace-admission.d.ts +3 -1
  119. package/dist/lib/workspace-admission.js +425 -211
  120. package/dist/lib/workspace-identity.js +8 -13
  121. package/dist/lib/workspace-retirement.d.ts +1 -1
  122. package/dist/lib/workspace-retirement.js +328 -140
  123. package/dist/lib/workspace-slots.js +8 -4
  124. package/dist/package.json +1 -1
  125. package/docs/architecture.md +31 -29
  126. package/docs/inbound.md +1 -1
  127. package/docs/multi-instance-bus.md +15 -3
  128. package/docs/outbound.md +1 -1
  129. package/docs/public-api.md +29 -1
  130. package/docs/ui-style.md +25 -8
  131. package/lib/activity-verbosity.ts +59 -82
  132. package/lib/activity.ts +146 -102
  133. package/lib/agent-messages.ts +12 -5
  134. package/lib/bindings.ts +389 -82
  135. package/lib/bus-api.ts +263 -102
  136. package/lib/bus-follower.ts +2440 -601
  137. package/lib/bus-leader.ts +2209 -1290
  138. package/lib/bus-transport.ts +46 -12
  139. package/lib/bus.ts +1673 -444
  140. package/lib/channel-posts.ts +848 -327
  141. package/lib/command-templates.ts +152 -265
  142. package/lib/commands.ts +2398 -555
  143. package/lib/config.ts +177 -170
  144. package/lib/delivery.ts +41 -29
  145. package/lib/extension.ts +1206 -433
  146. package/lib/generative-app-worker.mjs +19 -7
  147. package/lib/generative-apps.ts +324 -211
  148. package/lib/inbound.ts +95 -97
  149. package/lib/journal.ts +5311 -1763
  150. package/lib/keyboard.ts +1 -3
  151. package/lib/lifecycle.ts +128 -78
  152. package/lib/locks.ts +677 -203
  153. package/lib/logging.ts +147 -58
  154. package/lib/media.ts +82 -43
  155. package/lib/menu-model.ts +85 -18
  156. package/lib/menu-queue.ts +88 -129
  157. package/lib/menu-settings.ts +260 -155
  158. package/lib/menu-status.ts +20 -60
  159. package/lib/menu-thinking.ts +41 -56
  160. package/lib/menu.ts +112 -285
  161. package/lib/model.ts +8 -22
  162. package/lib/outbound-attachments.ts +156 -125
  163. package/lib/outbound-buttons.ts +76 -49
  164. package/lib/outbound-markup.ts +96 -94
  165. package/lib/outbound-voice.ts +33 -27
  166. package/lib/outbound.ts +128 -125
  167. package/lib/ownership.ts +19 -10
  168. package/lib/paths.ts +148 -49
  169. package/lib/pi.ts +35 -15
  170. package/lib/polling.ts +144 -147
  171. package/lib/preview.ts +93 -40
  172. package/lib/process-identity.ts +164 -0
  173. package/lib/prompts.ts +4 -11
  174. package/lib/queue.ts +516 -301
  175. package/lib/recovery.ts +50 -454
  176. package/lib/rendering.ts +1 -3
  177. package/lib/replies.ts +248 -209
  178. package/lib/routing.ts +8509 -2186
  179. package/lib/runtime.ts +1 -12
  180. package/lib/sections.ts +24 -89
  181. package/lib/setup.ts +1 -3
  182. package/lib/skills.ts +9 -4
  183. package/lib/status.ts +215 -110
  184. package/lib/sync.ts +448 -361
  185. package/lib/target.ts +22 -3
  186. package/lib/telegram-api.ts +302 -127
  187. package/lib/text-groups.ts +5 -39
  188. package/lib/thread-cleanup-manager.ts +833 -331
  189. package/lib/thread-display.ts +213 -97
  190. package/lib/thread-naming.ts +232 -87
  191. package/lib/thread-reconciler.ts +155 -72
  192. package/lib/threads.ts +5318 -1845
  193. package/lib/time-injection.ts +1 -4
  194. package/lib/turns.ts +15 -28
  195. package/lib/updates.ts +5184 -1612
  196. package/lib/voice.ts +7 -35
  197. package/lib/wire.ts +1 -1
  198. package/lib/workspace-admission.ts +996 -416
  199. package/lib/workspace-identity.ts +14 -17
  200. package/lib/workspace-retirement.ts +878 -376
  201. package/lib/workspace-slots.ts +22 -13
  202. package/package.json +1 -1
  203. package/scripts/check-downgrade.mjs +0 -472
  204. package/scripts/measure-workspace.mjs +0 -108
package/lib/inbound.ts CHANGED
@@ -9,9 +9,13 @@ import { basename } from "node:path";
9
9
 
10
10
  import {
11
11
  buildCommandTemplateInvocation,
12
- expandCommandTemplateConfigs,
12
+ createCommandTemplateRecovery,
13
+ getCommandTemplateCompositionSteps,
14
+ getCommandTemplateConfiguredTimeout,
15
+ getCommandTemplateStepTimeout,
13
16
  normalizeCommandTemplateConfig,
14
- substituteCommandTemplateToken,
17
+ resolveCommandTemplateNumericField,
18
+ shouldRunCommandTemplateConfig,
15
19
  type CommandTemplateConfig,
16
20
  type CommandTemplateObjectConfig,
17
21
  } from "./command-templates.ts";
@@ -30,9 +34,13 @@ export interface TelegramInboundHandlerConfig {
30
34
  mime?: string | string[];
31
35
  type?: string | string[];
32
36
  template?: string | TelegramInboundCommandTemplateConfig[];
37
+ /** Falsy skips this handler so selection continues with the next match. */
38
+ when?: CommandTemplateObjectConfig["when"];
33
39
  args?: string[];
34
40
  defaults?: Record<string, unknown>;
35
41
  timeout?: number | string;
42
+ retry?: CommandTemplateObjectConfig["retry"];
43
+ recover?: CommandTemplateObjectConfig["recover"];
36
44
  }
37
45
 
38
46
  export interface TelegramInboundHandlerFile {
@@ -64,6 +72,7 @@ export interface TelegramInboundHandlerExecOptions {
64
72
  signal?: AbortSignal;
65
73
  stdin?: string;
66
74
  retry?: number;
75
+ recover?: () => Promise<void>;
67
76
  }
68
77
 
69
78
  export interface TelegramInboundHandlerExecResult {
@@ -321,70 +330,15 @@ export function buildTelegramInboundHandlerInvocation(
321
330
  );
322
331
  }
323
332
 
324
- function resolveTelegramInboundNumericControlField(
325
- value: number | string | undefined,
326
- values: Record<string, unknown>,
327
- label: string,
328
- ): number | undefined {
329
- if (value === undefined) return undefined;
330
- const resolved =
331
- typeof value === "string"
332
- ? substituteCommandTemplateToken(value, values, label)
333
- : value;
334
- if (resolved === "") return undefined;
335
- const numeric = Number(resolved);
336
- if (!Number.isFinite(numeric) || numeric < 0)
337
- throw new Error(`Command template ${label} must be a non-negative number.`);
338
- return numeric;
339
- }
340
-
341
- function getTelegramInboundHandlerConfiguredTimeout(
342
- handler: TelegramInboundCommandTemplateConfig,
343
- ): number | undefined {
344
- const timeout = typeof handler === "string" ? undefined : handler.timeout;
345
- return resolveTelegramInboundNumericControlField(timeout, {}, "timeout");
346
- }
347
-
348
333
  function getTelegramInboundHandlerTimeout(
349
334
  handler: TelegramInboundCommandTemplateConfig,
350
335
  ): number {
351
336
  return (
352
- getTelegramInboundHandlerConfiguredTimeout(handler) ??
337
+ getCommandTemplateConfiguredTimeout(handler) ??
353
338
  DEFAULT_INBOUND_HANDLER_TIMEOUT_MS
354
339
  );
355
340
  }
356
341
 
357
- function getRemainingTelegramInboundTimeout(
358
- timeout: number,
359
- startedAt: number,
360
- ): number {
361
- return Math.max(1, timeout - (Date.now() - startedAt));
362
- }
363
-
364
- function getTelegramInboundInitialCompositionStepTimeout(
365
- handler: TelegramInboundHandlerConfig,
366
- step: TelegramInboundCommandTemplateConfig,
367
- ): number {
368
- const timeout = getTelegramInboundHandlerTimeout(handler);
369
- const stepTimeout = getTelegramInboundHandlerConfiguredTimeout(step);
370
- return stepTimeout === undefined ? timeout : Math.min(stepTimeout, timeout);
371
- }
372
-
373
- function getTelegramInboundCompositionStepTimeout(
374
- handler: TelegramInboundHandlerConfig,
375
- step: TelegramInboundCommandTemplateConfig,
376
- startedAt: number,
377
- ): number {
378
- const remaining = getRemainingTelegramInboundTimeout(
379
- getTelegramInboundHandlerTimeout(handler),
380
- startedAt,
381
- );
382
- const stepTimeout = getTelegramInboundHandlerConfiguredTimeout(step);
383
- return stepTimeout === undefined
384
- ? remaining
385
- : Math.min(stepTimeout, remaining);
386
- }
387
-
388
342
  function getTelegramInboundHandlerKind(
389
343
  handler: TelegramInboundHandlerConfig,
390
344
  ): string {
@@ -410,6 +364,25 @@ function formatTelegramInboundHandlerFailure(
410
364
  return parts.join("\n\n");
411
365
  }
412
366
 
367
+ function getTelegramInboundHandlerRetryOptions(
368
+ handler: TelegramInboundCommandTemplateConfig,
369
+ values: Record<string, string>,
370
+ cwd: string,
371
+ timeout: number,
372
+ deps: Pick<TelegramInboundHandlerRuntimeDeps<unknown>, "execCommand">,
373
+ ): Pick<TelegramInboundHandlerExecOptions, "retry" | "recover"> {
374
+ if (typeof handler !== "object" || handler.retry === undefined) return {};
375
+ const recover = createCommandTemplateRecovery(handler, values, {
376
+ cwd,
377
+ timeout,
378
+ execCommand: deps.execCommand,
379
+ });
380
+ return {
381
+ retry: resolveCommandTemplateNumericField(handler.retry, {}, "retry"),
382
+ ...(recover ? { recover } : {}),
383
+ };
384
+ }
385
+
413
386
  async function executeTelegramInboundHandlerInvocation(
414
387
  handler: TelegramInboundCommandTemplateConfig,
415
388
  file: TelegramInboundHandlerFile,
@@ -428,15 +401,13 @@ async function executeTelegramInboundHandlerInvocation(
428
401
  const result = await deps.execCommand(invocation.command, invocation.args, {
429
402
  cwd,
430
403
  timeout,
431
- ...(typeof handler === "object" && handler.retry !== undefined
432
- ? {
433
- retry: resolveTelegramInboundNumericControlField(
434
- handler.retry,
435
- {},
436
- "retry",
437
- ),
438
- }
439
- : {}),
404
+ ...getTelegramInboundHandlerRetryOptions(
405
+ handler,
406
+ getTelegramInboundHandlerTemplateValues(file),
407
+ cwd,
408
+ timeout,
409
+ deps,
410
+ ),
440
411
  ...(stdin !== undefined ? { stdin } : {}),
441
412
  });
442
413
  if (result.code !== 0)
@@ -444,17 +415,6 @@ async function executeTelegramInboundHandlerInvocation(
444
415
  return truncateTelegramInboundOutput(result.stdout);
445
416
  }
446
417
 
447
- function getTelegramInboundHandlerCompositionSteps(
448
- handler: TelegramInboundHandlerConfig,
449
- ): TelegramInboundCommandTemplateConfig[] {
450
- if (Array.isArray(handler.template)) {
451
- return expandCommandTemplateConfigs(
452
- handler,
453
- ) as TelegramInboundCommandTemplateConfig[];
454
- }
455
- return [];
456
- }
457
-
458
418
  function getTelegramTextHandlerFile(): TelegramInboundHandlerFile {
459
419
  return {
460
420
  path: "",
@@ -508,15 +468,16 @@ async function executeTelegramTextHandlerInvocation(
508
468
  cwd,
509
469
  timeout,
510
470
  stdin: text,
511
- ...(typeof handler === "object" && handler.retry !== undefined
512
- ? {
513
- retry: resolveTelegramInboundNumericControlField(
514
- handler.retry,
515
- {},
516
- "retry",
517
- ),
518
- }
519
- : {}),
471
+ ...getTelegramInboundHandlerRetryOptions(
472
+ handler,
473
+ getTelegramInboundHandlerTemplateValues(
474
+ getTelegramTextHandlerFile(),
475
+ text,
476
+ ),
477
+ cwd,
478
+ timeout,
479
+ deps,
480
+ ),
520
481
  });
521
482
  if (result.code !== 0)
522
483
  throw new Error(formatTelegramInboundHandlerFailure(result));
@@ -529,7 +490,7 @@ async function executeTelegramTextHandler(
529
490
  cwd: string,
530
491
  deps: Pick<TelegramInboundHandlerRuntimeDeps<unknown>, "execCommand">,
531
492
  ): Promise<string> {
532
- const steps = getTelegramInboundHandlerCompositionSteps(handler);
493
+ const steps = getCommandTemplateCompositionSteps(handler);
533
494
  if (steps.length === 0) {
534
495
  return (
535
496
  await executeTelegramTextHandlerInvocation(handler, text, cwd, deps)
@@ -538,15 +499,27 @@ async function executeTelegramTextHandler(
538
499
  const startedAt = Date.now();
539
500
  let output = text;
540
501
  for (const [index, step] of steps.entries()) {
502
+ if (
503
+ !shouldRunCommandTemplateConfig(
504
+ step,
505
+ getTelegramInboundHandlerTemplateValues(
506
+ getTelegramTextHandlerFile(),
507
+ output,
508
+ ),
509
+ )
510
+ )
511
+ continue;
541
512
  try {
542
513
  output = await executeTelegramTextHandlerInvocation(
543
514
  step,
544
515
  output,
545
516
  cwd,
546
517
  deps,
547
- index === 0
548
- ? getTelegramInboundInitialCompositionStepTimeout(handler, step)
549
- : getTelegramInboundCompositionStepTimeout(handler, step, startedAt),
518
+ getCommandTemplateStepTimeout(
519
+ getTelegramInboundHandlerTimeout(handler),
520
+ step,
521
+ index === 0 ? undefined : Date.now() - startedAt,
522
+ ),
550
523
  );
551
524
  } catch (error) {
552
525
  if (typeof step === "object" && step.failure === "root") throw error;
@@ -568,6 +541,17 @@ async function processTelegramTextHandlers(options: {
568
541
  let text = options.rawText;
569
542
  for (const handler of findTelegramTextHandlers(options.handlers)) {
570
543
  try {
544
+ // An unresolvable guard fails only this handler, like its command would.
545
+ if (
546
+ !shouldRunCommandTemplateConfig(
547
+ handler,
548
+ getTelegramInboundHandlerTemplateValues(
549
+ getTelegramTextHandlerFile(),
550
+ text,
551
+ ),
552
+ )
553
+ )
554
+ continue;
571
555
  const output = await executeTelegramTextHandler(
572
556
  handler,
573
557
  text,
@@ -681,7 +665,7 @@ async function executeTelegramInboundHandler(
681
665
  cwd: string,
682
666
  deps: Pick<TelegramInboundHandlerRuntimeDeps<unknown>, "execCommand">,
683
667
  ): Promise<string> {
684
- const steps = getTelegramInboundHandlerCompositionSteps(handler);
668
+ const steps = getCommandTemplateCompositionSteps(handler);
685
669
  if (steps.length === 0) {
686
670
  const output = await executeTelegramInboundHandlerInvocation(
687
671
  handler,
@@ -692,8 +676,13 @@ async function executeTelegramInboundHandler(
692
676
  return output.trim();
693
677
  }
694
678
  const startedAt = Date.now();
679
+ const values = getTelegramInboundHandlerTemplateValues(file);
695
680
  let output = "";
696
- for (const [index, step] of steps.entries()) {
681
+ let started = false;
682
+ for (const step of steps) {
683
+ if (!shouldRunCommandTemplateConfig(step, values)) continue;
684
+ const first = !started;
685
+ started = true;
697
686
  try {
698
687
  output = await executeTelegramInboundHandlerInvocation(
699
688
  step,
@@ -701,10 +690,12 @@ async function executeTelegramInboundHandler(
701
690
  cwd,
702
691
  deps,
703
692
  false,
704
- index === 0
705
- ? getTelegramInboundInitialCompositionStepTimeout(handler, step)
706
- : getTelegramInboundCompositionStepTimeout(handler, step, startedAt),
707
- index === 0 ? undefined : output,
693
+ getCommandTemplateStepTimeout(
694
+ getTelegramInboundHandlerTimeout(handler),
695
+ step,
696
+ first ? undefined : Date.now() - startedAt,
697
+ ),
698
+ first ? undefined : output,
708
699
  );
709
700
  } catch (error) {
710
701
  if (typeof step === "object" && step.failure === "root") throw error;
@@ -738,6 +729,13 @@ export async function processTelegramInboundHandlers<
738
729
  const handlers = findTelegramInboundHandlers(options.handlers, file);
739
730
  for (const handler of handlers) {
740
731
  try {
732
+ if (
733
+ !shouldRunCommandTemplateConfig(
734
+ handler,
735
+ getTelegramInboundHandlerTemplateValues(file),
736
+ )
737
+ )
738
+ continue;
741
739
  const output = await executeTelegramInboundHandler(
742
740
  handler,
743
741
  file,