@agentprojectcontext/apx 1.80.2 → 1.89.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 (838) hide show
  1. package/package.json +9 -8
  2. package/skills/apc-context/SKILL.md +14 -7
  3. package/skills/apx/SKILL.md +62 -2
  4. package/skills/apx-mcp/SKILL.md +42 -15
  5. package/src/core/agent/a2a/peers.js +161 -0
  6. package/src/core/agent/a2a/reply.js +379 -27
  7. package/src/core/agent/abort.js +25 -0
  8. package/src/core/agent/agent-model.js +58 -0
  9. package/src/core/agent/agent-tools.js +101 -0
  10. package/src/core/agent/author-line.js +110 -0
  11. package/src/core/agent/build-agent-system.js +52 -18
  12. package/src/core/agent/channels/voice-context.js +17 -2
  13. package/src/core/agent/closing-floor.js +117 -0
  14. package/src/core/agent/constants.js +119 -11
  15. package/src/core/agent/engine-call.js +56 -0
  16. package/src/core/agent/group/run-group-turn.js +218 -0
  17. package/src/core/agent/group/turn-resolver.js +165 -0
  18. package/src/core/agent/judge.js +138 -11
  19. package/src/core/agent/loop/side-effects.js +106 -3
  20. package/src/core/agent/memory.js +31 -18
  21. package/src/core/agent/model-capabilities.js +47 -0
  22. package/src/core/agent/model-router.js +11 -40
  23. package/src/core/agent/prompt-builder.js +47 -0
  24. package/src/core/agent/prompts/channels/a2a.md +12 -0
  25. package/src/core/agent/prompts/channels/code.md +3 -1
  26. package/src/core/agent/prompts/channels/telegram.md +2 -0
  27. package/src/core/agent/prompts/channels/web_code.md +1 -1
  28. package/src/core/agent/prompts/channels/whatsapp.md +37 -0
  29. package/src/core/agent/prompts/core/agent-base.md +2 -0
  30. package/src/core/agent/prompts/discipline/action.md +1 -0
  31. package/src/core/agent/prompts/discipline/two-segment.md +2 -1
  32. package/src/core/agent/prompts/modes/mobility.md +36 -0
  33. package/src/core/agent/retry.js +42 -0
  34. package/src/core/agent/run-agent.js +322 -25
  35. package/src/core/agent/run-turn.js +253 -0
  36. package/src/core/agent/self-memory.js +18 -52
  37. package/src/core/agent/skills/agent-skills.js +118 -0
  38. package/src/core/agent/skills/catalog.js +1 -1
  39. package/src/core/agent/skills/declared.js +13 -0
  40. package/src/core/agent/skills/index-store.js +8 -1
  41. package/src/core/agent/skills/inspector.js +20 -3
  42. package/src/core/agent/skills/loader.js +18 -3
  43. package/src/core/agent/skills/media.js +121 -0
  44. package/src/core/agent/skills/origin.js +61 -0
  45. package/src/core/agent/skills/sections.js +136 -0
  46. package/src/core/agent/super-agent.js +54 -14
  47. package/src/core/agent/tools/handlers/_calendar.js +50 -0
  48. package/src/core/agent/tools/handlers/add-mcp.js +103 -0
  49. package/src/core/agent/tools/handlers/asana-create-task.js +3 -1
  50. package/src/core/agent/tools/handlers/attach-media.js +56 -0
  51. package/src/core/agent/tools/handlers/calendar-create-event.js +38 -0
  52. package/src/core/agent/tools/handlers/calendar-find-slot.js +39 -0
  53. package/src/core/agent/tools/handlers/calendar-list-events.js +39 -0
  54. package/src/core/agent/tools/handlers/calendar-update-event.js +35 -0
  55. package/src/core/agent/tools/handlers/call-agent.js +14 -6
  56. package/src/core/agent/tools/handlers/call-runtime.js +27 -49
  57. package/src/core/agent/tools/handlers/comment-task.js +78 -0
  58. package/src/core/agent/tools/handlers/complete-task.js +60 -0
  59. package/src/core/agent/tools/handlers/configure-agent.js +70 -0
  60. package/src/core/agent/tools/handlers/create-agent.js +68 -0
  61. package/src/core/agent/tools/handlers/create-task.js +41 -3
  62. package/src/core/agent/tools/handlers/import-agent.js +5 -5
  63. package/src/core/agent/tools/handlers/list-mcp-tools.js +83 -0
  64. package/src/core/agent/tools/handlers/list-routines.js +46 -0
  65. package/src/core/agent/tools/handlers/list-tasks.js +8 -1
  66. package/src/core/agent/tools/handlers/mark-commitment.js +57 -0
  67. package/src/core/agent/tools/handlers/read-skill.js +64 -0
  68. package/src/core/agent/tools/handlers/remember-routine.js +2 -8
  69. package/src/core/agent/tools/handlers/remember.js +82 -6
  70. package/src/core/agent/tools/handlers/remove-agent.js +42 -0
  71. package/src/core/agent/tools/handlers/run-routine.js +94 -0
  72. package/src/core/agent/tools/handlers/run-shell.js +44 -2
  73. package/src/core/agent/tools/handlers/send-telegram.js +41 -19
  74. package/src/core/agent/tools/handlers/set-agent-prompt.js +44 -0
  75. package/src/core/agent/tools/handlers/view-media.js +69 -0
  76. package/src/core/agent/tools/handlers/write-agent-memory.js +52 -0
  77. package/src/core/agent/tools/helpers.js +36 -4
  78. package/src/core/agent/tools/names.js +64 -0
  79. package/src/core/agent/tools/registry-bridge.js +24 -1
  80. package/src/core/agent/tools/registry.js +79 -0
  81. package/src/core/agent/tools/tool-call-parser.js +136 -13
  82. package/src/core/agent/vision-bridge.js +69 -0
  83. package/src/core/apc/agent-identity.js +74 -0
  84. package/src/core/apc/agent-rename-refs.js +187 -0
  85. package/src/core/apc/agent-write.js +312 -0
  86. package/src/core/apc/agents-vault.js +1 -1
  87. package/src/core/apc/blob-keys.js +42 -0
  88. package/src/core/apc/frontmatter.js +166 -10
  89. package/src/core/apc/parser.js +33 -83
  90. package/src/core/apc/paths.js +4 -6
  91. package/src/core/apc/project-memory.js +44 -0
  92. package/src/core/apc/projects-helpers.js +33 -0
  93. package/src/core/apc/scaffold.js +36 -16
  94. package/src/core/channels/telegram/ask-callbacks.js +103 -0
  95. package/src/core/channels/telegram/dispatch.js +154 -30
  96. package/src/core/channels/telegram/helpers.js +59 -7
  97. package/src/core/channels/telegram/inbound/audio.js +26 -30
  98. package/src/core/channels/telegram/inbound/file.js +22 -32
  99. package/src/core/channels/telegram/inbound/photo.js +24 -28
  100. package/src/core/channels/telegram/progress-gate.js +76 -0
  101. package/src/core/channels/telegram/reply.js +151 -43
  102. package/src/core/channels/telegram/voice-note.js +150 -0
  103. package/src/core/config/index.js +53 -54
  104. package/src/core/config/paths.js +117 -31
  105. package/src/core/config/redact.js +89 -4
  106. package/src/core/config/secret-values.js +2 -4
  107. package/src/core/constants/actors.js +5 -0
  108. package/src/core/constants/channels.js +3 -1
  109. package/src/core/constants/task-categories.js +73 -0
  110. package/src/core/constants/task-fields.js +28 -0
  111. package/src/core/engines/_globs.js +33 -0
  112. package/src/core/engines/anthropic.js +19 -1
  113. package/src/core/engines/catalog.js +20 -0
  114. package/src/core/engines/gemini.js +84 -16
  115. package/src/core/engines/index.js +19 -3
  116. package/src/core/engines/mock.js +145 -1
  117. package/src/core/engines/openai-compatible.js +150 -15
  118. package/src/core/engines/presets.js +36 -9
  119. package/src/core/engines/zen.js +131 -0
  120. package/src/core/events/bus.js +140 -0
  121. package/src/core/events/mascot-notify.js +156 -0
  122. package/src/core/http-tools/browser.js +366 -36
  123. package/src/core/http-tools/catalog.js +206 -22
  124. package/src/core/http-tools/grep.js +62 -7
  125. package/src/core/http-tools/registry.js +3 -1
  126. package/src/core/i18n/en.js +34 -3
  127. package/src/core/i18n/es.js +36 -4
  128. package/src/core/i18n/index.js +5 -5
  129. package/src/core/i18n/pt.js +32 -3
  130. package/src/core/identity/self.js +14 -1
  131. package/src/core/images/engines/a1111.js +219 -0
  132. package/src/core/images/engines/index.js +187 -0
  133. package/src/core/images/engines/mock.js +74 -0
  134. package/src/core/images/engines/openai.js +130 -0
  135. package/src/core/images/engines/sdcpp.js +204 -0
  136. package/src/core/images/engines/shared.js +218 -0
  137. package/src/core/images/generate.js +260 -0
  138. package/src/core/integrations/catalog.js +8 -3
  139. package/src/core/integrations/plugins/_google-oauth.js +179 -0
  140. package/src/core/integrations/plugins/asana.js +7 -3
  141. package/src/core/integrations/plugins/calendar.js +404 -0
  142. package/src/core/integrations/store.js +2 -0
  143. package/src/core/memory/broker.js +16 -1
  144. package/src/core/memory/compactor.js +19 -3
  145. package/src/core/memory/consolidate.js +2 -2
  146. package/src/core/memory/dated-log.js +66 -0
  147. package/src/core/memory/embed-engines/custom.js +59 -0
  148. package/src/core/memory/embed-engines/gemini.js +9 -3
  149. package/src/core/memory/embed-engines/index.js +87 -15
  150. package/src/core/memory/embeddings.js +52 -24
  151. package/src/core/memory/index.js +13 -3
  152. package/src/core/memory/indexer.js +83 -27
  153. package/src/core/memory/prune.js +182 -0
  154. package/src/core/memory/store.js +22 -0
  155. package/src/core/memory/summarizer.js +72 -8
  156. package/src/core/mobility/answer.js +80 -0
  157. package/src/core/mobility/geofence.js +667 -0
  158. package/src/core/mobility/osm-route.js +282 -0
  159. package/src/core/mobility/preferences.js +91 -0
  160. package/src/core/mobility/state.js +245 -0
  161. package/src/core/mobility/trip-event.js +384 -0
  162. package/src/core/net/tailscale.js +168 -0
  163. package/src/core/profiles/bundled/secretary/PROFILE.md +32 -42
  164. package/src/core/profiles/bundled/secretary/config.schema.es.json +68 -0
  165. package/src/core/profiles/bundled/secretary/config.schema.json +30 -2
  166. package/src/core/profiles/bundled/secretary/profile.json +3 -1
  167. package/src/core/profiles/bundled/secretary/routines/a2a-sweep.json +20 -0
  168. package/src/core/profiles/bundled/secretary/routines/day-close.json +4 -1
  169. package/src/core/profiles/bundled/secretary/routines/day-open.json +7 -1
  170. package/src/core/profiles/bundled/secretary/routines/watch.json +13 -2
  171. package/src/core/profiles/lifecycle.js +243 -19
  172. package/src/core/profiles/paths.js +12 -0
  173. package/src/core/profiles/store.js +47 -0
  174. package/src/core/routines/active-runs.js +213 -0
  175. package/src/core/routines/delivery.js +612 -0
  176. package/src/core/routines/header.js +88 -0
  177. package/src/core/routines/index.js +26 -0
  178. package/src/core/routines/run-log.js +78 -0
  179. package/src/core/routines/runner.js +629 -66
  180. package/src/core/routines/signals.js +75 -0
  181. package/src/core/runtime-skills/apc-context/SKILL.md +14 -7
  182. package/src/core/runtime-skills/apx/SKILL.md +93 -1
  183. package/src/core/runtime-skills/apx-agency-agents/SKILL.md +2 -2
  184. package/src/core/runtime-skills/apx-agent/SKILL.md +134 -19
  185. package/src/core/runtime-skills/apx-commitment/SKILL.md +134 -0
  186. package/src/core/runtime-skills/apx-image/SKILL.md +60 -0
  187. package/src/core/runtime-skills/apx-integrations/SKILL.md +82 -0
  188. package/src/core/runtime-skills/apx-mcp/SKILL.md +45 -14
  189. package/src/core/runtime-skills/apx-mcp-builder/SKILL.md +4 -4
  190. package/src/core/runtime-skills/apx-profile/SKILL.md +27 -2
  191. package/src/core/runtime-skills/apx-project/SKILL.md +23 -2
  192. package/src/core/runtime-skills/apx-routine/SKILL.md +40 -17
  193. package/src/core/runtime-skills/apx-runtime/SKILL.md +124 -14
  194. package/src/core/runtime-skills/apx-sessions/SKILL.md +7 -6
  195. package/src/core/runtime-skills/apx-skill-builder/SKILL.md +15 -13
  196. package/src/core/runtime-skills/apx-task/SKILL.md +79 -26
  197. package/src/core/runtime-skills/apx-telegram/SKILL.md +12 -12
  198. package/src/core/runtime-skills/apx-transcribe/SKILL.md +56 -0
  199. package/src/core/runtime-skills/apx-voice/SKILL.md +27 -8
  200. package/src/core/runtime-skills/claude-code/SKILL.md +8 -0
  201. package/src/core/runtime-skills/openrouter/SKILL.md +8 -2
  202. package/src/core/runtimes/_spawn.js +9 -1
  203. package/src/core/runtimes/claude-code.js +11 -2
  204. package/src/core/runtimes/codex.js +44 -10
  205. package/src/core/runtimes/index.js +17 -2
  206. package/src/core/runtimes/opencode.js +88 -9
  207. package/src/core/runtimes/outcome.js +119 -0
  208. package/src/core/sessions/index.js +193 -1
  209. package/src/core/stores/agent-inbox.js +109 -23
  210. package/src/core/stores/code-sessions.js +21 -0
  211. package/src/core/stores/commitments.js +27 -3
  212. package/src/core/stores/conversations.js +220 -20
  213. package/src/core/stores/deliveries.js +177 -0
  214. package/src/core/stores/media-archive.js +228 -0
  215. package/src/core/stores/messages.js +1096 -112
  216. package/src/core/stores/organization.js +34 -0
  217. package/src/core/stores/project-memory.js +71 -0
  218. package/src/core/stores/routine-memory.js +16 -8
  219. package/src/core/stores/routines.js +27 -49
  220. package/src/core/stores/sessions.js +4 -8
  221. package/src/core/stores/tasks.js +212 -18
  222. package/src/core/stores/turn-record.js +209 -0
  223. package/src/core/tasks/columns.js +136 -0
  224. package/src/core/tasks/comment-turn.js +258 -0
  225. package/src/core/util/time.js +13 -0
  226. package/src/core/voice/engines/index.js +54 -1
  227. package/src/core/voice/engines/openai.js +50 -4
  228. package/src/core/voice/opus.js +67 -0
  229. package/src/core/voice/pronounceable.js +43 -0
  230. package/src/core/voice/transcription.js +4 -0
  231. package/src/core/voice/tts.js +114 -24
  232. package/src/host/daemon/active-turns.js +188 -0
  233. package/src/host/daemon/api/admin-config.js +9 -0
  234. package/src/host/daemon/api/agents.js +99 -90
  235. package/src/host/daemon/api/artifact-preview.js +7 -6
  236. package/src/host/daemon/api/artifacts.js +3 -2
  237. package/src/host/daemon/api/code.js +55 -9
  238. package/src/host/daemon/api/commitments.js +11 -0
  239. package/src/host/daemon/api/confirm.js +3 -2
  240. package/src/host/daemon/api/conversations.js +543 -35
  241. package/src/host/daemon/api/deck.js +9 -8
  242. package/src/host/daemon/api/deliveries.js +33 -0
  243. package/src/host/daemon/api/desktop.js +5 -4
  244. package/src/host/daemon/api/embeddings.js +15 -6
  245. package/src/host/daemon/api/engines.js +59 -8
  246. package/src/host/daemon/api/exec.js +437 -121
  247. package/src/host/daemon/api/groups.js +215 -0
  248. package/src/host/daemon/api/images.js +107 -0
  249. package/src/host/daemon/api/inbox.js +123 -2
  250. package/src/host/daemon/api/integrations.js +64 -2
  251. package/src/host/daemon/api/mcps.js +7 -6
  252. package/src/host/daemon/api/media.js +283 -0
  253. package/src/host/daemon/api/mobility.js +177 -0
  254. package/src/host/daemon/api/net.js +182 -0
  255. package/src/host/daemon/api/pairing.js +38 -5
  256. package/src/host/daemon/api/profiles.js +30 -2
  257. package/src/host/daemon/api/routines.js +36 -4
  258. package/src/host/daemon/api/runtimes.js +74 -39
  259. package/src/host/daemon/api/sessions-search.js +7 -2
  260. package/src/host/daemon/api/sessions.js +44 -2
  261. package/src/host/daemon/api/shared.js +127 -20
  262. package/src/host/daemon/api/skills.js +11 -4
  263. package/src/host/daemon/api/super-agent.js +384 -53
  264. package/src/host/daemon/api/tasks.js +180 -10
  265. package/src/host/daemon/api/telegram.js +11 -10
  266. package/src/host/daemon/api/thread-faces.js +159 -0
  267. package/src/host/daemon/api/top-level.js +3 -3
  268. package/src/host/daemon/api/transcribe.js +11 -10
  269. package/src/host/daemon/api/tts.js +97 -4
  270. package/src/host/daemon/api/turn-abort.js +23 -0
  271. package/src/host/daemon/api/turns.js +49 -0
  272. package/src/host/daemon/api/voice.js +5 -4
  273. package/src/host/daemon/api/web.js +98 -0
  274. package/src/host/daemon/api.js +39 -0
  275. package/src/host/daemon/delivery-sweep.js +58 -0
  276. package/src/host/daemon/desktop-ws.js +5 -23
  277. package/src/host/daemon/events-ws.js +273 -0
  278. package/src/host/daemon/index.js +59 -15
  279. package/src/host/daemon/plugins/desktop/index.js +17 -4
  280. package/src/host/daemon/plugins/telegram/index.js +78 -40
  281. package/src/host/daemon/pty-bridge.py +99 -0
  282. package/src/host/daemon/routines-scheduler.js +1 -0
  283. package/src/host/daemon/smoke.js +1 -2
  284. package/src/host/daemon/terminal-ws.js +132 -0
  285. package/src/host/daemon/tts-keepwarm.js +87 -0
  286. package/src/host/daemon/wakeup.js +11 -6
  287. package/src/host/daemon/whisper-server.js +44 -0
  288. package/src/host/daemon/whisper-server.py +70 -13
  289. package/src/host/daemon/ws-auth.js +28 -0
  290. package/src/interfaces/android/app/build.gradle +42 -0
  291. package/src/interfaces/android/app/proguard-rules.pro +4 -0
  292. package/src/interfaces/android/app/src/main/AndroidManifest.xml +139 -0
  293. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/AlertScreen.java +139 -0
  294. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/AndroidAutoDetector.java +106 -0
  295. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ApxCarAppService.java +57 -0
  296. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ApxPreferences.java +165 -0
  297. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarAlertStore.java +84 -0
  298. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarMessageActionReceiver.java +47 -0
  299. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/CarMessageNotification.java +152 -0
  300. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DaemonAddress.java +35 -0
  301. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DaemonClient.java +339 -0
  302. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/DeviceLocation.java +38 -0
  303. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ErrandScreen.java +127 -0
  304. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MainActivity.java +872 -0
  305. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsNavigationDetector.java +63 -0
  306. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsNavigationListenerService.java +453 -0
  307. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MapsShareIntentParser.java +93 -0
  308. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotBlobCatalog.java +66 -0
  309. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotOverlayService.java +448 -0
  310. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MascotView.java +249 -0
  311. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/MessageFrameParser.java +240 -0
  312. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/NotifyChannels.java +69 -0
  313. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ProximityActionReceiver.java +78 -0
  314. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/ProximityNotification.java +161 -0
  315. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/StartupReceiver.java +57 -0
  316. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TravelEventGate.java +62 -0
  317. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TravelStatusBanner.java +116 -0
  318. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripLocationService.java +272 -0
  319. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripPlacesSheet.java +203 -0
  320. package/src/interfaces/android/app/src/main/java/dev/agentprojectcontext/apx/TripScreen.java +182 -0
  321. package/src/interfaces/android/app/src/main/res/drawable/app_background.xml +12 -0
  322. package/src/interfaces/android/app/src/main/res/drawable/ic_apx_app.xml +10 -0
  323. package/src/interfaces/android/app/src/main/res/drawable/ic_apx_launcher_foreground.xml +12 -0
  324. package/src/interfaces/android/app/src/main/res/drawable/ic_apx_notification.xml +22 -0
  325. package/src/interfaces/android/app/src/main/res/drawable/ic_trip_car.xml +37 -0
  326. package/src/interfaces/android/app/src/main/res/drawable-nodpi/apx_logo.png +0 -0
  327. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_amatista.png +0 -0
  328. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_aqua.png +0 -0
  329. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_brasa.png +0 -0
  330. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_campana.png +0 -0
  331. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_caracol.png +0 -0
  332. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_carbon.png +0 -0
  333. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cobalto.png +0 -0
  334. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cometa.png +0 -0
  335. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_coral.png +0 -0
  336. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_cubi.png +0 -0
  337. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_eclipse.png +0 -0
  338. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_faro.png +0 -0
  339. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_gajo.png +0 -0
  340. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_iris.png +0 -0
  341. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_kiwi.png +0 -0
  342. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_laguna.png +0 -0
  343. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_lila.png +0 -0
  344. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_menta.png +0 -0
  345. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_nimbo.png +0 -0
  346. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_noche.png +0 -0
  347. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_onyx.png +0 -0
  348. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_orbita.png +0 -0
  349. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_ovni.png +0 -0
  350. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_papa.png +0 -0
  351. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_parche.png +0 -0
  352. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_peon.png +0 -0
  353. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_perla.png +0 -0
  354. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_pino.png +0 -0
  355. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_quad.png +0 -0
  356. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_rubi.png +0 -0
  357. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_saturno.png +0 -0
  358. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_trebol.png +0 -0
  359. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_trino.png +0 -0
  360. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_volcan.png +0 -0
  361. package/src/interfaces/android/app/src/main/res/drawable-nodpi/mascot_zafiro.png +0 -0
  362. package/src/interfaces/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
  363. package/src/interfaces/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
  364. package/src/interfaces/android/app/src/main/res/raw/apx_notification.mp3 +0 -0
  365. package/src/interfaces/android/app/src/main/res/values/colors.xml +4 -0
  366. package/src/interfaces/android/app/src/main/res/values/strings.xml +25 -0
  367. package/src/interfaces/android/app/src/main/res/values/styles.xml +10 -0
  368. package/src/interfaces/android/app/src/main/res/values-v31/styles.xml +14 -0
  369. package/src/interfaces/android/app/src/main/res/xml/automotive_app_desc.xml +9 -0
  370. package/src/interfaces/android/app/src/main/res/xml/network_security_config.xml +10 -0
  371. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/AndroidAutoDetectorTest.java +85 -0
  372. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/CarAlertStoreTest.java +104 -0
  373. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/DaemonAddressTest.java +23 -0
  374. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MapsNavigationDetectorTest.java +69 -0
  375. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MapsShareIntentParserTest.java +31 -0
  376. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/MessageFrameParserTest.java +180 -0
  377. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/TravelEventGateTest.java +64 -0
  378. package/src/interfaces/android/app/src/test/java/dev/agentprojectcontext/apx/TripPlacesSheetTest.java +66 -0
  379. package/src/interfaces/android/build.gradle +3 -0
  380. package/src/interfaces/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  381. package/src/interfaces/android/gradle/wrapper/gradle-wrapper.properties +9 -0
  382. package/src/interfaces/android/gradle.properties +3 -0
  383. package/src/interfaces/android/gradlew +248 -0
  384. package/src/interfaces/android/gradlew.bat +82 -0
  385. package/src/interfaces/android/settings.gradle +18 -0
  386. package/src/interfaces/cli/commands/a2a.js +145 -4
  387. package/src/interfaces/cli/commands/agent.js +247 -22
  388. package/src/interfaces/cli/commands/code.js +1 -1
  389. package/src/interfaces/cli/commands/commitment.js +5 -0
  390. package/src/interfaces/cli/commands/config.js +85 -6
  391. package/src/interfaces/cli/commands/exec.js +90 -1
  392. package/src/interfaces/cli/commands/image.js +314 -0
  393. package/src/interfaces/cli/commands/mcp.js +87 -23
  394. package/src/interfaces/cli/commands/memory.js +35 -22
  395. package/src/interfaces/cli/commands/panel.js +94 -0
  396. package/src/interfaces/cli/commands/profile.js +14 -0
  397. package/src/interfaces/cli/commands/project.js +29 -0
  398. package/src/interfaces/cli/commands/routine.js +45 -10
  399. package/src/interfaces/cli/commands/runtime.js +30 -7
  400. package/src/interfaces/cli/commands/session.js +90 -38
  401. package/src/interfaces/cli/commands/sessions.js +35 -2
  402. package/src/interfaces/cli/commands/skills.js +15 -9
  403. package/src/interfaces/cli/commands/status.js +2 -3
  404. package/src/interfaces/cli/commands/task.js +54 -5
  405. package/src/interfaces/cli/commands/telegram.js +12 -4
  406. package/src/interfaces/cli/commands/transcribe.js +177 -0
  407. package/src/interfaces/cli/help/index.js +311 -72
  408. package/src/interfaces/cli/http.js +61 -13
  409. package/src/interfaces/cli/index.js +1 -1
  410. package/src/interfaces/cli/routes/agent.js +5 -4
  411. package/src/interfaces/cli/routes/commitment.js +3 -2
  412. package/src/interfaces/cli/routes/config.js +7 -2
  413. package/src/interfaces/cli/routes/image.js +11 -0
  414. package/src/interfaces/cli/routes/index.js +2 -0
  415. package/src/interfaces/cli/routes/log.js +1 -1
  416. package/src/interfaces/cli/routes/memory.js +3 -2
  417. package/src/interfaces/cli/routes/panel.js +15 -2
  418. package/src/interfaces/cli/routes/profile.js +3 -2
  419. package/src/interfaces/cli/routes/transcribe.js +10 -0
  420. package/src/interfaces/cli/stdin.js +29 -0
  421. package/src/interfaces/desktop/assets/blobs/amatista.png +0 -0
  422. package/src/interfaces/desktop/assets/blobs/aqua.png +0 -0
  423. package/src/interfaces/desktop/assets/blobs/brasa.png +0 -0
  424. package/src/interfaces/desktop/assets/blobs/campana.png +0 -0
  425. package/src/interfaces/desktop/assets/blobs/caracol.png +0 -0
  426. package/src/interfaces/desktop/assets/blobs/carbon.png +0 -0
  427. package/src/interfaces/desktop/assets/blobs/cobalto.png +0 -0
  428. package/src/interfaces/desktop/assets/blobs/cometa.png +0 -0
  429. package/src/interfaces/desktop/assets/blobs/coral.png +0 -0
  430. package/src/interfaces/desktop/assets/blobs/cubi.png +0 -0
  431. package/src/interfaces/desktop/assets/blobs/eclipse.png +0 -0
  432. package/src/interfaces/desktop/assets/blobs/faro.png +0 -0
  433. package/src/interfaces/desktop/assets/blobs/gajo.png +0 -0
  434. package/src/interfaces/desktop/assets/blobs/iris.png +0 -0
  435. package/src/interfaces/desktop/assets/blobs/kiwi.png +0 -0
  436. package/src/interfaces/desktop/assets/blobs/laguna.png +0 -0
  437. package/src/interfaces/desktop/assets/blobs/lila.png +0 -0
  438. package/src/interfaces/desktop/assets/blobs/menta.png +0 -0
  439. package/src/interfaces/desktop/assets/blobs/nimbo.png +0 -0
  440. package/src/interfaces/desktop/assets/blobs/noche.png +0 -0
  441. package/src/interfaces/desktop/assets/blobs/onyx.png +0 -0
  442. package/src/interfaces/desktop/assets/blobs/orbita.png +0 -0
  443. package/src/interfaces/desktop/assets/blobs/ovni.png +0 -0
  444. package/src/interfaces/desktop/assets/blobs/papa.png +0 -0
  445. package/src/interfaces/desktop/assets/blobs/parche.png +0 -0
  446. package/src/interfaces/desktop/assets/blobs/peon.png +0 -0
  447. package/src/interfaces/desktop/assets/blobs/perla.png +0 -0
  448. package/src/interfaces/desktop/assets/blobs/pino.png +0 -0
  449. package/src/interfaces/desktop/assets/blobs/quad.png +0 -0
  450. package/src/interfaces/desktop/assets/blobs/rubi.png +0 -0
  451. package/src/interfaces/desktop/assets/blobs/saturno.png +0 -0
  452. package/src/interfaces/desktop/assets/blobs/trebol.png +0 -0
  453. package/src/interfaces/desktop/assets/blobs/trino.png +0 -0
  454. package/src/interfaces/desktop/assets/blobs/volcan.png +0 -0
  455. package/src/interfaces/desktop/assets/blobs/zafiro.png +0 -0
  456. package/src/interfaces/desktop/assets/notification.mp3 +0 -0
  457. package/src/interfaces/desktop/main.js +473 -29
  458. package/src/interfaces/desktop/mascot-blobs.js +41 -0
  459. package/src/interfaces/desktop/mascot-preload.js +32 -0
  460. package/src/interfaces/desktop/mascot.css +186 -0
  461. package/src/interfaces/desktop/mascot.html +40 -0
  462. package/src/interfaces/desktop/mascot.js +163 -0
  463. package/src/interfaces/desktop/preload.js +10 -0
  464. package/src/interfaces/desktop/renderer.js +308 -48
  465. package/src/interfaces/desktop/style.css +34 -0
  466. package/src/interfaces/mcp-server/index.js +87 -0
  467. package/src/interfaces/tui/_shims/util-locale.ts +0 -2
  468. package/src/interfaces/tui/app.tsx +0 -6
  469. package/src/interfaces/tui/attach.ts +0 -1
  470. package/src/interfaces/tui/context/sdk-apx.tsx +0 -4
  471. package/src/interfaces/tui/plugin/api.tsx +0 -3
  472. package/src/interfaces/tui/plugin/runtime.ts +0 -3
  473. package/src/interfaces/tui/thread.ts +0 -16
  474. package/src/interfaces/web/README.md +22 -14
  475. package/src/interfaces/web/dist/assets/claude-XtpLmGtF.webp +0 -0
  476. package/src/interfaces/web/dist/assets/codex-DExPUgvh.webp +0 -0
  477. package/src/interfaces/web/dist/assets/index-BEoRgIqd.css +32 -0
  478. package/src/interfaces/web/dist/assets/index-BEoRgIqd.css.br +0 -0
  479. package/src/interfaces/web/dist/assets/index-BEoRgIqd.css.gz +0 -0
  480. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js +1074 -0
  481. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.br +0 -0
  482. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.gz +0 -0
  483. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map +1 -0
  484. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map.br +0 -0
  485. package/src/interfaces/web/dist/assets/index-C6fXHc1p.js.map.gz +0 -0
  486. package/src/interfaces/web/dist/favicon/dark/site.webmanifest +12 -6
  487. package/src/interfaces/web/dist/favicon/white/site.webmanifest +12 -6
  488. package/src/interfaces/web/dist/index.html +22 -6
  489. package/src/interfaces/web/dist/index.html.br +0 -0
  490. package/src/interfaces/web/dist/index.html.gz +0 -0
  491. package/src/interfaces/web/dist/manifest.webmanifest +25 -0
  492. package/src/interfaces/web/dist/modules/blobs/amatista.png +0 -0
  493. package/src/interfaces/web/dist/modules/blobs/aqua.png +0 -0
  494. package/src/interfaces/web/dist/modules/blobs/brasa.png +0 -0
  495. package/src/interfaces/web/dist/modules/blobs/campana.png +0 -0
  496. package/src/interfaces/web/dist/modules/blobs/caracol.png +0 -0
  497. package/src/interfaces/web/dist/modules/blobs/carbon.png +0 -0
  498. package/src/interfaces/web/dist/modules/blobs/cobalto.png +0 -0
  499. package/src/interfaces/web/dist/modules/blobs/cometa.png +0 -0
  500. package/src/interfaces/web/dist/modules/blobs/coral.png +0 -0
  501. package/src/interfaces/web/dist/modules/blobs/cubi.png +0 -0
  502. package/src/interfaces/web/dist/modules/blobs/eclipse.png +0 -0
  503. package/src/interfaces/web/dist/modules/blobs/faro.png +0 -0
  504. package/src/interfaces/web/dist/modules/blobs/gajo.png +0 -0
  505. package/src/interfaces/web/dist/modules/blobs/iris.png +0 -0
  506. package/src/interfaces/web/dist/modules/blobs/kiwi.png +0 -0
  507. package/src/interfaces/web/dist/modules/blobs/laguna.png +0 -0
  508. package/src/interfaces/web/dist/modules/blobs/lila.png +0 -0
  509. package/src/interfaces/web/dist/modules/blobs/menta.png +0 -0
  510. package/src/interfaces/web/dist/modules/blobs/nimbo.png +0 -0
  511. package/src/interfaces/web/dist/modules/blobs/noche.png +0 -0
  512. package/src/interfaces/web/dist/modules/blobs/onyx.png +0 -0
  513. package/src/interfaces/web/dist/modules/blobs/orbita.png +0 -0
  514. package/src/interfaces/web/dist/modules/blobs/ovni.png +0 -0
  515. package/src/interfaces/web/dist/modules/blobs/papa.png +0 -0
  516. package/src/interfaces/web/dist/modules/blobs/parche.png +0 -0
  517. package/src/interfaces/web/dist/modules/blobs/peon.png +0 -0
  518. package/src/interfaces/web/dist/modules/blobs/perla.png +0 -0
  519. package/src/interfaces/web/dist/modules/blobs/pino.png +0 -0
  520. package/src/interfaces/web/dist/modules/blobs/quad.png +0 -0
  521. package/src/interfaces/web/dist/modules/blobs/rubi.png +0 -0
  522. package/src/interfaces/web/dist/modules/blobs/saturno.png +0 -0
  523. package/src/interfaces/web/dist/modules/blobs/trebol.png +0 -0
  524. package/src/interfaces/web/dist/modules/blobs/trino.png +0 -0
  525. package/src/interfaces/web/dist/modules/blobs/volcan.png +0 -0
  526. package/src/interfaces/web/dist/modules/blobs/zafiro.png +0 -0
  527. package/src/interfaces/web/dist/sw.js +106 -0
  528. package/src/interfaces/web/dist/sw.js.br +0 -0
  529. package/src/interfaces/web/dist/sw.js.gz +0 -0
  530. package/src/interfaces/web/eslint.config.js +83 -0
  531. package/src/interfaces/web/index.html +20 -4
  532. package/src/interfaces/web/package-lock.json +1651 -1280
  533. package/src/interfaces/web/package.json +9 -10
  534. package/src/interfaces/web/pnpm-lock.yaml +867 -869
  535. package/src/interfaces/web/public/favicon/dark/site.webmanifest +12 -6
  536. package/src/interfaces/web/public/favicon/white/site.webmanifest +12 -6
  537. package/src/interfaces/web/public/manifest.webmanifest +25 -0
  538. package/src/interfaces/web/public/modules/blobs/amatista.png +0 -0
  539. package/src/interfaces/web/public/modules/blobs/aqua.png +0 -0
  540. package/src/interfaces/web/public/modules/blobs/brasa.png +0 -0
  541. package/src/interfaces/web/public/modules/blobs/campana.png +0 -0
  542. package/src/interfaces/web/public/modules/blobs/caracol.png +0 -0
  543. package/src/interfaces/web/public/modules/blobs/carbon.png +0 -0
  544. package/src/interfaces/web/public/modules/blobs/cobalto.png +0 -0
  545. package/src/interfaces/web/public/modules/blobs/cometa.png +0 -0
  546. package/src/interfaces/web/public/modules/blobs/coral.png +0 -0
  547. package/src/interfaces/web/public/modules/blobs/cubi.png +0 -0
  548. package/src/interfaces/web/public/modules/blobs/eclipse.png +0 -0
  549. package/src/interfaces/web/public/modules/blobs/faro.png +0 -0
  550. package/src/interfaces/web/public/modules/blobs/gajo.png +0 -0
  551. package/src/interfaces/web/public/modules/blobs/iris.png +0 -0
  552. package/src/interfaces/web/public/modules/blobs/kiwi.png +0 -0
  553. package/src/interfaces/web/public/modules/blobs/laguna.png +0 -0
  554. package/src/interfaces/web/public/modules/blobs/lila.png +0 -0
  555. package/src/interfaces/web/public/modules/blobs/menta.png +0 -0
  556. package/src/interfaces/web/public/modules/blobs/nimbo.png +0 -0
  557. package/src/interfaces/web/public/modules/blobs/noche.png +0 -0
  558. package/src/interfaces/web/public/modules/blobs/onyx.png +0 -0
  559. package/src/interfaces/web/public/modules/blobs/orbita.png +0 -0
  560. package/src/interfaces/web/public/modules/blobs/ovni.png +0 -0
  561. package/src/interfaces/web/public/modules/blobs/papa.png +0 -0
  562. package/src/interfaces/web/public/modules/blobs/parche.png +0 -0
  563. package/src/interfaces/web/public/modules/blobs/peon.png +0 -0
  564. package/src/interfaces/web/public/modules/blobs/perla.png +0 -0
  565. package/src/interfaces/web/public/modules/blobs/pino.png +0 -0
  566. package/src/interfaces/web/public/modules/blobs/quad.png +0 -0
  567. package/src/interfaces/web/public/modules/blobs/rubi.png +0 -0
  568. package/src/interfaces/web/public/modules/blobs/saturno.png +0 -0
  569. package/src/interfaces/web/public/modules/blobs/trebol.png +0 -0
  570. package/src/interfaces/web/public/modules/blobs/trino.png +0 -0
  571. package/src/interfaces/web/public/modules/blobs/volcan.png +0 -0
  572. package/src/interfaces/web/public/modules/blobs/zafiro.png +0 -0
  573. package/src/interfaces/web/public/sw.js +106 -0
  574. package/src/interfaces/web/src/App.tsx +106 -10
  575. package/src/interfaces/web/src/assets/cli/claude.webp +0 -0
  576. package/src/interfaces/web/src/assets/cli/codex.webp +0 -0
  577. package/src/interfaces/web/src/assets/cli/cursor.svg +1 -0
  578. package/src/interfaces/web/src/assets/cli/opencode.png +0 -0
  579. package/src/interfaces/web/src/components/Combobox.tsx +201 -0
  580. package/src/interfaces/web/src/components/MobileHint.tsx +95 -0
  581. package/src/interfaces/web/src/components/MobileLinkDialog.tsx +156 -0
  582. package/src/interfaces/web/src/components/ModelCombobox.tsx +21 -113
  583. package/src/interfaces/web/src/components/{routines/ReadOnlyBlock.tsx → ReadOnlyBlock.tsx} +13 -4
  584. package/src/interfaces/web/src/components/Roby.tsx +5 -3
  585. package/src/interfaces/web/src/components/RobyBubble.tsx +23 -5
  586. package/src/interfaces/web/src/components/RowMenu.tsx +46 -0
  587. package/src/interfaces/web/src/components/TimezoneSelect.tsx +4 -1
  588. package/src/interfaces/web/src/components/Toast.tsx +50 -14
  589. package/src/interfaces/web/src/components/UiSelect.tsx +12 -5
  590. package/src/interfaces/web/src/components/agents/AgentAvatar.tsx +171 -0
  591. package/src/interfaces/web/src/components/agents/AgentFormFields.tsx +42 -11
  592. package/src/interfaces/web/src/components/agents/AgentModelBadge.tsx +157 -0
  593. package/src/interfaces/web/src/components/agents/AgentModelSelect.tsx +57 -0
  594. package/src/interfaces/web/src/components/agents/AgentSkillsPicker.tsx +115 -0
  595. package/src/interfaces/web/src/components/agents/BlobAvatar.tsx +50 -0
  596. package/src/interfaces/web/src/components/agents/blobPresets.ts +50 -0
  597. package/src/interfaces/web/src/components/agents/modelCatalog.ts +66 -0
  598. package/src/interfaces/web/src/components/chat/ActionGroup.tsx +162 -0
  599. package/src/interfaces/web/src/components/chat/AskAnswersCard.tsx +4 -3
  600. package/src/interfaces/web/src/components/chat/AskQuestionsCard.tsx +1 -1
  601. package/src/interfaces/web/src/components/chat/Attachment.tsx +220 -0
  602. package/src/interfaces/web/src/components/chat/ChatList.tsx +226 -51
  603. package/src/interfaces/web/src/components/chat/ChatRowActivity.tsx +45 -0
  604. package/src/interfaces/web/src/components/chat/Composer.tsx +672 -23
  605. package/src/interfaces/web/src/components/chat/ComposerCommands.tsx +175 -0
  606. package/src/interfaces/web/src/components/chat/ComposerSuggest.tsx +215 -0
  607. package/src/interfaces/web/src/components/chat/ContextBar.tsx +133 -65
  608. package/src/interfaces/web/src/components/chat/InlineAskPanel.tsx +107 -47
  609. package/src/interfaces/web/src/components/chat/MessageBubble.tsx +460 -119
  610. package/src/interfaces/web/src/components/chat/MessageList.tsx +165 -18
  611. package/src/interfaces/web/src/components/chat/ReasoningBlock.tsx +58 -0
  612. package/src/interfaces/web/src/components/chat/SessionPicker.tsx +182 -0
  613. package/src/interfaces/web/src/components/chat/SkillTrace.tsx +183 -0
  614. package/src/interfaces/web/src/components/chat/ToolCall.tsx +11 -11
  615. package/src/interfaces/web/src/components/code/CodeContextTab.tsx +87 -53
  616. package/src/interfaces/web/src/components/code/CodeFileTree.tsx +11 -52
  617. package/src/interfaces/web/src/components/code/CodeFileViewer.tsx +5 -4
  618. package/src/interfaces/web/src/components/code/CodeProjectPicker.tsx +31 -7
  619. package/src/interfaces/web/src/components/code/CodeSessionList.tsx +32 -11
  620. package/src/interfaces/web/src/components/code/CodeSidePanel.tsx +33 -3
  621. package/src/interfaces/web/src/components/code/CodeTerminal.tsx +5 -4
  622. package/src/interfaces/web/src/components/code/NewCodeSessionDialog.tsx +164 -0
  623. package/src/interfaces/web/src/components/commitments/CommitmentDetail.tsx +162 -0
  624. package/src/interfaces/web/src/components/commitments/CommitmentFormDialog.tsx +158 -0
  625. package/src/interfaces/web/src/components/commitments/CommitmentList.tsx +194 -0
  626. package/src/interfaces/web/src/components/commitments/commitmentState.tsx +46 -0
  627. package/src/interfaces/web/src/components/common/BulkActionBar.tsx +60 -0
  628. package/src/interfaces/web/src/components/common/ConfirmDialog.tsx +4 -1
  629. package/src/interfaces/web/src/components/common/SelectCheckbox.tsx +40 -0
  630. package/src/interfaces/web/src/components/common/TabNav.tsx +1 -1
  631. package/src/interfaces/web/src/components/cron/CronPicker.tsx +1 -1
  632. package/src/interfaces/web/src/components/files/FileBrowser.tsx +1 -1
  633. package/src/interfaces/web/src/components/files/FileTree.tsx +6 -4
  634. package/src/interfaces/web/src/components/files/FileViewer.tsx +9 -5
  635. package/src/interfaces/web/src/components/files/MarkdownPreview.tsx +45 -9
  636. package/src/interfaces/web/src/components/images/ImageDefaultsCard.tsx +93 -0
  637. package/src/interfaces/web/src/components/images/ImageProviderList.tsx +142 -0
  638. package/src/interfaces/web/src/components/images/ImageProviderModal.tsx +263 -0
  639. package/src/interfaces/web/src/components/images/ImageTestCard.tsx +142 -0
  640. package/src/interfaces/web/src/components/inbox/ChannelFilter.tsx +178 -0
  641. package/src/interfaces/web/src/components/inbox/InboxList.tsx +77 -81
  642. package/src/interfaces/web/src/components/inbox/InboxRowItem.tsx +140 -0
  643. package/src/interfaces/web/src/components/integrations/ComingSoonPlugin.tsx +2 -2
  644. package/src/interfaces/web/src/components/integrations/PluginConnect.tsx +208 -30
  645. package/src/interfaces/web/src/components/integrations/PluginToolsSection.tsx +1 -1
  646. package/src/interfaces/web/src/components/layout/ProjectAvatar.tsx +39 -24
  647. package/src/interfaces/web/src/components/layout/ProjectSidebar.tsx +253 -58
  648. package/src/interfaces/web/src/components/memory/MemoryBrowser.tsx +94 -47
  649. package/src/interfaces/web/src/components/routines/ExecutionsList.tsx +202 -90
  650. package/src/interfaces/web/src/components/routines/RoutineDetail.tsx +28 -6
  651. package/src/interfaces/web/src/components/routines/RoutineEditor.tsx +16 -5
  652. package/src/interfaces/web/src/components/routines/RoutineList.tsx +49 -9
  653. package/src/interfaces/web/src/components/routines/VarTextarea.tsx +1 -1
  654. package/src/interfaces/web/src/components/routines/runChat.ts +121 -0
  655. package/src/interfaces/web/src/components/sessions/SessionDetail.tsx +148 -0
  656. package/src/interfaces/web/src/components/sessions/SessionTerminal.tsx +98 -0
  657. package/src/interfaces/web/src/components/settings/AccessPanel.tsx +205 -0
  658. package/src/interfaces/web/src/components/settings/DefaultRouterCard.tsx +246 -101
  659. package/src/interfaces/web/src/components/settings/DesktopSettingsPanel.tsx +36 -2
  660. package/src/interfaces/web/src/components/settings/DevicesPanel.tsx +19 -6
  661. package/src/interfaces/web/src/components/settings/EmbedProviderList.tsx +274 -0
  662. package/src/interfaces/web/src/components/settings/EnginesPanel.tsx +26 -6
  663. package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +118 -119
  664. package/src/interfaces/web/src/components/settings/NudgePanel.tsx +4 -3
  665. package/src/interfaces/web/src/components/settings/PairDeviceDialog.tsx +15 -4
  666. package/src/interfaces/web/src/components/settings/PanelPrefs.tsx +374 -0
  667. package/src/interfaces/web/src/components/settings/ProfilePanel.tsx +70 -2
  668. package/src/interfaces/web/src/components/settings/RoutingPanel.tsx +2 -1
  669. package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +102 -43
  670. package/src/interfaces/web/src/components/settings/SkillsManager.tsx +76 -21
  671. package/src/interfaces/web/src/components/settings/SkillsSettings.tsx +10 -3
  672. package/src/interfaces/web/src/components/settings/SuperAgentPanel.tsx +8 -0
  673. package/src/interfaces/web/src/components/settings/TelegramChannelsPanel.tsx +11 -2
  674. package/src/interfaces/web/src/components/settings/TelegramContactsPanel.tsx +19 -8
  675. package/src/interfaces/web/src/components/settings/TelegramRolesPanel.tsx +12 -2
  676. package/src/interfaces/web/src/components/settings/WebPanel.tsx +22 -31
  677. package/src/interfaces/web/src/components/settings/providers/ProviderCard.tsx +15 -3
  678. package/src/interfaces/web/src/components/settings/providers/ProviderModal.tsx +97 -66
  679. package/src/interfaces/web/src/components/settings/providers/ProviderTestDialog.tsx +150 -0
  680. package/src/interfaces/web/src/components/settings/providers/typeStyles.ts +67 -25
  681. package/src/interfaces/web/src/components/settings/providers/types.ts +3 -0
  682. package/src/interfaces/web/src/components/tasks/TaskBoard.tsx +201 -0
  683. package/src/interfaces/web/src/components/tasks/TaskColumnsDialog.tsx +243 -0
  684. package/src/interfaces/web/src/components/tasks/TaskComments.tsx +167 -0
  685. package/src/interfaces/web/src/components/tasks/TaskDetail.tsx +335 -0
  686. package/src/interfaces/web/src/components/tasks/TaskFormDialog.tsx +406 -0
  687. package/src/interfaces/web/src/components/tasks/TaskList.tsx +258 -0
  688. package/src/interfaces/web/src/components/tasks/TaskSubtasks.tsx +126 -0
  689. package/src/interfaces/web/src/components/tasks/columns.ts +51 -0
  690. package/src/interfaces/web/src/components/tasks/taskStatus.tsx +159 -34
  691. package/src/interfaces/web/src/components/tasks/taskViewPrefs.ts +73 -0
  692. package/src/interfaces/web/src/components/tasks/useTaskColumns.ts +31 -0
  693. package/src/interfaces/web/src/components/ui/chat-input.tsx +136 -12
  694. package/src/interfaces/web/src/components/ui/context-menu.tsx +15 -198
  695. package/src/interfaces/web/src/components/ui/dialog.tsx +3 -2
  696. package/src/interfaces/web/src/components/ui/filter-chips.tsx +4 -0
  697. package/src/interfaces/web/src/components/ui/popover.tsx +14 -49
  698. package/src/interfaces/web/src/components/ui/sheet.tsx +2 -1
  699. package/src/interfaces/web/src/components/ui/spinner.tsx +2 -1
  700. package/src/interfaces/web/src/components/ui.tsx +62 -23
  701. package/src/interfaces/web/src/components/voice/VoiceProviderList.tsx +2 -1
  702. package/src/interfaces/web/src/components/voice/VoiceProviderModal.tsx +66 -8
  703. package/src/interfaces/web/src/components/voice/VoiceQvoxInstallCard.tsx +63 -0
  704. package/src/interfaces/web/src/components/voice/VoiceQvoxStatusCard.tsx +51 -0
  705. package/src/interfaces/web/src/components/voice/VoiceSttCard.tsx +4 -3
  706. package/src/interfaces/web/src/components/voice/VoiceTestCard.tsx +38 -4
  707. package/src/interfaces/web/src/constants/index.ts +1 -0
  708. package/src/interfaces/web/src/hooks/useChannelPrefs.ts +39 -0
  709. package/src/interfaces/web/src/hooks/useChat.ts +1092 -85
  710. package/src/interfaces/web/src/hooks/useChatActivity.ts +24 -0
  711. package/src/interfaces/web/src/hooks/useInbox.ts +26 -4
  712. package/src/interfaces/web/src/hooks/useLiveMessages.ts +16 -0
  713. package/src/interfaces/web/src/hooks/useOllamaModels.ts +79 -0
  714. package/src/interfaces/web/src/hooks/useRecorder.ts +198 -0
  715. package/src/interfaces/web/src/hooks/useTokenBootstrap.ts +23 -6
  716. package/src/interfaces/web/src/i18n/en.ts +832 -175
  717. package/src/interfaces/web/src/i18n/es.ts +841 -188
  718. package/src/interfaces/web/src/lib/api/agents.ts +23 -4
  719. package/src/interfaces/web/src/lib/api/code.ts +17 -0
  720. package/src/interfaces/web/src/lib/api/commitments.ts +7 -1
  721. package/src/interfaces/web/src/lib/api/conversations.ts +38 -11
  722. package/src/interfaces/web/src/lib/api/embeddings.ts +3 -0
  723. package/src/interfaces/web/src/lib/api/engines.ts +14 -0
  724. package/src/interfaces/web/src/lib/api/groups.ts +93 -0
  725. package/src/interfaces/web/src/lib/api/images.ts +193 -0
  726. package/src/interfaces/web/src/lib/api/inbox.ts +29 -5
  727. package/src/interfaces/web/src/lib/api/integrations.ts +9 -0
  728. package/src/interfaces/web/src/lib/api/media.ts +126 -0
  729. package/src/interfaces/web/src/lib/api/net.ts +44 -0
  730. package/src/interfaces/web/src/lib/api/profiles.ts +12 -0
  731. package/src/interfaces/web/src/lib/api/projects.ts +9 -1
  732. package/src/interfaces/web/src/lib/api/routines.ts +9 -1
  733. package/src/interfaces/web/src/lib/api/sessions.ts +18 -0
  734. package/src/interfaces/web/src/lib/api/skills.ts +8 -0
  735. package/src/interfaces/web/src/lib/api/super_agent.ts +3 -0
  736. package/src/interfaces/web/src/lib/api/tasks.ts +46 -6
  737. package/src/interfaces/web/src/lib/api/tools.ts +2 -0
  738. package/src/interfaces/web/src/lib/api/transcribe.ts +31 -0
  739. package/src/interfaces/web/src/lib/api/turns.ts +20 -0
  740. package/src/interfaces/web/src/lib/api/voice.ts +72 -2
  741. package/src/interfaces/web/src/lib/api.ts +3 -0
  742. package/src/interfaces/web/src/lib/channels.ts +214 -0
  743. package/src/interfaces/web/src/lib/chat-activity.ts +175 -0
  744. package/src/interfaces/web/src/lib/chat-prefs.ts +48 -0
  745. package/src/interfaces/web/src/lib/code-context.ts +0 -2
  746. package/src/interfaces/web/src/lib/http.ts +51 -17
  747. package/src/interfaces/web/src/lib/inbox-selection.ts +29 -0
  748. package/src/interfaces/web/src/lib/live.ts +252 -0
  749. package/src/interfaces/web/src/lib/net.ts +211 -0
  750. package/src/interfaces/web/src/lib/notify.ts +331 -0
  751. package/src/interfaces/web/src/lib/projectNav.ts +40 -0
  752. package/src/interfaces/web/src/lib/pwa.ts +115 -0
  753. package/src/interfaces/web/src/lib/qvox.ts +24 -0
  754. package/src/interfaces/web/src/lib/slug.ts +3 -0
  755. package/src/interfaces/web/src/lib/tone.ts +150 -0
  756. package/src/interfaces/web/src/main.tsx +15 -4
  757. package/src/interfaces/web/src/screens/ApxAdminScreen.tsx +33 -11
  758. package/src/interfaces/web/src/screens/InboxScreen.tsx +126 -71
  759. package/src/interfaces/web/src/screens/ProjectScreen.tsx +8 -4
  760. package/src/interfaces/web/src/screens/SettingsScreen.tsx +7 -4
  761. package/src/interfaces/web/src/screens/base/AgentDefaultsTab.tsx +30 -9
  762. package/src/interfaces/web/src/screens/base/CommitmentsTab.tsx +150 -168
  763. package/src/interfaces/web/src/screens/base/LogsTab.tsx +8 -7
  764. package/src/interfaces/web/src/screens/base/SessionsTab.tsx +99 -37
  765. package/src/interfaces/web/src/screens/base/WorkspacesTab.tsx +1 -1
  766. package/src/interfaces/web/src/screens/mobile/MobileChat.tsx +85 -0
  767. package/src/interfaces/web/src/screens/mobile/MobileChatList.tsx +244 -0
  768. package/src/interfaces/web/src/screens/mobile/MobileCommitments.tsx +350 -0
  769. package/src/interfaces/web/src/screens/mobile/MobileScreen.tsx +138 -0
  770. package/src/interfaces/web/src/screens/mobile/MobileTabBar.tsx +105 -0
  771. package/src/interfaces/web/src/screens/mobile/MobileTasks.tsx +407 -0
  772. package/src/interfaces/web/src/screens/mobile/NewChatSheet.tsx +313 -0
  773. package/src/interfaces/web/src/screens/mobile/mobileList.tsx +194 -0
  774. package/src/interfaces/web/src/screens/mobile/routes.ts +239 -0
  775. package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +135 -64
  776. package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +0 -1
  777. package/src/interfaces/web/src/screens/modules/ImagesScreen.tsx +172 -0
  778. package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +36 -4
  779. package/src/interfaces/web/src/screens/project/AgentBrainGraph.tsx +117 -30
  780. package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +537 -92
  781. package/src/interfaces/web/src/screens/project/AgentsTab.tsx +344 -93
  782. package/src/interfaces/web/src/screens/project/ArtifactsTab.tsx +1 -1
  783. package/src/interfaces/web/src/screens/project/ChatTab.tsx +1160 -94
  784. package/src/interfaces/web/src/screens/project/IntegrationsTab.tsx +3 -2
  785. package/src/interfaces/web/src/screens/project/McpsTab.tsx +62 -14
  786. package/src/interfaces/web/src/screens/project/Overview.tsx +36 -15
  787. package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +93 -8
  788. package/src/interfaces/web/src/screens/project/SkillsTab.tsx +4 -1
  789. package/src/interfaces/web/src/screens/project/StructureTab.tsx +5 -4
  790. package/src/interfaces/web/src/screens/project/TasksTab.tsx +351 -129
  791. package/src/interfaces/web/src/screens/project/VarsTab.tsx +17 -5
  792. package/src/interfaces/web/src/styles.css +106 -31
  793. package/src/interfaces/web/src/types/daemon.ts +246 -2
  794. package/src/interfaces/web/src/vite-env.d.ts +20 -0
  795. package/src/interfaces/tui/plugin/command-shim.ts +0 -109
  796. package/src/interfaces/web/components.json +0 -25
  797. package/src/interfaces/web/dist/assets/index-CvEoGtTf.js +0 -849
  798. package/src/interfaces/web/dist/assets/index-CvEoGtTf.js.map +0 -1
  799. package/src/interfaces/web/dist/assets/index-DzBBXFaO.css +0 -1
  800. package/src/interfaces/web/src/components/tasks/TaskDetailPanel.tsx +0 -142
  801. package/src/interfaces/web/src/components/ui/accordion.tsx +0 -72
  802. package/src/interfaces/web/src/components/ui/alert-dialog.tsx +0 -187
  803. package/src/interfaces/web/src/components/ui/alert.tsx +0 -76
  804. package/src/interfaces/web/src/components/ui/aspect-ratio.tsx +0 -22
  805. package/src/interfaces/web/src/components/ui/avatar.tsx +0 -107
  806. package/src/interfaces/web/src/components/ui/breadcrumb.tsx +0 -125
  807. package/src/interfaces/web/src/components/ui/button-group.tsx +0 -87
  808. package/src/interfaces/web/src/components/ui/calendar.tsx +0 -221
  809. package/src/interfaces/web/src/components/ui/card.tsx +0 -103
  810. package/src/interfaces/web/src/components/ui/carousel.tsx +0 -242
  811. package/src/interfaces/web/src/components/ui/chart.tsx +0 -371
  812. package/src/interfaces/web/src/components/ui/checkbox.tsx +0 -29
  813. package/src/interfaces/web/src/components/ui/collapsible.tsx +0 -19
  814. package/src/interfaces/web/src/components/ui/combobox.tsx +0 -295
  815. package/src/interfaces/web/src/components/ui/command.tsx +0 -196
  816. package/src/interfaces/web/src/components/ui/direction.tsx +0 -4
  817. package/src/interfaces/web/src/components/ui/drawer.tsx +0 -134
  818. package/src/interfaces/web/src/components/ui/empty.tsx +0 -104
  819. package/src/interfaces/web/src/components/ui/field.tsx +0 -236
  820. package/src/interfaces/web/src/components/ui/hover-card.tsx +0 -51
  821. package/src/interfaces/web/src/components/ui/input-otp.tsx +0 -85
  822. package/src/interfaces/web/src/components/ui/item.tsx +0 -201
  823. package/src/interfaces/web/src/components/ui/menubar.tsx +0 -280
  824. package/src/interfaces/web/src/components/ui/native-select.tsx +0 -61
  825. package/src/interfaces/web/src/components/ui/navigation-menu.tsx +0 -168
  826. package/src/interfaces/web/src/components/ui/pagination.tsx +0 -130
  827. package/src/interfaces/web/src/components/ui/progress.tsx +0 -83
  828. package/src/interfaces/web/src/components/ui/radio-group.tsx +0 -36
  829. package/src/interfaces/web/src/components/ui/resizable.tsx +0 -50
  830. package/src/interfaces/web/src/components/ui/scroll-area.tsx +0 -53
  831. package/src/interfaces/web/src/components/ui/sidebar.tsx +0 -726
  832. package/src/interfaces/web/src/components/ui/slider.tsx +0 -52
  833. package/src/interfaces/web/src/components/ui/sonner.tsx +0 -49
  834. package/src/interfaces/web/src/components/ui/table.tsx +0 -116
  835. package/src/interfaces/web/src/components/ui/toggle-group.tsx +0 -87
  836. package/src/interfaces/web/src/components/ui/toggle.tsx +0 -45
  837. package/src/interfaces/web/src/hooks/use-mobile.ts +0 -19
  838. package/src/interfaces/web/src/screens/base/GlobalTasksTab.tsx +0 -161
@@ -13,6 +13,12 @@ import { getRecentTelegramTurnsFromFs, appendGlobalMessage } from "#core/stores/
13
13
  import { CHANNELS } from "#core/constants/channels.js";
14
14
  import { SUPERAGENT_ACTOR_ID } from "#core/identity/index.js";
15
15
  import { applyNudgeCallback } from "#core/nudge/index.js";
16
+ import { recordDelivery } from "#core/stores/deliveries.js";
17
+ import { silenceMobilityToday } from "#core/mobility/preferences.js";
18
+ import { getMobilityAlert, recordMobilityResponse } from "#core/mobility/state.js";
19
+ import { answerMobilityAlert } from "#core/mobility/answer.js";
20
+ import { doneTask } from "#core/stores/tasks.js";
21
+ import { resolveLang } from "#core/i18n/index.js";
16
22
 
17
23
  /**
18
24
  * The label the user actually tapped, recovered from the keyboard attached to
@@ -52,6 +58,10 @@ export async function handleCallbackQuery(self, callbackQuery) {
52
58
  await handleNudgeCallback(self, callbackQuery);
53
59
  return;
54
60
  }
61
+ if (data.startsWith("apx:mobility:")) {
62
+ await handleMobilityCallback(self, callbackQuery);
63
+ return;
64
+ }
55
65
  const adapter = createTelegramConfirmAdapter({
56
66
  token: resolveBotToken(self.channel),
57
67
  chatId: callbackQuery.message?.chat?.id,
@@ -94,6 +104,98 @@ export async function handleCallbackQuery(self, callbackQuery) {
94
104
  });
95
105
  }
96
106
 
107
+ /**
108
+ * A proximity chip: "voy" / "hoy no" while driving, "hecho" / "todavía no"
109
+ * when the follow-up comes back after the trip. Each one carries the alert id
110
+ * (apx:mobility:<action>:<id>) because the answer has to land on the ONE place
111
+ * it was asked about — the owner can have two of these open at once, and a
112
+ * bare "yes" would close whichever came last.
113
+ */
114
+ export async function handleMobilityAlertCallback(self, callbackQuery, action, alertId) {
115
+ const lang = resolveLang(self.globalConfig);
116
+ const alert = getMobilityAlert(alertId);
117
+ if (!alert) {
118
+ await self._answerCallback({ callback_query_id: callbackQuery.id });
119
+ await clearKeyboard(self, callbackQuery);
120
+ self.log(`telegram[${self.channel.name}] mobility alert ${alertId} is gone`);
121
+ return;
122
+ }
123
+
124
+ // The answer itself lives in core (core/mobility/answer.js) so a tap here
125
+ // and a tap on the car card mean the same thing. This adapter supplies the
126
+ // one piece core cannot have: resolving the project a task lives in.
127
+ const { ack } = answerMobilityAlert(alertId, action, {
128
+ lang,
129
+ closeTask: (target) => {
130
+ const closed = closeAlertTask(self, target);
131
+ if (!closed) self.log(`telegram[${self.channel.name}] mobility task ${target.task_id} not found — nothing closed`);
132
+ return closed;
133
+ },
134
+ });
135
+ await self._answerCallback({ callback_query_id: callbackQuery.id, text: ack });
136
+ await clearKeyboard(self, callbackQuery);
137
+ }
138
+
139
+ /**
140
+ * Close the task the alert was about. The alert stores the project the task
141
+ * came from, so this resolves that project rather than searching every one —
142
+ * two projects can hold tasks with the same short id prefix.
143
+ */
144
+ function closeAlertTask(self, alert) {
145
+ if (!alert.task_id) return false;
146
+ let storagePath = null;
147
+ try {
148
+ storagePath = self.projects.get(alert.project_id)?.storagePath || null;
149
+ } catch {
150
+ storagePath = null;
151
+ }
152
+ if (!storagePath) return false;
153
+ try {
154
+ return Boolean(doneTask(storagePath, alert.task_id, "mobility"));
155
+ } catch (error) {
156
+ self.log(`telegram[${self.channel.name}] could not close task: ${error.message}`);
157
+ return false;
158
+ }
159
+ }
160
+
161
+ export async function handleMobilityCallback(self, callbackQuery) {
162
+ const parts = String(callbackQuery.data || "").split(":");
163
+ const action = parts[2] || "";
164
+ const alertId = parts[3] || "";
165
+ if (alertId) return handleMobilityAlertCallback(self, callbackQuery, action, alertId);
166
+ recordMobilityResponse(action);
167
+ const chatId = callbackQuery.message?.chat?.id;
168
+ let ack = "Listo.";
169
+ let response = "";
170
+ if (action === "later") {
171
+ const project = self.resolveProject();
172
+ const original = String(callbackQuery.message?.text || "recordatorio de viaje").slice(0, 500);
173
+ const id = project?.storagePath ? recordDelivery(project.storagePath, {
174
+ agent: "super_agent",
175
+ agentName: "Roby",
176
+ routine: "mobility-reminder",
177
+ notify: `Recordatorio pospuesto por usuario: ${original}`,
178
+ priority: false,
179
+ project_id: project.id,
180
+ }) : null;
181
+ ack = id ? "Lo guardé para próxima ronda." : "No pude guardar el recordatorio.";
182
+ response = ack;
183
+ } else if (action === "silence") {
184
+ silenceMobilityToday();
185
+ ack = "Sin avisos de viaje por hoy.";
186
+ response = ack;
187
+ } else if (action === "yes" || action === "no") {
188
+ // Retired from the trip card — they asked "¿vas ahora?" and did nothing
189
+ // with the answer. Still handled because cards carrying them are sitting
190
+ // in the chat history on a phone, and a button that answers nothing is
191
+ // worse than an outdated one.
192
+ ack = action === "yes" ? "Marcado: vas ahora." : "Entendido: no vas ahora.";
193
+ }
194
+ await self._answerCallback({ callback_query_id: callbackQuery.id, text: ack });
195
+ await clearKeyboard(self, callbackQuery);
196
+ if (response && chatId) await self._send({ chat_id: chatId, text: response });
197
+ }
198
+
97
199
  /** Best-effort: take the keyboard off a message whose buttons are now dead. */
98
200
  async function clearKeyboard(self, callbackQuery) {
99
201
  const chatId = callbackQuery.message?.chat?.id;
@@ -352,6 +454,7 @@ export async function runResumedTurn(self, ctx) {
352
454
  saTrace,
353
455
  streamedCount: state.streamedCount,
354
456
  lastStreamedText: state.lastStreamedText,
457
+ heldCount: state.heldCount,
355
458
  agentDisplay,
356
459
  extraMeta: { ask_resume: true },
357
460
  });
@@ -17,21 +17,39 @@ import { getRecentTelegramTurnsFromFs, appendGlobalMessage } from "#core/stores/
17
17
  import { compactChannelIfNeeded, agentScopedMemoryBlock } from "#core/memory/index.js";
18
18
  import { readAgents } from "#core/apc/parser.js";
19
19
  import { buildAgentSystem } from "#core/agent/build-agent-system.js";
20
+ import { resolveAgentModel } from "#core/agent/agent-model.js";
20
21
  import { resolveAgentName, SUPERAGENT_ACTOR_ID } from "#core/identity/index.js";
21
22
  import { registerSender, resolveAllowedTools } from "#core/identity/telegram.js";
22
23
  import { buildRelationshipBlock } from "#core/agent/index.js";
24
+ import { authorLine } from "#core/agent/author-line.js";
23
25
  import { CHANNELS } from "#core/constants/channels.js";
24
26
  import { tryResolveSkillCommand } from "#core/agent/skills/trigger.js";
25
27
  import * as askFlow from "./ask.js";
26
- import { telegramAuthorLabel } from "./helpers.js";
28
+ import { telegramAuthorLabel, releaseActiveRequest, isImpatientResend } from "./helpers.js";
27
29
  import { handleIncomingPhoto } from "./inbound/photo.js";
28
30
  import { handleIncomingAudio } from "./inbound/audio.js";
29
31
  import { handleIncomingFile, detectIncomingFile } from "./inbound/file.js";
30
32
  import { buildStreamHandler, runTelegramSuperAgent, telegramErrorText, sendFinalReply, runFollowupTurn } from "./reply.js";
31
33
  import { t, resolveLang } from "#core/i18n/index.js";
34
+ import { isMobilitySilenceCommand, silenceMobilityToday } from "#core/mobility/preferences.js";
32
35
 
33
36
  const nowIso = () => new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
34
37
 
38
+ // One Telegram message = ONE stored record. The media handlers used to append
39
+ // their own row AND rewrite `text`, so dispatch's inbound log stored the same
40
+ // turn a second time: the viewer showed it twice, the current transcript landed
41
+ // in its own history (the media row was already on disk by the time we read it
42
+ // back), and the next turn replayed it twice more. They now return what they
43
+ // archived and this folds it into the single inbound record, so the file
44
+ // metadata (local_path, file_id, …) is not lost with the duplicate.
45
+ function mediaMeta(media) {
46
+ if (!media.length) return {};
47
+ return {
48
+ ...Object.assign({}, ...media.map((m) => m.meta)),
49
+ media_kind: media.length === 1 ? media[0].kind : media.map((m) => m.kind),
50
+ };
51
+ }
52
+
35
53
  export async function handleUpdate(self, u) {
36
54
  self.lastUpdateAt = nowIso();
37
55
 
@@ -72,43 +90,103 @@ export async function handleUpdate(self, u) {
72
90
  // Role-based tool gating for the super-agent path (guests → no tools).
73
91
  const allowedTools = resolveAllowedTools(self.globalConfig, sender);
74
92
 
75
- // Default Interrupt: abort any running request for this chat_id
93
+ // What the user actually typed, needed before the interrupt decision below.
94
+ // Media handlers rewrite it further down; a resend is plain text, so the raw
95
+ // field is enough here.
96
+ let text = msg.text || msg.caption || "";
97
+ if (isMobilitySilenceCommand(text)) silenceMobilityToday();
98
+
99
+ // Default Interrupt: a new message aborts the running turn for this chat —
100
+ // "no, stop, do this instead". Except when the "new" message is the SAME
101
+ // one the turn is already working on: that is the user checking whether a
102
+ // quiet turn is still alive, and aborting it restarts the work from zero
103
+ // (see isImpatientResend). Then we let the running turn finish and say so.
76
104
  if (chat_id) {
77
105
  const prev = self.activeRequests.get(chat_id);
106
+ if (prev && isImpatientResend(prev, text)) {
107
+ const secs = Math.round((Date.now() - prev.startedAt) / 1000);
108
+ self.log(
109
+ `telegram[${self.channel.name}] resend of the in-flight message for chat ${chat_id} ` +
110
+ `(${secs}s in) — keeping the running turn`
111
+ );
112
+ // Logged so the history is honest about what was sent, flagged so the
113
+ // turn that eventually answers knows it was asked twice.
114
+ appendGlobalMessage({
115
+ channel: CHANNELS.TELEGRAM,
116
+ direction: "in",
117
+ type: "user",
118
+ actor_id: msg.from?.id ? String(msg.from.id) : author,
119
+ external_id: String(u.update_id),
120
+ author,
121
+ body: text,
122
+ meta: {
123
+ chat_id,
124
+ user_id: msg.from?.id || null,
125
+ message_id: msg.message_id,
126
+ tg_channel: self.channel.name,
127
+ resend_of_in_flight: true,
128
+ },
129
+ });
130
+ try {
131
+ // Its own words, from the situation — not a canned "please wait".
132
+ const line = await authorLine({
133
+ globalConfig: self.globalConfig,
134
+ instruction:
135
+ `You are ${Math.round(secs / 60) || 1} minute(s) into working on exactly this request ` +
136
+ `and the user just sent it again, which means the quiet made them think you stopped. ` +
137
+ `In ONE short line: you are still on it, and say what you are doing right now. ` +
138
+ `Do not restart, do not apologise at length, do not promise a time.`,
139
+ });
140
+ if (line) await self._send({ chat_id, text: line });
141
+ } catch (e) {
142
+ self.log(`telegram[${self.channel.name}] resend ack failed: ${e.message}`);
143
+ }
144
+ return;
145
+ }
78
146
  if (prev) {
79
147
  self.log(`telegram[${self.channel.name}] interrupting previous request for chat ${chat_id}`);
80
148
  prev.abort();
81
149
  }
82
150
  }
83
151
  const abortCtrl = new AbortController();
152
+ // The turn's own text and start time ride on the controller so the next
153
+ // inbound can tell "do something else" from "are you still there".
154
+ abortCtrl.text = text;
155
+ abortCtrl.startedAt = Date.now();
84
156
  if (chat_id) self.activeRequests.set(chat_id, abortCtrl);
85
157
 
86
- let text = msg.text || msg.caption || "";
87
-
88
158
  // ── Incoming media ────────────────────────────────────────────────────
89
- // Photo and voice/audio each download + archive the file and rewrite `text`
90
- // so the rest of the pipeline treats them like a typed message. The handlers
91
- // live in ./inbound/ to keep this dispatcher focused on routing. Each one
159
+ // Photo, voice/audio and files each download the attachment and rewrite
160
+ // `text` so the rest of the pipeline treats them like a typed message; the
161
+ // file metadata comes back in `media` and is stored on the single inbound
162
+ // record below. The handlers live in ./inbound/ to keep this dispatcher
163
+ // focused on routing. Each one
92
164
  // injects a marker so a caption-less attachment is never an empty turn:
93
165
  // photos an `[image]` marker (plus the pixels, as an attachment, for a
94
166
  // multimodal engine), audio its `[audio]` transcript, files a description
95
167
  // with the local path.
96
168
  const attachments = [];
169
+ const media = []; // what the handlers downloaded, folded into the inbound record below
97
170
  if (msg.photo && msg.photo.length > 0) {
98
- let attachment;
99
- ({ text, attachment } = await handleIncomingPhoto(self, { msg, u, author, chat_id, text }));
171
+ let attachment, archived;
172
+ ({ text, attachment, media: archived } = await handleIncomingPhoto(self, { msg, text }));
100
173
  if (attachment) attachments.push(attachment);
174
+ if (archived) media.push(archived);
101
175
  }
102
176
  const incomingAudio = msg.voice || msg.audio;
103
177
  if (incomingAudio && incomingAudio.file_id) {
104
- ({ text } = await handleIncomingAudio(self, { msg, u, author, chat_id, text, incomingAudio }));
178
+ let archived;
179
+ ({ text, media: archived } = await handleIncomingAudio(self, { chat_id, text, incomingAudio }));
180
+ if (archived) media.push(archived);
105
181
  }
106
182
  // Documents, video, video notes and GIFs. Without this a file sent with no
107
183
  // caption left `text` empty, the turn was dropped, and the bot answered
108
184
  // nothing at all.
109
185
  const incomingFile = detectIncomingFile(msg);
110
186
  if (incomingFile) {
111
- ({ text } = await handleIncomingFile(self, { msg, u, author, chat_id, text, incoming: incomingFile }));
187
+ let archived;
188
+ ({ text, media: archived } = await handleIncomingFile(self, { text, incoming: incomingFile }));
189
+ if (archived) media.push(archived);
112
190
  }
113
191
 
114
192
  // If there's a pending ask_questions flow for this chat AND the current
@@ -125,6 +203,7 @@ export async function handleUpdate(self, u) {
125
203
  author,
126
204
  body: text,
127
205
  meta: {
206
+ ...mediaMeta(media),
128
207
  chat_id,
129
208
  user_id: msg.from?.id || null,
130
209
  message_id: msg.message_id,
@@ -188,6 +267,7 @@ export async function handleUpdate(self, u) {
188
267
  author,
189
268
  body: text,
190
269
  meta: {
270
+ ...mediaMeta(media),
191
271
  chat_id,
192
272
  user_id: msg.from?.id || null,
193
273
  message_id: msg.message_id,
@@ -197,20 +277,37 @@ export async function handleUpdate(self, u) {
197
277
 
198
278
  // Super-agent is ALWAYS active on Telegram: respond_with_engine === false
199
279
  // used to silently drop user messages, which looked to the user like the
200
- // bot ignored them. Honour the legacy flag only as a soft hint (skip the
280
+ // bot ignored them. Honour the flag only as a soft hint (skip the
201
281
  // routed-agent shortcut so we fall straight to super-agent) but never let
202
282
  // it short-circuit the whole reply. To genuinely silence the bot, disable
203
283
  // the channel entirely (telegram.enabled = false in config).
204
284
  const skipRoutedAgent = self.channel.respond_with_engine === false;
205
285
  if (!text) return;
206
286
 
207
- // Short-circuit /reset / /new: send an ack and don't engage the engine.
208
- // The marker we just logged is enough getRecentTelegramTurns will
209
- // honor it for future messages.
287
+ // Short-circuit /reset / /new: confirm and stop. No turn runs the one
288
+ // model call below writes the confirmation itself, it does not answer the
289
+ // command. The marker we just logged is enough — getRecentTelegramTurns
290
+ // will honor it for future messages.
210
291
  if (isReset) {
211
292
  try {
212
- const ack = t("telegram.reset_ack", { lang: resolveLang(self.globalConfig) });
293
+ // The ack is ours to trigger, not to word: the model writes it, and the
294
+ // canned line is only what goes out if it can't (engine down, no model
295
+ // configured). See core/agent/author-line.js.
296
+ const lang = resolveLang(self.globalConfig);
297
+ // Writing it takes a second or two, which on a chat reads as nothing
298
+ // happening — the same indicator a normal turn puts up covers it.
299
+ const stopAckTyping = self._startTyping(chat_id);
300
+ let ack;
301
+ try {
302
+ ack = (await authorLine({
303
+ globalConfig: self.globalConfig,
304
+ instruction: "The user just cleared this conversation — from here you remember none of it and the thread starts fresh. Confirm that in one line and invite what comes next.",
305
+ })) || t("telegram.reset_ack", { lang });
306
+ } finally {
307
+ stopAckTyping();
308
+ }
213
309
  await self._send({ chat_id, text: ack });
310
+ // attribution-exempt: /reset ack — a short model-authored line whose attribution the ack path does not surface.
214
311
  appendGlobalMessage({
215
312
  channel: CHANNELS.TELEGRAM,
216
313
  direction: "out",
@@ -231,6 +328,11 @@ export async function handleUpdate(self, u) {
231
328
  // Start "typing..." indicator. Stops when we send the reply (or fail).
232
329
  const stopTyping = self._startTyping(chat_id);
233
330
 
331
+ // Detach the model turn from the poll loop. Awaiting it here used to freeze
332
+ // getUpdates for the whole run, so a newer Telegram message could never
333
+ // abort this one — Default Interrupt existed, but never fired.
334
+ const replyTurn = (async () => {
335
+
234
336
  // Preset to the super-agent defaults so every exit path (including one where
235
337
  // neither the routed-agent nor the super-agent branch runs) has a valid
236
338
  // actor — the routed-agent / super-agent branches override these on success,
@@ -242,16 +344,20 @@ export async function handleUpdate(self, u) {
242
344
  let replyModel = null; // model that actually produced the reply
243
345
  let replyUsage = null; // token accounting for this turn
244
346
  let replyTrace = null; // what the turn actually did (summarised on the message)
347
+ let replyJudge = null; // verdict trail, when the turn was continued past a stop
245
348
  const projectCfg = target.config || self.globalConfig;
246
349
  // Display name for the super-agent persona on this channel (from identity.json).
247
350
  const agentDisplay = resolveAgentName(self.globalConfig);
248
351
 
249
- // Try the project's chosen agent first (skipped if the legacy
352
+ // Try the project's chosen agent first (skipped when the
250
353
  // respond_with_engine === false hint asked to bypass routed agents).
251
354
  const routeSlug = skipRoutedAgent ? null : self.channel.route_to_agent;
252
355
  if (routeSlug) {
253
356
  const agent = readAgents(target.path).find((a) => a.slug === routeSlug);
254
- if (agent && agent.fields.Model) {
357
+ // An agent that inherits its model is still usable: the router resolves
358
+ // one for it, same as a direct chat.
359
+ const agentModel = agent ? await resolveAgentModel({ agent, config: projectCfg }) : null;
360
+ if (agent && agentModel) {
255
361
  try {
256
362
  const scopedMemory = await agentScopedMemoryBlock(text, { project: target, agent, config: projectCfg });
257
363
  const system = buildAgentSystem(target, agent, {
@@ -261,18 +367,19 @@ export async function handleUpdate(self, u) {
261
367
  extraParts: [relationshipBlock, scopedMemory].filter(Boolean),
262
368
  });
263
369
  const result = await callEngine({
264
- modelId: agent.fields.Model,
370
+ modelId: agentModel,
265
371
  system,
266
372
  messages: [{ role: "user", content: text }],
267
373
  config: projectCfg,
374
+ signal: abortCtrl.signal,
268
375
  });
269
376
  replyText = result.text;
270
377
  replyAuthor = agent.slug;
271
378
  replyActorId = agent.slug;
272
379
  replyKind = "agent";
273
- // Fully-qualified id from the agent card (provider:model) — callEngine
274
- // resolves it internally and doesn't hand it back.
275
- replyModel = agent.fields.Model;
380
+ // Fully-qualified id (provider:model) — callEngine resolves it
381
+ // internally and doesn't hand it back.
382
+ replyModel = agentModel;
276
383
  replyUsage = result.usage || null;
277
384
  } catch (e) {
278
385
  self.log(`telegram[${self.channel.name}] agent reply failed: ${e.message}`);
@@ -293,13 +400,15 @@ export async function handleUpdate(self, u) {
293
400
  }
294
401
  }
295
402
 
296
- // Fallback: super-agent — STREAMED. Each iteration's assistant text is sent
297
- // to Telegram as its own message the moment the model produces it; tool
298
- // calls are logged but never sent (internal). The streamed turn + its final
299
- // send live in ./reply.js so this dispatcher and the ask-flow resume
403
+ // Fallback: super-agent — STREAMED, but not narrated step by step. One
404
+ // notice goes out when work starts, the notes before every later step are
405
+ // held (./progress-gate.js), and the closing message carries the result;
406
+ // tool calls are logged but never sent (internal). The streamed turn + its
407
+ // final send live in ./reply.js so this dispatcher and the ask-flow resume
300
408
  // (_runResumedTurn in the host poller) share ONE reply path — no drift.
301
409
  let streamedCount = 0;
302
410
  let lastStreamedText = "";
411
+ let heldCount = 0;
303
412
  if (!replyText && isSuperAgentEnabled(self.globalConfig)) {
304
413
  const { onEvent, state } = buildStreamHandler(self, { chat_id, update_id: u.update_id, agentDisplay });
305
414
 
@@ -351,6 +460,7 @@ export async function handleUpdate(self, u) {
351
460
  replyKind = "superagent";
352
461
  replyUsage = sa.usage;
353
462
  replyTrace = sa.trace || null;
463
+ replyJudge = sa.judge || null;
354
464
  replyModel = sa.model || state.model || null;
355
465
 
356
466
  // ── ask_questions integration ────────────────────────────────────
@@ -360,7 +470,7 @@ export async function handleUpdate(self, u) {
360
470
  // (via _runResumedTurn) once every answer is collected.
361
471
  const askQuestions = askFlow.extractAskQuestionsFromTrace(sa.trace);
362
472
  if (askQuestions && chat_id) {
363
- self.activeRequests.delete(chat_id);
473
+ releaseActiveRequest(self.activeRequests, chat_id, abortCtrl);
364
474
  stopTyping();
365
475
  try {
366
476
  await self._startAskFlow({
@@ -383,12 +493,13 @@ export async function handleUpdate(self, u) {
383
493
  }
384
494
  streamedCount = state.streamedCount;
385
495
  lastStreamedText = state.lastStreamedText;
496
+ heldCount = state.heldCount;
386
497
  } catch (e) {
387
498
  if (abortCtrl.signal.aborted) {
388
499
  // A newer message superseded this one. Whatever streamed so far is
389
500
  // already sent + logged; the newer message's run continues the thread.
390
501
  self.log(`telegram[${self.channel.name}] request aborted for chat ${chat_id}`);
391
- if (chat_id) self.activeRequests.delete(chat_id);
502
+ releaseActiveRequest(self.activeRequests, chat_id, abortCtrl);
392
503
  stopTyping();
393
504
  return;
394
505
  }
@@ -402,7 +513,13 @@ export async function handleUpdate(self, u) {
402
513
  }
403
514
  }
404
515
 
405
- if (chat_id) self.activeRequests.delete(chat_id);
516
+ if (abortCtrl.signal.aborted) {
517
+ self.log(`telegram[${self.channel.name}] request aborted for chat ${chat_id}`);
518
+ releaseActiveRequest(self.activeRequests, chat_id, abortCtrl);
519
+ stopTyping();
520
+ return;
521
+ }
522
+ releaseActiveRequest(self.activeRequests, chat_id, abortCtrl);
406
523
  stopTyping();
407
524
  await sendFinalReply(self, {
408
525
  chat_id,
@@ -416,7 +533,14 @@ export async function handleUpdate(self, u) {
416
533
  saTrace: replyTrace,
417
534
  streamedCount,
418
535
  lastStreamedText,
536
+ heldCount,
419
537
  agentDisplay,
538
+ // Recoverable after the fact: this turn ran longer because a verdict said
539
+ // it wasn't finished, not because the model rambled.
540
+ extraMeta: replyJudge ? { judge: replyJudge } : {},
541
+ });
542
+ })();
543
+ replyTurn.catch((e) => {
544
+ self.log(`telegram[${self.channel.name}] reply turn crashed: ${e.message}`);
420
545
  });
421
546
  }
422
-
@@ -76,7 +76,7 @@ export function loadState() {
76
76
  if (!fs.existsSync(TELEGRAM_STATE_PATH)) return { channels: {} };
77
77
  try {
78
78
  const raw = JSON.parse(fs.readFileSync(TELEGRAM_STATE_PATH, "utf8"));
79
- return { channels: raw.channels || {}, _legacy_offset: raw.offset || 0 };
79
+ return { channels: raw.channels || {} };
80
80
  } catch {
81
81
  return { channels: {} };
82
82
  }
@@ -116,8 +116,9 @@ export function tokenSource(channel) {
116
116
  }
117
117
 
118
118
  /**
119
- * Resolve the list of telegram channels to poll, honouring both the
120
- * canonical telegram.channels[] and the legacy single-channel mode.
119
+ * Resolve the list of telegram channels to poll. Credentials live in
120
+ * telegram.channels[]; with none configured we fall back to a single implicit
121
+ * "default" channel whose token/chat id come from the environment.
121
122
  */
122
123
  export function resolveChannels(globalConfig) {
123
124
  const tg = globalConfig.telegram || {};
@@ -135,15 +136,17 @@ export function resolveChannels(globalConfig) {
135
136
  poll_interval_ms: c.poll_interval_ms || tg.poll_interval_ms || 1500,
136
137
  }));
137
138
  }
138
- // Legacy single-channel mode
139
- if (!tg.bot_token && !process.env.BOT_TELEGRAM_TOKEN && !process.env.TELEGRAM_BOT_TOKEN) {
139
+ // Env-only mode: no channels configured, but a token is in the environment.
140
+ // resolveBotToken()/resolveChatId() fill the blanks from BOT_TELEGRAM_TOKEN
141
+ // / TELEGRAM_CHAT_ID at call time.
142
+ if (!process.env.BOT_TELEGRAM_TOKEN && !process.env.TELEGRAM_BOT_TOKEN) {
140
143
  return [];
141
144
  }
142
145
  return [
143
146
  {
144
147
  name: "default",
145
- bot_token: tg.bot_token || "",
146
- chat_id: tg.chat_id || "",
148
+ bot_token: "",
149
+ chat_id: "",
147
150
  route_to_agent: tg.route_to_agent || "",
148
151
  project: null,
149
152
  respond_with_engine: tg.respond_with_engine !== false,
@@ -155,3 +158,52 @@ export function resolveChannels(globalConfig) {
155
158
  export function sleep(ms) {
156
159
  return new Promise((resolve) => setTimeout(resolve, ms));
157
160
  }
161
+
162
+ /**
163
+ * Drop this chat's AbortController only if it is still the one we own.
164
+ * An aborted turn used to `activeRequests.delete(chat_id)` unconditionally,
165
+ * which wiped the NEWER turn's controller and made the next interrupt a no-op.
166
+ */
167
+ export function releaseActiveRequest(activeRequests, chat_id, abortCtrl) {
168
+ if (chat_id && activeRequests.get(chat_id) === abortCtrl) {
169
+ activeRequests.delete(chat_id);
170
+ }
171
+ }
172
+
173
+ // Below this, a resend of the same text is impatience, not a new instruction.
174
+ // Past it, the run has been going long enough that "again" plausibly means
175
+ // "that is stuck, start over" — so the interrupt goes through as usual.
176
+ const RESEND_WINDOW_MS = 10 * 60_000;
177
+
178
+ /** Comparable form of a chat message: case, accents and punctuation dropped. */
179
+ function normalizeForResend(text) {
180
+ return String(text || "")
181
+ .toLowerCase()
182
+ .normalize("NFD")
183
+ .replace(/[\u0300-\u036f]/g, "")
184
+ .replace(/[^\p{L}\p{N}]+/gu, " ")
185
+ .trim();
186
+ }
187
+
188
+ /**
189
+ * Is this inbound the SAME message the chat is already working on?
190
+ *
191
+ * Default Interrupt aborts the running turn on every new message, which is
192
+ * right for "no, stop, do this instead" and exactly wrong for the case that
193
+ * actually happens: a long turn goes quiet (one progress note per 90s), the
194
+ * user assumes it died and sends the same request again. The resend killed the
195
+ * work in flight and restarted it from zero — so the next one looked stuck too.
196
+ * Six resends of one message in 35 minutes, and nothing ever finished.
197
+ *
198
+ * A verbatim repeat inside the window is treated as "still here?", not as a new
199
+ * turn: the running work keeps its abort controller and finishes.
200
+ *
201
+ * @returns {boolean} true when the caller should let the running turn continue.
202
+ */
203
+ export function isImpatientResend(prev, text, { now = Date.now } = {}) {
204
+ if (!prev?.text) return false;
205
+ const incoming = normalizeForResend(text);
206
+ if (!incoming) return false;
207
+ if (incoming !== normalizeForResend(prev.text)) return false;
208
+ return now() - (prev.startedAt || 0) < RESEND_WINDOW_MS;
209
+ }
@@ -6,19 +6,22 @@
6
6
  //
7
7
  // Takes the poller instance (`self`, for logging, channel + the typing
8
8
  // indicator) plus the parsed update context, and returns the `text` the rest of
9
- // the pipeline should run — the transcript merged into any existing caption.
10
- import { appendGlobalMessage } from "#core/stores/messages.js";
11
- import { CHANNELS } from "#core/constants/channels.js";
9
+ // the pipeline should run — the transcript merged into any existing caption
10
+ // plus the `media` metadata dispatch folds into the ONE record it writes for
11
+ // this update. This handler deliberately writes nothing itself: it used to
12
+ // append its own row while also rewriting `text`, so the same turn was stored
13
+ // twice (see dispatch.js).
12
14
  import { transcribe as transcribeAudioFile } from "#core/voice/transcription.js";
13
15
  import { resolveBotToken, telegramMediaDir } from "../helpers.js";
14
16
  import { downloadTelegramFile } from "../media.js";
15
17
 
16
18
  /**
17
19
  * @param {object} self poller instance (uses self.log, self.channel, self._startTyping)
18
- * @param {object} ctx { msg, u, author, chat_id, text, incomingAudio }
19
- * @returns {Promise<{ text: string }>} text to continue the pipeline with
20
+ * @param {object} ctx { chat_id, text, incomingAudio }
21
+ * @returns {Promise<{ text: string, media: object }>} text to continue the
22
+ * pipeline with, and what was archived for the inbound record
20
23
  */
21
- export async function handleIncomingAudio(self, { msg, u, author, chat_id, text, incomingAudio }) {
24
+ export async function handleIncomingAudio(self, { chat_id, text, incomingAudio }) {
22
25
  const token = resolveBotToken(self.channel);
23
26
  const mediaDir = telegramMediaDir();
24
27
 
@@ -53,30 +56,23 @@ export async function handleIncomingAudio(self, { msg, u, author, chat_id, text,
53
56
  ? `[audio] ${transcript}`
54
57
  : `[audio] (transcription unavailable${transcribeError ? ": " + transcribeError : ""})`;
55
58
 
56
- appendGlobalMessage({
57
- channel: CHANNELS.TELEGRAM,
58
- direction: "in",
59
- type: "audio",
60
- actor_id: msg.from?.id ? String(msg.from.id) : author,
61
- external_id: String(u.update_id),
62
- author,
63
- body: audioBody,
64
- meta: {
65
- chat_id,
66
- user_id: msg.from?.id || null,
67
- message_id: msg.message_id,
68
- tg_channel: self.channel.name,
69
- local_path: localPath,
70
- file_id: incomingAudio.file_id,
71
- duration: incomingAudio.duration,
72
- mime_type: incomingAudio.mime_type,
73
- transcription_backend: transcribeBackend,
74
- transcription_error: transcribeError,
75
- },
76
- });
77
-
78
59
  // Inject the transcribed text into `text` so the rest of the agent pipeline
79
60
  // treats it identically to a typed message. If there was a caption alongside
80
- // the audio, prepend the audio marker to it.
81
- return { text: text ? `${audioBody}\n${text}` : audioBody };
61
+ // the audio, prepend the audio marker to it. The file metadata rides back
62
+ // with it so the stored turn keeps it, download or transcription failures
63
+ // included.
64
+ return {
65
+ text: text ? `${audioBody}\n${text}` : audioBody,
66
+ media: {
67
+ kind: "audio",
68
+ meta: {
69
+ local_path: localPath,
70
+ file_id: incomingAudio.file_id,
71
+ duration: incomingAudio.duration,
72
+ mime_type: incomingAudio.mime_type,
73
+ transcription_backend: transcribeBackend,
74
+ transcription_error: transcribeError,
75
+ },
76
+ },
77
+ };
82
78
  }