@llblab/pi-kit 0.1.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.
Files changed (523) hide show
  1. package/AGENTS.md +35 -0
  2. package/BACKLOG.md +3 -0
  3. package/CHANGELOG.md +9 -0
  4. package/LICENSE +21 -0
  5. package/README.md +43 -0
  6. package/node_modules/@llblab/pi-actors/AGENTS.md +150 -0
  7. package/node_modules/@llblab/pi-actors/BACKLOG.md +6 -0
  8. package/node_modules/@llblab/pi-actors/CHANGELOG.md +865 -0
  9. package/node_modules/@llblab/pi-actors/README.md +231 -0
  10. package/node_modules/@llblab/pi-actors/banner.jpg +0 -0
  11. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/artifact-manifest.json +9 -0
  12. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/control-endpoint.json +6 -0
  13. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/control-record.json +9 -0
  14. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/recipe-summary.json +8 -0
  15. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/run-state.json +10 -0
  16. package/node_modules/@llblab/pi-actors/dist/fixtures/protocol/trace-event.json +9 -0
  17. package/node_modules/@llblab/pi-actors/dist/index.d.ts +7 -0
  18. package/node_modules/@llblab/pi-actors/dist/index.js +17 -0
  19. package/node_modules/@llblab/pi-actors/dist/lib/async-runs.d.ts +146 -0
  20. package/node_modules/@llblab/pi-actors/dist/lib/async-runs.js +800 -0
  21. package/node_modules/@llblab/pi-actors/dist/lib/automatic-review-runtime.d.ts +20 -0
  22. package/node_modules/@llblab/pi-actors/dist/lib/automatic-review-runtime.js +103 -0
  23. package/node_modules/@llblab/pi-actors/dist/lib/command-templates.d.ts +85 -0
  24. package/node_modules/@llblab/pi-actors/dist/lib/command-templates.js +804 -0
  25. package/node_modules/@llblab/pi-actors/dist/lib/config.d.ts +34 -0
  26. package/node_modules/@llblab/pi-actors/dist/lib/config.js +216 -0
  27. package/node_modules/@llblab/pi-actors/dist/lib/control-projection.d.ts +20 -0
  28. package/node_modules/@llblab/pi-actors/dist/lib/control-projection.js +66 -0
  29. package/node_modules/@llblab/pi-actors/dist/lib/control.d.ts +15 -0
  30. package/node_modules/@llblab/pi-actors/dist/lib/control.js +97 -0
  31. package/node_modules/@llblab/pi-actors/dist/lib/draft-consolidation-transaction.d.ts +65 -0
  32. package/node_modules/@llblab/pi-actors/dist/lib/draft-consolidation-transaction.js +610 -0
  33. package/node_modules/@llblab/pi-actors/dist/lib/draft-consolidation.d.ts +35 -0
  34. package/node_modules/@llblab/pi-actors/dist/lib/draft-consolidation.js +126 -0
  35. package/node_modules/@llblab/pi-actors/dist/lib/draft-review.d.ts +56 -0
  36. package/node_modules/@llblab/pi-actors/dist/lib/draft-review.js +254 -0
  37. package/node_modules/@llblab/pi-actors/dist/lib/draft-sleep.d.ts +65 -0
  38. package/node_modules/@llblab/pi-actors/dist/lib/draft-sleep.js +467 -0
  39. package/node_modules/@llblab/pi-actors/dist/lib/execution-output.d.ts +25 -0
  40. package/node_modules/@llblab/pi-actors/dist/lib/execution-output.js +88 -0
  41. package/node_modules/@llblab/pi-actors/dist/lib/execution-sessions.d.ts +17 -0
  42. package/node_modules/@llblab/pi-actors/dist/lib/execution-sessions.js +85 -0
  43. package/node_modules/@llblab/pi-actors/dist/lib/execution.d.ts +99 -0
  44. package/node_modules/@llblab/pi-actors/dist/lib/execution.js +725 -0
  45. package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.d.ts +21 -0
  46. package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.js +141 -0
  47. package/node_modules/@llblab/pi-actors/dist/lib/file-state.d.ts +18 -0
  48. package/node_modules/@llblab/pi-actors/dist/lib/file-state.js +310 -0
  49. package/node_modules/@llblab/pi-actors/dist/lib/identity.d.ts +9 -0
  50. package/node_modules/@llblab/pi-actors/dist/lib/identity.js +27 -0
  51. package/node_modules/@llblab/pi-actors/dist/lib/inspector-actions.d.ts +16 -0
  52. package/node_modules/@llblab/pi-actors/dist/lib/inspector-actions.js +57 -0
  53. package/node_modules/@llblab/pi-actors/dist/lib/inspector-command.d.ts +7 -0
  54. package/node_modules/@llblab/pi-actors/dist/lib/inspector-command.js +37 -0
  55. package/node_modules/@llblab/pi-actors/dist/lib/inspector-overlay.d.ts +100 -0
  56. package/node_modules/@llblab/pi-actors/dist/lib/inspector-overlay.js +824 -0
  57. package/node_modules/@llblab/pi-actors/dist/lib/inspector.d.ts +20 -0
  58. package/node_modules/@llblab/pi-actors/dist/lib/inspector.js +136 -0
  59. package/node_modules/@llblab/pi-actors/dist/lib/limits.d.ts +28 -0
  60. package/node_modules/@llblab/pi-actors/dist/lib/limits.js +28 -0
  61. package/node_modules/@llblab/pi-actors/dist/lib/model-context.d.ts +56 -0
  62. package/node_modules/@llblab/pi-actors/dist/lib/model-context.js +220 -0
  63. package/node_modules/@llblab/pi-actors/dist/lib/observability.d.ts +186 -0
  64. package/node_modules/@llblab/pi-actors/dist/lib/observability.js +951 -0
  65. package/node_modules/@llblab/pi-actors/dist/lib/paths.d.ts +27 -0
  66. package/node_modules/@llblab/pi-actors/dist/lib/paths.js +72 -0
  67. package/node_modules/@llblab/pi-actors/dist/lib/pi.d.ts +19 -0
  68. package/node_modules/@llblab/pi-actors/dist/lib/pi.js +21 -0
  69. package/node_modules/@llblab/pi-actors/dist/lib/preflight-diagnostics.d.ts +27 -0
  70. package/node_modules/@llblab/pi-actors/dist/lib/preflight-diagnostics.js +86 -0
  71. package/node_modules/@llblab/pi-actors/dist/lib/prompts.d.ts +24 -0
  72. package/node_modules/@llblab/pi-actors/dist/lib/prompts.js +49 -0
  73. package/node_modules/@llblab/pi-actors/dist/lib/recipe-control.d.ts +7 -0
  74. package/node_modules/@llblab/pi-actors/dist/lib/recipe-control.js +43 -0
  75. package/node_modules/@llblab/pi-actors/dist/lib/recipes-context.d.ts +36 -0
  76. package/node_modules/@llblab/pi-actors/dist/lib/recipes-context.js +197 -0
  77. package/node_modules/@llblab/pi-actors/dist/lib/recipes-discovery.d.ts +77 -0
  78. package/node_modules/@llblab/pi-actors/dist/lib/recipes-discovery.js +783 -0
  79. package/node_modules/@llblab/pi-actors/dist/lib/recipes-references.d.ts +113 -0
  80. package/node_modules/@llblab/pi-actors/dist/lib/recipes-references.js +1108 -0
  81. package/node_modules/@llblab/pi-actors/dist/lib/recipes-usage.d.ts +21 -0
  82. package/node_modules/@llblab/pi-actors/dist/lib/recipes-usage.js +494 -0
  83. package/node_modules/@llblab/pi-actors/dist/lib/registry.d.ts +67 -0
  84. package/node_modules/@llblab/pi-actors/dist/lib/registry.js +504 -0
  85. package/node_modules/@llblab/pi-actors/dist/lib/review-control.d.ts +14 -0
  86. package/node_modules/@llblab/pi-actors/dist/lib/review-control.js +110 -0
  87. package/node_modules/@llblab/pi-actors/dist/lib/review-diagnostics.d.ts +11 -0
  88. package/node_modules/@llblab/pi-actors/dist/lib/review-diagnostics.js +148 -0
  89. package/node_modules/@llblab/pi-actors/dist/lib/review-projection.d.ts +14 -0
  90. package/node_modules/@llblab/pi-actors/dist/lib/review-projection.js +166 -0
  91. package/node_modules/@llblab/pi-actors/dist/lib/run-evidence-policy.d.ts +95 -0
  92. package/node_modules/@llblab/pi-actors/dist/lib/run-evidence-policy.js +177 -0
  93. package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.d.ts +18 -0
  94. package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.js +125 -0
  95. package/node_modules/@llblab/pi-actors/dist/lib/runs-artifacts.d.ts +21 -0
  96. package/node_modules/@llblab/pi-actors/dist/lib/runs-artifacts.js +68 -0
  97. package/node_modules/@llblab/pi-actors/dist/lib/runs-control-delivery.d.ts +28 -0
  98. package/node_modules/@llblab/pi-actors/dist/lib/runs-control-delivery.js +150 -0
  99. package/node_modules/@llblab/pi-actors/dist/lib/runs-control.d.ts +21 -0
  100. package/node_modules/@llblab/pi-actors/dist/lib/runs-control.js +89 -0
  101. package/node_modules/@llblab/pi-actors/dist/lib/runs-controls.d.ts +39 -0
  102. package/node_modules/@llblab/pi-actors/dist/lib/runs-controls.js +283 -0
  103. package/node_modules/@llblab/pi-actors/dist/lib/runs-identity.d.ts +5 -0
  104. package/node_modules/@llblab/pi-actors/dist/lib/runs-identity.js +11 -0
  105. package/node_modules/@llblab/pi-actors/dist/lib/runs-index.d.ts +27 -0
  106. package/node_modules/@llblab/pi-actors/dist/lib/runs-index.js +142 -0
  107. package/node_modules/@llblab/pi-actors/dist/lib/runs-ownership.d.ts +7 -0
  108. package/node_modules/@llblab/pi-actors/dist/lib/runs-ownership.js +96 -0
  109. package/node_modules/@llblab/pi-actors/dist/lib/runs-parent-teardown.d.ts +51 -0
  110. package/node_modules/@llblab/pi-actors/dist/lib/runs-parent-teardown.js +172 -0
  111. package/node_modules/@llblab/pi-actors/dist/lib/runs-process.d.ts +22 -0
  112. package/node_modules/@llblab/pi-actors/dist/lib/runs-process.js +125 -0
  113. package/node_modules/@llblab/pi-actors/dist/lib/runs-retention.d.ts +18 -0
  114. package/node_modules/@llblab/pi-actors/dist/lib/runs-retention.js +108 -0
  115. package/node_modules/@llblab/pi-actors/dist/lib/runs-start.d.ts +12 -0
  116. package/node_modules/@llblab/pi-actors/dist/lib/runs-start.js +68 -0
  117. package/node_modules/@llblab/pi-actors/dist/lib/runs-status.d.ts +10 -0
  118. package/node_modules/@llblab/pi-actors/dist/lib/runs-status.js +68 -0
  119. package/node_modules/@llblab/pi-actors/dist/lib/runs-trace.d.ts +48 -0
  120. package/node_modules/@llblab/pi-actors/dist/lib/runs-trace.js +491 -0
  121. package/node_modules/@llblab/pi-actors/dist/lib/runtime-identity.d.ts +7 -0
  122. package/node_modules/@llblab/pi-actors/dist/lib/runtime-identity.js +35 -0
  123. package/node_modules/@llblab/pi-actors/dist/lib/runtime-triage.d.ts +29 -0
  124. package/node_modules/@llblab/pi-actors/dist/lib/runtime-triage.js +60 -0
  125. package/node_modules/@llblab/pi-actors/dist/lib/runtime.d.ts +69 -0
  126. package/node_modules/@llblab/pi-actors/dist/lib/runtime.js +339 -0
  127. package/node_modules/@llblab/pi-actors/dist/lib/schema.d.ts +60 -0
  128. package/node_modules/@llblab/pi-actors/dist/lib/schema.js +428 -0
  129. package/node_modules/@llblab/pi-actors/dist/lib/session-evidence.d.ts +45 -0
  130. package/node_modules/@llblab/pi-actors/dist/lib/session-evidence.js +204 -0
  131. package/node_modules/@llblab/pi-actors/dist/lib/state-readers.d.ts +21 -0
  132. package/node_modules/@llblab/pi-actors/dist/lib/state-readers.js +74 -0
  133. package/node_modules/@llblab/pi-actors/dist/lib/temp.d.ts +10 -0
  134. package/node_modules/@llblab/pi-actors/dist/lib/temp.js +90 -0
  135. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-lineage-transaction.d.ts +27 -0
  136. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-lineage-transaction.js +597 -0
  137. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-lineage.d.ts +24 -0
  138. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-lineage.js +98 -0
  139. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-scheduler.d.ts +80 -0
  140. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-scheduler.js +494 -0
  141. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-transaction.d.ts +50 -0
  142. package/node_modules/@llblab/pi-actors/dist/lib/tool-review-transaction.js +362 -0
  143. package/node_modules/@llblab/pi-actors/dist/lib/tool-review.d.ts +56 -0
  144. package/node_modules/@llblab/pi-actors/dist/lib/tool-review.js +197 -0
  145. package/node_modules/@llblab/pi-actors/dist/lib/tools-access.d.ts +19 -0
  146. package/node_modules/@llblab/pi-actors/dist/lib/tools-access.js +44 -0
  147. package/node_modules/@llblab/pi-actors/dist/lib/tools-inspect.d.ts +15 -0
  148. package/node_modules/@llblab/pi-actors/dist/lib/tools-inspect.js +532 -0
  149. package/node_modules/@llblab/pi-actors/dist/lib/tools-local.d.ts +17 -0
  150. package/node_modules/@llblab/pi-actors/dist/lib/tools-local.js +191 -0
  151. package/node_modules/@llblab/pi-actors/dist/lib/tools-message.d.ts +9 -0
  152. package/node_modules/@llblab/pi-actors/dist/lib/tools-message.js +139 -0
  153. package/node_modules/@llblab/pi-actors/dist/lib/tools-register.d.ts +18 -0
  154. package/node_modules/@llblab/pi-actors/dist/lib/tools-register.js +41 -0
  155. package/node_modules/@llblab/pi-actors/dist/lib/tools-response.d.ts +20 -0
  156. package/node_modules/@llblab/pi-actors/dist/lib/tools-response.js +243 -0
  157. package/node_modules/@llblab/pi-actors/dist/lib/tools-spawn.d.ts +15 -0
  158. package/node_modules/@llblab/pi-actors/dist/lib/tools-spawn.js +133 -0
  159. package/node_modules/@llblab/pi-actors/dist/lib/tools.d.ts +28 -0
  160. package/node_modules/@llblab/pi-actors/dist/lib/tools.js +49 -0
  161. package/node_modules/@llblab/pi-actors/dist/lib/trace-projection.d.ts +22 -0
  162. package/node_modules/@llblab/pi-actors/dist/lib/trace-projection.js +231 -0
  163. package/node_modules/@llblab/pi-actors/dist/pi-actors/index.js +1 -0
  164. package/node_modules/@llblab/pi-actors/dist/scripts/async-runner.mjs +555 -0
  165. package/node_modules/@llblab/pi-actors/dist/scripts/build-dist.mjs +60 -0
  166. package/node_modules/@llblab/pi-actors/dist/scripts/conformance.mjs +63 -0
  167. package/node_modules/@llblab/pi-actors/dist/skills/actors/SKILL.md +126 -0
  168. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/command-validate.json +13 -0
  169. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/jsonl-tail.json +10 -0
  170. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/recipe-validate.json +11 -0
  171. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/resource-locker-snapshot.json +11 -0
  172. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/resource-locker.json +25 -0
  173. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/run-ops-snapshot.json +15 -0
  174. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/run-state-files.json +13 -0
  175. package/node_modules/@llblab/pi-actors/dist/skills/actors/recipes/run-summary.json +9 -0
  176. package/node_modules/@llblab/pi-actors/dist/skills/actors/references/diagnostics.md +44 -0
  177. package/node_modules/@llblab/pi-actors/dist/skills/actors/references/persistent-tools.md +76 -0
  178. package/node_modules/@llblab/pi-actors/dist/skills/actors/references/recipes.md +51 -0
  179. package/node_modules/@llblab/pi-actors/dist/skills/actors/references/runs.md +41 -0
  180. package/node_modules/@llblab/pi-actors/dist/skills/actors/scripts/resource-locker.mjs +425 -0
  181. package/node_modules/@llblab/pi-actors/dist/skills/actors/scripts/run-utils.mjs +164 -0
  182. package/node_modules/@llblab/pi-actors/dist/skills/actors/scripts/validate-recipe.mjs +370 -0
  183. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/SKILL.md +33 -0
  184. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/recipes/bundle.json +77 -0
  185. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/recipes/file-write.json +14 -0
  186. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/recipes/manifest.json +14 -0
  187. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/recipes/report.json +39 -0
  188. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/recipes/write.json +53 -0
  189. package/node_modules/@llblab/pi-actors/dist/skills/artifacts/scripts/artifact-utils.mjs +63 -0
  190. package/node_modules/@llblab/pi-actors/dist/skills/music-player/SKILL.md +57 -0
  191. package/node_modules/@llblab/pi-actors/dist/skills/music-player/genapps/music-player.mjs +360 -0
  192. package/node_modules/@llblab/pi-actors/dist/skills/music-player/recipes/playback.json +29 -0
  193. package/node_modules/@llblab/pi-actors/dist/skills/music-player/scripts/playback-client.mjs +143 -0
  194. package/node_modules/@llblab/pi-actors/dist/skills/music-player/scripts/playback.mjs +1446 -0
  195. package/node_modules/@llblab/pi-actors/dist/skills/project-work/SKILL.md +37 -0
  196. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/changelog-head.json +11 -0
  197. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/changelog-section.json +11 -0
  198. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/docs-maintenance.json +66 -0
  199. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/git-log.json +11 -0
  200. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/git-status.json +9 -0
  201. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/markdown-index.json +14 -0
  202. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/package-summary.json +9 -0
  203. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/release-readiness.json +115 -0
  204. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/release-summary.json +74 -0
  205. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/repo-health.json +75 -0
  206. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/run-ops.json +56 -0
  207. package/node_modules/@llblab/pi-actors/dist/skills/project-work/recipes/skill-summary.json +11 -0
  208. package/node_modules/@llblab/pi-actors/dist/skills/project-work/scripts/project-utils.mjs +89 -0
  209. package/node_modules/@llblab/pi-actors/dist/skills/recipe-memory/SKILL.md +36 -0
  210. package/node_modules/@llblab/pi-actors/dist/skills/recipe-memory/recipes/draft-review.json +14 -0
  211. package/node_modules/@llblab/pi-actors/dist/skills/recipe-memory/recipes/tool-review.json +14 -0
  212. package/node_modules/@llblab/pi-actors/dist/skills/swarm/SKILL.md +84 -0
  213. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/architect.json +82 -0
  214. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/checkpoint-continuation.json +51 -0
  215. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/development-tasking.json +67 -0
  216. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/lens-review.json +63 -0
  217. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/quorum-review.json +65 -0
  218. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/research-synthesis.json +81 -0
  219. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/review-readiness.json +59 -0
  220. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-artifact.json +21 -0
  221. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-checkpoint.json +21 -0
  222. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-conflict-report.json +19 -0
  223. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-contradiction-map.json +20 -0
  224. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-critic.json +22 -0
  225. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-evidence-map.json +20 -0
  226. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-followup.json +21 -0
  227. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-judge.json +22 -0
  228. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-merge.json +24 -0
  229. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-normalize.json +20 -0
  230. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-plan.json +20 -0
  231. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-preflight.json +18 -0
  232. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-prompt.json +16 -0
  233. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-prompts.json +39 -0
  234. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-quorum.json +31 -0
  235. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-review-coordinator.json +170 -0
  236. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-review.json +26 -0
  237. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-task-card.json +22 -0
  238. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-tools.json +15 -0
  239. package/node_modules/@llblab/pi-actors/dist/skills/swarm/recipes/subagent-verify.json +23 -0
  240. package/node_modules/@llblab/pi-actors/dist/skills/swarm/references/development-swarm.md +189 -0
  241. package/node_modules/@llblab/pi-actors/dist/skills/swarm/references/review-swarms.md +115 -0
  242. package/node_modules/@llblab/pi-actors/docs/README.md +20 -0
  243. package/node_modules/@llblab/pi-actors/docs/actor-inspector.md +50 -0
  244. package/node_modules/@llblab/pi-actors/docs/async-runs.md +141 -0
  245. package/node_modules/@llblab/pi-actors/docs/command-templates.md +321 -0
  246. package/node_modules/@llblab/pi-actors/docs/recipe-library.md +89 -0
  247. package/node_modules/@llblab/pi-actors/docs/releasing.md +28 -0
  248. package/node_modules/@llblab/pi-actors/docs/template-recipes.md +175 -0
  249. package/node_modules/@llblab/pi-actors/docs/tool-registry.md +90 -0
  250. package/node_modules/@llblab/pi-actors/fixtures/protocol/artifact-manifest.json +9 -0
  251. package/node_modules/@llblab/pi-actors/fixtures/protocol/control-endpoint.json +6 -0
  252. package/node_modules/@llblab/pi-actors/fixtures/protocol/control-record.json +9 -0
  253. package/node_modules/@llblab/pi-actors/fixtures/protocol/recipe-summary.json +8 -0
  254. package/node_modules/@llblab/pi-actors/fixtures/protocol/run-state.json +10 -0
  255. package/node_modules/@llblab/pi-actors/fixtures/protocol/trace-event.json +9 -0
  256. package/node_modules/@llblab/pi-actors/index.ts +30 -0
  257. package/node_modules/@llblab/pi-actors/lib/async-runs.ts +1245 -0
  258. package/node_modules/@llblab/pi-actors/lib/automatic-review-runtime.ts +148 -0
  259. package/node_modules/@llblab/pi-actors/lib/command-templates.ts +1116 -0
  260. package/node_modules/@llblab/pi-actors/lib/config.ts +261 -0
  261. package/node_modules/@llblab/pi-actors/lib/control-projection.ts +105 -0
  262. package/node_modules/@llblab/pi-actors/lib/control.ts +117 -0
  263. package/node_modules/@llblab/pi-actors/lib/draft-consolidation-transaction.ts +821 -0
  264. package/node_modules/@llblab/pi-actors/lib/draft-consolidation.ts +181 -0
  265. package/node_modules/@llblab/pi-actors/lib/draft-review.ts +325 -0
  266. package/node_modules/@llblab/pi-actors/lib/draft-sleep.ts +575 -0
  267. package/node_modules/@llblab/pi-actors/lib/execution-output.ts +123 -0
  268. package/node_modules/@llblab/pi-actors/lib/execution-sessions.ts +111 -0
  269. package/node_modules/@llblab/pi-actors/lib/execution.ts +1153 -0
  270. package/node_modules/@llblab/pi-actors/lib/extension-runtime.ts +181 -0
  271. package/node_modules/@llblab/pi-actors/lib/file-state.ts +306 -0
  272. package/node_modules/@llblab/pi-actors/lib/identity.ts +29 -0
  273. package/node_modules/@llblab/pi-actors/lib/inspector-actions.ts +79 -0
  274. package/node_modules/@llblab/pi-actors/lib/inspector-command.ts +54 -0
  275. package/node_modules/@llblab/pi-actors/lib/inspector-overlay.ts +901 -0
  276. package/node_modules/@llblab/pi-actors/lib/inspector.ts +204 -0
  277. package/node_modules/@llblab/pi-actors/lib/limits.ts +29 -0
  278. package/node_modules/@llblab/pi-actors/lib/model-context.ts +359 -0
  279. package/node_modules/@llblab/pi-actors/lib/observability.ts +1337 -0
  280. package/node_modules/@llblab/pi-actors/lib/paths.ts +111 -0
  281. package/node_modules/@llblab/pi-actors/lib/pi.ts +47 -0
  282. package/node_modules/@llblab/pi-actors/lib/preflight-diagnostics.ts +132 -0
  283. package/node_modules/@llblab/pi-actors/lib/prompts.ts +69 -0
  284. package/node_modules/@llblab/pi-actors/lib/recipe-control.ts +52 -0
  285. package/node_modules/@llblab/pi-actors/lib/recipes-context.ts +268 -0
  286. package/node_modules/@llblab/pi-actors/lib/recipes-discovery.ts +1060 -0
  287. package/node_modules/@llblab/pi-actors/lib/recipes-references.ts +1598 -0
  288. package/node_modules/@llblab/pi-actors/lib/recipes-usage.ts +638 -0
  289. package/node_modules/@llblab/pi-actors/lib/registry.ts +806 -0
  290. package/node_modules/@llblab/pi-actors/lib/review-control.ts +136 -0
  291. package/node_modules/@llblab/pi-actors/lib/review-diagnostics.ts +164 -0
  292. package/node_modules/@llblab/pi-actors/lib/review-projection.ts +196 -0
  293. package/node_modules/@llblab/pi-actors/lib/run-evidence-policy.ts +242 -0
  294. package/node_modules/@llblab/pi-actors/lib/run-ui-runtime.ts +155 -0
  295. package/node_modules/@llblab/pi-actors/lib/runs-artifacts.ts +96 -0
  296. package/node_modules/@llblab/pi-actors/lib/runs-control-delivery.ts +209 -0
  297. package/node_modules/@llblab/pi-actors/lib/runs-control.ts +148 -0
  298. package/node_modules/@llblab/pi-actors/lib/runs-controls.ts +282 -0
  299. package/node_modules/@llblab/pi-actors/lib/runs-identity.ts +14 -0
  300. package/node_modules/@llblab/pi-actors/lib/runs-index.ts +192 -0
  301. package/node_modules/@llblab/pi-actors/lib/runs-ownership.ts +136 -0
  302. package/node_modules/@llblab/pi-actors/lib/runs-parent-teardown.ts +257 -0
  303. package/node_modules/@llblab/pi-actors/lib/runs-process.ts +174 -0
  304. package/node_modules/@llblab/pi-actors/lib/runs-retention.ts +140 -0
  305. package/node_modules/@llblab/pi-actors/lib/runs-start.ts +113 -0
  306. package/node_modules/@llblab/pi-actors/lib/runs-status.ts +101 -0
  307. package/node_modules/@llblab/pi-actors/lib/runs-trace.ts +611 -0
  308. package/node_modules/@llblab/pi-actors/lib/runtime-identity.ts +39 -0
  309. package/node_modules/@llblab/pi-actors/lib/runtime-triage.ts +106 -0
  310. package/node_modules/@llblab/pi-actors/lib/runtime.ts +430 -0
  311. package/node_modules/@llblab/pi-actors/lib/schema.ts +525 -0
  312. package/node_modules/@llblab/pi-actors/lib/session-evidence.ts +302 -0
  313. package/node_modules/@llblab/pi-actors/lib/state-readers.ts +93 -0
  314. package/node_modules/@llblab/pi-actors/lib/temp.ts +99 -0
  315. package/node_modules/@llblab/pi-actors/lib/tool-review-lineage-transaction.ts +881 -0
  316. package/node_modules/@llblab/pi-actors/lib/tool-review-lineage.ts +145 -0
  317. package/node_modules/@llblab/pi-actors/lib/tool-review-scheduler.ts +635 -0
  318. package/node_modules/@llblab/pi-actors/lib/tool-review-transaction.ts +563 -0
  319. package/node_modules/@llblab/pi-actors/lib/tool-review.ts +270 -0
  320. package/node_modules/@llblab/pi-actors/lib/tools-access.ts +68 -0
  321. package/node_modules/@llblab/pi-actors/lib/tools-inspect.ts +673 -0
  322. package/node_modules/@llblab/pi-actors/lib/tools-local.ts +303 -0
  323. package/node_modules/@llblab/pi-actors/lib/tools-message.ts +176 -0
  324. package/node_modules/@llblab/pi-actors/lib/tools-register.ts +63 -0
  325. package/node_modules/@llblab/pi-actors/lib/tools-response.ts +285 -0
  326. package/node_modules/@llblab/pi-actors/lib/tools-spawn.ts +212 -0
  327. package/node_modules/@llblab/pi-actors/lib/tools.ts +88 -0
  328. package/node_modules/@llblab/pi-actors/lib/trace-projection.ts +306 -0
  329. package/node_modules/@llblab/pi-actors/package.json +76 -0
  330. package/node_modules/@llblab/pi-actors/scripts/async-runner.mjs +555 -0
  331. package/node_modules/@llblab/pi-actors/scripts/build-dist.mjs +60 -0
  332. package/node_modules/@llblab/pi-actors/scripts/conformance.mjs +63 -0
  333. package/node_modules/@llblab/pi-actors/skills/actors/SKILL.md +126 -0
  334. package/node_modules/@llblab/pi-actors/skills/actors/recipes/command-validate.json +13 -0
  335. package/node_modules/@llblab/pi-actors/skills/actors/recipes/jsonl-tail.json +10 -0
  336. package/node_modules/@llblab/pi-actors/skills/actors/recipes/recipe-validate.json +11 -0
  337. package/node_modules/@llblab/pi-actors/skills/actors/recipes/resource-locker-snapshot.json +11 -0
  338. package/node_modules/@llblab/pi-actors/skills/actors/recipes/resource-locker.json +25 -0
  339. package/node_modules/@llblab/pi-actors/skills/actors/recipes/run-ops-snapshot.json +15 -0
  340. package/node_modules/@llblab/pi-actors/skills/actors/recipes/run-state-files.json +13 -0
  341. package/node_modules/@llblab/pi-actors/skills/actors/recipes/run-summary.json +9 -0
  342. package/node_modules/@llblab/pi-actors/skills/actors/references/diagnostics.md +44 -0
  343. package/node_modules/@llblab/pi-actors/skills/actors/references/persistent-tools.md +76 -0
  344. package/node_modules/@llblab/pi-actors/skills/actors/references/recipes.md +51 -0
  345. package/node_modules/@llblab/pi-actors/skills/actors/references/runs.md +41 -0
  346. package/node_modules/@llblab/pi-actors/skills/actors/scripts/resource-locker.mjs +425 -0
  347. package/node_modules/@llblab/pi-actors/skills/actors/scripts/run-utils.mjs +164 -0
  348. package/node_modules/@llblab/pi-actors/skills/actors/scripts/validate-recipe.mjs +370 -0
  349. package/node_modules/@llblab/pi-actors/skills/artifacts/SKILL.md +33 -0
  350. package/node_modules/@llblab/pi-actors/skills/artifacts/recipes/bundle.json +77 -0
  351. package/node_modules/@llblab/pi-actors/skills/artifacts/recipes/file-write.json +14 -0
  352. package/node_modules/@llblab/pi-actors/skills/artifacts/recipes/manifest.json +14 -0
  353. package/node_modules/@llblab/pi-actors/skills/artifacts/recipes/report.json +39 -0
  354. package/node_modules/@llblab/pi-actors/skills/artifacts/recipes/write.json +53 -0
  355. package/node_modules/@llblab/pi-actors/skills/artifacts/scripts/artifact-utils.mjs +63 -0
  356. package/node_modules/@llblab/pi-actors/skills/music-player/SKILL.md +57 -0
  357. package/node_modules/@llblab/pi-actors/skills/music-player/genapps/music-player.mjs +360 -0
  358. package/node_modules/@llblab/pi-actors/skills/music-player/recipes/playback.json +29 -0
  359. package/node_modules/@llblab/pi-actors/skills/music-player/scripts/playback-client.mjs +143 -0
  360. package/node_modules/@llblab/pi-actors/skills/music-player/scripts/playback.mjs +1446 -0
  361. package/node_modules/@llblab/pi-actors/skills/project-work/SKILL.md +37 -0
  362. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/changelog-head.json +11 -0
  363. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/changelog-section.json +11 -0
  364. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/docs-maintenance.json +66 -0
  365. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/git-log.json +11 -0
  366. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/git-status.json +9 -0
  367. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/markdown-index.json +14 -0
  368. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/package-summary.json +9 -0
  369. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/release-readiness.json +115 -0
  370. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/release-summary.json +74 -0
  371. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/repo-health.json +75 -0
  372. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/run-ops.json +56 -0
  373. package/node_modules/@llblab/pi-actors/skills/project-work/recipes/skill-summary.json +11 -0
  374. package/node_modules/@llblab/pi-actors/skills/project-work/scripts/project-utils.mjs +89 -0
  375. package/node_modules/@llblab/pi-actors/skills/recipe-memory/SKILL.md +36 -0
  376. package/node_modules/@llblab/pi-actors/skills/recipe-memory/recipes/draft-review.json +14 -0
  377. package/node_modules/@llblab/pi-actors/skills/recipe-memory/recipes/tool-review.json +14 -0
  378. package/node_modules/@llblab/pi-actors/skills/swarm/SKILL.md +84 -0
  379. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/architect.json +82 -0
  380. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/checkpoint-continuation.json +51 -0
  381. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/development-tasking.json +67 -0
  382. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/lens-review.json +63 -0
  383. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/quorum-review.json +65 -0
  384. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/research-synthesis.json +81 -0
  385. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/review-readiness.json +59 -0
  386. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-artifact.json +21 -0
  387. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-checkpoint.json +21 -0
  388. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-conflict-report.json +19 -0
  389. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-contradiction-map.json +20 -0
  390. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-critic.json +22 -0
  391. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-evidence-map.json +20 -0
  392. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-followup.json +21 -0
  393. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-judge.json +22 -0
  394. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-merge.json +24 -0
  395. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-normalize.json +20 -0
  396. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-plan.json +20 -0
  397. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-preflight.json +18 -0
  398. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-prompt.json +16 -0
  399. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-prompts.json +39 -0
  400. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-quorum.json +31 -0
  401. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-review-coordinator.json +170 -0
  402. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-review.json +26 -0
  403. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-task-card.json +22 -0
  404. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-tools.json +15 -0
  405. package/node_modules/@llblab/pi-actors/skills/swarm/recipes/subagent-verify.json +23 -0
  406. package/node_modules/@llblab/pi-actors/skills/swarm/references/development-swarm.md +189 -0
  407. package/node_modules/@llblab/pi-actors/skills/swarm/references/review-swarms.md +115 -0
  408. package/node_modules/@llblab/pi-codex-usage/AGENTS.md +17 -0
  409. package/node_modules/@llblab/pi-codex-usage/BACKLOG.md +8 -0
  410. package/node_modules/@llblab/pi-codex-usage/CHANGELOG.md +80 -0
  411. package/node_modules/@llblab/pi-codex-usage/LICENSE +22 -0
  412. package/node_modules/@llblab/pi-codex-usage/README.md +113 -0
  413. package/node_modules/@llblab/pi-codex-usage/banner.jpg +0 -0
  414. package/node_modules/@llblab/pi-codex-usage/index.ts +1525 -0
  415. package/node_modules/@llblab/pi-codex-usage/package.json +59 -0
  416. package/node_modules/@llblab/pi-grow-loop/AGENTS.md +56 -0
  417. package/node_modules/@llblab/pi-grow-loop/BACKLOG.md +3 -0
  418. package/node_modules/@llblab/pi-grow-loop/CHANGELOG.md +126 -0
  419. package/node_modules/@llblab/pi-grow-loop/README.md +216 -0
  420. package/node_modules/@llblab/pi-grow-loop/banner.jpg +0 -0
  421. package/node_modules/@llblab/pi-grow-loop/index.ts +219 -0
  422. package/node_modules/@llblab/pi-grow-loop/package.json +64 -0
  423. package/node_modules/@llblab/pi-grow-loop/skills/grow-loop/SKILL.md +131 -0
  424. package/node_modules/@llblab/pi-grow-loop/skills/while-true/SKILL.md +233 -0
  425. package/node_modules/@llblab/pi-telegram/AGENTS.md +157 -0
  426. package/node_modules/@llblab/pi-telegram/BACKLOG.md +15 -0
  427. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +886 -0
  428. package/node_modules/@llblab/pi-telegram/README.md +330 -0
  429. package/node_modules/@llblab/pi-telegram/api/activity.ts +15 -0
  430. package/node_modules/@llblab/pi-telegram/api/commands.ts +11 -0
  431. package/node_modules/@llblab/pi-telegram/api/delivery.ts +21 -0
  432. package/node_modules/@llblab/pi-telegram/api/inbound.ts +14 -0
  433. package/node_modules/@llblab/pi-telegram/api/keyboard.ts +11 -0
  434. package/node_modules/@llblab/pi-telegram/api/outbound.ts +11 -0
  435. package/node_modules/@llblab/pi-telegram/api/sections.ts +17 -0
  436. package/node_modules/@llblab/pi-telegram/api/status.ts +12 -0
  437. package/node_modules/@llblab/pi-telegram/api/updates.ts +16 -0
  438. package/node_modules/@llblab/pi-telegram/api/voice.ts +24 -0
  439. package/node_modules/@llblab/pi-telegram/docs/README.md +25 -0
  440. package/node_modules/@llblab/pi-telegram/docs/activity.md +304 -0
  441. package/node_modules/@llblab/pi-telegram/docs/architecture.md +418 -0
  442. package/node_modules/@llblab/pi-telegram/docs/callback-namespaces.md +48 -0
  443. package/node_modules/@llblab/pi-telegram/docs/command-templates.md +365 -0
  444. package/node_modules/@llblab/pi-telegram/docs/compact-matrix-literal.md +176 -0
  445. package/node_modules/@llblab/pi-telegram/docs/delivery.md +225 -0
  446. package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +310 -0
  447. package/node_modules/@llblab/pi-telegram/docs/inbound.md +136 -0
  448. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +467 -0
  449. package/node_modules/@llblab/pi-telegram/docs/outbound.md +193 -0
  450. package/node_modules/@llblab/pi-telegram/docs/public-api.md +599 -0
  451. package/node_modules/@llblab/pi-telegram/docs/sections.md +452 -0
  452. package/node_modules/@llblab/pi-telegram/docs/ui-style.md +256 -0
  453. package/node_modules/@llblab/pi-telegram/docs/updates.md +171 -0
  454. package/node_modules/@llblab/pi-telegram/docs/voice.md +217 -0
  455. package/node_modules/@llblab/pi-telegram/index.ts +1336 -0
  456. package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +714 -0
  457. package/node_modules/@llblab/pi-telegram/lib/activity.ts +782 -0
  458. package/node_modules/@llblab/pi-telegram/lib/agent-messages.ts +121 -0
  459. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +1129 -0
  460. package/node_modules/@llblab/pi-telegram/lib/bus-api.ts +379 -0
  461. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +1941 -0
  462. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +2119 -0
  463. package/node_modules/@llblab/pi-telegram/lib/bus-transport.ts +244 -0
  464. package/node_modules/@llblab/pi-telegram/lib/bus.ts +2645 -0
  465. package/node_modules/@llblab/pi-telegram/lib/command-templates.ts +954 -0
  466. package/node_modules/@llblab/pi-telegram/lib/commands.ts +1854 -0
  467. package/node_modules/@llblab/pi-telegram/lib/config.ts +1143 -0
  468. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +891 -0
  469. package/node_modules/@llblab/pi-telegram/lib/generative-app-worker.mjs +104 -0
  470. package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +958 -0
  471. package/node_modules/@llblab/pi-telegram/lib/inbound.ts +824 -0
  472. package/node_modules/@llblab/pi-telegram/lib/journal.ts +3140 -0
  473. package/node_modules/@llblab/pi-telegram/lib/keyboard.ts +59 -0
  474. package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +623 -0
  475. package/node_modules/@llblab/pi-telegram/lib/locks.ts +1422 -0
  476. package/node_modules/@llblab/pi-telegram/lib/logs.ts +393 -0
  477. package/node_modules/@llblab/pi-telegram/lib/media.ts +921 -0
  478. package/node_modules/@llblab/pi-telegram/lib/menu-model.ts +1182 -0
  479. package/node_modules/@llblab/pi-telegram/lib/menu-queue.ts +926 -0
  480. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +876 -0
  481. package/node_modules/@llblab/pi-telegram/lib/menu-status.ts +274 -0
  482. package/node_modules/@llblab/pi-telegram/lib/menu-thinking.ts +185 -0
  483. package/node_modules/@llblab/pi-telegram/lib/menu.ts +867 -0
  484. package/node_modules/@llblab/pi-telegram/lib/model.ts +672 -0
  485. package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +981 -0
  486. package/node_modules/@llblab/pi-telegram/lib/outbound-buttons.ts +331 -0
  487. package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +515 -0
  488. package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +285 -0
  489. package/node_modules/@llblab/pi-telegram/lib/outbound.ts +1007 -0
  490. package/node_modules/@llblab/pi-telegram/lib/ownership.ts +298 -0
  491. package/node_modules/@llblab/pi-telegram/lib/paths.ts +127 -0
  492. package/node_modules/@llblab/pi-telegram/lib/pi.ts +197 -0
  493. package/node_modules/@llblab/pi-telegram/lib/polling.ts +1588 -0
  494. package/node_modules/@llblab/pi-telegram/lib/preview.ts +846 -0
  495. package/node_modules/@llblab/pi-telegram/lib/prompt-templates.ts +158 -0
  496. package/node_modules/@llblab/pi-telegram/lib/prompts.ts +218 -0
  497. package/node_modules/@llblab/pi-telegram/lib/queue.ts +3075 -0
  498. package/node_modules/@llblab/pi-telegram/lib/recovery.ts +464 -0
  499. package/node_modules/@llblab/pi-telegram/lib/rendering.ts +1213 -0
  500. package/node_modules/@llblab/pi-telegram/lib/replies.ts +892 -0
  501. package/node_modules/@llblab/pi-telegram/lib/routing.ts +2889 -0
  502. package/node_modules/@llblab/pi-telegram/lib/runtime.ts +628 -0
  503. package/node_modules/@llblab/pi-telegram/lib/sections.ts +710 -0
  504. package/node_modules/@llblab/pi-telegram/lib/setup.ts +220 -0
  505. package/node_modules/@llblab/pi-telegram/lib/skills.ts +21 -0
  506. package/node_modules/@llblab/pi-telegram/lib/status.ts +1550 -0
  507. package/node_modules/@llblab/pi-telegram/lib/sync.ts +883 -0
  508. package/node_modules/@llblab/pi-telegram/lib/target.ts +49 -0
  509. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +1747 -0
  510. package/node_modules/@llblab/pi-telegram/lib/text-groups.ts +487 -0
  511. package/node_modules/@llblab/pi-telegram/lib/thread-reconciler.ts +1002 -0
  512. package/node_modules/@llblab/pi-telegram/lib/threads.ts +3183 -0
  513. package/node_modules/@llblab/pi-telegram/lib/time-injection.ts +78 -0
  514. package/node_modules/@llblab/pi-telegram/lib/turns.ts +753 -0
  515. package/node_modules/@llblab/pi-telegram/lib/updates.ts +4950 -0
  516. package/node_modules/@llblab/pi-telegram/lib/voice.ts +340 -0
  517. package/node_modules/@llblab/pi-telegram/package.json +83 -0
  518. package/node_modules/@llblab/pi-telegram/screenshot.png +0 -0
  519. package/node_modules/@llblab/pi-telegram/scripts/check-downgrade.mjs +435 -0
  520. package/node_modules/@llblab/pi-telegram/skills/generated-control-surface/SKILL.md +241 -0
  521. package/node_modules/@llblab/pi-telegram/skills/generative-apps/SKILL.md +114 -0
  522. package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/SKILL.md +149 -0
  523. package/package.json +67 -0
@@ -0,0 +1,1182 @@
1
+ /**
2
+ * Telegram model menu UI helpers
3
+ * Zones: telegram ui, model controls, menu composition
4
+ * Owns model-menu state, scoped model pages, model callback planning, and model-menu message rendering
5
+ */
6
+
7
+ import type { TelegramInlineKeyboardMarkup } from "./keyboard.ts";
8
+ import {
9
+ getCanonicalModelId,
10
+ type MenuModel,
11
+ modelsMatch,
12
+ parseTelegramCliScopedModelPatterns,
13
+ resolveScopedModelPatterns,
14
+ type ScopedTelegramModel,
15
+ sortScopedModels,
16
+ type ThinkingLevel,
17
+ } from "./model.ts";
18
+
19
+ const TELEGRAM_MODEL_MENU_CACHE_TTL_MS = 5000;
20
+ const TELEGRAM_MODEL_MENU_STATE_TTL_MS = 10 * 60 * 1000;
21
+ const MAX_STORED_TELEGRAM_MODEL_MENUS = 50;
22
+
23
+ export type TelegramModelScope = "all" | "scoped";
24
+
25
+ export interface TelegramModelMenuState<TModel extends MenuModel = MenuModel> {
26
+ chatId: number;
27
+ threadId?: number;
28
+ messageId: number;
29
+ page: number;
30
+ scope: TelegramModelScope;
31
+ scopedModels: ScopedTelegramModel<TModel>[];
32
+ allModels: ScopedTelegramModel<TModel>[];
33
+ note?: string;
34
+ selectedModelIndex?: number;
35
+ selectedModelKey?: string;
36
+ scopedModelPatterns?: string[];
37
+ canMutateScope?: boolean;
38
+ mode:
39
+ | "status"
40
+ | "model"
41
+ | "model-pages"
42
+ | "model-detail"
43
+ | "thinking"
44
+ | "queue"
45
+ | "settings";
46
+ }
47
+
48
+ export interface StoredTelegramModelMenuState<
49
+ TModel extends MenuModel = MenuModel,
50
+ > {
51
+ state: TelegramModelMenuState<TModel>;
52
+ updatedAt: number;
53
+ }
54
+
55
+ export interface TelegramModelMenuStoreOptions {
56
+ maxAgeMs: number;
57
+ maxStoredMenus: number;
58
+ now?: number;
59
+ }
60
+
61
+ export interface CachedTelegramModelMenuInputs<
62
+ TModel extends MenuModel = MenuModel,
63
+ > {
64
+ expiresAt: number;
65
+ availableModels: TModel[];
66
+ configuredScopedModelPatterns: string[];
67
+ cliScopedModelPatterns?: string[];
68
+ }
69
+
70
+ export interface TelegramModelMenuInputCacheDeps<
71
+ TModel extends MenuModel = MenuModel,
72
+ > {
73
+ cacheTtlMs: number;
74
+ now?: number;
75
+ reloadSettings: () => Promise<void>;
76
+ refreshAvailableModels: () => TModel[];
77
+ getConfiguredScopedModelPatterns: () => string[] | undefined;
78
+ getCliScopedModelPatterns: () => string[] | undefined;
79
+ }
80
+
81
+ export interface TelegramModelMenuRuntimeContext<
82
+ TModel extends MenuModel = MenuModel,
83
+ > {
84
+ modelRegistry: {
85
+ refresh: () => void;
86
+ getAvailable: () => TModel[];
87
+ };
88
+ }
89
+
90
+ export interface TelegramModelMenuRuntimeOptions<
91
+ TContext extends TelegramModelMenuRuntimeContext<TModel>,
92
+ TModel extends MenuModel = MenuModel,
93
+ > {
94
+ chatId: number;
95
+ threadId?: number;
96
+ activeModel: TModel | undefined;
97
+ cachedInputs: CachedTelegramModelMenuInputs<TModel> | undefined;
98
+ cacheTtlMs: number;
99
+ ctx: TContext;
100
+ reloadSettings: () => Promise<void>;
101
+ getConfiguredScopedModelPatterns: () => string[] | undefined;
102
+ getCliScopedModelPatterns?: () => string[] | undefined;
103
+ }
104
+
105
+ export interface MenuSettingsManager {
106
+ reload: () => Promise<void>;
107
+ flush?: () => Promise<void>;
108
+ getEnabledModels: () => string[] | undefined;
109
+ setEnabledModels?: (patterns: string[] | undefined) => void;
110
+ }
111
+
112
+ export type TelegramModelMenuStateBuilderContext<
113
+ TModel extends MenuModel = MenuModel,
114
+ > = TelegramModelMenuRuntimeContext<TModel> & { cwd: string };
115
+
116
+ export interface TelegramModelMenuStateBuilderDeps<
117
+ TModel extends MenuModel = MenuModel,
118
+ TContext extends TelegramModelMenuStateBuilderContext<TModel> =
119
+ TelegramModelMenuStateBuilderContext<TModel>,
120
+ > {
121
+ runtime: TelegramModelMenuRuntime<TModel>;
122
+ createSettingsManager: (cwd: string) => MenuSettingsManager;
123
+ getActiveModel: (ctx: TContext) => TModel | undefined;
124
+ }
125
+
126
+ export type TelegramReplyMarkup = TelegramInlineKeyboardMarkup;
127
+
128
+ export interface TelegramMenuMessageRuntimeDeps {
129
+ editInteractiveMessage: (
130
+ chatId: number,
131
+ messageId: number,
132
+ text: string,
133
+ mode: "markdown" | "html" | "plain",
134
+ replyMarkup: TelegramReplyMarkup,
135
+ ) => Promise<void>;
136
+ sendInteractiveMessage: (
137
+ chatId: number,
138
+ text: string,
139
+ mode: "markdown" | "html" | "plain",
140
+ replyMarkup: TelegramReplyMarkup,
141
+ options?: { target?: { chatId: number; threadId?: number } },
142
+ ) => Promise<number | undefined>;
143
+ }
144
+
145
+ export type TelegramModelMenuCallbackDeps<
146
+ TModel extends MenuModel = MenuModel,
147
+ > = {
148
+ answerCallbackQuery: (
149
+ callbackQueryId: string,
150
+ text?: string,
151
+ ) => Promise<void>;
152
+ updateModelMenuMessage: () => Promise<void>;
153
+ updateStatusMessage: () => Promise<void>;
154
+ persistScopedModelPatterns?: (patterns: string[]) => Promise<void>;
155
+ setModel: (model: TModel) => Promise<boolean>;
156
+ setCurrentModel: (model: TModel) => void;
157
+ setThinkingLevel: (level: ThinkingLevel) => void;
158
+ stagePendingModelSwitch: (selection: ScopedTelegramModel<TModel>) => void;
159
+ restartInterruptedTelegramTurn: (
160
+ selection: ScopedTelegramModel<TModel>,
161
+ ) => Promise<boolean> | boolean;
162
+ };
163
+
164
+ export interface TelegramModelMenuOpenDeps<
165
+ TModel extends MenuModel = MenuModel,
166
+ > {
167
+ isIdle: () => boolean;
168
+ canOfferInFlightModelSwitch: () => boolean;
169
+ sendBusyMessage: () => Promise<void>;
170
+ sendNoModelsMessage: () => Promise<void>;
171
+ getModelMenuState: () => Promise<TelegramModelMenuState<TModel>>;
172
+ getActiveModel: () => TModel | undefined;
173
+ sendModelMenu: (
174
+ state: TelegramModelMenuState<TModel>,
175
+ activeModel: TModel | undefined,
176
+ ) => Promise<number | undefined>;
177
+ storeModelMenuState: (state: TelegramModelMenuState<TModel>) => void;
178
+ }
179
+
180
+ export interface BuildTelegramModelMenuStateParams<
181
+ TModel extends MenuModel = MenuModel,
182
+ > {
183
+ chatId: number;
184
+ threadId?: number;
185
+ activeModel: TModel | undefined;
186
+ availableModels: TModel[];
187
+ configuredScopedModelPatterns: string[];
188
+ cliScopedModelPatterns?: string[];
189
+ }
190
+
191
+ export type TelegramMenuMutationResult = "invalid" | "unchanged" | "changed";
192
+ export type TelegramMenuSelectionResult<TModel extends MenuModel = MenuModel> =
193
+ | { kind: "invalid" }
194
+ | { kind: "missing" }
195
+ | { kind: "selected"; selection: ScopedTelegramModel<TModel> };
196
+
197
+ export interface TelegramModelMenuPage<TModel extends MenuModel = MenuModel> {
198
+ page: number;
199
+ pageCount: number;
200
+ start: number;
201
+ items: ScopedTelegramModel<TModel>[];
202
+ }
203
+
204
+ export interface TelegramMenuRenderPayload {
205
+ nextMode: TelegramModelMenuState["mode"];
206
+ text: string;
207
+ mode: "markdown" | "html" | "plain";
208
+ replyMarkup: TelegramReplyMarkup;
209
+ }
210
+
211
+ export type TelegramModelCallbackPlan<TModel extends MenuModel = MenuModel> =
212
+ | { kind: "ignore" }
213
+ | { kind: "answer"; text?: string }
214
+ | { kind: "update-menu"; text?: string }
215
+ | { kind: "persist-scope"; patterns: string[]; text: string }
216
+ | {
217
+ kind: "refresh-status";
218
+ selection: ScopedTelegramModel<TModel>;
219
+ callbackText: string;
220
+ shouldApplyThinkingLevel: boolean;
221
+ }
222
+ | {
223
+ kind: "switch-model";
224
+ selection: ScopedTelegramModel<TModel>;
225
+ mode: "idle" | "restart-now" | "restart-after-tool";
226
+ callbackText: string;
227
+ };
228
+
229
+ export interface BuildTelegramModelCallbackPlanParams<
230
+ TModel extends MenuModel = MenuModel,
231
+ > {
232
+ data: string | undefined;
233
+ state: TelegramModelMenuState<TModel>;
234
+ activeModel: TModel | undefined;
235
+ currentThinkingLevel: ThinkingLevel;
236
+ isIdle: boolean;
237
+ canRestartBusyRun: boolean;
238
+ hasActiveToolExecutions: boolean;
239
+ }
240
+
241
+ export interface TelegramModelMenuRuntime<
242
+ TModel extends MenuModel = MenuModel,
243
+ > {
244
+ storeState: (state: TelegramModelMenuState<TModel>) => void;
245
+ getState: (
246
+ messageId: number | undefined,
247
+ chatId?: number,
248
+ ) => TelegramModelMenuState<TModel> | undefined;
249
+ clear: () => void;
250
+ clearCachedInputs: () => void;
251
+ buildState: <TContext extends TelegramModelMenuRuntimeContext<TModel>>(
252
+ options: Omit<
253
+ TelegramModelMenuRuntimeOptions<TContext, TModel>,
254
+ "cachedInputs" | "cacheTtlMs"
255
+ >,
256
+ ) => Promise<TelegramModelMenuState<TModel>>;
257
+ }
258
+
259
+ export const TELEGRAM_MODEL_PAGE_SIZE = 6;
260
+ const TELEGRAM_MODEL_PAGE_PICKER_ROW_SIZE = 4;
261
+ export const MODEL_MENU_TITLE = "<b>🤖 Choose a model:</b>";
262
+ export const MODEL_PAGE_MENU_TITLE = "<b>Choose a page:</b>";
263
+ export const MODEL_DETAIL_MENU_TITLE = "<b>🤖 Model:</b>";
264
+
265
+ function truncateTelegramButtonLabel(label: string, maxLength = 56): string {
266
+ return label.length <= maxLength
267
+ ? label
268
+ : `${label.slice(0, maxLength - 1)}…`;
269
+ }
270
+
271
+ function getTelegramCliScopedModelPatterns(): string[] | undefined {
272
+ return parseTelegramCliScopedModelPatterns(process.argv.slice(2));
273
+ }
274
+
275
+ function parseTelegramModelMenuCallbackAction(data: string | undefined):
276
+ | {
277
+ action:
278
+ | "noop"
279
+ | "scope"
280
+ | "page"
281
+ | "pages"
282
+ | "open"
283
+ | "pick"
284
+ | "pick-selected"
285
+ | "scope-enable"
286
+ | "scope-disable"
287
+ | "scope-toggle";
288
+ value?: string;
289
+ }
290
+ | undefined {
291
+ if (!data?.startsWith("model:")) return undefined;
292
+ const [, action, value] = data.split(":");
293
+ if (
294
+ action === "noop" ||
295
+ action === "scope" ||
296
+ action === "page" ||
297
+ action === "pages" ||
298
+ action === "open" ||
299
+ action === "pick" ||
300
+ action === "pick-selected" ||
301
+ action === "scope-enable" ||
302
+ action === "scope-disable" ||
303
+ action === "scope-toggle"
304
+ ) {
305
+ return { action, value };
306
+ }
307
+ return undefined;
308
+ }
309
+
310
+ function applyTelegramMenuRenderPayload(
311
+ state: TelegramModelMenuState,
312
+ payload: TelegramMenuRenderPayload,
313
+ ): TelegramMenuRenderPayload {
314
+ state.mode = payload.nextMode;
315
+ return payload;
316
+ }
317
+
318
+ async function editTelegramMenuMessage(
319
+ state: TelegramModelMenuState,
320
+ payload: TelegramMenuRenderPayload,
321
+ deps: TelegramMenuMessageRuntimeDeps,
322
+ ): Promise<void> {
323
+ const appliedPayload = applyTelegramMenuRenderPayload(state, payload);
324
+ await deps.editInteractiveMessage(
325
+ state.chatId,
326
+ state.messageId,
327
+ appliedPayload.text,
328
+ appliedPayload.mode,
329
+ appliedPayload.replyMarkup,
330
+ );
331
+ }
332
+
333
+ function sendTelegramMenuMessage(
334
+ state: TelegramModelMenuState,
335
+ payload: TelegramMenuRenderPayload,
336
+ deps: TelegramMenuMessageRuntimeDeps,
337
+ ): Promise<number | undefined> {
338
+ const appliedPayload = applyTelegramMenuRenderPayload(state, payload);
339
+ return deps.sendInteractiveMessage(
340
+ state.chatId,
341
+ appliedPayload.text,
342
+ appliedPayload.mode,
343
+ appliedPayload.replyMarkup,
344
+ state.threadId !== undefined
345
+ ? { target: { chatId: state.chatId, threadId: state.threadId } }
346
+ : undefined,
347
+ );
348
+ }
349
+
350
+ export function formatScopedModelButtonText<
351
+ TModel extends MenuModel = MenuModel,
352
+ >(
353
+ entry: ScopedTelegramModel<TModel>,
354
+ currentModel: TModel | undefined,
355
+ ): string {
356
+ let label = `${modelsMatch(entry.model, currentModel) ? "🟢 " : ""}${entry.model.provider}/${entry.model.id}`;
357
+ if (entry.thinkingLevel) {
358
+ label += ` (${entry.thinkingLevel})`;
359
+ }
360
+ return truncateTelegramButtonLabel(label);
361
+ }
362
+
363
+ export function formatStatusButtonLabel(label: string, value: string): string {
364
+ return truncateTelegramButtonLabel(`${label}: ${value}`, 64);
365
+ }
366
+
367
+ export function getModelMenuItems<TModel extends MenuModel = MenuModel>(
368
+ state: TelegramModelMenuState<TModel>,
369
+ ): ScopedTelegramModel<TModel>[] {
370
+ return state.scope === "scoped" && state.scopedModels.length > 0
371
+ ? state.scopedModels
372
+ : state.allModels;
373
+ }
374
+
375
+ function getTelegramMenuStateKey(chatId: number, messageId: number): string {
376
+ return `${chatId}:${messageId}`;
377
+ }
378
+
379
+ export function pruneStoredTelegramModelMenus<
380
+ TModel extends MenuModel = MenuModel,
381
+ >(
382
+ menus: Map<string, StoredTelegramModelMenuState<TModel>>,
383
+ options: TelegramModelMenuStoreOptions,
384
+ ): void {
385
+ const now = options.now ?? Date.now();
386
+ for (const [messageId, entry] of menus.entries()) {
387
+ if (now - entry.updatedAt <= options.maxAgeMs) continue;
388
+ menus.delete(messageId);
389
+ }
390
+ while (menus.size > options.maxStoredMenus) {
391
+ const oldestKey = menus.keys().next().value as string | undefined;
392
+ if (oldestKey === undefined) return;
393
+ menus.delete(oldestKey);
394
+ }
395
+ }
396
+
397
+ export function storeTelegramModelMenuState<
398
+ TModel extends MenuModel = MenuModel,
399
+ >(
400
+ menus: Map<string, StoredTelegramModelMenuState<TModel>>,
401
+ state: TelegramModelMenuState<TModel>,
402
+ options: TelegramModelMenuStoreOptions,
403
+ ): void {
404
+ const now = options.now ?? Date.now();
405
+ pruneStoredTelegramModelMenus(menus, { ...options, now });
406
+ menus.set(getTelegramMenuStateKey(state.chatId, state.messageId), {
407
+ state,
408
+ updatedAt: now,
409
+ });
410
+ pruneStoredTelegramModelMenus(menus, { ...options, now });
411
+ }
412
+
413
+ export function getStoredTelegramModelMenuState<
414
+ TModel extends MenuModel = MenuModel,
415
+ >(
416
+ menus: Map<string, StoredTelegramModelMenuState<TModel>>,
417
+ messageId: number | undefined,
418
+ options: TelegramModelMenuStoreOptions,
419
+ chatId?: number,
420
+ ): TelegramModelMenuState<TModel> | undefined {
421
+ if (messageId === undefined) return undefined;
422
+ const now = options.now ?? Date.now();
423
+ pruneStoredTelegramModelMenus(menus, { ...options, now });
424
+ const key =
425
+ typeof chatId === "number"
426
+ ? getTelegramMenuStateKey(chatId, messageId)
427
+ : [...menus.keys()].find((candidate) =>
428
+ candidate.endsWith(`:${messageId}`),
429
+ );
430
+ if (!key) return undefined;
431
+ const entry = menus.get(key);
432
+ if (!entry) return undefined;
433
+ menus.delete(key);
434
+ entry.updatedAt = now;
435
+ menus.set(key, entry);
436
+ return entry.state;
437
+ }
438
+
439
+ export function createTelegramModelMenuRuntime<
440
+ TModel extends MenuModel = MenuModel,
441
+ >(
442
+ options: Partial<TelegramModelMenuStoreOptions> = {},
443
+ ): TelegramModelMenuRuntime<TModel> {
444
+ const menus = new Map<string, StoredTelegramModelMenuState<TModel>>();
445
+ let cachedInputs: CachedTelegramModelMenuInputs<TModel> | undefined;
446
+ const getStoreOptions = (): TelegramModelMenuStoreOptions => ({
447
+ maxAgeMs: options.maxAgeMs ?? TELEGRAM_MODEL_MENU_STATE_TTL_MS,
448
+ maxStoredMenus: options.maxStoredMenus ?? MAX_STORED_TELEGRAM_MODEL_MENUS,
449
+ now: options.now,
450
+ });
451
+ return {
452
+ storeState: (state) => {
453
+ storeTelegramModelMenuState(menus, state, getStoreOptions());
454
+ },
455
+ getState: (messageId, chatId) =>
456
+ getStoredTelegramModelMenuState(
457
+ menus,
458
+ messageId,
459
+ getStoreOptions(),
460
+ chatId,
461
+ ),
462
+ clear: () => {
463
+ menus.clear();
464
+ cachedInputs = undefined;
465
+ },
466
+ clearCachedInputs: () => {
467
+ cachedInputs = undefined;
468
+ },
469
+ buildState: async (stateOptions) => {
470
+ const result = await buildTelegramModelMenuStateRuntime({
471
+ ...stateOptions,
472
+ cachedInputs,
473
+ cacheTtlMs: TELEGRAM_MODEL_MENU_CACHE_TTL_MS,
474
+ });
475
+ cachedInputs = result.cachedInputs;
476
+ return result.state;
477
+ },
478
+ };
479
+ }
480
+
481
+ export function createTelegramModelMenuStateBuilder<
482
+ TModel extends MenuModel = MenuModel,
483
+ TContext extends TelegramModelMenuStateBuilderContext<TModel> =
484
+ TelegramModelMenuStateBuilderContext<TModel>,
485
+ >(
486
+ deps: TelegramModelMenuStateBuilderDeps<TModel, TContext>,
487
+ ): (
488
+ chatId: number,
489
+ ctx: TContext,
490
+ threadId?: number,
491
+ ) => Promise<TelegramModelMenuState<TModel>> {
492
+ return async (chatId, ctx, threadId) => {
493
+ const settingsManager = deps.createSettingsManager(ctx.cwd);
494
+ return deps.runtime.buildState({
495
+ chatId,
496
+ threadId,
497
+ activeModel: deps.getActiveModel(ctx),
498
+ ctx,
499
+ reloadSettings: () => settingsManager.reload(),
500
+ getConfiguredScopedModelPatterns: () =>
501
+ settingsManager.getEnabledModels(),
502
+ });
503
+ };
504
+ }
505
+
506
+ export async function resolveCachedTelegramModelMenuInputs<
507
+ TModel extends MenuModel = MenuModel,
508
+ >(
509
+ cachedInputs: CachedTelegramModelMenuInputs<TModel> | undefined,
510
+ deps: TelegramModelMenuInputCacheDeps<TModel>,
511
+ ): Promise<CachedTelegramModelMenuInputs<TModel>> {
512
+ const now = deps.now ?? Date.now();
513
+ if (cachedInputs && cachedInputs.expiresAt > now) return cachedInputs;
514
+ await deps.reloadSettings();
515
+ const availableModels = deps.refreshAvailableModels();
516
+ const cliScopedModelPatterns = deps.getCliScopedModelPatterns();
517
+ const configuredScopedModelPatterns =
518
+ cliScopedModelPatterns ?? deps.getConfiguredScopedModelPatterns() ?? [];
519
+ return {
520
+ expiresAt: now + deps.cacheTtlMs,
521
+ availableModels,
522
+ configuredScopedModelPatterns,
523
+ cliScopedModelPatterns,
524
+ };
525
+ }
526
+
527
+ export function buildTelegramModelMenuState<
528
+ TModel extends MenuModel = MenuModel,
529
+ >(
530
+ params: BuildTelegramModelMenuStateParams<TModel>,
531
+ ): TelegramModelMenuState<TModel> {
532
+ const allModels = sortScopedModels(
533
+ params.availableModels.map((model) => ({ model })),
534
+ params.activeModel,
535
+ );
536
+ const scopedModels =
537
+ params.configuredScopedModelPatterns.length > 0
538
+ ? sortScopedModels(
539
+ resolveScopedModelPatterns(
540
+ params.configuredScopedModelPatterns,
541
+ params.availableModels,
542
+ ),
543
+ params.activeModel,
544
+ )
545
+ : [];
546
+ let note: string | undefined;
547
+ if (
548
+ params.configuredScopedModelPatterns.length > 0 &&
549
+ scopedModels.length === 0
550
+ ) {
551
+ note = params.cliScopedModelPatterns
552
+ ? "No CLI scoped models matched the current auth configuration. Showing all available models."
553
+ : "No scoped models matched the current auth configuration. Showing all available models.";
554
+ }
555
+ return {
556
+ chatId: params.chatId,
557
+ threadId: params.threadId,
558
+ messageId: 0,
559
+ page: 0,
560
+ scope: scopedModels.length > 0 ? "scoped" : "all",
561
+ scopedModels,
562
+ allModels,
563
+ note,
564
+ selectedModelIndex: undefined,
565
+ scopedModelPatterns: params.configuredScopedModelPatterns,
566
+ canMutateScope: !params.cliScopedModelPatterns,
567
+ mode: "status",
568
+ };
569
+ }
570
+
571
+ export async function buildTelegramModelMenuStateRuntime<
572
+ TContext extends TelegramModelMenuRuntimeContext<TModel>,
573
+ TModel extends MenuModel = MenuModel,
574
+ >(
575
+ options: TelegramModelMenuRuntimeOptions<TContext, TModel>,
576
+ ): Promise<{
577
+ state: TelegramModelMenuState<TModel>;
578
+ cachedInputs: CachedTelegramModelMenuInputs<TModel>;
579
+ }> {
580
+ const cachedInputs = await resolveCachedTelegramModelMenuInputs(
581
+ options.cachedInputs,
582
+ {
583
+ cacheTtlMs: options.cacheTtlMs,
584
+ reloadSettings: options.reloadSettings,
585
+ refreshAvailableModels: () => {
586
+ options.ctx.modelRegistry.refresh();
587
+ return options.ctx.modelRegistry.getAvailable();
588
+ },
589
+ getConfiguredScopedModelPatterns:
590
+ options.getConfiguredScopedModelPatterns,
591
+ getCliScopedModelPatterns:
592
+ options.getCliScopedModelPatterns ?? getTelegramCliScopedModelPatterns,
593
+ },
594
+ );
595
+ return {
596
+ cachedInputs,
597
+ state: buildTelegramModelMenuState({
598
+ chatId: options.chatId,
599
+ threadId: options.threadId,
600
+ activeModel: options.activeModel,
601
+ availableModels: cachedInputs.availableModels,
602
+ configuredScopedModelPatterns: cachedInputs.configuredScopedModelPatterns,
603
+ cliScopedModelPatterns: cachedInputs.cliScopedModelPatterns,
604
+ }),
605
+ };
606
+ }
607
+
608
+ export function applyTelegramModelScopeSelection(
609
+ state: TelegramModelMenuState,
610
+ value: string | undefined,
611
+ ): TelegramMenuMutationResult {
612
+ if (value !== "all" && value !== "scoped") return "invalid";
613
+ if (value === state.scope) return "unchanged";
614
+ state.scope = value;
615
+ state.page = 0;
616
+ return "changed";
617
+ }
618
+
619
+ export function applyTelegramModelPageSelection(
620
+ state: TelegramModelMenuState,
621
+ value: string | undefined,
622
+ ): TelegramMenuMutationResult {
623
+ const page = Number(value);
624
+ if (!Number.isFinite(page)) return "invalid";
625
+ if (page === state.page) return "unchanged";
626
+ state.page = page;
627
+ return "changed";
628
+ }
629
+
630
+ export function getTelegramModelSelection<TModel extends MenuModel = MenuModel>(
631
+ state: TelegramModelMenuState<TModel>,
632
+ value: string | undefined,
633
+ ): TelegramMenuSelectionResult<TModel> {
634
+ const index = Number(value);
635
+ if (!Number.isFinite(index)) return { kind: "invalid" };
636
+ const selection = getModelMenuItems(state)[index];
637
+ if (!selection) return { kind: "missing" };
638
+ return { kind: "selected", selection };
639
+ }
640
+
641
+ export function applyTelegramModelDetailSelection(
642
+ state: TelegramModelMenuState,
643
+ value: string | undefined,
644
+ ): TelegramMenuMutationResult {
645
+ const index = Number(value);
646
+ if (!Number.isFinite(index)) return "invalid";
647
+ const selection = getModelMenuItems(state)[index];
648
+ if (!selection) return "invalid";
649
+ state.selectedModelIndex = index;
650
+ state.selectedModelKey = getCanonicalModelId(selection.model);
651
+ state.mode = "model-detail";
652
+ return "changed";
653
+ }
654
+
655
+ export function getTelegramSelectedDetailModel<
656
+ TModel extends MenuModel = MenuModel,
657
+ >(state: TelegramModelMenuState<TModel>): TelegramMenuSelectionResult<TModel> {
658
+ const indexedSelection = getTelegramModelSelection(
659
+ state,
660
+ state.selectedModelIndex?.toString(),
661
+ );
662
+ if (indexedSelection.kind === "selected") {
663
+ if (!state.selectedModelKey) return indexedSelection;
664
+ const indexedKey = getCanonicalModelId(
665
+ indexedSelection.selection.model,
666
+ ).toLowerCase();
667
+ if (indexedKey === state.selectedModelKey.toLowerCase()) {
668
+ return indexedSelection;
669
+ }
670
+ }
671
+ if (state.selectedModelKey) {
672
+ const lowerKey = state.selectedModelKey.toLowerCase();
673
+ const selection = state.allModels.find(
674
+ (entry) => getCanonicalModelId(entry.model).toLowerCase() === lowerKey,
675
+ );
676
+ if (selection) return { kind: "selected", selection };
677
+ }
678
+ return indexedSelection;
679
+ }
680
+
681
+ export function isTelegramModelScoped(
682
+ state: TelegramModelMenuState,
683
+ model: MenuModel,
684
+ ): boolean {
685
+ const key = getCanonicalModelId(model);
686
+ return state.scopedModels.some(
687
+ (entry) => getCanonicalModelId(entry.model) === key,
688
+ );
689
+ }
690
+
691
+ export function focusTelegramModelListPage(
692
+ state: TelegramModelMenuState,
693
+ model: MenuModel,
694
+ pageSize = TELEGRAM_MODEL_PAGE_SIZE,
695
+ ): void {
696
+ const key = getCanonicalModelId(model).toLowerCase();
697
+ const index = getModelMenuItems(state).findIndex(
698
+ (entry) => getCanonicalModelId(entry.model).toLowerCase() === key,
699
+ );
700
+ state.page = index < 0 ? 0 : Math.floor(index / pageSize);
701
+ state.mode = "model";
702
+ }
703
+
704
+ function formatScopedModelPattern(entry: ScopedTelegramModel): string {
705
+ const key = getCanonicalModelId(entry.model);
706
+ return entry.thinkingLevel ? `${key}:${entry.thinkingLevel}` : key;
707
+ }
708
+
709
+ export function setTelegramModelScope(
710
+ state: TelegramModelMenuState,
711
+ model: MenuModel,
712
+ enabled: boolean,
713
+ ): { patterns: string[]; enabled: boolean } {
714
+ const key = getCanonicalModelId(model);
715
+ const lowerKey = key.toLowerCase();
716
+ const scopedModelPatterns = state.scopedModelPatterns ?? [];
717
+ const allModels = state.allModels.map((entry) => entry.model);
718
+ const patterns: string[] = [];
719
+ for (const pattern of scopedModelPatterns) {
720
+ const resolved = resolveScopedModelPatterns([pattern], allModels);
721
+ const matchesModel = resolved.some(
722
+ (entry) => getCanonicalModelId(entry.model).toLowerCase() === lowerKey,
723
+ );
724
+ if (enabled || !matchesModel) {
725
+ if (pattern.toLowerCase() !== lowerKey) patterns.push(pattern);
726
+ continue;
727
+ }
728
+ for (const entry of resolved) {
729
+ if (getCanonicalModelId(entry.model).toLowerCase() === lowerKey) continue;
730
+ const expandedPattern = formatScopedModelPattern(entry);
731
+ const duplicated = patterns.some(
732
+ (item) => item.toLowerCase() === expandedPattern.toLowerCase(),
733
+ );
734
+ if (!duplicated) patterns.push(expandedPattern);
735
+ }
736
+ }
737
+ if (enabled) patterns.push(key);
738
+ state.scopedModelPatterns = patterns;
739
+ state.scopedModels = sortScopedModels(
740
+ resolveScopedModelPatterns(
741
+ patterns,
742
+ state.allModels.map((entry) => entry.model),
743
+ ),
744
+ model,
745
+ );
746
+ if (state.scope === "scoped" && state.scopedModels.length === 0) {
747
+ state.scope = "all";
748
+ }
749
+ return { patterns, enabled };
750
+ }
751
+
752
+ export function buildTelegramModelCallbackPlan<
753
+ TModel extends MenuModel = MenuModel,
754
+ >(
755
+ params: BuildTelegramModelCallbackPlanParams<TModel>,
756
+ ): TelegramModelCallbackPlan<TModel> {
757
+ const action = parseTelegramModelMenuCallbackAction(params.data);
758
+ if (!action) return { kind: "ignore" };
759
+ if (action.action === "noop") return { kind: "answer" };
760
+ if (action.action === "scope") {
761
+ const scopeResult = applyTelegramModelScopeSelection(
762
+ params.state,
763
+ action.value,
764
+ );
765
+ if (scopeResult === "invalid") {
766
+ return { kind: "answer", text: "Unknown model scope." };
767
+ }
768
+ if (scopeResult === "unchanged") {
769
+ return { kind: "answer" };
770
+ }
771
+ return {
772
+ kind: "update-menu",
773
+ text: params.state.scope === "scoped" ? "Scoped models" : "All models",
774
+ };
775
+ }
776
+ if (action.action === "pages") {
777
+ if (action.value === "back") {
778
+ params.state.mode = "model";
779
+ return { kind: "update-menu" };
780
+ }
781
+ params.state.mode = "model-pages";
782
+ return { kind: "update-menu" };
783
+ }
784
+ if (action.action === "page") {
785
+ const pageResult = applyTelegramModelPageSelection(
786
+ params.state,
787
+ action.value,
788
+ );
789
+ if (pageResult === "invalid") {
790
+ return { kind: "answer", text: "Invalid page." };
791
+ }
792
+ params.state.mode = "model";
793
+ if (pageResult === "unchanged") {
794
+ return { kind: "update-menu" };
795
+ }
796
+ return { kind: "update-menu" };
797
+ }
798
+ if (action.action === "open") {
799
+ const detailResult = applyTelegramModelDetailSelection(
800
+ params.state,
801
+ action.value,
802
+ );
803
+ if (detailResult === "invalid") {
804
+ return { kind: "answer", text: "Selected model is no longer available." };
805
+ }
806
+ return { kind: "update-menu" };
807
+ }
808
+ if (
809
+ action.action === "scope-toggle" ||
810
+ action.action === "scope-enable" ||
811
+ action.action === "scope-disable"
812
+ ) {
813
+ if (params.state.canMutateScope === false) {
814
+ return {
815
+ kind: "answer",
816
+ text: "Model scope is controlled by CLI --models.",
817
+ };
818
+ }
819
+ const selectionResult = getTelegramSelectedDetailModel(params.state);
820
+ if (selectionResult.kind !== "selected") {
821
+ return { kind: "answer", text: "Selected model is no longer available." };
822
+ }
823
+ const model = selectionResult.selection.model;
824
+ const enabled =
825
+ action.action === "scope-toggle"
826
+ ? !isTelegramModelScoped(params.state, model)
827
+ : action.action === "scope-enable";
828
+ if (enabled === isTelegramModelScoped(params.state, model)) {
829
+ return { kind: "answer" };
830
+ }
831
+ const result = setTelegramModelScope(params.state, model, enabled);
832
+ return {
833
+ kind: "persist-scope",
834
+ patterns: result.patterns,
835
+ text: result.enabled
836
+ ? "Added to scoped models"
837
+ : "Removed from scoped models",
838
+ };
839
+ }
840
+ if (action.action !== "pick" && action.action !== "pick-selected") {
841
+ return { kind: "answer" };
842
+ }
843
+ const selectionResult =
844
+ action.action === "pick-selected"
845
+ ? getTelegramSelectedDetailModel(params.state)
846
+ : getTelegramModelSelection(params.state, action.value);
847
+ if (selectionResult.kind === "invalid") {
848
+ return { kind: "answer", text: "Invalid model selection." };
849
+ }
850
+ if (selectionResult.kind === "missing") {
851
+ return { kind: "answer", text: "Selected model is no longer available." };
852
+ }
853
+ const selection = selectionResult.selection;
854
+ if (modelsMatch(selection.model, params.activeModel)) {
855
+ if (action.action === "pick-selected") {
856
+ focusTelegramModelListPage(params.state, selection.model);
857
+ }
858
+ return {
859
+ kind: "refresh-status",
860
+ selection,
861
+ callbackText: `Model: ${selection.model.id}`,
862
+ shouldApplyThinkingLevel:
863
+ !!selection.thinkingLevel &&
864
+ selection.thinkingLevel !== params.currentThinkingLevel,
865
+ };
866
+ }
867
+ if (!params.isIdle) {
868
+ if (!params.canRestartBusyRun) {
869
+ return {
870
+ kind: "answer",
871
+ text: "Pi is busy. Send /abort, /next, or /stop.",
872
+ };
873
+ }
874
+ return {
875
+ kind: "switch-model",
876
+ selection,
877
+ mode: params.hasActiveToolExecutions
878
+ ? "restart-after-tool"
879
+ : "restart-now",
880
+ callbackText: params.hasActiveToolExecutions
881
+ ? `Switched to ${selection.model.id}. Restarting after the current tool finishes…`
882
+ : `Switching to ${selection.model.id} and continuing…`,
883
+ };
884
+ }
885
+ return {
886
+ kind: "switch-model",
887
+ selection,
888
+ mode: "idle",
889
+ callbackText: `Switched to ${selection.model.id}`,
890
+ };
891
+ }
892
+
893
+ export async function openTelegramModelMenu<
894
+ TModel extends MenuModel = MenuModel,
895
+ >(deps: TelegramModelMenuOpenDeps<TModel>): Promise<void> {
896
+ if (!deps.isIdle() && !deps.canOfferInFlightModelSwitch()) {
897
+ await deps.sendBusyMessage();
898
+ return;
899
+ }
900
+ const state = await deps.getModelMenuState();
901
+ if (state.allModels.length === 0) {
902
+ await deps.sendNoModelsMessage();
903
+ return;
904
+ }
905
+ const messageId = await deps.sendModelMenu(state, deps.getActiveModel());
906
+ if (messageId === undefined) return;
907
+ state.messageId = messageId;
908
+ state.mode = "model";
909
+ deps.storeModelMenuState(state);
910
+ }
911
+
912
+ export async function handleTelegramModelMenuCallbackAction<
913
+ TModel extends MenuModel = MenuModel,
914
+ >(
915
+ callbackQueryId: string,
916
+ params: BuildTelegramModelCallbackPlanParams<TModel>,
917
+ deps: TelegramModelMenuCallbackDeps<TModel>,
918
+ ): Promise<boolean> {
919
+ const plan = buildTelegramModelCallbackPlan(params);
920
+ if (plan.kind === "ignore") return false;
921
+ if (plan.kind === "answer") {
922
+ await deps.answerCallbackQuery(callbackQueryId, plan.text);
923
+ return true;
924
+ }
925
+ if (plan.kind === "update-menu") {
926
+ await deps.updateModelMenuMessage();
927
+ await deps.answerCallbackQuery(callbackQueryId, plan.text);
928
+ return true;
929
+ }
930
+ if (plan.kind === "persist-scope") {
931
+ if (!deps.persistScopedModelPatterns) {
932
+ await deps.answerCallbackQuery(
933
+ callbackQueryId,
934
+ "Scoped model persistence is unavailable.",
935
+ );
936
+ return true;
937
+ }
938
+ await deps.persistScopedModelPatterns(plan.patterns);
939
+ await deps.updateModelMenuMessage();
940
+ await deps.answerCallbackQuery(callbackQueryId, plan.text);
941
+ return true;
942
+ }
943
+ if (plan.kind === "refresh-status") {
944
+ if (plan.shouldApplyThinkingLevel && plan.selection.thinkingLevel) {
945
+ deps.setThinkingLevel(plan.selection.thinkingLevel);
946
+ }
947
+ await deps.updateModelMenuMessage();
948
+ await deps.answerCallbackQuery(callbackQueryId, plan.callbackText);
949
+ return true;
950
+ }
951
+ const changed = await deps.setModel(plan.selection.model);
952
+ if (changed === false) {
953
+ await deps.answerCallbackQuery(callbackQueryId, "Model is not available.");
954
+ return true;
955
+ }
956
+ deps.setCurrentModel(plan.selection.model);
957
+ if (plan.selection.thinkingLevel) {
958
+ deps.setThinkingLevel(plan.selection.thinkingLevel);
959
+ }
960
+ await deps.updateModelMenuMessage();
961
+ if (plan.mode === "restart-after-tool") {
962
+ deps.stagePendingModelSwitch(plan.selection);
963
+ await deps.answerCallbackQuery(callbackQueryId, plan.callbackText);
964
+ return true;
965
+ }
966
+ if (plan.mode === "restart-now") {
967
+ const restarted = await deps.restartInterruptedTelegramTurn(plan.selection);
968
+ if (!restarted) {
969
+ await deps.answerCallbackQuery(
970
+ callbackQueryId,
971
+ "Pi is busy. Send /abort, /next, or /stop.",
972
+ );
973
+ return true;
974
+ }
975
+ }
976
+ await deps.answerCallbackQuery(callbackQueryId, plan.callbackText);
977
+ return true;
978
+ }
979
+
980
+ export function getTelegramModelMenuPage(
981
+ state: TelegramModelMenuState,
982
+ pageSize: number,
983
+ ): TelegramModelMenuPage {
984
+ const items = getModelMenuItems(state);
985
+ const pageCount = Math.max(1, Math.ceil(items.length / pageSize));
986
+ const page = Math.max(0, Math.min(state.page, pageCount - 1));
987
+ const start = page * pageSize;
988
+ return {
989
+ page,
990
+ pageCount,
991
+ start,
992
+ items: items.slice(start, start + pageSize),
993
+ };
994
+ }
995
+
996
+ export function buildModelMenuReplyMarkup(
997
+ state: TelegramModelMenuState,
998
+ currentModel: MenuModel | undefined,
999
+ pageSize: number,
1000
+ ): TelegramReplyMarkup {
1001
+ const menuPage = getTelegramModelMenuPage(state, pageSize);
1002
+ const rows = [[{ text: "⬆️ Main menu", callback_data: "menu:back" }]];
1003
+ if (state.scopedModels.length > 0) {
1004
+ rows.push([
1005
+ {
1006
+ text: state.scope === "scoped" ? "🟡 Scoped" : "⚫️ Scoped",
1007
+ callback_data: "model:scope:scoped",
1008
+ },
1009
+ {
1010
+ text: state.scope === "all" ? "🟣 All" : "⚫️ All",
1011
+ callback_data: "model:scope:all",
1012
+ },
1013
+ ]);
1014
+ }
1015
+ const previousPage =
1016
+ menuPage.page === 0 ? menuPage.pageCount - 1 : menuPage.page - 1;
1017
+ const nextPage =
1018
+ menuPage.page === menuPage.pageCount - 1 ? 0 : menuPage.page + 1;
1019
+ if (menuPage.pageCount > 1) {
1020
+ rows.push([
1021
+ { text: "⬅️", callback_data: `model:page:${previousPage}` },
1022
+ {
1023
+ text: `${menuPage.page + 1}/${menuPage.pageCount}`,
1024
+ callback_data: "model:pages",
1025
+ },
1026
+ { text: "➡️", callback_data: `model:page:${nextPage}` },
1027
+ ]);
1028
+ }
1029
+ rows.push(
1030
+ ...menuPage.items.map((entry, index) => [
1031
+ {
1032
+ text: formatScopedModelButtonText(entry, currentModel),
1033
+ callback_data: `model:open:${menuPage.start + index}`,
1034
+ },
1035
+ ]),
1036
+ );
1037
+ return { inline_keyboard: rows };
1038
+ }
1039
+
1040
+ export function buildModelDetailMenuReplyMarkup(
1041
+ state: TelegramModelMenuState,
1042
+ currentModel: MenuModel | undefined,
1043
+ ): TelegramReplyMarkup {
1044
+ const selection = getTelegramSelectedDetailModel(state);
1045
+ if (selection.kind !== "selected") {
1046
+ return {
1047
+ inline_keyboard: [
1048
+ [{ text: "⬆️ Back", callback_data: "model:pages:back" }],
1049
+ ],
1050
+ };
1051
+ }
1052
+ const model = selection.selection.model;
1053
+ const active = modelsMatch(model, currentModel);
1054
+ const scoped = isTelegramModelScoped(state, model);
1055
+ return {
1056
+ inline_keyboard: [
1057
+ [{ text: "⬆️ Back", callback_data: "model:pages:back" }],
1058
+ [
1059
+ {
1060
+ text: active ? "🟢 Active" : "☑️ Activate",
1061
+ callback_data: "model:pick-selected",
1062
+ },
1063
+ ],
1064
+ [
1065
+ {
1066
+ text: scoped ? "🟡 Scoped" : "⚫️ Scoped",
1067
+ callback_data: "model:scope-enable",
1068
+ },
1069
+ {
1070
+ text: scoped ? "⚫️ All" : "🟣 All",
1071
+ callback_data: "model:scope-disable",
1072
+ },
1073
+ ],
1074
+ ],
1075
+ };
1076
+ }
1077
+
1078
+ export function buildModelDetailMenuText(
1079
+ state: TelegramModelMenuState,
1080
+ ): string {
1081
+ const selection = getTelegramSelectedDetailModel(state);
1082
+ if (selection.kind !== "selected") return MODEL_DETAIL_MENU_TITLE;
1083
+ const model = selection.selection.model;
1084
+ return `${MODEL_DETAIL_MENU_TITLE}\n${getCanonicalModelId(model)}`;
1085
+ }
1086
+
1087
+ export function buildModelPageMenuReplyMarkup(
1088
+ state: TelegramModelMenuState,
1089
+ pageSize: number,
1090
+ ): TelegramReplyMarkup {
1091
+ const menuPage = getTelegramModelMenuPage(state, pageSize);
1092
+ const rows = [[{ text: "⬆️ Back", callback_data: "model:pages:back" }]];
1093
+ for (
1094
+ let page = 0;
1095
+ page < menuPage.pageCount;
1096
+ page += TELEGRAM_MODEL_PAGE_PICKER_ROW_SIZE
1097
+ ) {
1098
+ rows.push(
1099
+ Array.from(
1100
+ {
1101
+ length: Math.min(
1102
+ TELEGRAM_MODEL_PAGE_PICKER_ROW_SIZE,
1103
+ menuPage.pageCount - page,
1104
+ ),
1105
+ },
1106
+ (_unused, offset) => {
1107
+ const pageIndex = page + offset;
1108
+ return {
1109
+ text:
1110
+ pageIndex === menuPage.page
1111
+ ? `🟣 ${pageIndex + 1}`
1112
+ : String(pageIndex + 1),
1113
+ callback_data: `model:page:${pageIndex}`,
1114
+ };
1115
+ },
1116
+ ),
1117
+ );
1118
+ }
1119
+ return { inline_keyboard: rows };
1120
+ }
1121
+
1122
+ export function buildTelegramModelPageMenuRenderPayload(
1123
+ state: TelegramModelMenuState,
1124
+ ): TelegramMenuRenderPayload {
1125
+ return {
1126
+ nextMode: "model-pages",
1127
+ text: MODEL_PAGE_MENU_TITLE,
1128
+ mode: "html",
1129
+ replyMarkup: buildModelPageMenuReplyMarkup(state, TELEGRAM_MODEL_PAGE_SIZE),
1130
+ };
1131
+ }
1132
+
1133
+ export function buildTelegramModelMenuRenderPayload(
1134
+ state: TelegramModelMenuState,
1135
+ activeModel: MenuModel | undefined,
1136
+ ): TelegramMenuRenderPayload {
1137
+ if (state.mode === "model-pages") {
1138
+ return buildTelegramModelPageMenuRenderPayload(state);
1139
+ }
1140
+ if (state.mode === "model-detail") {
1141
+ return {
1142
+ nextMode: "model-detail",
1143
+ text: buildModelDetailMenuText(state),
1144
+ mode: "html",
1145
+ replyMarkup: buildModelDetailMenuReplyMarkup(state, activeModel),
1146
+ };
1147
+ }
1148
+ return {
1149
+ nextMode: "model",
1150
+ text: MODEL_MENU_TITLE,
1151
+ mode: "html",
1152
+ replyMarkup: buildModelMenuReplyMarkup(
1153
+ state,
1154
+ activeModel,
1155
+ TELEGRAM_MODEL_PAGE_SIZE,
1156
+ ),
1157
+ };
1158
+ }
1159
+
1160
+ export async function updateTelegramModelMenuMessage(
1161
+ state: TelegramModelMenuState,
1162
+ activeModel: MenuModel | undefined,
1163
+ deps: TelegramMenuMessageRuntimeDeps,
1164
+ ): Promise<void> {
1165
+ await editTelegramMenuMessage(
1166
+ state,
1167
+ buildTelegramModelMenuRenderPayload(state, activeModel),
1168
+ deps,
1169
+ );
1170
+ }
1171
+
1172
+ export function sendTelegramModelMenuMessage(
1173
+ state: TelegramModelMenuState,
1174
+ activeModel: MenuModel | undefined,
1175
+ deps: TelegramMenuMessageRuntimeDeps,
1176
+ ): Promise<number | undefined> {
1177
+ return sendTelegramMenuMessage(
1178
+ state,
1179
+ buildTelegramModelMenuRenderPayload(state, activeModel),
1180
+ deps,
1181
+ );
1182
+ }