@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
@@ -6,14 +6,58 @@
6
6
  // POST /projects/:pid/agents/:slug/compact
7
7
  // POST /projects/:pid/agents/:slug/conversations/:id/compact
8
8
  // POST /projects/:pid/send (agent-to-agent)
9
+ import fs from "node:fs";
9
10
  import { readAgents } from "#core/apc/parser.js";
10
- import { listConversations, readConversation, deleteConversation } from "#core/stores/conversations.js";
11
- import { listGlobalThreads, readGlobalThread, deleteGlobalThread } from "#core/stores/messages.js";
11
+ import { listConversations, readConversation, deleteConversation, truncateConversation, setConversationMeta, shapeConversationMessage } from "#core/stores/conversations.js";
12
+ import { listGlobalThreads, readGlobalThread, deleteGlobalThread, setGlobalThreadMeta, listProjectA2AThreads, readProjectA2AThread, listProjectGroupThreads, readProjectGroupThread, deleteGroupThread, deleteA2AThread, readProjectMessages, readA2APeerSession, dedupA2A } from "#core/stores/messages.js";
13
+ import { shortId } from "#core/util/ids.js";
14
+
15
+ // Prior turns of an a2a thread between `from` and `to`, oldest→newest, shaped as
16
+ // LLM messages from `viewer`'s side (its own lines = assistant, the peer's =
17
+ // user). This is what gives an a2a reply MEMORY: without it every --deliver is a
18
+ // stateless one-shot and the agent forgets the previous turn. Loaded BEFORE the
19
+ // current message is logged, so it excludes it.
20
+ function a2aPairHistory(storageRoot, from, to, viewer, limit = 24) {
21
+ const pair = new Set([from, to]);
22
+ const rows = readProjectMessages(storageRoot, { channel: "a2a", limit: 300 }).filter((m) => {
23
+ const parts = [m.agent_slug, m.author, m.meta?.from, m.meta?.to].filter(Boolean);
24
+ return parts.length > 0 && parts.every((s) => pair.has(s));
25
+ });
26
+ return dedupA2A(rows)
27
+ .sort((a, b) => (a.ts || "").localeCompare(b.ts || ""))
28
+ .slice(-limit)
29
+ .map((m) =>
30
+ m.author === viewer
31
+ ? { role: "assistant", content: m.body || "" }
32
+ : { role: "user", content: `From ${m.author}:\n\n${m.body || ""}` },
33
+ );
34
+ }
35
+ /** The sender's working directory, if it still is one. This is untrusted input
36
+ * naming a directory we are about to spawn a coding CLI in, so it gets checked
37
+ * rather than believed; anything else falls back to the project path. */
38
+ function senderCwd(raw) {
39
+ if (!raw || typeof raw !== "string") return null;
40
+ try {
41
+ return fs.statSync(raw).isDirectory() ? raw : null;
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+
12
47
  import { compactConversation } from "#core/stores/conversations-compactor.js";
13
- import { replyAsAgent } from "#core/agent/a2a/reply.js";
14
- import { nowIso, asyncRoute } from "./shared.js";
48
+ import { getActiveTurnByKey, convTurnKey, superAgentTurnKey } from "../active-turns.js";
49
+ import { replyToPeer } from "#core/agent/a2a/reply.js";
50
+ import { resolvePeer, peerAddress, refusesCodeMode, NO_CODE_PEERS } from "#core/agent/a2a/peers.js";
51
+ import { createCodeSession, getCodeSession, appendTurn as appendCodeTurn } from "#core/stores/code-sessions.js";
52
+ import { CODE_MODES } from "#core/constants/code-modes.js";
53
+ import { RUNTIME_IDS } from "#core/runtimes/index.js";
54
+ import { resolveAgentModel } from "#core/agent/agent-model.js";
55
+ import { notifyOwnerViaRoby } from "#core/routines/delivery.js";
56
+ import { A2A_SEVERITY } from "#core/routines/signals.js";
57
+ import { nowIso, asyncRoute, a2aSlugThreadId, rejectA2AWrite } from "./shared.js";
58
+ import { faceResolverFor, readAgentsSafe } from "./thread-faces.js";
15
59
 
16
- export function register(api, { project, config }) {
60
+ export function register(api, { projects, project, config, plugins, registries }) {
17
61
  // The super-agent (default name "apx") is a pseudo-agent: it owns
18
62
  // conversations per project but is NOT listed in AGENTS.md. Resolve its slug
19
63
  // so `apx conversations list` (which defaults to the super-agent) works
@@ -22,38 +66,131 @@ export function register(api, { project, config }) {
22
66
  const agentResolvable = (p, slug) =>
23
67
  slug === superAgentSlug() || readAgents(p.path).some((a) => a.slug === slug);
24
68
 
69
+ // The inbox lists a2a "group chats" under a SYNTHETIC slug, `a2a:<pairId>`
70
+ // (see api/inbox.js) — a pair exchange is nobody's individual conversation,
71
+ // so it has no agents/<slug>/conversations/ directory. Those rows are opened
72
+ // through this same per-agent surface, so unless the slug resolves here every
73
+ // a2a row in the inbox dead-ends on "agent not found".
74
+ //
75
+ // NOT a URL-parsing problem: Express hands `a2a:cursor~roby` through intact,
76
+ // percent-encoded or not (verified both ways against the running daemon).
77
+ // The id was reaching the handler fine; there was simply no code path that
78
+ // could read a pair thread. `readProjectA2AThread` already existed and
79
+ // already returns the viewer's shape — it was never wired to a route.
80
+
25
81
  api.get("/projects/:pid/agents/:slug/conversations", (req, res) => {
26
82
  const p = project(req, res);
27
83
  if (!p) return;
84
+ const listA2A = a2aSlugThreadId(req.params.slug);
85
+ if (listA2A !== null) {
86
+ const found = listProjectA2AThreads(p.storagePath).find((t) => t.id === listA2A);
87
+ const th = found && faceResolverFor(projects).decorate(found, readAgentsSafe(p.path));
88
+ // One pair id is one thread. Shaped like a conversation summary so the
89
+ // sidebar renders it beside the ordinary ones.
90
+ return res.json(th ? [{
91
+ id: th.id,
92
+ filename: `${th.id}.a2a`,
93
+ agent_slug: req.params.slug,
94
+ started_at: th.started_at || "",
95
+ last_turn_at: th.last_ts || th.started_at || "",
96
+ channel: "a2a",
97
+ messages: th.messages,
98
+ title: th.title,
99
+ participants: th.participants,
100
+ participant_faces: th.participant_faces,
101
+ preview: th.preview || undefined,
102
+ preview_at: th.last_ts || undefined,
103
+ }] : []);
104
+ }
105
+ if (!agentResolvable(p, req.params.slug))
106
+ return res.status(404).json({ error: "agent not found" });
107
+ res.json(
108
+ listConversations(p.storagePath, req.params.slug, {
109
+ includeArchived: req.query.include_archived === "1",
110
+ }).map((conversation) => ({
111
+ ...conversation,
112
+ active_turn: getActiveTurnByKey(convTurnKey(p.id, conversation.id)),
113
+ })),
114
+ );
115
+ });
116
+
117
+ // Rename, or put away. Archiving is the smaller decision — the file stays
118
+ // exactly where it is and only drops out of the lists that offer chats to
119
+ // resume, so it stays a decision you can take back.
120
+ api.patch("/projects/:pid/agents/:slug/conversations/:id", (req, res) => {
121
+ const p = project(req, res);
122
+ if (!p) return;
123
+ // An a2a thread is derived from the message ledger, not a file with
124
+ // frontmatter, so there is nothing to rename or archive. Say that, rather
125
+ // than the misleading "agent not found" this used to answer.
126
+ if (rejectA2AWrite(req, res, "renamed or archived")) return;
28
127
  if (!agentResolvable(p, req.params.slug))
29
128
  return res.status(404).json({ error: "agent not found" });
30
- res.json(listConversations(p.storagePath, req.params.slug));
129
+ const { title, archived } = req.body || {};
130
+ if (title === undefined && archived === undefined)
131
+ return res.status(400).json({ error: "nothing to change" });
132
+ const ok = setConversationMeta(p.storagePath, req.params.slug, req.params.id, {
133
+ ...(title !== undefined ? { title } : {}),
134
+ ...(archived !== undefined ? { archived: !!archived } : {}),
135
+ });
136
+ if (!ok) return res.status(404).json({ error: "conversation not found" });
137
+ res.json({ ok: true });
31
138
  });
32
139
 
33
140
  api.get("/projects/:pid/agents/:slug/conversations/:id", (req, res) => {
34
141
  const p = project(req, res);
35
142
  if (!p) return;
143
+ const detailA2A = a2aSlugThreadId(req.params.slug);
144
+ if (detailA2A !== null) {
145
+ const found = readProjectA2AThread(p.storagePath, detailA2A || req.params.id);
146
+ if (!found) return res.status(404).json({ error: "conversation not found" });
147
+ const th = faceResolverFor(projects).decorate(found, readAgentsSafe(p.path));
148
+ return res.json({
149
+ id: th.id,
150
+ agent_slug: req.params.slug,
151
+ channel: "a2a",
152
+ messages: th.messages,
153
+ meta: {
154
+ channel: "a2a",
155
+ title: th.title,
156
+ participants: th.participants,
157
+ participant_faces: th.participant_faces,
158
+ },
159
+ });
160
+ }
36
161
  const conv = readConversation(p.storagePath, req.params.slug, req.params.id);
37
162
  if (!conv) return res.status(404).json({ error: "conversation not found" });
38
163
  // Shape the response as the `ConversationDetail` the web client expects:
39
164
  // `messages[]` (mapped from the parsed `turns`) + id/agent/channel. Without
40
165
  // this the client's `detail.messages.filter(...)` throws on every load.
166
+ //
167
+ // `active_turn` is the turn being written RIGHT NOW, if any — so a surface
168
+ // opening (or re-opening) this chat mid-answer shows the partial and then
169
+ // follows the live "turn" frames, instead of a blank pane that fills all at
170
+ // once when the turn happens to finish.
41
171
  res.json({
42
172
  id: req.params.id,
43
173
  agent_slug: req.params.slug,
44
174
  channel: conv.fm?.channel,
45
- messages: (conv.turns || []).map((t) => ({
46
- role: t.role,
47
- content: t.content,
48
- ts: t.ts,
49
- })),
175
+ messages: (conv.turns || []).map(shapeConversationMessage),
50
176
  meta: conv.fm || {},
177
+ active_turn: getActiveTurnByKey(convTurnKey(p.id, req.params.id)),
51
178
  });
52
179
  });
53
180
 
54
181
  api.delete("/projects/:pid/agents/:slug/conversations/:id", (req, res) => {
55
182
  const p = project(req, res);
56
183
  if (!p) return;
184
+ // Deleting IS something an a2a thread can do — it is the one write on this
185
+ // surface that has a meaning for a derived thread, so it delegates to the
186
+ // pair delete instead of refusing. The refusals left below (rename, archive,
187
+ // compact, chat) are the ones with nothing to act on.
188
+ const delA2A = a2aSlugThreadId(req.params.slug);
189
+ if (delA2A !== null) {
190
+ const out = deleteA2AThread(p.storagePath, delA2A || req.params.id);
191
+ if (!out.removed) return res.status(404).json({ error: "conversation not found" });
192
+ return res.json({ ok: true, ...out });
193
+ }
57
194
  if (!agentResolvable(p, req.params.slug))
58
195
  return res.status(404).json({ error: "agent not found" });
59
196
  const ok = deleteConversation(p.storagePath, req.params.slug, req.params.id);
@@ -61,32 +198,144 @@ export function register(api, { project, config }) {
61
198
  res.json({ ok: true });
62
199
  });
63
200
 
201
+ // Rewind a conversation to its first `turns` turns, dropping the rest. Backs
202
+ // "regenerate" and "edit & resend": the pane rewinds to a turn and the file
203
+ // must rewind with it, or a project agent (whose history the daemon rebuilds
204
+ // from this file) would keep answering with the dropped turns still present.
205
+ api.post("/projects/:pid/agents/:slug/conversations/:id/truncate", (req, res) => {
206
+ const p = project(req, res);
207
+ if (!p) return;
208
+ if (rejectA2AWrite(req, res, "truncated")) return;
209
+ if (!agentResolvable(p, req.params.slug))
210
+ return res.status(404).json({ error: "agent not found" });
211
+ const keepVisible = Number(req.body?.keep_visible);
212
+ if (!Number.isInteger(keepVisible) || keepVisible < 0)
213
+ return res.status(400).json({ error: "keep_visible must be a non-negative integer" });
214
+ const ok = truncateConversation(p.storagePath, req.params.slug, req.params.id, { keepVisible });
215
+ if (!ok) return res.status(404).json({ error: "conversation not found" });
216
+ res.json({ ok: true });
217
+ });
218
+
64
219
  // ---- Super-agent channel threads ----
65
220
  // The super-agent's chats (telegram, web quick-chat, desktop, deck …) live
66
221
  // in the global per-channel ledger, not in per-agent conversation files.
67
222
  // These endpoints surface that ledger as day-threads so the web Chats
68
223
  // sidebar can list and reopen them.
224
+ //
225
+ // Scope: each project lists only the super-agent chats that happened in it.
226
+ // The default workspace (project 0) additionally owns every unstamped turn —
227
+ // Telegram, desktop and deck have no project of their own, so that is where
228
+ // those conversations live. Passing `undefined` for project 0, as this used
229
+ // to, means "no filter", and the unstamped-rows-belong-everywhere rule it
230
+ // paired with then listed the same ~90 Telegram threads under every project.
231
+ // Channel grouping is untouched: a project with its own Telegram routing
232
+ // still gets a Telegram group holding just its chats.
233
+ const threadScope = (p) => String(p.id);
234
+
69
235
  api.get("/projects/:pid/super-agent/threads", (req, res) => {
70
236
  const p = project(req, res);
71
237
  if (!p) return;
72
- res.json(listGlobalThreads());
238
+ // Global channel threads (telegram/web/desktop…) live in the cross-project
239
+ // ledger; a2a "group chats" are project-scoped, so they come from this
240
+ // project's own messages. Both fold into the same channel-grouped sidebar.
241
+ const global = listGlobalThreads({
242
+ project: threadScope(p),
243
+ includeArchived: req.query.include_archived === "1",
244
+ }).map((thread) => {
245
+ const active = getActiveTurnByKey(superAgentTurnKey(p.id, thread.channel));
246
+ return {
247
+ ...thread,
248
+ active_turn: active?.thread_id === thread.id ? active : null,
249
+ };
250
+ });
251
+ let a2a = [];
252
+ try { a2a = listProjectA2AThreads(p.storagePath); } catch { /* best-effort */ }
253
+ let groups = [];
254
+ try { groups = listProjectGroupThreads(p.storagePath); } catch { /* best-effort */ }
255
+ // a2a and group threads carry their participants' faces and a title made of
256
+ // real names — the same decoration the inbox rows get, from the same
257
+ // resolver (thread-faces.js). Without it the sidebar had to re-derive faces
258
+ // from its own agent list (which does not know the super-agent or a coding
259
+ // CLI) and the thread header, having no list at all, fell back to printing
260
+ // the raw pair id: `andy~claude-code` where "Andy · Claude" belongs.
261
+ const faces = faceResolverFor(projects);
262
+ const agents = readAgentsSafe(p.path);
263
+ const decorated = [...a2a, ...groups].map((th) => faces.decorate(th, agents));
264
+ res.json([...global, ...decorated]);
73
265
  });
74
266
 
75
267
  api.get("/projects/:pid/super-agent/threads/:channel/:id", (req, res) => {
76
268
  const p = project(req, res);
77
269
  if (!p) return;
78
- const thread = readGlobalThread({
270
+ // a2a threads are keyed by participant-pair id, not a date — read them from
271
+ // the project ledger; everything else is a global channel+date thread.
272
+ const thread = req.params.channel === "a2a"
273
+ ? readProjectA2AThread(p.storagePath, req.params.id)
274
+ : req.params.channel === "group"
275
+ ? readProjectGroupThread(p.storagePath, req.params.id)
276
+ : readGlobalThread({
277
+ channel: req.params.channel,
278
+ date: req.params.id,
279
+ project: threadScope(p),
280
+ });
281
+ if (!thread) return res.status(404).json({ error: "thread not found" });
282
+ // Same decoration as the list: whoever opens a thread directly (a deep link,
283
+ // the phone, a pane that was handed no row) gets the faces and the name with
284
+ // the messages, instead of having to ask a second surface for them.
285
+ const decorated = faceResolverFor(projects).decorate(thread, readAgentsSafe(p.path));
286
+ const active = req.params.channel === "a2a" || req.params.channel === "group"
287
+ ? null
288
+ : getActiveTurnByKey(superAgentTurnKey(p.id, req.params.channel));
289
+ res.json({
290
+ ...decorated,
291
+ active_turn: active?.thread_id === req.params.id ? active : null,
292
+ });
293
+ });
294
+
295
+ api.delete("/projects/:pid/super-agent/threads/:channel/:id", (req, res) => {
296
+ const p = project(req, res);
297
+ if (!p) return;
298
+ // A group is a ledger thread of its own — delete every row for it, not a
299
+ // global channel+date file (which is what 404'd before).
300
+ //
301
+ // An a2a pair is the same shape of thing: rows in THIS project's ledger,
302
+ // not a global channel+date file. It fell through to `deleteGlobalThread`,
303
+ // which looks for a file named after the pair id and never finds one — so
304
+ // the panel's Delete answered 404 on every agent-to-agent chat, and there
305
+ // was no other way to remove one. Reading a thread nobody can delete is
306
+ // half a surface.
307
+ if (req.params.channel === "group" || req.params.channel === "a2a") {
308
+ const out = req.params.channel === "group"
309
+ ? deleteGroupThread(p.storagePath, req.params.id)
310
+ : deleteA2AThread(p.storagePath, req.params.id);
311
+ try { projects.rebuild(p.id); } catch { /* best-effort */ }
312
+ if (!out.removed) return res.status(404).json({ error: "thread not found" });
313
+ return res.json({ ok: true, ...out });
314
+ }
315
+ const ok = deleteGlobalThread({
79
316
  channel: req.params.channel,
80
317
  date: req.params.id,
318
+ project: threadScope(p),
81
319
  });
82
- if (!thread) return res.status(404).json({ error: "thread not found" });
83
- res.json(thread);
320
+ if (!ok) return res.status(404).json({ error: "thread not found" });
321
+ res.json({ ok: true });
84
322
  });
85
323
 
86
- api.delete("/projects/:pid/super-agent/threads/:channel/:id", (req, res) => {
324
+ // A channel thread has no file of its own to carry a name, so the two
325
+ // decisions a reader can make about one — what to call it, whether to put it
326
+ // away — live in a small index beside the ledger. The messages are untouched.
327
+ api.patch("/projects/:pid/super-agent/threads/:channel/:id", (req, res) => {
87
328
  const p = project(req, res);
88
329
  if (!p) return;
89
- const ok = deleteGlobalThread({ channel: req.params.channel, date: req.params.id });
330
+ const { title, archived } = req.body || {};
331
+ if (title === undefined && archived === undefined)
332
+ return res.status(400).json({ error: "nothing to change" });
333
+ const ok = setGlobalThreadMeta({
334
+ channel: req.params.channel,
335
+ date: req.params.id,
336
+ ...(title !== undefined ? { title } : {}),
337
+ ...(archived !== undefined ? { archived: !!archived } : {}),
338
+ });
90
339
  if (!ok) return res.status(404).json({ error: "thread not found" });
91
340
  res.json({ ok: true });
92
341
  });
@@ -94,10 +343,15 @@ export function register(api, { project, config }) {
94
343
  async function handleCompact(req, res, filename) {
95
344
  const p = project(req, res);
96
345
  if (!p) return;
346
+ if (rejectA2AWrite(req, res, "compacted")) return;
97
347
  const agents = readAgents(p.path);
98
348
  const agent = agents.find((a) => a.slug === req.params.slug);
99
349
  if (!agent) return res.status(404).json({ error: "agent not found" });
100
- const modelId = (req.body || {}).model || agent.fields.Model;
350
+ const modelId = await resolveAgentModel({
351
+ agent,
352
+ config: p.config || config,
353
+ override: (req.body || {}).model,
354
+ });
101
355
  if (!modelId) return res.status(400).json({ error: "agent has no model" });
102
356
  try {
103
357
  const result = await compactConversation({
@@ -126,64 +380,254 @@ export function register(api, { project, config }) {
126
380
  api.post("/projects/:pid/send", asyncRoute(async (req, res) => {
127
381
  const p = project(req, res);
128
382
  if (!p) return;
129
- const { from, to, body, deliver = false, _depth = 0 } = req.body || {};
130
- if (!from || !to || !body)
383
+ const { from, to: toRaw, body, deliver = false, _depth = 0, requested_by = null, severity = null, model = null, usage = null, code = false, background = false, timeout_s = null } = req.body || {};
384
+ // Two kinds of exchange, and the difference is real: a `chat` peer runs in
385
+ // its own read-only mode, a `code` peer may write. Chat is the default
386
+ // because receiving a message must not be enough to let the sender rewrite
387
+ // your checkout — opening a coding session is a decision.
388
+ const mode = code ? "code" : "chat";
389
+ // A conversation answers in seconds; a coding session does not. Background
390
+ // runs get the hour that `call_runtime` gives its own detached spawns.
391
+ const timeoutMs = (Number(timeout_s) || (background ? 3600 : 300)) * 1000;
392
+ if (!from || !toRaw || !body)
131
393
  return res.status(400).json({ error: "from, to, body required" });
132
394
  if (_depth > 3)
133
395
  return res.status(429).json({ error: "a2a depth limit (3) exceeded" });
134
396
 
397
+ // Urgency tag: blocker|status|fyi. Only a known tag is kept — an unknown one
398
+ // is dropped rather than stored as a severity the detector can't map.
399
+ const sevTag = severity && A2A_SEVERITY[String(severity).toLowerCase()]
400
+ ? String(severity).toLowerCase() : null;
401
+ const sevMeta = sevTag ? { severity: sevTag } : {};
402
+
135
403
  const agents = readAgents(p.path);
136
- const fromAgent = agents.find((a) => a.slug === from);
137
- const toAgent = agents.find((a) => a.slug === to);
138
- if (!fromAgent)
139
- return res.status(404).json({ error: `from agent "${from}" not found` });
140
- if (!toAgent)
141
- return res.status(404).json({ error: `to agent "${to}" not found` });
404
+ // The SENDER may be a project agent, the super-agent, or an external
405
+ // identity that isn't registered anywhere — a coding CLI (claude/codex/…)
406
+ // relaying to an agent, a routine, a system actor. Requiring `from` to be an
407
+ // AGENTS.md agent is what blocked CLI→agent relays (404 "from not found").
408
+ // A synthetic sender ({slug}) is enough: the reply layer only reads `from.slug`,
409
+ // and the a2a log records the label. The RECIPIENT still has to exist, so a
410
+ // typo'd or wrong-project target fails loudly instead of vanishing.
411
+ const fromAgent = agents.find((a) => a.slug === from) || { slug: from, fields: {}, synthetic: true };
412
+ // The RECIPIENT is a PEER, not necessarily an agent: `to` may name an
413
+ // AGENTS.md agent or an external coding runtime (opencode, codex,
414
+ // claude-code, …), optionally with a `#thread` suffix that keeps two
415
+ // exchanges with the same peer from reading each other's mail. A name that
416
+ // nothing claims still fails loudly rather than vanishing.
417
+ const peer = resolvePeer(toRaw, agents, p.config || config);
418
+ if (!peer)
419
+ return res.status(404).json({
420
+ error: `no agent or runtime "${toRaw}" in project "${p.name}"`,
421
+ project: p.name,
422
+ available: agents.map((a) => a.slug),
423
+ runtimes: RUNTIME_IDS,
424
+ hint: "run `apx agent list --all` for agents and their projects; a runtime peer is any id in `runtimes`",
425
+ });
426
+
427
+ // One peer, one thread. Everything below files under the name the peer
428
+ // actually has — `Magui`, `magui`, `default`, `roby` and `apx` are not five
429
+ // correspondents. Addressing the super-agent by any of its aliases used to
430
+ // open a thread per alias, keyed by a string the inbox could not resolve to
431
+ // anyone; a project agent addressed by display name or in the wrong case did
432
+ // the same. The `:thread` suffix survives — that one IS a discriminator.
433
+ const to = peerAddress(peer);
434
+
435
+ if (mode === "code" && refusesCodeMode(peer)) {
436
+ return res.status(400).json({
437
+ error: `"${peer.runtime}" cannot be opened as a --code peer`,
438
+ no_code_peers: NO_CODE_PEERS,
439
+ hint:
440
+ `${peer.runtime} is a CLI you drive yourself — a message must not also start it writing to the same ` +
441
+ `checkout. Send without --code to ask it something, or open the coding session on another peer.`,
442
+ });
443
+ }
444
+
445
+ // Snapshot the prior conversation BEFORE we log the new message, so the
446
+ // reply sees history without the turn it is answering.
447
+ const history = deliver ? a2aPairHistory(p.storagePath, from, to, to) : [];
448
+
449
+ // Attribute the sender's message the way every other channel does: an
450
+ // explicit override wins (a caller that knows the real cost — a routine
451
+ // relaying its run — passes model/usage); otherwise stamp the sender agent's
452
+ // configured model, so an a2a message shows whose model spoke instead of a
453
+ // blank row. Usage stays absent on a plain relay — it spends no tokens.
454
+ const attrib = {};
455
+ const overrideModel = typeof model === "string" && model ? model : null;
456
+ let senderModel = overrideModel;
457
+ if (!senderModel && !fromAgent.synthetic) {
458
+ try { senderModel = await resolveAgentModel({ agent: fromAgent, config: p.config || config }); }
459
+ catch { /* no model resolvable → leave the row unattributed */ }
460
+ }
461
+ if (senderModel) attrib.model = senderModel;
462
+ if (usage && typeof usage === "object") attrib.usage = usage;
142
463
 
143
464
  const ts = nowIso();
465
+ const messageId = shortId("a2a");
144
466
  p.logMessage({
145
467
  agent_slug: from,
146
468
  channel: "a2a",
147
469
  direction: "out",
148
470
  author: from,
149
471
  body,
150
- meta: { to, depth: _depth },
472
+ meta: { to, depth: _depth, final: true, ...sevMeta, ...attrib, ...(requested_by ? { requested_by } : {}) },
151
473
  ts,
474
+ external_id: messageId,
152
475
  });
476
+
477
+ // A `blocker` is an alert, not a note for the next digest: Roby pings the
478
+ // owner in the act (canNudge's critical-bypass crosses budget and quiet
479
+ // hours). Done here — before the inbound row a watch would pick up later —
480
+ // so the ping never waits for a scheduled sweep. A successful ping stamps
481
+ // the inbound row `owner_notified` so the watch does not tell him twice; if
482
+ // it is held/skipped the flag is absent, so the watch remains the fallback.
483
+ let ownerNotify = null;
484
+ if (sevTag === "blocker") {
485
+ try {
486
+ ownerNotify = await notifyOwnerViaRoby(
487
+ { project: p, plugins, registries, globalConfig: p.config || config },
488
+ {
489
+ routine: { name: `a2a:${from}->${to}`, id: "" },
490
+ agent: { slug: from, name: from },
491
+ text: body,
492
+ notify: body,
493
+ gate: { severity: "critical", scheduled: false, unsolicited: true, project_id: p.id ?? null },
494
+ severity: "critical",
495
+ },
496
+ );
497
+ } catch (e) {
498
+ ownerNotify = { skipped: true, reason: e?.message || String(e) };
499
+ }
500
+ }
501
+ const ownerNotified = ownerNotify?.sent === true;
502
+
153
503
  p.logMessage({
154
504
  agent_slug: to,
155
505
  channel: "a2a",
156
506
  direction: "in",
157
507
  author: from,
158
508
  body,
159
- meta: { from, depth: _depth },
509
+ meta: {
510
+ from, depth: _depth, ...sevMeta, ...attrib,
511
+ ...(ownerNotified ? { owner_notified: true } : {}),
512
+ ...(requested_by ? { requested_by } : {}),
513
+ },
160
514
  ts,
515
+ external_id: messageId,
161
516
  });
162
517
 
163
- let reply = null;
164
- if (deliver && toAgent.fields.Model) {
518
+ // Run the peer and file both halves of its answer. Returns the payload the
519
+ // caller gets back; NEVER throws, so the background path can fire it
520
+ // un-awaited without an unhandled rejection taking the daemon with it.
521
+ // A --code exchange IS a coding session, so it has to live where coding
522
+ // sessions live. Without this it exists only as an a2a thread and the Code
523
+ // panel — the one place you go to see what was built — never shows it.
524
+ // Sender is the user turn; the peer that does the work is the assistant,
525
+ // which is the same shape /code writes for its own sessions.
526
+ const openCodeSession = () => {
527
+ if (mode !== "code") return null;
528
+ const known = readA2APeerSession(p.storagePath, { from, to, key: "code_session_id" });
529
+ let session = known ? getCodeSession(p.storagePath, known) : null;
530
+ if (!session) {
531
+ session = createCodeSession(p.storagePath, {
532
+ projectId: p.id,
533
+ title: `a2a: ${from} -> ${to}`,
534
+ mode: CODE_MODES.BUILD,
535
+ agentSlug: to,
536
+ });
537
+ }
538
+ appendCodeTurn(p.storagePath, session.id, {
539
+ role: "user",
540
+ parts: [{ kind: "text", text: body }],
541
+ mode: CODE_MODES.BUILD,
542
+ });
543
+ return session;
544
+ };
545
+
546
+ const runReply = async () => {
547
+ const codeSession = openCodeSession();
165
548
  try {
166
- const result = await replyAsAgent({
549
+ const result = await replyToPeer({
550
+ peer,
551
+ project: p,
167
552
  projectPath: p.path,
168
- toAgent,
169
553
  fromAgent,
554
+ fromAddress: from,
170
555
  body,
171
556
  config: p.config || config,
557
+ history,
558
+ projectId: p.id,
559
+ projects,
560
+ plugins,
561
+ registries,
562
+ // A runtime peer runs where the sender is, falling back to the
563
+ // project. It also continues the session this thread already opened
564
+ // instead of starting a stranger.
565
+ cwd: senderCwd(req.body?.cwd) || p.path,
566
+ projectName: p.name,
567
+ resumeSessionId: readA2APeerSession(p.storagePath, { from, to }),
568
+ mode,
569
+ timeoutMs,
172
570
  });
173
571
 
572
+ const replyTs = nowIso();
573
+ const replyMessageId = shortId("a2a");
574
+ if (Array.isArray(result.trace)) {
575
+ for (const step of result.trace) {
576
+ if (!step?.tool) continue;
577
+ p.logMessage({
578
+ agent_slug: to,
579
+ channel: "a2a",
580
+ direction: "out",
581
+ type: "tool",
582
+ actor_kind: "agent",
583
+ actor_id: step.tool,
584
+ author: to,
585
+ body: typeof step.result === "string" ? step.result : JSON.stringify(step.result || ""),
586
+ meta: {
587
+ to: from,
588
+ tool: step.tool,
589
+ args: step.args,
590
+ result: step.result,
591
+ },
592
+ ts: replyTs,
593
+ });
594
+ }
595
+ }
174
596
  p.logMessage({
175
597
  agent_slug: to,
176
598
  channel: "a2a",
177
599
  direction: "out",
600
+ type: "agent",
601
+ actor_kind: "agent",
602
+ actor_id: to,
178
603
  author: to,
179
604
  body: result.text,
180
605
  meta: {
181
606
  to: from,
182
607
  depth: _depth + 1,
183
608
  reply_to: fromAgent.slug,
609
+ final: true,
610
+ model: result.model,
184
611
  usage: result.usage,
612
+ // Where this thread's external session lives, so the NEXT turn
613
+ // resumes it. Stored on the ledger rather than in a side table: a
614
+ // thread that gets deleted takes its session pointer with it.
615
+ ...(result.runtime ? { runtime: result.runtime } : {}),
616
+ ...(result.mode ? { mode: result.mode } : {}),
617
+ ...(result.sessionId ? { runtime_session_id: result.sessionId } : {}),
618
+ ...(codeSession ? { code_session_id: codeSession.id } : {}),
185
619
  },
620
+ ts: replyTs,
621
+ external_id: replyMessageId,
186
622
  });
623
+ if (codeSession) {
624
+ appendCodeTurn(p.storagePath, codeSession.id, {
625
+ role: "assistant",
626
+ parts: [{ kind: "text", text: result.text }],
627
+ mode: CODE_MODES.BUILD,
628
+ ...(result.model ? { model: result.model } : { model: result.runtime || to }),
629
+ });
630
+ }
187
631
  p.logMessage({
188
632
  agent_slug: from,
189
633
  channel: "a2a",
@@ -191,13 +635,77 @@ export function register(api, { project, config }) {
191
635
  author: to,
192
636
  body: result.text,
193
637
  meta: { from: to, depth: _depth + 1 },
638
+ ts: replyTs,
639
+ external_id: replyMessageId,
194
640
  });
195
- reply = { text: result.text, usage: result.usage };
641
+ return {
642
+ text: result.text,
643
+ usage: result.usage,
644
+ ...(result.runtime ? { runtime: result.runtime } : {}),
645
+ ...(result.sessionId ? { session_id: result.sessionId } : {}),
646
+ ...(result.sessionNote ? { session_note: result.sessionNote } : {}),
647
+ ...(codeSession ? { code_session_id: codeSession.id } : {}),
648
+ };
196
649
  } catch (e) {
197
- reply = { error: e.message };
650
+ // A peer that did not answer is news, and in the background there is no
651
+ // response left to carry it — so the failure goes on the thread, marked
652
+ // as a failure rather than dressed up as something the peer said.
653
+ p.logMessage({
654
+ agent_slug: to,
655
+ channel: "a2a",
656
+ direction: "out",
657
+ // attribution-exempt: a delivery failure, not a turn — nothing was
658
+ // spent and no model spoke, so there is no model or usage to record.
659
+ type: "agent",
660
+ actor_kind: "agent",
661
+ actor_id: to,
662
+ author: to,
663
+ body: `did not answer: ${e.message}`,
664
+ meta: {
665
+ to: from,
666
+ depth: _depth + 1,
667
+ reply_to: fromAgent.slug,
668
+ final: true,
669
+ failed: true,
670
+ failure_reason: e.message,
671
+ ...(codeSession ? { code_session_id: codeSession.id } : {}),
672
+ },
673
+ });
674
+ // The coding session must show the failure too, or it reads as a
675
+ // request nobody ever answered.
676
+ if (codeSession) {
677
+ appendCodeTurn(p.storagePath, codeSession.id, {
678
+ role: "assistant",
679
+ parts: [{ kind: "text", text: `did not answer: ${e.message}` }],
680
+ mode: CODE_MODES.BUILD,
681
+ model: to,
682
+ });
683
+ }
684
+ return { error: e.message, ...(codeSession ? { code_session_id: codeSession.id } : {}) };
198
685
  }
686
+ };
687
+
688
+ // An agent that inherits still replies: replyToPeer resolves the router
689
+ // default for it. `deliver` is the only gate here.
690
+ let reply = null;
691
+ if (deliver && background) {
692
+ // Un-awaited on purpose: a coding session can run for an hour, and the
693
+ // sender should not hold a socket open for it. The reply lands on the
694
+ // thread when it lands, and every surface that reads the thread sees it.
695
+ runReply();
696
+ reply = { status: "delivering", background: true, timeout_s: Math.round(timeoutMs / 1000) };
697
+ } else if (deliver) {
698
+ reply = await runReply();
199
699
  }
200
700
 
201
- res.json({ from, to, body, ts, reply });
701
+ res.json({
702
+ from, to, body, ts, reply,
703
+ ...(sevTag ? { severity: sevTag } : {}),
704
+ ...(ownerNotify ? {
705
+ owner_notified: ownerNotified,
706
+ ...(ownerNotify.line ? { owner_notified_line: ownerNotify.line } : {}),
707
+ ...(!ownerNotified ? { owner_notify_reason: ownerNotify.reason || (ownerNotify.skipped ? "skipped" : "not sent") } : {}),
708
+ } : {}),
709
+ });
202
710
  }));
203
711
  }