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
@@ -0,0 +1,387 @@
1
+ /**
2
+ * The agent-host seam — the contract between the daemon and the process
3
+ * that hosts the Claude Agent SDK.
4
+ *
5
+ * `docs/agent-host-sidecar.md` Phase 1. Today the SDK runs inside the
6
+ * daemon: an OOM or an SDK bug takes down every frontend with it. The
7
+ * sidecar moves it into its own process, and this file is the boundary
8
+ * that move happens across — written first, on purpose, so Phase 2 is a
9
+ * transport swap rather than a redesign.
10
+ *
11
+ * Two halves:
12
+ *
13
+ * - **The wire vocabulary.** `HostRequest` / `HostReply` / `HostEvent` /
14
+ * `HostNotice` are the NDJSON messages of the design's protocol
15
+ * table, one TypeScript type per row, plus `parseHostMessage` /
16
+ * `serializeHostMessage` — the codec both sides run, replayed against
17
+ * `protocol/fixtures/agent-host_v1.json` in
18
+ * `src/__tests__/agent-host-protocol.test.ts`.
19
+ * - **The client.** `AgentHostClient` is what the daemon holds. Phase 1
20
+ * ships one implementation (`backend/claude-sdk/host/in-process.ts`,
21
+ * a direct call-through); Phase 2 adds a second that speaks the
22
+ * messages above over a child process's stdio. The `Backend` object
23
+ * the rest of the daemon sees is identical either way.
24
+ *
25
+ * Layering: the interface and the codec live in `core/` because `core/`
26
+ * may not import `backend/` (depcruise `core-not-to-backend`). Every
27
+ * implementation lives under `backend/`.
28
+ *
29
+ * Wire types vs client types
30
+ * ──────────────────────────
31
+ * They are deliberately not the same types. Two client arguments do not
32
+ * survive a process boundary and the wire shapes say so:
33
+ *
34
+ * - `OneShotAgentParams` carries an `AbortController` and an
35
+ * `appendLog` callback. `HostOneShotParams` is the serialisable
36
+ * subset; Phase 2 maps `appendLog` onto `log` notices and the
37
+ * abort onto an `interrupt`-shaped request.
38
+ * - `hello.config` is the `claude-sdk` slice of `TalonConfig` as
39
+ * JSON. The in-process client takes the real `TalonConfig` object.
40
+ *
41
+ * Forward compatibility: unknown fields on a known message type are
42
+ * additive evolution and must be preserved, never rejected. An unknown
43
+ * `type` parses to `HostUnknown`, which callers log and drop — the codec
44
+ * never throws, so one bad line can't kill a turn or the loop reading it.
45
+ */
46
+
47
+ import type { AgentEvent, AgentError } from "./events.js";
48
+ import type { ChatRunParams, PlanUsage } from "./capabilities.js";
49
+ import type {
50
+ OneShotAgentParams,
51
+ OneShotUsage,
52
+ ReasoningEffortLevel,
53
+ UnifiedModelInfo,
54
+ } from "../types.js";
55
+
56
+ /** Wire-format version. Bump only on a breaking change — prefer additive. */
57
+ export const AGENT_HOST_PROTOCOL_VERSION = 1;
58
+
59
+ // ── Shared payload shapes ───────────────────────────────────────────────────
60
+
61
+ /**
62
+ * The serialisable half of `OneShotAgentParams`. `abortController` and
63
+ * `appendLog` are host-local concerns (see the file header); everything
64
+ * else is exactly what a background run needs.
65
+ *
66
+ * Unexported on purpose — it is reachable as
67
+ * `Extract<HostRequest, { type: "one_shot" }>["params"]`, and a second
68
+ * name for the same shape is a thing to keep in sync for nothing.
69
+ */
70
+ interface HostOneShotParams {
71
+ prompt: string;
72
+ systemPrompt: string;
73
+ workspace: string;
74
+ model: string;
75
+ reasoningEffort?: ReasoningEffortLevel;
76
+ contextLabel: string;
77
+ }
78
+
79
+ /**
80
+ * The MCP diff `set_mcp_servers` / `refresh_tools` answer with — the same
81
+ * shape `ToolRuntime.refreshTools` returns to the dispatcher today.
82
+ */
83
+ export interface HostToolRefresh {
84
+ added: string[];
85
+ removed: string[];
86
+ errors: Record<string, string>;
87
+ }
88
+
89
+ /**
90
+ * What the host knows about one chat's session. `sessionId` is the SDK's
91
+ * resume handle; the context figures are the ones `warm_session` populates
92
+ * — which is why this query exists at all. In-process those numbers land
93
+ * in the daemon's own session store; across a process boundary they have
94
+ * to be asked for.
95
+ */
96
+ export interface HostSessionInfo {
97
+ chatId: string;
98
+ sessionId?: string;
99
+ turns: number;
100
+ contextTokens: number;
101
+ contextWindow: number;
102
+ }
103
+
104
+ /** `ready`'s payload — the handshake answer, minus the envelope. */
105
+ export interface HostReadyInfo {
106
+ protocol: number;
107
+ /** The host build's version. */
108
+ host: string;
109
+ /**
110
+ * The Claude Agent SDK version the host is running. Absent in-process,
111
+ * where there is no separately-pinned SDK to report (Phase 4 gives the
112
+ * host its own `package.json`).
113
+ */
114
+ sdk?: string;
115
+ }
116
+
117
+ // ── Daemon → host ───────────────────────────────────────────────────────────
118
+
119
+ /**
120
+ * Every request the daemon can send. Each carries an `id`; the reply
121
+ * carries the same `id`. Turn-shaped requests (`run_turn`, `one_shot`)
122
+ * additionally carry a `runId`, which every streamed `event` repeats.
123
+ */
124
+ export type HostRequest =
125
+ | {
126
+ type: "hello";
127
+ id: string;
128
+ protocol: number;
129
+ /** The daemon's version, for the host's compatibility log line. */
130
+ daemon: string;
131
+ /** The `claude-sdk` slice of `TalonConfig`, as JSON. */
132
+ config: Record<string, unknown>;
133
+ }
134
+ | { type: "run_turn"; id: string; runId: string; params: ChatRunParams }
135
+ | { type: "interrupt"; id: string; chatId: string }
136
+ | { type: "one_shot"; id: string; runId: string; params: HostOneShotParams }
137
+ | { type: "warm_session"; id: string; chatId: string }
138
+ | {
139
+ type: "set_mcp_servers";
140
+ id: string;
141
+ chatId: string;
142
+ /** SDK `McpServerConfig` map, opaque here — the host hands it to the SDK. */
143
+ servers: Record<string, unknown>;
144
+ }
145
+ | { type: "refresh_tools"; id: string; chatId: string }
146
+ | { type: "list_models"; id: string; filter?: "free" | "all" }
147
+ | { type: "plan_usage"; id: string }
148
+ | { type: "session_info"; id: string; chatId: string }
149
+ | { type: "reset_session"; id: string; chatId: string }
150
+ | { type: "shutdown"; id: string };
151
+
152
+ // ── Host → daemon ───────────────────────────────────────────────────────────
153
+
154
+ /**
155
+ * Every reply. `ok` is the generic ack, with one optional field per
156
+ * request that has something to say back; the queries get their own
157
+ * types so a reply is never ambiguous with the request that asked for it
158
+ * (`list_models` → `models`, `plan_usage` → `usage`, `session_info` →
159
+ * `session`).
160
+ */
161
+ export type HostReply =
162
+ | ({ type: "ready"; id: string } & HostReadyInfo)
163
+ | {
164
+ type: "ok";
165
+ id: string;
166
+ /** `interrupt` — a running turn was found and signalled. */
167
+ interrupted?: boolean;
168
+ /** `set_mcp_servers` / `refresh_tools` — `null` when the chat has no live query. */
169
+ tools?: HostToolRefresh | null;
170
+ /** `reset_session` — host-side per-chat state was dropped. */
171
+ cleared?: boolean;
172
+ }
173
+ | { type: "run_done"; id: string; runId: string; usage?: OneShotUsage }
174
+ | { type: "error"; id: string; error: AgentError }
175
+ | { type: "models"; id: string; models: UnifiedModelInfo[]; total: number }
176
+ | { type: "usage"; id: string; usage?: PlanUsage }
177
+ | { type: "session"; id: string; session?: HostSessionInfo }
178
+ | { type: "bye"; id: string };
179
+
180
+ /**
181
+ * One turn event. The `AgentEvent` union is unchanged and unwrapped —
182
+ * that is the whole point of the seam: the daemon's consumers switch on
183
+ * `event.type` exactly as they do against an in-process backend.
184
+ */
185
+ export interface HostEvent {
186
+ type: "event";
187
+ runId: string;
188
+ event: AgentEvent;
189
+ }
190
+
191
+ /**
192
+ * Unsolicited host → daemon traffic, carrying no `id` because nothing
193
+ * asked for it. `log` is the host's stdout logging (stderr is tailed by
194
+ * the supervisor like an MCP child's); `metric` forwards the `cache.*`
195
+ * and turn counters the host records so the daemon's rollups are
196
+ * unchanged by the move.
197
+ */
198
+ export type HostNotice =
199
+ | {
200
+ type: "log";
201
+ level: "debug" | "info" | "warn" | "error";
202
+ component: string;
203
+ msg: string;
204
+ }
205
+ | { type: "metric"; name: string; value: number };
206
+
207
+ /** Anything that can appear on the wire, either direction. */
208
+ export type HostMessage = HostRequest | HostReply | HostEvent | HostNotice;
209
+
210
+ /**
211
+ * A line the codec could not place. Never thrown — returned, so the
212
+ * reader logs it and drops it. `raw` is whatever came off the wire so
213
+ * the log can say what was skipped.
214
+ */
215
+ export interface HostUnknown {
216
+ type: "unknown";
217
+ reason: "malformed_json" | "not_an_object" | "unknown_type";
218
+ raw: unknown;
219
+ }
220
+
221
+ // ── The type registry the codec discriminates on ────────────────────────────
222
+
223
+ /**
224
+ * `satisfies` rejects typos here; the `AssertNever` checks in
225
+ * `src/__tests__/agent-host-protocol.test.ts` fail to compile when a new
226
+ * member joins a union without being listed — which forces a fixture
227
+ * sample too, because the fixture test asserts these lists exactly.
228
+ */
229
+ export const HOST_REQUEST_TYPES = [
230
+ "hello",
231
+ "run_turn",
232
+ "interrupt",
233
+ "one_shot",
234
+ "warm_session",
235
+ "set_mcp_servers",
236
+ "refresh_tools",
237
+ "list_models",
238
+ "plan_usage",
239
+ "session_info",
240
+ "reset_session",
241
+ "shutdown",
242
+ ] as const satisfies readonly HostRequest["type"][];
243
+
244
+ export const HOST_REPLY_TYPES = [
245
+ "ready",
246
+ "ok",
247
+ "run_done",
248
+ "error",
249
+ "models",
250
+ "usage",
251
+ "session",
252
+ "bye",
253
+ ] as const satisfies readonly HostReply["type"][];
254
+
255
+ export const HOST_NOTICE_TYPES = [
256
+ "log",
257
+ "metric",
258
+ ] as const satisfies readonly HostNotice["type"][];
259
+
260
+ const KNOWN_TYPES: ReadonlySet<string> = new Set<string>([
261
+ ...HOST_REQUEST_TYPES,
262
+ ...HOST_REPLY_TYPES,
263
+ ...HOST_NOTICE_TYPES,
264
+ "event",
265
+ ]);
266
+
267
+ // ── Codec ───────────────────────────────────────────────────────────────────
268
+
269
+ /**
270
+ * Render one message as its NDJSON line — no trailing newline, so the
271
+ * transport owns the framing. Symmetric with `parseHostMessage`.
272
+ */
273
+ export function serializeHostMessage(message: HostMessage): string {
274
+ return JSON.stringify(message);
275
+ }
276
+
277
+ /**
278
+ * Parse one NDJSON line. Total: malformed JSON, non-objects and unknown
279
+ * `type`s all come back as `HostUnknown` rather than throwing, because a
280
+ * single bad line from a newer peer must not take down the read loop.
281
+ *
282
+ * Unknown FIELDS on a known type are preserved as-is — additive evolution
283
+ * is the protocol's normal path, and dropping them here would silently
284
+ * downgrade a message the other end meant to send.
285
+ */
286
+ export function parseHostMessage(line: string): HostMessage | HostUnknown {
287
+ let parsed: unknown;
288
+ try {
289
+ parsed = JSON.parse(line);
290
+ } catch {
291
+ return { type: "unknown", reason: "malformed_json", raw: line };
292
+ }
293
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
294
+ return { type: "unknown", reason: "not_an_object", raw: parsed };
295
+ }
296
+ const type = (parsed as { type?: unknown }).type;
297
+ if (typeof type !== "string" || !KNOWN_TYPES.has(type)) {
298
+ return { type: "unknown", reason: "unknown_type", raw: parsed };
299
+ }
300
+ return parsed as HostMessage;
301
+ }
302
+
303
+ // ── The client the daemon holds ─────────────────────────────────────────────
304
+
305
+ /**
306
+ * What the daemon calls instead of reaching into `backend/claude-sdk/`
307
+ * directly. One method per protocol-table row, with the signatures the
308
+ * claude-sdk `BackendFactory` actually uses today — no capability the
309
+ * backend does not have is invented here.
310
+ *
311
+ * Bound into the `Backend` object in Phase 1: `hello`, `runTurn`,
312
+ * `interrupt`, `runOneShot`, `warmSession`, `refreshTools`, `listModels`,
313
+ * `planUsage`. Defined-but-unbound: `setMcpServers` (the primitive
314
+ * `refreshTools` is built from), `sessionInfo` and `resetSession` (the
315
+ * Claude SDK backend exposes neither a `getSessionSnapshot` nor a
316
+ * `resetChat` slot, and Phase 1 may not change the `Backend` object), and
317
+ * `shutdown` (nothing to stop until there is a process).
318
+ */
319
+ export interface AgentHostClient {
320
+ /**
321
+ * Handshake + initialisation. In-process this is `initAgent(config)`;
322
+ * across a process it is `hello` → `ready`. Must resolve before any
323
+ * other call — model discovery happens here.
324
+ */
325
+ hello(): Promise<HostReadyInfo>;
326
+
327
+ /**
328
+ * One chat turn. The returned stream is the canonical `AgentEvent`
329
+ * sequence, `run_started` first and `completed`/`error` last, exactly
330
+ * as `ChatBackend.runChatTurn` promises.
331
+ */
332
+ runTurn(params: ChatRunParams): AsyncIterable<AgentEvent>;
333
+
334
+ /** Best-effort stop of a chat's in-flight turn. `true` when one was signalled. */
335
+ interrupt(chatId: string): Promise<boolean>;
336
+
337
+ /**
338
+ * One background run (heartbeat / dream / cron). Resolves with the
339
+ * run's usage when the SDK reports it.
340
+ *
341
+ * Callback-shaped, not a stream: `OneShotAgentParams.appendLog` is how
342
+ * the background producers write their markdown logs today, and turning
343
+ * that into an event stream would be a behaviour change, not a seam.
344
+ * The design's "stream as above" row is Phase 2's problem, and the wire
345
+ * type (`HostOneShotParams`) already records what has to give.
346
+ */
347
+ runOneShot(params: OneShotAgentParams): Promise<OneShotUsage | void>;
348
+
349
+ /** Cold-start hint: spawn a throwaway query to prime the context figures. */
350
+ warmSession(chatId: string): Promise<void>;
351
+
352
+ /**
353
+ * Install an MCP server set on the chat's live query. `null` when the
354
+ * chat has no query in flight. The primitive `refreshTools` is built
355
+ * from; the two-phase teardown lives in the host, not the caller,
356
+ * because `Query` handles do not cross a process boundary.
357
+ */
358
+ setMcpServers(
359
+ chatId: string,
360
+ servers: Record<string, unknown>,
361
+ ): Promise<HostToolRefresh | null>;
362
+
363
+ /** Re-derive the chat's MCP config from the live plugin registry. */
364
+ refreshTools(chatId: string): Promise<HostToolRefresh | null>;
365
+
366
+ /**
367
+ * The model catalog, as the host discovered it from the SDK. The other
368
+ * seven `ModelCatalog` members are pure daemon-side formatting over
369
+ * `core/models/catalog.ts`, which `hello` populates — see
370
+ * `docs/agent-host-sidecar.md` Phase 1.
371
+ */
372
+ listModels(
373
+ filter?: "free" | "all",
374
+ ): Promise<{ models: UnifiedModelInfo[]; total: number }>;
375
+
376
+ /** Subscription rate-limit windows for `/status`. */
377
+ planUsage(): Promise<PlanUsage | undefined>;
378
+
379
+ /** What the host knows about a chat's session, including the context figures. */
380
+ sessionInfo(chatId: string): Promise<HostSessionInfo | undefined>;
381
+
382
+ /** Drop the host's per-chat state. `true` when there was something to drop. */
383
+ resetSession(chatId: string): Promise<boolean>;
384
+
385
+ /** Drain in-flight turns, then stop. A no-op while the host is in-process. */
386
+ shutdown(): Promise<void>;
387
+ }
@@ -56,6 +56,17 @@ export interface ChatRunParams {
56
56
  isGroup?: boolean;
57
57
  /** Provider message ID. Telegram is numeric; Discord snowflakes are strings. */
58
58
  messageId?: number | string;
59
+ /**
60
+ * Memory retrieved for this turn by `core/memory/turn-retrieval.ts`,
61
+ * already ranked, trust-filtered and budgeted. The Weaver resolves it
62
+ * before the call; a backend's only job is to hand it to
63
+ * `formatUserPrompt`, which owns the rendering.
64
+ *
65
+ * Turn-scoped and user-turn-only: it must never reach
66
+ * `prepareSystemPrompt()` or a backend `system` field, or the
67
+ * per-session frozen prompt stops being frozen (plan §3.6).
68
+ */
69
+ retrievedMemory?: string;
59
70
  }
60
71
 
61
72
  // ── Catalog types ───────────────────────────────────────────────────────────
@@ -199,6 +199,80 @@ export async function assertCompletedUsageMatchesUsageEvent(
199
199
  }
200
200
  }
201
201
 
202
+ /**
203
+ * `ChatRunParams.retrievedMemory` must reach the prompt the backend
204
+ * sends, in the USER turn, after the message text.
205
+ *
206
+ * This is the clause #639 was written in the absence of: the old
207
+ * pre-retrieval field was honoured by two backends and dropped in
208
+ * silence by the other four, a divergence that would have become a
209
+ * real bug the day a retriever existed. Now there is one renderer
210
+ * (`backend/runtime/prompt/prompt-format.ts`) that every backend already calls
211
+ * for its time tag and `msg_id` framing — and this assertion is what
212
+ * stops a backend from quietly building its prompt some other way.
213
+ *
214
+ * The caller supplies `capturePrompt`, returning the prompt the
215
+ * backend built for the last run: `core/` cannot import `backend/`, so
216
+ * the rendering itself is asserted by the caller, which can. `marker`
217
+ * is the retrieved text; it must appear after the user's own text, and
218
+ * must not appear at all when the field is absent.
219
+ */
220
+ export async function assertChatBackendCarriesRetrievedMemory(
221
+ backend: Backend,
222
+ capturePrompt: () => string | undefined,
223
+ options: { text?: string; chatId?: string; marker?: string } = {},
224
+ ): Promise<void> {
225
+ const chat = backend.chat;
226
+ if (!chat) return;
227
+ const text = options.text ?? "ping";
228
+ const marker = options.marker ?? "#1 [fact] contract: remembered thing";
229
+ const run = async (retrievedMemory?: string): Promise<string> => {
230
+ await drain(
231
+ chat.runChatTurn({
232
+ chatId: options.chatId ?? "contract-test-chat",
233
+ model: makeBareModelRef(backend.id, "contract-test-model"),
234
+ text,
235
+ senderName: "ContractTest",
236
+ ...(retrievedMemory !== undefined ? { retrievedMemory } : {}),
237
+ }),
238
+ );
239
+ const prompt = capturePrompt();
240
+ if (prompt === undefined) {
241
+ throw new ContractViolation(
242
+ backend.id,
243
+ "ChatBackend.carriesRetrievedMemory",
244
+ "the backend built no prompt for the turn",
245
+ );
246
+ }
247
+ return prompt;
248
+ };
249
+
250
+ const withMemory = await run(marker);
251
+ if (!withMemory.includes(marker)) {
252
+ throw new ContractViolation(
253
+ backend.id,
254
+ "ChatBackend.carriesRetrievedMemory",
255
+ `retrievedMemory never reached the prompt: ${JSON.stringify(withMemory)}`,
256
+ );
257
+ }
258
+ if (withMemory.indexOf(marker) < withMemory.indexOf(text)) {
259
+ throw new ContractViolation(
260
+ backend.id,
261
+ "ChatBackend.carriesRetrievedMemory",
262
+ "the memory block precedes the user text; it must be appended after it",
263
+ );
264
+ }
265
+
266
+ const without = await run();
267
+ if (without.includes(marker)) {
268
+ throw new ContractViolation(
269
+ backend.id,
270
+ "ChatBackend.carriesRetrievedMemory",
271
+ "the memory block appeared in a turn that carried no retrievedMemory",
272
+ );
273
+ }
274
+ }
275
+
202
276
  /**
203
277
  * Backends that expose a `BackgroundRunner` must terminate with
204
278
  * `completed` or `error` and must emit `run_started` first — same
@@ -323,7 +397,16 @@ export async function assertUsageTelemetryShape(
323
397
  */
324
398
  export async function assertBackendContract(
325
399
  backend: Backend,
326
- options: { text?: string; chatId?: string } = {},
400
+ options: {
401
+ text?: string;
402
+ chatId?: string;
403
+ /**
404
+ * The prompt the backend built for the last run, when the fixture
405
+ * can capture it. Supplying it opts the turn-retrieval clause into
406
+ * the suite; omitting it skips that clause only.
407
+ */
408
+ capturePrompt?: () => string | undefined;
409
+ } = {},
327
410
  ): Promise<string[]> {
328
411
  const checked: string[] = [];
329
412
 
@@ -336,6 +419,14 @@ export async function assertBackendContract(
336
419
  checked.push("ChatBackend.singleUsage");
337
420
  await assertCompletedUsageMatchesUsageEvent(backend, options);
338
421
  checked.push("ChatBackend.completedUsageMatches");
422
+ if (options.capturePrompt) {
423
+ await assertChatBackendCarriesRetrievedMemory(
424
+ backend,
425
+ options.capturePrompt,
426
+ options,
427
+ );
428
+ checked.push("ChatBackend.carriesRetrievedMemory");
429
+ }
339
430
  }
340
431
  if (backend.background) {
341
432
  await assertBackgroundRunnerLifecycle(backend);
@@ -9,7 +9,7 @@
9
9
  * longer render markdown logs themselves and core no longer parses
10
10
  * backend-specific output.
11
11
  *
12
- * The shared wrapper `backend/shared/handler-to-events.ts` converts
12
+ * The shared wrapper `backend/runtime/turn/handler-to-events.ts` converts
13
13
  * each backend's existing callback-driven `handleMessage` into the
14
14
  * canonical sequence: `run_started → text_delta* →
15
15
  * assistant_message* → tool_call* → usage → completed`. Backends
@@ -14,9 +14,9 @@
14
14
  * unset to avoid sweeping the other context's subprocesses.
15
15
  */
16
16
 
17
- import type { BackgroundRunner } from "../agent-runtime/capabilities.js";
18
- import type { OneShotAgentParams, OneShotUsage } from "../types.js";
19
- import { logWarn, logError } from "../../util/log.js";
17
+ import type { BackgroundRunner } from "../../agent-runtime/capabilities.js";
18
+ import type { OneShotAgentParams, OneShotUsage } from "../../types.js";
19
+ import { logWarn, logError } from "../../../util/log.js";
20
20
 
21
21
  /** Default bounded grace after an abort before giving up on the backend. */
22
22
  const DEFAULT_ABORT_GRACE_MS = 30 * 1000;
@@ -22,7 +22,7 @@ import {
22
22
  CLOSED_BREAKER,
23
23
  stepBreaker,
24
24
  type Breaker,
25
- } from "../../native/scheduler-core.js";
25
+ } from "../../../native/scheduler-core.js";
26
26
 
27
27
  export type JobHealthOptions = {
28
28
  /** Consecutive failures before the breaker opens. */
@@ -14,14 +14,14 @@
14
14
  */
15
15
 
16
16
  import { mkdir, appendFile } from "node:fs/promises";
17
- import { dirs } from "../../util/paths.js";
18
- import { log, logWarn } from "../../util/log.js";
17
+ import { dirs } from "../../../util/paths.js";
18
+ import { log, logWarn } from "../../../util/log.js";
19
19
  import {
20
20
  acquireBackendInstance,
21
21
  isModelValidForBackend,
22
- } from "../engine/backend-controller/index.js";
23
- import { taskTable } from "../tasks/index.js";
24
- import type { OneShotAgentParams } from "../types.js";
22
+ } from "../../engine/backend-controller/index.js";
23
+ import { taskTable } from "../../tasks/index.js";
24
+ import type { OneShotAgentParams } from "../../types.js";
25
25
  import { runIsolatedAgent } from "./isolated-agent.js";
26
26
  import {
27
27
  buildJobSystemPrompt,
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { resolve } from "node:path";
8
- import { dirs } from "../../util/paths.js";
8
+ import { dirs } from "../../../util/paths.js";
9
9
 
10
10
  export type JobKind = "trigger" | "cron";
11
11
 
@@ -20,7 +20,7 @@
20
20
  */
21
21
 
22
22
  import { Cron } from "croner";
23
- import { getActiveCount } from "../engine/dispatcher.js";
23
+ import { getActiveCount } from "../../engine/dispatcher.js";
24
24
  import {
25
25
  getAllCronJobs,
26
26
  getCronJob,
@@ -31,10 +31,10 @@ import {
31
31
  describeSchedule,
32
32
  type CronJob,
33
33
  type CronRunOutcome,
34
- } from "../../storage/cron.js";
35
- import { appendDailyLog } from "../../storage/daily-log.js";
36
- import { log, logError, logWarn } from "../../util/log.js";
37
- import { numericChatIdFor } from "../../util/chat-id.js";
34
+ } from "../../../storage/cron.js";
35
+ import { appendDailyLog } from "../../../storage/daily-log.js";
36
+ import { log, logError, logWarn } from "../../../util/log.js";
37
+ import { numericChatIdFor } from "../../frontend-runtime/chat-id.js";
38
38
  import { runJobOneShot } from "./job-oneshot.js";
39
39
  import {
40
40
  jobAllowsRun,
@@ -46,7 +46,7 @@ import {
46
46
  import {
47
47
  catchupRunCount,
48
48
  missedRunCount,
49
- } from "../../native/scheduler-core.js";
49
+ } from "../../../native/scheduler-core.js";
50
50
 
51
51
  // ── Dependencies (injected at startup) ──────────────────────────────────────
52
52
 
@@ -18,7 +18,7 @@ import {
18
18
  type CatchupPolicy,
19
19
  type CronJob,
20
20
  type CronJobType,
21
- } from "../../storage/cron.js";
21
+ } from "../../../storage/cron.js";
22
22
 
23
23
  /** The scheduler ticks once a minute, so sub-minute intervals are meaningless. */
24
24
  const MIN_INTERVAL_SECONDS = 60;
@@ -13,18 +13,17 @@
13
13
 
14
14
  import { existsSync, mkdirSync, appendFileSync } from "node:fs";
15
15
  import { resolve } from "node:path";
16
- import { files as pathFiles, dirs } from "../../util/paths.js";
17
- import { kvGet, kvSet } from "../../storage/kv.js";
18
- import { importLegacyJson } from "../../storage/legacy-import.js";
16
+ import { files as pathFiles, dirs } from "../../../util/paths.js";
17
+ import { kvGet, kvSet } from "../../../storage/kv.js";
18
+ import { importLegacyJson } from "../../../storage/legacy-import.js";
19
19
  import { readPromptAsset } from "#prompt-assets";
20
- import { log, logError, logWarn } from "../../util/log.js";
21
- import { getDefaultModel } from "../models/catalog.js";
22
- import type { OneShotAgentParams, ReasoningEffortLevel } from "../types.js";
23
- import type { Backend } from "../agent-runtime/capabilities.js";
24
- import { getSoul } from "../soul/service.js";
25
- import { taskTable } from "../tasks/index.js";
26
- import { resolveBackgroundEffort } from "./effort.js";
27
- import { FailureBackoff } from "./failure-backoff.js";
20
+ import { log, logError, logWarn } from "../../../util/log.js";
21
+ import { getDefaultModel } from "../../models/catalog.js";
22
+ import type { OneShotAgentParams, ReasoningEffortLevel } from "../../types.js";
23
+ import type { Backend } from "../../agent-runtime/capabilities.js";
24
+ import { taskTable } from "../../tasks/index.js";
25
+ import { resolveBackgroundEffort } from "../effort.js";
26
+ import { FailureBackoff } from "../failure-backoff.js";
28
27
 
29
28
  // ── Types ────────────────────────────────────────────────────────────────────
30
29
 
@@ -160,10 +159,6 @@ async function executeDream(trigger: "auto" | "forced"): Promise<void> {
160
159
  "dream",
161
160
  `Memory consolidation complete (${trigger}), log: ${dreamLogPath}`,
162
161
  );
163
- // The soul's organic maintenance shares the dream cadence. Inert (no-op)
164
- // unless the soul is enabled, and isolated so a soul failure never breaks
165
- // memory consolidation.
166
- await getSoul().dream();
167
162
  } catch (err) {
168
163
  logError("dream", `Memory consolidation failed (${trigger})`, err);
169
164
  writeDreamState({ last_run: state?.last_run ?? 0, status: "idle" });