talon-agent 4.6.1 → 5.0.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 (310) hide show
  1. package/README.md +3 -3
  2. package/package.json +2 -1
  3. package/prompts/README.md +2 -2
  4. package/prompts/system/memory-recall.md +16 -0
  5. package/src/app.ts +22 -7
  6. package/src/backend/claude-sdk/factory.ts +21 -41
  7. package/src/backend/claude-sdk/handler.ts +28 -7
  8. package/src/backend/claude-sdk/host/in-process.ts +147 -0
  9. package/src/backend/claude-sdk/one-shot.ts +1 -1
  10. package/src/backend/claude-sdk/options.ts +7 -6
  11. package/src/backend/claude-sdk/stream.ts +30 -3
  12. package/src/backend/claude-sdk/warm.ts +1 -1
  13. package/src/backend/codex/constants.ts +1 -1
  14. package/src/backend/codex/factory.ts +2 -2
  15. package/src/backend/codex/handler/events.ts +1 -1
  16. package/src/backend/codex/handler/message.ts +26 -12
  17. package/src/backend/codex/handler/rollout-accounting.ts +1 -1
  18. package/src/backend/codex/init.ts +1 -1
  19. package/src/backend/codex/mcp-config.ts +2 -2
  20. package/src/backend/codex/one-shot.ts +1 -1
  21. package/src/backend/kilo/handler/message.ts +4 -1
  22. package/src/backend/openai-agents/constants.ts +1 -1
  23. package/src/backend/openai-agents/factory.ts +2 -2
  24. package/src/backend/openai-agents/handler/events.ts +1 -1
  25. package/src/backend/openai-agents/handler/message.ts +8 -4
  26. package/src/backend/openai-agents/init.ts +1 -1
  27. package/src/backend/openai-agents/mcp-pool.ts +2 -2
  28. package/src/backend/opencode/handler/message.ts +4 -1
  29. package/src/backend/remote-server/chat-turn.ts +31 -23
  30. package/src/backend/remote-server/events.ts +3 -3
  31. package/src/backend/remote-server/factory.ts +6 -3
  32. package/src/backend/remote-server/index.ts +1 -1
  33. package/src/backend/remote-server/mcp.ts +1 -1
  34. package/src/backend/remote-server/one-shot.ts +1 -1
  35. package/src/backend/remote-server/server-bindings.ts +1 -1
  36. package/src/backend/remote-server/turn.ts +1 -1
  37. package/src/backend/runtime/cache/cache-metrics.ts +126 -0
  38. package/src/backend/{shared → runtime/cache}/cache-telemetry.ts +22 -2
  39. package/src/backend/{shared → runtime}/index.ts +34 -25
  40. package/src/backend/{shared → runtime/prompt}/delivery-contract.ts +1 -1
  41. package/src/backend/{shared → runtime/prompt}/prompt-format.ts +46 -2
  42. package/src/backend/{shared → runtime/prompt}/system-prompt.ts +4 -4
  43. package/src/backend/{shared → runtime/turn}/delivered-text.ts +1 -1
  44. package/src/backend/{shared → runtime/turn}/delivery.ts +3 -3
  45. package/src/backend/{shared → runtime/turn}/handle-retry.ts +5 -5
  46. package/src/backend/{shared → runtime/turn}/handler-to-events.ts +24 -10
  47. package/src/backend/{shared → runtime/turn}/handler-types.ts +7 -1
  48. package/src/backend/{shared → runtime/turn}/model-retry.ts +2 -2
  49. package/src/backend/{shared → runtime/turn}/result-events.ts +2 -2
  50. package/src/backend/{shared → runtime/turn}/stream-state.ts +2 -2
  51. package/src/backend/{shared → runtime/turn}/turn-interrupt.ts +2 -2
  52. package/src/backend/{shared → runtime/turn}/turn-phases.ts +6 -6
  53. package/src/bootstrap.ts +6 -21
  54. package/src/cli.ts +6 -3
  55. package/src/core/agent-runtime/README.md +15 -0
  56. package/src/core/agent-runtime/agent-host.ts +387 -0
  57. package/src/core/agent-runtime/capabilities.ts +11 -0
  58. package/src/core/agent-runtime/contract-tests.ts +92 -1
  59. package/src/core/agent-runtime/events.ts +1 -1
  60. package/src/core/background/{isolated-agent.ts → cron/isolated-agent.ts} +3 -3
  61. package/src/core/background/{job-health.ts → cron/job-health.ts} +1 -1
  62. package/src/core/background/{job-oneshot.ts → cron/job-oneshot.ts} +5 -5
  63. package/src/core/background/{job-prompt.ts → cron/job-prompt.ts} +1 -1
  64. package/src/core/background/{cron.ts → cron/scheduler.ts} +6 -6
  65. package/src/core/background/{cron-spec.ts → cron/spec.ts} +1 -1
  66. package/src/core/background/{dream.ts → dream/index.ts} +10 -15
  67. package/src/core/background/{plan-alerts.ts → pulse/plan-alerts.ts} +3 -3
  68. package/src/core/background/{pulse.ts → pulse/pulse.ts} +8 -5
  69. package/src/core/background/triggers/command.ts +2 -2
  70. package/src/{util → core/config}/harden.ts +1 -1
  71. package/src/core/config/index.ts +16 -12
  72. package/src/{util → core/daemon}/boot-timer.ts +15 -1
  73. package/src/core/daemon/pidfile.ts +1 -1
  74. package/src/core/daemon/resource-sampler.ts +121 -0
  75. package/src/{util → core/daemon}/respawn.ts +1 -1
  76. package/src/core/doctor/index.ts +1 -1
  77. package/src/core/engine/dispatcher.ts +16 -0
  78. package/src/core/engine/gateway-actions/cron.ts +2 -2
  79. package/src/core/engine/gateway-actions/fetch-url.ts +1 -1
  80. package/src/core/engine/gateway-actions/index.ts +4 -1
  81. package/src/core/engine/gateway-actions/memory.ts +335 -0
  82. package/src/core/engine/gateway-actions/native/exec-background.ts +129 -0
  83. package/src/core/engine/gateway-actions/native/exec-remote.ts +85 -0
  84. package/src/core/engine/gateway-actions/native/exec.ts +182 -0
  85. package/src/core/engine/gateway-actions/native/index.ts +46 -0
  86. package/src/core/engine/gateway-actions/native/params.ts +46 -0
  87. package/src/core/engine/gateway-actions/native/read.ts +182 -0
  88. package/src/core/engine/gateway-actions/native/results.ts +34 -0
  89. package/src/core/engine/gateway-actions/native/search.ts +212 -0
  90. package/src/core/engine/gateway-actions/native/shell.ts +39 -0
  91. package/src/core/engine/gateway-actions/native/teleport.ts +55 -0
  92. package/src/core/engine/gateway-actions/native/write.ts +170 -0
  93. package/src/core/engine/gateway.ts +0 -6
  94. package/src/core/frontend-runtime/builtins.ts +2 -2
  95. package/src/{util → core/frontend-runtime}/chat-id.ts +30 -0
  96. package/src/core/mcp-hub/index.ts +1 -1
  97. package/src/core/mcp-hub/talon-server.ts +1 -1
  98. package/src/core/memory/import.ts +3 -2
  99. package/src/core/memory/taps.ts +199 -0
  100. package/src/core/memory/turn-retrieval.ts +222 -0
  101. package/src/core/plugin/mcp.ts +1 -1
  102. package/src/core/prompt/assemble.ts +2 -12
  103. package/src/core/prompt/index.ts +2 -2
  104. package/src/core/prompt/invalidation.ts +1 -1
  105. package/src/core/{scripting/lua-runner.ts → scripts/lua.ts} +1 -1
  106. package/src/core/tasks/index.ts +1 -1
  107. package/src/core/tools/{chat.ts → chat/chat.ts} +1 -1
  108. package/src/core/tools/{cross-send.ts → chat/cross-send.ts} +1 -1
  109. package/src/core/tools/{history.ts → chat/history.ts} +2 -2
  110. package/src/core/tools/{media.ts → chat/media.ts} +1 -1
  111. package/src/core/tools/{members.ts → chat/members.ts} +2 -2
  112. package/src/core/tools/{messaging.ts → chat/messaging.ts} +2 -2
  113. package/src/core/tools/{moderation.ts → chat/moderation.ts} +2 -2
  114. package/src/core/tools/{stickers.ts → chat/stickers.ts} +2 -2
  115. package/src/core/tools/{whatsapp.ts → chat/whatsapp.ts} +1 -1
  116. package/src/core/tools/content/memory.ts +128 -0
  117. package/src/core/tools/{web.ts → content/web.ts} +1 -1
  118. package/src/core/tools/index.ts +21 -19
  119. package/src/core/tools/{admin.ts → ops/admin.ts} +1 -1
  120. package/src/core/tools/{bridge.ts → ops/bridge.ts} +2 -2
  121. package/src/core/tools/{goals.ts → ops/goals.ts} +2 -2
  122. package/src/core/tools/{mesh.ts → ops/mesh.ts} +1 -1
  123. package/src/core/tools/{models.ts → ops/models.ts} +1 -1
  124. package/src/core/tools/{native.ts → ops/native.ts} +1 -1
  125. package/src/core/tools/{scheduling.ts → ops/scheduling.ts} +1 -1
  126. package/src/core/tools/{scripts.ts → ops/scripts.ts} +1 -1
  127. package/src/core/tools/{skills.ts → ops/skills.ts} +1 -1
  128. package/src/core/tools/{triggers.ts → ops/triggers.ts} +1 -1
  129. package/src/core/tools/types.ts +1 -0
  130. package/src/{util → core/vfs}/workspace.ts +2 -2
  131. package/src/core/weaver/turn-cpu.ts +32 -0
  132. package/src/core/weaver/weaver.ts +36 -0
  133. package/src/frontend/discord/admin.ts +1 -1
  134. package/src/frontend/discord/callbacks/components/backend-select.ts +1 -1
  135. package/src/frontend/discord/callbacks/components/effort.ts +1 -1
  136. package/src/frontend/discord/callbacks/components/index.ts +1 -1
  137. package/src/frontend/discord/callbacks/components/pulse.ts +1 -1
  138. package/src/frontend/discord/callbacks/components/settings.ts +2 -2
  139. package/src/frontend/discord/callbacks/modals.ts +4 -1
  140. package/src/frontend/discord/commands/admin.ts +2 -36
  141. package/src/frontend/discord/commands/definitions.ts +0 -11
  142. package/src/frontend/discord/commands/info.ts +1 -1
  143. package/src/frontend/discord/commands/interaction.ts +1 -1
  144. package/src/frontend/discord/commands/router.ts +0 -3
  145. package/src/frontend/discord/commands/session.ts +8 -2
  146. package/src/frontend/discord/commands/settings.ts +2 -2
  147. package/src/frontend/discord/handlers/messages.ts +1 -1
  148. package/src/frontend/discord/handlers/state.ts +1 -1
  149. package/src/frontend/discord/middleware.ts +2 -26
  150. package/src/frontend/discord/ready.ts +1 -1
  151. package/src/frontend/discord/render.ts +41 -259
  152. package/src/frontend/discord/runtime.ts +1 -2
  153. package/src/frontend/native/{auth.ts → bridge/auth.ts} +2 -2
  154. package/src/frontend/native/{discovery.ts → bridge/discovery.ts} +3 -3
  155. package/src/frontend/native/{routes → bridge/routes}/chats.ts +1 -1
  156. package/src/frontend/native/{routes → bridge/routes}/daemon.ts +1 -1
  157. package/src/frontend/native/{routes → bridge/routes}/host.ts +6 -3
  158. package/src/frontend/native/{routes → bridge/routes}/pre-auth.ts +1 -1
  159. package/src/frontend/native/{server.ts → bridge/server.ts} +3 -3
  160. package/src/frontend/native/{tls.ts → bridge/tls.ts} +2 -2
  161. package/src/frontend/native/{chat-lifecycle.ts → chats/chat-lifecycle.ts} +3 -3
  162. package/src/frontend/native/{chat-wire.ts → chats/chat-wire.ts} +4 -4
  163. package/src/frontend/native/{chats.ts → chats/chats.ts} +4 -4
  164. package/src/frontend/native/{empty-chat-sweep.ts → chats/empty-chat-sweep.ts} +4 -4
  165. package/src/frontend/native/{history.ts → chats/history.ts} +7 -7
  166. package/src/frontend/native/{reset.ts → chats/reset.ts} +7 -7
  167. package/src/frontend/native/index.ts +13 -10
  168. package/src/frontend/native/{media.ts → media/media.ts} +3 -3
  169. package/src/frontend/native/runtime.ts +1 -1
  170. package/src/frontend/native/{control.ts → surface/control.ts} +4 -4
  171. package/src/frontend/native/{extensions.ts → surface/extensions.ts} +12 -9
  172. package/src/frontend/native/{handlers.ts → surface/handlers.ts} +19 -14
  173. package/src/frontend/native/{logs.ts → surface/logs.ts} +2 -2
  174. package/src/frontend/native/{memory.ts → surface/memory.ts} +2 -2
  175. package/src/frontend/native/{models.ts → surface/models.ts} +17 -10
  176. package/src/frontend/native/{settings.ts → surface/settings.ts} +9 -9
  177. package/src/frontend/native/{status.ts → surface/status.ts} +3 -3
  178. package/src/frontend/native/{actions.ts → turn/actions.ts} +7 -4
  179. package/src/frontend/native/{context.ts → turn/context.ts} +8 -8
  180. package/src/frontend/native/{emit.ts → turn/emit.ts} +7 -7
  181. package/src/frontend/native/{queue.ts → turn/queue.ts} +3 -3
  182. package/src/frontend/native/{turn-meta.ts → turn/turn-meta.ts} +2 -2
  183. package/src/frontend/native/{turn.ts → turn/turn.ts} +9 -9
  184. package/src/frontend/{shared → presentation}/format.ts +4 -3
  185. package/src/frontend/{shared → presentation}/model-commands.ts +1 -1
  186. package/src/frontend/{shared → presentation}/reasoning-levels.ts +12 -0
  187. package/src/frontend/presentation/reports.ts +493 -0
  188. package/src/frontend/{shared → presentation}/session-status.ts +36 -9
  189. package/src/frontend/{shared → presentation}/status-context.ts +101 -2
  190. package/src/frontend/teams/commands.ts +2 -2
  191. package/src/frontend/teams/turn.ts +1 -1
  192. package/src/frontend/telegram/admin/background.ts +1 -1
  193. package/src/frontend/telegram/admin/health.ts +1 -1
  194. package/src/frontend/telegram/admin/sessions.ts +1 -1
  195. package/src/frontend/telegram/callbacks/effort.ts +2 -2
  196. package/src/frontend/telegram/callbacks/metrics.ts +1 -1
  197. package/src/frontend/telegram/callbacks/model/backend.ts +1 -1
  198. package/src/frontend/telegram/callbacks/model/views.ts +1 -1
  199. package/src/frontend/telegram/callbacks/pulse.ts +1 -1
  200. package/src/frontend/telegram/callbacks/query.ts +1 -1
  201. package/src/frontend/telegram/callbacks/settings.ts +3 -3
  202. package/src/frontend/telegram/commands/admin.ts +6 -41
  203. package/src/frontend/telegram/commands/index.ts +1 -1
  204. package/src/frontend/telegram/commands/info.ts +2 -2
  205. package/src/frontend/telegram/commands/session.ts +9 -3
  206. package/src/frontend/telegram/commands/settings.ts +5 -3
  207. package/src/frontend/telegram/handlers/messages.ts +0 -10
  208. package/src/frontend/telegram/handlers/state.ts +1 -1
  209. package/src/frontend/telegram/index.ts +1 -5
  210. package/src/frontend/telegram/middleware.ts +1 -15
  211. package/src/frontend/telegram/model-menu.ts +1 -1
  212. package/src/frontend/telegram/render/html.ts +30 -0
  213. package/src/frontend/telegram/{helpers → render}/menu.ts +46 -19
  214. package/src/frontend/telegram/render/reports.ts +182 -0
  215. package/src/frontend/terminal/builtins/context.ts +2 -2
  216. package/src/frontend/terminal/builtins/session.ts +1 -1
  217. package/src/frontend/terminal/builtins/status.ts +2 -2
  218. package/src/frontend/terminal/index.ts +2 -2
  219. package/src/frontend/terminal/renderer.ts +1 -1
  220. package/src/frontend/whatsapp/access.ts +2 -2
  221. package/src/frontend/whatsapp/actions/history.ts +2 -2
  222. package/src/frontend/whatsapp/actions/messaging.ts +2 -2
  223. package/src/frontend/whatsapp/actions/moderation.ts +1 -1
  224. package/src/frontend/whatsapp/actions/send.ts +1 -1
  225. package/src/frontend/whatsapp/commands.ts +12 -6
  226. package/src/frontend/whatsapp/{connection.ts → connection/connection.ts} +5 -5
  227. package/src/frontend/whatsapp/{pairing-service.ts → connection/pairing-service.ts} +3 -3
  228. package/src/frontend/whatsapp/{wa-logger.ts → connection/wa-logger.ts} +2 -2
  229. package/src/frontend/whatsapp/index.ts +4 -4
  230. package/src/frontend/whatsapp/{inbound.ts → messages/inbound.ts} +15 -15
  231. package/src/frontend/whatsapp/{media-store.ts → messages/media-store.ts} +4 -4
  232. package/src/frontend/whatsapp/{message-store.ts → messages/message-store.ts} +1 -1
  233. package/src/frontend/whatsapp/{turn-recovery.ts → messages/turn-recovery.ts} +4 -4
  234. package/src/frontend/whatsapp/registry.ts +2 -2
  235. package/src/frontend/whatsapp/runtime.ts +1 -1
  236. package/src/index.ts +6 -3
  237. package/src/storage/db.ts +6 -1
  238. package/src/storage/memory.ts +59 -8
  239. package/src/storage/metrics.ts +38 -0
  240. package/src/storage/repositories/sessions-repo.ts +6 -0
  241. package/src/storage/session-record.ts +13 -2
  242. package/src/storage/sessions.ts +12 -0
  243. package/src/storage/sql/db.sql +5 -0
  244. package/src/storage/sql/schema.sql +4 -0
  245. package/src/storage/sql/sessions.sql +3 -3
  246. package/src/storage/sql/statements.generated.ts +10 -3
  247. package/src/storage/sql/turn-meta.sql +1 -1
  248. package/src/util/log.ts +1 -1
  249. package/src/util/paths.ts +0 -2
  250. package/src/util/runtime.ts +1 -1
  251. package/src/core/engine/gateway-actions/native.ts +0 -1035
  252. package/src/core/soul/README.md +0 -110
  253. package/src/core/soul/RESEARCH.md +0 -98
  254. package/src/core/soul/associative.ts +0 -98
  255. package/src/core/soul/centrality.ts +0 -98
  256. package/src/core/soul/cluster.ts +0 -83
  257. package/src/core/soul/compiler.ts +0 -207
  258. package/src/core/soul/consolidate.ts +0 -179
  259. package/src/core/soul/critic.ts +0 -162
  260. package/src/core/soul/dag.ts +0 -265
  261. package/src/core/soul/delta.ts +0 -123
  262. package/src/core/soul/drift.ts +0 -99
  263. package/src/core/soul/embedder.ts +0 -129
  264. package/src/core/soul/emergent-critic.ts +0 -96
  265. package/src/core/soul/forgetting.ts +0 -131
  266. package/src/core/soul/governance.ts +0 -93
  267. package/src/core/soul/hash.ts +0 -97
  268. package/src/core/soul/hdc.ts +0 -154
  269. package/src/core/soul/kernel.ts +0 -540
  270. package/src/core/soul/lattice.ts +0 -103
  271. package/src/core/soul/lens.ts +0 -110
  272. package/src/core/soul/projector.ts +0 -240
  273. package/src/core/soul/reflect.ts +0 -170
  274. package/src/core/soul/reflex.ts +0 -164
  275. package/src/core/soul/retrieve.ts +0 -146
  276. package/src/core/soul/salience.ts +0 -146
  277. package/src/core/soul/service.ts +0 -204
  278. package/src/core/soul/settings.ts +0 -47
  279. package/src/core/soul/signals.ts +0 -117
  280. package/src/core/soul/talon-embedder.ts +0 -80
  281. package/src/core/soul/taps.ts +0 -199
  282. package/src/core/soul/types.ts +0 -298
  283. package/src/core/soul/valence.ts +0 -83
  284. package/src/frontend/telegram/helpers/diagnostics.ts +0 -428
  285. package/src/frontend/telegram/helpers/format.ts +0 -42
  286. package/src/frontend/telegram/helpers/index.ts +0 -13
  287. package/src/util/cleanup-registry.ts +0 -36
  288. /package/src/backend/{shared → runtime}/frontends.ts +0 -0
  289. /package/src/backend/{shared → runtime}/metrics.ts +0 -0
  290. /package/src/backend/{shared → runtime}/sleep.ts +0 -0
  291. /package/src/backend/{shared → runtime/turn}/flow-violation.ts +0 -0
  292. /package/src/backend/{shared → runtime}/usage.ts +0 -0
  293. /package/src/{util/mcp-launcher.ts → core/mcp-hub/launcher.ts} +0 -0
  294. /package/src/{util → core/tools/content}/web-content.ts +0 -0
  295. /package/src/core/tools/{mcp-env.ts → ops/mcp-env.ts} +0 -0
  296. /package/src/{util → core/weaver}/session-name.ts +0 -0
  297. /package/src/frontend/native/{routes → bridge/routes}/index.ts +0 -0
  298. /package/src/frontend/native/{routes → bridge/routes}/memory.ts +0 -0
  299. /package/src/frontend/native/{routes → bridge/routes}/mesh.ts +0 -0
  300. /package/src/frontend/native/{routes → bridge/routes}/models.ts +0 -0
  301. /package/src/frontend/native/{routes → bridge/routes}/params.ts +0 -0
  302. /package/src/frontend/native/{routes → bridge/routes}/table.ts +0 -0
  303. /package/src/frontend/native/{tool-result.ts → turn/tool-result.ts} +0 -0
  304. /package/src/frontend/{shared → presentation}/access.ts +0 -0
  305. /package/src/frontend/{shared → presentation}/plan-usage-report.ts +0 -0
  306. /package/src/frontend/whatsapp/{auth-state.ts → connection/auth-state.ts} +0 -0
  307. /package/src/frontend/whatsapp/{identity.ts → connection/identity.ts} +0 -0
  308. /package/src/frontend/whatsapp/{pairing-lock.ts → connection/pairing-lock.ts} +0 -0
  309. /package/src/frontend/whatsapp/{pairing.ts → connection/pairing.ts} +0 -0
  310. /package/src/frontend/whatsapp/{pins.ts → messages/pins.ts} +0 -0
@@ -2,7 +2,7 @@
2
2
  * Session commands — /reset and /status.
3
3
  *
4
4
  * Data gathering and the reset sequence live in
5
- * frontend/shared/session-status.ts; this file only renders Discord markdown.
5
+ * frontend/presentation/session-status.ts; this file only renders Discord markdown.
6
6
  */
7
7
 
8
8
  import { type ChatInputCommandInteraction, MessageFlags } from "discord.js";
@@ -22,7 +22,11 @@ import {
22
22
  import {
23
23
  performSessionReset,
24
24
  collectSessionStatus,
25
- } from "../../shared/session-status.js";
25
+ } from "../../presentation/session-status.js";
26
+ import {
27
+ formatCacheTempLine,
28
+ formatDaemonLine,
29
+ } from "../../presentation/status-context.js";
26
30
  import { stopCurrentTurn } from "../../../core/engine/dispatcher.js";
27
31
  import { reply } from "./interaction.js";
28
32
 
@@ -92,6 +96,7 @@ export async function handleStatus(
92
96
  ` Read ${formatTokenCount(s.cache.read)}${s.cache.showsWrite ? ` Write ${formatTokenCount(s.cache.write)}` : ""}`,
93
97
  ]
94
98
  : []),
99
+ ...(s.cacheTemp ? [` ${formatCacheTempLine(s.cacheTemp)}`] : []),
95
100
  ` Input ${formatTokenCount(s.inputTokens)} Output ${formatTokenCount(s.outputTokens)}${s.costUsd > 0 ? ` Cost ${formatUsd(s.costUsd)}` : ""}`,
96
101
  "",
97
102
  ...(s.plan
@@ -109,6 +114,7 @@ export async function handleStatus(
109
114
  `**Session** ${s.sessionName ? `"${s.sessionName}" ` : ""}${s.sessionId ? "`" + s.sessionId.slice(0, 8) + "...`" : "_(new)_"} · ${s.sessionAge} old`,
110
115
  `**Uptime** ${s.uptime} · ${s.activeSessionCount} active session${s.activeSessionCount === 1 ? "" : "s"}`,
111
116
  `**Runtime** ${s.runtime} · ${formatBytes(s.rssBytes)} RSS`,
117
+ formatDaemonLine(s.daemon),
112
118
  ];
113
119
  await i.editReply(lines.join("\n"));
114
120
  }
@@ -26,7 +26,7 @@ import {
26
26
  disablePulse,
27
27
  enablePulse,
28
28
  isPulseEnabled,
29
- } from "../../../core/background/pulse.js";
29
+ } from "../../../core/background/pulse/pulse.js";
30
30
  import {
31
31
  formatModelLabel,
32
32
  formatDuration,
@@ -38,7 +38,7 @@ import {
38
38
  displayReasoningEffort,
39
39
  getActiveReasoningLevels,
40
40
  supportsReasoningLevel,
41
- } from "../../shared/reasoning-levels.js";
41
+ } from "../../presentation/reasoning-levels.js";
42
42
  import {
43
43
  getBackendIdForChat,
44
44
  resolveChatBackend,
@@ -9,7 +9,7 @@ import { ChannelType } from "discord.js";
9
9
  import type { TalonConfig } from "../../../core/config/index.js";
10
10
  import { setMessageFilePath } from "../../../storage/history.js";
11
11
  import { addMedia } from "../../../storage/media-index.js";
12
- import { deriveNumericChatId } from "../../../util/chat-id.js";
12
+ import { deriveNumericChatId } from "../../../core/frontend-runtime/chat-id.js";
13
13
  import { logError } from "../../../util/log.js";
14
14
  import {
15
15
  shouldHandleInGuild,
@@ -11,7 +11,7 @@ import {
11
11
  createDmUserTracker,
12
12
  createNoticeCooldown,
13
13
  createRateLimiter,
14
- } from "../../shared/access.js";
14
+ } from "../../presentation/access.js";
15
15
 
16
16
  // ── Chat registry: numericChatId → Discord channel info ─────────────────────
17
17
  // The gateway/dispatcher uses numeric chatIds. Action handlers need to map
@@ -18,10 +18,9 @@ import type { Client, Message } from "discord.js";
18
18
  import { ChannelType } from "discord.js";
19
19
  import type { TalonConfig } from "../../core/config/index.js";
20
20
  import { pushMessage } from "../../storage/history.js";
21
- import { registerChat } from "../../core/background/pulse.js";
22
- import { deriveNumericChatId } from "../../util/chat-id.js";
21
+ import { registerChat } from "../../core/background/pulse/pulse.js";
22
+ import { deriveNumericChatId } from "../../core/frontend-runtime/chat-id.js";
23
23
  import { handleMessage, getSenderName } from "./handlers/index.js";
24
- import { recordReactionToBot } from "../../core/soul/taps.js";
25
24
 
26
25
  export function registerMiddleware(client: Client, config: TalonConfig): void {
27
26
  client.on("messageCreate", (msg: Message) => {
@@ -86,27 +85,4 @@ export function registerMiddleware(client: Client, config: TalonConfig): void {
86
85
  /* logged inside */
87
86
  });
88
87
  });
89
-
90
- // ── Reaction tap — feed reactions on Talon's own messages to the soul ────
91
- // The gateway records outgoing message ids as `Number(snowflake)`, so the
92
- // lookup here must use the same conversion to match. Inert unless the soul
93
- // is enabled.
94
- client.on("messageReactionAdd", async (reaction, user) => {
95
- if (user.id === client.user?.id) return;
96
- try {
97
- // A partial arrives when the message predates the cache; the chat id
98
- // can't be built without the channel/guild it belongs to.
99
- if (reaction.partial) await reaction.fetch();
100
- } catch {
101
- return;
102
- }
103
- const msg = reaction.message;
104
- const emoji = reaction.emoji.name;
105
- if (!emoji) return;
106
- const chatId =
107
- msg.channel.type === ChannelType.DM
108
- ? `discord_dm_${msg.author?.id ?? user.id}`
109
- : `discord_guild_${msg.guildId}_${msg.channelId}`;
110
- recordReactionToBot(chatId, Number(msg.id), [emoji]);
111
- });
112
88
  }
@@ -6,7 +6,7 @@
6
6
 
7
7
  import { ActivityType, type Client } from "discord.js";
8
8
  import { log, logError } from "../../util/log.js";
9
- import { deriveNumericChatId } from "../../util/chat-id.js";
9
+ import { deriveNumericChatId } from "../../core/frontend-runtime/chat-id.js";
10
10
  import { registerCommandsForGuilds } from "./commands/index.js";
11
11
  import { registerDiscordChat } from "./handlers/index.js";
12
12
  import { leaveNonWhitelistedGuilds } from "./guild-policy.js";
@@ -2,13 +2,17 @@
2
2
  * Message rendering for Discord commands, callbacks, and the settings panel:
3
3
  * metrics, doctor, mesh, usage and settings text, sized to Discord's limits.
4
4
  *
5
- * Discord-specific quirks vs the Telegram helpers:
5
+ * The reports themselves live in `frontend/presentation/reports.ts` — this
6
+ * file is Discord's dialect of them (`DISCORD_REPORTS`) plus the wrappers
7
+ * that keep each command to a single import.
8
+ *
9
+ * Discord-specific quirks vs the Telegram renderers:
6
10
  * - settings panel uses Components (Buttons + Select Menus), not inline keyboard.
7
11
  * - custom_id strings are limited to 100 chars total — keep payload compact.
8
12
  * - chat IDs are Discord snowflakes (strings), not numbers.
13
+ * - markdown needs no escaping, so `escape` is the identity function.
9
14
  */
10
15
 
11
- import { REASONING_LEVEL_DESCRIPTIONS } from "../../core/models/reasoning-levels.js";
12
16
  import {
13
17
  DISCORD_MAX_TEXT,
14
18
  DISCORD_SAFE_RESERVE,
@@ -16,13 +20,18 @@ import {
16
20
  } from "./formatting.js";
17
21
  import type { DoctorReport } from "../../core/doctor/index.js";
18
22
  import type { MeshPingResult } from "../../core/mesh/service.js";
19
- import type { BackendUsageEntry } from "../shared/plan-usage-report.js";
23
+ import type { BackendUsageEntry } from "../presentation/plan-usage-report.js";
20
24
  import {
21
- DEFAULT_PULSE_INTERVAL_MS,
22
- formatDuration,
23
- formatBytes,
24
- formatModelLabel,
25
- } from "../shared/format.js";
25
+ renderDoctorReport,
26
+ renderMeshReport as renderMeshReportWith,
27
+ renderMetricsMessages as renderMetricsMessagesWith,
28
+ renderSettingsText as renderSettingsTextWith,
29
+ renderUsageMessage as renderUsageMessageWith,
30
+ type MetricsSnapshot,
31
+ type ReportFormatter,
32
+ } from "../presentation/reports.js";
33
+
34
+ export { EFFORT_DESCRIPTIONS } from "../presentation/reasoning-levels.js";
26
35
 
27
36
  export {
28
37
  parseInterval,
@@ -31,28 +40,23 @@ export {
31
40
  formatBytes,
32
41
  formatUsd,
33
42
  formatModelLabel,
34
- } from "../shared/format.js";
43
+ } from "../presentation/format.js";
35
44
 
36
- /** Per-message length budget for metrics output. */
45
+ /** Per-message length budget for report output. */
37
46
  const DEFAULT_METRICS_MESSAGE_MAX = DISCORD_MAX_TEXT - DISCORD_SAFE_RESERVE;
38
47
 
39
- /** Effort level descriptions shown next to each option in select menus. */
40
- export const EFFORT_DESCRIPTIONS: Record<string, string> = {
41
- ...REASONING_LEVEL_DESCRIPTIONS,
42
- };
43
-
44
- type MetricsSnapshot = {
45
- counters: Record<string, number>;
46
- histograms: Record<
47
- string,
48
- { count: number; avg: number; min: number; max: number }
49
- >;
48
+ /** Discord markdown: bold/italic/code markers, no escaping, 2000-char messages. */
49
+ const DISCORD_REPORTS: ReportFormatter = {
50
+ bold: (s) => `**${s}**`,
51
+ italic: (s) => `_${s}_`,
52
+ emphasis: (s) => `*${s}*`,
53
+ code: (s) => `\`${s}\``,
54
+ escape: (s) => s,
55
+ lineLimit: DEFAULT_METRICS_MESSAGE_MAX,
56
+ metricLabelMax: 60,
57
+ pulseLabel: "🔔 Pulse:",
50
58
  };
51
59
 
52
- function truncateMetricLabel(label: string, max = 60): string {
53
- return label.length <= max ? label : `${label.slice(0, max - 3)}...`;
54
- }
55
-
56
60
  /**
57
61
  * Render the metrics report into one or more Discord messages, each ≤ maxLen
58
62
  * (default ~1900 chars to leave headroom under the 2000-char limit).
@@ -62,117 +66,9 @@ export function renderMetricsMessages(
62
66
  maxLen = DEFAULT_METRICS_MESSAGE_MAX,
63
67
  title = "📊 Metrics",
64
68
  ): string[] {
65
- const firstHeader = `**${title}**`;
66
- const continuationHeader = `**${title} (cont.)**`;
67
- const sections: string[][] = [];
68
-
69
- // Histograms come in two flavours: durations (keys ending in `_ms`,
70
- // rendered as human times) and plain counts like `tool_calls_per_turn`
71
- // (rendered as bare numbers — "min=1ms" for a count is nonsense).
72
- const histKeys = Object.keys(metrics.histograms).sort();
73
- const durationKeys = histKeys.filter((key) => key.endsWith("_ms"));
74
- const countKeys = histKeys.filter((key) => !key.endsWith("_ms"));
75
- const histLine = (key: string, fmt: (v: number) => string): string => {
76
- const h = metrics.histograms[key];
77
- return (
78
- ` \`${truncateMetricLabel(key)}\` n=${h.count} ` +
79
- `avg=${fmt(h.avg)} min=${fmt(h.min)} ` +
80
- `max=${fmt(h.max)}`
81
- );
82
- };
83
- if (durationKeys.length > 0) {
84
- sections.push([
85
- "**Latency**",
86
- ...durationKeys.map((key) => histLine(key, formatDuration)),
87
- ]);
88
- }
89
- if (countKeys.length > 0) {
90
- sections.push([
91
- "**Distributions**",
92
- ...countKeys.map((key) => histLine(key, String)),
93
- ]);
94
- }
95
-
96
- const counterKeys = Object.keys(metrics.counters).sort();
97
- if (counterKeys.length > 0) {
98
- const groups = new Map<string, string[]>();
99
- for (const key of counterKeys) {
100
- const prefix = key.includes(".") ? key.split(".")[0]! : "general";
101
- if (!groups.has(prefix)) groups.set(prefix, []);
102
- groups.get(prefix)!.push(key);
103
- }
104
- for (const prefix of [...groups.keys()].sort()) {
105
- // tool_calls reads best as a leaderboard — busiest tools first.
106
- // Other groups keep alphabetical order (stable lookup by name).
107
- const keys =
108
- prefix === "tool_calls"
109
- ? [...groups.get(prefix)!].sort(
110
- (a, b) =>
111
- metrics.counters[b]! - metrics.counters[a]! ||
112
- a.localeCompare(b),
113
- )
114
- : groups.get(prefix)!;
115
- sections.push([
116
- `**${prefix}**`,
117
- ...keys.map((key) => {
118
- const label = key.includes(".")
119
- ? key.split(".").slice(1).join(".")
120
- : key;
121
- return ` \`${truncateMetricLabel(label)}\` ${metrics.counters[key]!.toLocaleString()}`;
122
- }),
123
- ]);
124
- }
125
- }
126
-
127
- if (sections.length === 0) {
128
- return [`${firstHeader}\n\n_No metrics recorded yet._`];
129
- }
130
-
131
- const chunks: string[] = [];
132
- let header = firstHeader;
133
- let current = header;
134
- const flush = () => {
135
- chunks.push(current);
136
- header = continuationHeader;
137
- current = header;
138
- };
139
- const appendLine = (line: string) => {
140
- if (!line && current === header) return;
141
- const candidate = `${current}\n${line}`;
142
- if (candidate.length <= maxLen) {
143
- current = candidate;
144
- return;
145
- }
146
- if (current !== header) {
147
- flush();
148
- if (!line) return;
149
- }
150
- const available = maxLen - header.length - 1;
151
- if (available < 0) return;
152
- const safeLine =
153
- line.length <= available
154
- ? line
155
- : available >= 4
156
- ? `${line.slice(0, available - 3)}...`
157
- : line.slice(0, available);
158
- current = `${current}\n${safeLine}`;
159
- };
160
-
161
- for (const section of sections) {
162
- appendLine("");
163
- for (const line of section) appendLine(line);
164
- }
165
- if (current !== header || chunks.length === 0) chunks.push(current);
166
- return chunks;
69
+ return renderMetricsMessagesWith(metrics, DISCORD_REPORTS, maxLen, title);
167
70
  }
168
71
 
169
- const DOCTOR_ICONS: Record<string, string> = {
170
- ok: "✅",
171
- warn: "⚠️",
172
- fail: "❌",
173
- info: "▫️",
174
- };
175
-
176
72
  /**
177
73
  * Render a DoctorReport as Discord markdown, split to fit the message cap.
178
74
  * Same data as `talon doctor` and Telegram's /doctor.
@@ -181,59 +77,7 @@ export function renderDoctorMessages(
181
77
  report: DoctorReport,
182
78
  maxLen = DEFAULT_METRICS_MESSAGE_MAX,
183
79
  ): string[] {
184
- const lines = ["**🩺 Talon Doctor**", "", "**Environment**"];
185
-
186
- const render = (check: DoctorReport["checks"][number]): string =>
187
- `${DOCTOR_ICONS[check.status]} ${check.label}${check.detail ? ` (${check.detail})` : ""}`;
188
-
189
- for (const check of report.checks.filter((c) => !c.inactive)) {
190
- lines.push(render(check));
191
- }
192
-
193
- // Configured-but-idle backends get their own block: they describe what a
194
- // switch would run into, not the state of the running deployment.
195
- const idle = report.checks.filter((c) => c.inactive);
196
- if (idle.length > 0) {
197
- lines.push("", "**Other backends**", ...idle.map(render));
198
- }
199
-
200
- lines.push("", "**Native modules**");
201
- for (const mod of report.native) {
202
- const size =
203
- mod.sizeBytes !== undefined ? ` · ${formatBytes(mod.sizeBytes)}` : "";
204
- const note = mod.note ? ` (${mod.note})` : "";
205
- lines.push(
206
- `${mod.ok ? DOCTOR_ICONS.ok : DOCTOR_ICONS.fail} \`${mod.name}\` — ${mod.language} → ${mod.target}${size}${note}`,
207
- );
208
- }
209
-
210
- lines.push(
211
- "",
212
- "**Process**",
213
- `Uptime ${formatDuration(process.uptime() * 1000)} · PID ${process.pid} · Node ${process.versions.node}`,
214
- "",
215
- report.issues === 0
216
- ? `${DOCTOR_ICONS.ok} All checks passed.`
217
- : `${DOCTOR_ICONS.warn} ${report.issues} issue(s) found.`,
218
- );
219
-
220
- return splitMessage(lines.join("\n"), maxLen);
221
- }
222
-
223
- function meshDeviceLine(r: MeshPingResult, now: number): string {
224
- const d = r.device;
225
- const bits: string[] = [d.platform];
226
- if (r.reachable && typeof r.latencyMs === "number") {
227
- bits.push(`${r.latencyMs} ms`);
228
- } else if (d.online && r.error) {
229
- bits.push(r.error);
230
- } else if (!d.online) {
231
- bits.push(`last seen ${formatDuration(now - d.lastSeen)} ago`);
232
- }
233
- if (typeof d.battery === "number") {
234
- bits.push(`${d.battery}%${d.charging ? " charging" : ""}`);
235
- }
236
- return ` **${d.name}** — ${bits.join(" · ")}`;
80
+ return splitMessage(renderDoctorReport(report, DISCORD_REPORTS), maxLen);
237
81
  }
238
82
 
239
83
  /**
@@ -244,71 +88,12 @@ export function renderMeshReport(
244
88
  results: MeshPingResult[],
245
89
  now = Date.now(),
246
90
  ): string {
247
- if (results.length === 0) {
248
- return "**Mesh**\n\n_No devices have registered yet._";
249
- }
250
-
251
- const responding = results
252
- .filter((r) => r.reachable)
253
- .sort((a, b) => (a.latencyMs ?? Infinity) - (b.latencyMs ?? Infinity));
254
- const unreachable = results
255
- .filter((r) => !r.reachable && r.device.online)
256
- .sort((a, b) => a.device.name.localeCompare(b.device.name));
257
- const offline = results
258
- .filter((r) => !r.reachable && !r.device.online)
259
- .sort((a, b) => b.device.lastSeen - a.device.lastSeen);
260
-
261
- const summary = [
262
- `${results.length} device${results.length === 1 ? "" : "s"}`,
263
- `${responding.length} responding`,
264
- ...(unreachable.length > 0 ? [`${unreachable.length} unreachable`] : []),
265
- ...(offline.length > 0 ? [`${offline.length} offline`] : []),
266
- ].join(" · ");
267
-
268
- const lines = ["**Mesh**", summary];
269
- const section = (title: string, entries: MeshPingResult[]): void => {
270
- if (entries.length === 0) return;
271
- lines.push(
272
- "",
273
- `**${title}**`,
274
- ...entries.map((r) => meshDeviceLine(r, now)),
275
- );
276
- };
277
- section("Responding", responding);
278
- section("Unreachable", unreachable);
279
- section("Offline", offline);
280
-
281
- return lines.join("\n");
91
+ return renderMeshReportWith(results, DISCORD_REPORTS, now);
282
92
  }
283
93
 
284
94
  /** Render the `/usage` report — one block per exposed backend. */
285
95
  export function renderUsageMessage(entries: BackendUsageEntry[]): string {
286
- const lines = ["**📊 Plan usage**"];
287
-
288
- for (const entry of entries) {
289
- const name = entry.label || entry.id;
290
- if (!entry.plan) {
291
- lines.push("", `**${name}** — _${entry.note ?? ""}_`);
292
- continue;
293
- }
294
- const age = entry.plan.ageLabel ? ` *(${entry.plan.ageLabel})*` : "";
295
- const plan = entry.plan.plan ? ` · ${entry.plan.plan}` : "";
296
- lines.push("", `**${name}**${plan}${age}`);
297
- if (entry.plan.resetsAvailable) {
298
- const n = entry.plan.resetsAvailable;
299
- lines.push(
300
- ` • You have **${n}** usage limit reset${n === 1 ? "" : "s"} available`,
301
- );
302
- }
303
- for (const w of entry.plan.windows) {
304
- const reset = w.resetLabel ? ` reset ${w.resetLabel}` : "";
305
- lines.push(
306
- ` \`${w.label.padEnd(6)}${w.bar} ${String(w.percent).padStart(3)}%\`${reset}`,
307
- );
308
- }
309
- }
310
-
311
- return lines.join("\n");
96
+ return renderUsageMessageWith(entries, DISCORD_REPORTS);
312
97
  }
313
98
 
314
99
  /** Settings panel: build the markdown body. */
@@ -319,15 +104,12 @@ export function renderSettingsText(
319
104
  pulseIntervalMs?: number,
320
105
  modelDetails?: Array<string>,
321
106
  ): string {
322
- const intervalStr = pulseIntervalMs
323
- ? formatDuration(pulseIntervalMs)
324
- : formatDuration(DEFAULT_PULSE_INTERVAL_MS);
325
- return [
326
- "**🦅 Settings**",
327
- "",
328
- `**Model:** \`${formatModelLabel(model)}\``,
329
- ...(modelDetails?.length ? modelDetails : []),
330
- `**Effort:** ${effort}`,
331
- `**🔔 Pulse:** ${proactive ? "on" : "off"} (every ${intervalStr})`,
332
- ].join("\n");
107
+ return renderSettingsTextWith(
108
+ DISCORD_REPORTS,
109
+ model,
110
+ effort,
111
+ proactive,
112
+ pulseIntervalMs,
113
+ modelDetails,
114
+ );
333
115
  }
@@ -34,8 +34,7 @@ function createClient(): Client {
34
34
  GatewayIntentBits.DirectMessageReactions,
35
35
  ],
36
36
  // Partials.Reaction is what makes reactions on messages that predate the
37
- // current cache arrive at all — without it the soul's reaction tap only
38
- // ever sees freshly-cached messages.
37
+ // current cache arrive at all, rather than being dropped silently.
39
38
  partials: [
40
39
  Partials.Channel,
41
40
  Partials.Message,
@@ -15,8 +15,8 @@
15
15
  import { randomBytes } from "node:crypto";
16
16
  import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
17
17
  import { resolve } from "node:path";
18
- import { dirs } from "../../util/paths.js";
19
- import { log } from "../../util/log.js";
18
+ import { dirs } from "../../../util/paths.js";
19
+ import { log } from "../../../util/log.js";
20
20
 
21
21
  const TOKEN_FILE = "bridge-token";
22
22
  /** 32 random bytes → 43 base64url chars; comfortably beyond brute force. */
@@ -1,9 +1,9 @@
1
1
  import { mkdir, rename, rm, writeFile, chmod } from "node:fs/promises";
2
2
  import { dirname, join } from "node:path";
3
3
  import { randomUUID } from "node:crypto";
4
- import { log, logError } from "../../util/log.js";
5
- import { files } from "../../util/paths.js";
6
- import { BRIDGE_PROTOCOL_VERSION } from "./protocol.js";
4
+ import { log, logError } from "../../../util/log.js";
5
+ import { files } from "../../../util/paths.js";
6
+ import { BRIDGE_PROTOCOL_VERSION } from "../protocol.js";
7
7
 
8
8
  export type BridgeDiscoveryInfo = {
9
9
  port: number;
@@ -6,7 +6,7 @@ import {
6
6
  asString,
7
7
  deviceIdParam,
8
8
  } from "./params.js";
9
- import { log, logWarn } from "../../../util/log.js";
9
+ import { log, logWarn } from "../../../../util/log.js";
10
10
 
11
11
  export function chatRoutes(
12
12
  host: RouteHost,
@@ -1,6 +1,6 @@
1
1
  import type { RouteHost } from "./host.js";
2
2
  import type { BridgeRoutes } from "./table.js";
3
- import { isLogLevel } from "../protocol.js";
3
+ import { isLogLevel } from "../../protocol.js";
4
4
  import { asPositiveInt, asString } from "./params.js";
5
5
 
6
6
  export function daemonRoutes(
@@ -18,9 +18,12 @@ import type {
18
18
  SearchResult,
19
19
  SkillItem,
20
20
  ToggleResult,
21
- } from "../protocol.js";
22
- import type { MemoryListQuery, MemoryListResult } from "../memory.js";
23
- import type { ConfigSnapshot } from "../settings.js";
21
+ } from "../../protocol.js";
22
+ import type {
23
+ MemoryListQuery,
24
+ MemoryListResult,
25
+ } from "../../surface/memory.js";
26
+ import type { ConfigSnapshot } from "../../surface/settings.js";
24
27
 
25
28
  /** Optional attachment references carried alongside a sent message. */
26
29
  export type SendOptions = {
@@ -1,6 +1,6 @@
1
1
  import type { RouteHost } from "./host.js";
2
2
  import type { BridgeRoutes } from "./table.js";
3
- import { BRIDGE_PROTOCOL_VERSION } from "../protocol.js";
3
+ import { BRIDGE_PROTOCOL_VERSION } from "../../protocol.js";
4
4
 
5
5
  export function preAuthRoutes(
6
6
  host: RouteHost,
@@ -24,10 +24,10 @@ import { createServer as createTlsServer } from "node:https";
24
24
  import { createHash, timingSafeEqual } from "node:crypto";
25
25
  import { createReadStream } from "node:fs";
26
26
  import { stat } from "node:fs/promises";
27
- import { log, logError, logDebug, logWarn } from "../../util/log.js";
27
+ import { log, logError, logDebug, logWarn } from "../../../util/log.js";
28
28
  import { formatFingerprint, type BridgeTlsIdentity } from "./tls.js";
29
- import { contentTypeFor } from "./media.js";
30
- import { type BridgeEvent } from "./protocol.js";
29
+ import { contentTypeFor } from "../media/media.js";
30
+ import { type BridgeEvent } from "../protocol.js";
31
31
  import { buildRoutes } from "./routes/index.js";
32
32
  import type { BridgeServerHandlers, RouteHost } from "./routes/host.js";
33
33
  import {
@@ -28,8 +28,8 @@ import {
28
28
  } from "node:crypto";
29
29
  import { mkdir, readFile, writeFile, chmod } from "node:fs/promises";
30
30
  import { resolve } from "node:path";
31
- import { dirs } from "../../util/paths.js";
32
- import { log, logWarn } from "../../util/log.js";
31
+ import { dirs } from "../../../util/paths.js";
32
+ import { log, logWarn } from "../../../util/log.js";
33
33
 
34
34
  export interface BridgeTlsIdentity {
35
35
  /** PKCS#8 private key, PEM. */
@@ -4,9 +4,9 @@
4
4
  */
5
5
 
6
6
  import { toClientChat } from "./chat-wire.js";
7
- import type { ClientChat } from "./protocol.js";
8
- import type { NativeRuntime } from "./runtime.js";
9
- import { clearTurnMeta } from "./turn-meta.js";
7
+ import type { ClientChat } from "../protocol.js";
8
+ import type { NativeRuntime } from "../runtime.js";
9
+ import { clearTurnMeta } from "../turn/turn-meta.js";
10
10
 
11
11
  export function createChat(runtime: NativeRuntime, title?: string): ClientChat {
12
12
  const entry = runtime.chats.create(title);
@@ -8,11 +8,11 @@
8
8
  import {
9
9
  getChatSettings,
10
10
  getChatModelForBackend,
11
- } from "../../storage/chat-settings.js";
12
- import { getBackendIdForChat } from "../../core/engine/backend-controller/index.js";
11
+ } from "../../../storage/chat-settings.js";
12
+ import { getBackendIdForChat } from "../../../core/engine/backend-controller/index.js";
13
13
  import type { ChatEntry } from "./chats.js";
14
- import type { ClientChat, QueuedMessage } from "./protocol.js";
15
- import type { NativeRuntime } from "./runtime.js";
14
+ import type { ClientChat, QueuedMessage } from "../protocol.js";
15
+ import type { NativeRuntime } from "../runtime.js";
16
16
 
17
17
  /** Project the stored queue entry to its wire shape (text + attachments). */
18
18
  function toQueued(
@@ -11,14 +11,14 @@ import {
11
11
  generateNativeChatId,
12
12
  deriveNumericChatId,
13
13
  isNativeChatId,
14
- } from "../../util/chat-id.js";
14
+ } from "../../../core/frontend-runtime/chat-id.js";
15
15
  import {
16
16
  getAllSessions,
17
17
  setSessionName,
18
18
  deleteSession,
19
- } from "../../storage/sessions.js";
20
- import { getRecentHistory, clearHistory } from "../../storage/history.js";
21
- import { previewOf } from "./protocol.js";
19
+ } from "../../../storage/sessions.js";
20
+ import { getRecentHistory, clearHistory } from "../../../storage/history.js";
21
+ import { previewOf } from "../protocol.js";
22
22
 
23
23
  export type ChatEntry = {
24
24
  id: string;