talon-agent 1.12.0 → 1.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/README.md +111 -52
  2. package/package.json +39 -12
  3. package/prompts/README.md +112 -0
  4. package/prompts/base.md +12 -12
  5. package/prompts/discord.md +10 -47
  6. package/prompts/heartbeat.md +23 -8
  7. package/prompts/identity.md +12 -22
  8. package/prompts/native.md +23 -0
  9. package/prompts/system/contract-text-or-tools.md +8 -0
  10. package/prompts/system/contract-text-preferred.md +5 -0
  11. package/prompts/system/contract-tool-only.md +10 -0
  12. package/prompts/system/cron.md +3 -0
  13. package/prompts/system/daily-memory.md +3 -0
  14. package/prompts/system/goals.md +7 -0
  15. package/prompts/system/heartbeat-agent.md +44 -0
  16. package/prompts/system/persistent-memory.md +8 -0
  17. package/prompts/system/skills.md +9 -0
  18. package/prompts/system/triggers.md +5 -0
  19. package/prompts/system/workspace.md +9 -0
  20. package/prompts/teams.md +4 -14
  21. package/prompts/telegram.md +17 -89
  22. package/src/app.ts +278 -0
  23. package/src/backend/claude-sdk/constants.ts +22 -10
  24. package/src/backend/claude-sdk/factory.ts +79 -22
  25. package/src/backend/claude-sdk/handler.ts +431 -160
  26. package/src/backend/claude-sdk/index.ts +6 -2
  27. package/src/backend/claude-sdk/mcp-ready.ts +54 -0
  28. package/src/backend/claude-sdk/model-drift.ts +65 -0
  29. package/src/backend/claude-sdk/model-provider.ts +12 -6
  30. package/src/backend/claude-sdk/models/convert.ts +169 -0
  31. package/src/backend/claude-sdk/models/discovery.ts +203 -0
  32. package/src/backend/claude-sdk/models/index.ts +18 -0
  33. package/src/backend/claude-sdk/models/parsing.ts +264 -0
  34. package/src/backend/claude-sdk/models/static.ts +45 -0
  35. package/src/backend/claude-sdk/one-shot.ts +19 -13
  36. package/src/backend/claude-sdk/options.ts +228 -104
  37. package/src/backend/claude-sdk/state.ts +1 -1
  38. package/src/backend/claude-sdk/stream.ts +153 -45
  39. package/src/backend/claude-sdk/warm.ts +12 -5
  40. package/src/backend/codex/auth.ts +216 -40
  41. package/src/backend/codex/constants.ts +63 -22
  42. package/src/backend/codex/discovery.ts +427 -0
  43. package/src/backend/codex/factory.ts +63 -33
  44. package/src/backend/codex/handler/events.ts +239 -0
  45. package/src/backend/codex/handler/index.ts +15 -0
  46. package/src/backend/codex/handler/message.ts +669 -0
  47. package/src/backend/codex/handler/state.ts +14 -0
  48. package/src/backend/codex/handler/usage.ts +68 -0
  49. package/src/backend/codex/index.ts +2 -2
  50. package/src/backend/codex/init.ts +92 -11
  51. package/src/backend/codex/mcp-config.ts +89 -62
  52. package/src/backend/codex/models.ts +305 -54
  53. package/src/backend/codex/oauth-incompat.ts +302 -0
  54. package/src/backend/codex/one-shot.ts +91 -8
  55. package/src/backend/codex/state.ts +54 -3
  56. package/src/backend/codex/token-usage.ts +434 -0
  57. package/src/backend/kilo/factory.ts +60 -35
  58. package/src/backend/kilo/handler/index.ts +13 -0
  59. package/src/backend/kilo/handler/message.ts +317 -0
  60. package/src/backend/kilo/handler/state.ts +14 -0
  61. package/src/backend/kilo/handler/turn.ts +321 -0
  62. package/src/backend/kilo/index.ts +5 -5
  63. package/src/backend/kilo/model-provider.ts +26 -168
  64. package/src/backend/kilo/models/index.ts +52 -0
  65. package/src/backend/kilo/one-shot.ts +20 -142
  66. package/src/backend/kilo/server.ts +14 -21
  67. package/src/backend/openai-agents/builtins.ts +215 -114
  68. package/src/backend/openai-agents/constants.ts +41 -15
  69. package/src/backend/openai-agents/discovery.ts +332 -0
  70. package/src/backend/openai-agents/factory.ts +66 -28
  71. package/src/backend/openai-agents/handler/events.ts +170 -0
  72. package/src/backend/openai-agents/handler/index.ts +13 -0
  73. package/src/backend/openai-agents/handler/message.ts +527 -0
  74. package/src/backend/openai-agents/handler/state.ts +13 -0
  75. package/src/backend/openai-agents/index.ts +22 -4
  76. package/src/backend/openai-agents/init.ts +51 -88
  77. package/src/backend/openai-agents/mcp-pool.ts +252 -0
  78. package/src/backend/openai-agents/models.ts +118 -11
  79. package/src/backend/openai-agents/session.ts +277 -0
  80. package/src/backend/openai-agents/state.ts +82 -11
  81. package/src/backend/opencode/factory.ts +54 -25
  82. package/src/backend/opencode/handler/index.ts +13 -0
  83. package/src/backend/opencode/handler/message.ts +325 -0
  84. package/src/backend/opencode/handler/state.ts +14 -0
  85. package/src/backend/opencode/handler/turn.ts +304 -0
  86. package/src/backend/opencode/index.ts +2 -2
  87. package/src/backend/opencode/model-provider.ts +26 -168
  88. package/src/backend/opencode/models/index.ts +51 -0
  89. package/src/backend/opencode/one-shot.ts +20 -137
  90. package/src/backend/opencode/server.ts +12 -11
  91. package/src/backend/remote-server/client.ts +13 -6
  92. package/src/backend/remote-server/events.ts +59 -9
  93. package/src/backend/remote-server/lifecycle.ts +3 -1
  94. package/src/backend/remote-server/mcp.ts +52 -19
  95. package/src/backend/remote-server/model-catalog/catalog.ts +270 -0
  96. package/src/backend/remote-server/model-catalog/index.ts +100 -0
  97. package/src/backend/remote-server/model-catalog/presentation.ts +298 -0
  98. package/src/backend/remote-server/model-catalog/provider.ts +193 -0
  99. package/src/backend/remote-server/model-catalog/resolve.ts +225 -0
  100. package/src/backend/remote-server/model-catalog/types.ts +136 -0
  101. package/src/backend/remote-server/one-shot.ts +225 -0
  102. package/src/backend/remote-server/session-helpers.ts +3 -4
  103. package/src/backend/remote-server/state.ts +1 -1
  104. package/src/backend/shared/delivery-contract.ts +161 -0
  105. package/src/backend/shared/delivery.ts +49 -0
  106. package/src/backend/shared/flow-violation.ts +38 -7
  107. package/src/backend/shared/frontends.ts +66 -0
  108. package/src/backend/shared/handle-retry.ts +244 -0
  109. package/src/backend/shared/handler-to-events.ts +186 -0
  110. package/src/backend/shared/handler-types.ts +57 -0
  111. package/src/backend/shared/index.ts +51 -5
  112. package/src/backend/shared/metrics.ts +199 -0
  113. package/src/backend/shared/model-retry.ts +1 -1
  114. package/src/backend/shared/prompt-format.ts +69 -0
  115. package/src/backend/shared/session-name.ts +1 -1
  116. package/src/backend/shared/stream-state.ts +36 -2
  117. package/src/backend/shared/system-prompt.ts +200 -23
  118. package/src/bootstrap.ts +338 -38
  119. package/src/cli/chat.ts +49 -0
  120. package/src/cli/config-view.ts +100 -0
  121. package/src/cli/config.ts +105 -0
  122. package/src/cli/context.ts +23 -0
  123. package/src/cli/daemon.ts +95 -0
  124. package/src/cli/doctor.ts +53 -0
  125. package/src/cli/index.ts +139 -0
  126. package/src/cli/logs.ts +60 -0
  127. package/src/cli/menu.ts +104 -0
  128. package/src/cli/setup.ts +455 -0
  129. package/src/cli/status.ts +75 -0
  130. package/src/cli.ts +20 -1211
  131. package/src/core/agent-runtime/README.md +173 -0
  132. package/src/{backend/registry.ts → core/agent-runtime/backend-registry.ts} +15 -6
  133. package/src/core/agent-runtime/capabilities.ts +330 -0
  134. package/src/core/agent-runtime/contract-tests.ts +378 -0
  135. package/src/core/agent-runtime/events.ts +291 -0
  136. package/src/core/agent-runtime/index.ts +62 -0
  137. package/src/core/agent-runtime/model-ref.ts +130 -0
  138. package/src/core/background/cron.ts +469 -0
  139. package/src/core/{dream.ts → background/dream.ts} +118 -53
  140. package/src/core/background/heartbeat/agent.ts +333 -0
  141. package/src/core/background/heartbeat/index.ts +25 -0
  142. package/src/core/background/heartbeat/scheduler.ts +211 -0
  143. package/src/core/background/heartbeat/state.ts +153 -0
  144. package/src/core/background/index.ts +21 -0
  145. package/src/core/background/isolated-agent.ts +115 -0
  146. package/src/core/background/job-health.ts +140 -0
  147. package/src/core/background/job-oneshot.ts +165 -0
  148. package/src/core/background/job-prompt.ts +54 -0
  149. package/src/core/{pulse.ts → background/pulse.ts} +6 -5
  150. package/src/core/background/triggers/command.ts +60 -0
  151. package/src/core/background/triggers/exit.ts +202 -0
  152. package/src/core/background/triggers/index.ts +38 -0
  153. package/src/core/background/triggers/output.ts +142 -0
  154. package/src/core/background/triggers/resume.ts +127 -0
  155. package/src/core/background/triggers/spawn.ts +282 -0
  156. package/src/core/background/triggers/state.ts +52 -0
  157. package/src/core/constants.ts +57 -28
  158. package/src/core/daemon/control.ts +229 -0
  159. package/src/core/daemon/discovery.ts +169 -0
  160. package/src/core/daemon/pidfile.ts +98 -0
  161. package/src/core/doctor.ts +459 -0
  162. package/src/core/engine/backend-controller/holders.ts +17 -0
  163. package/src/core/engine/backend-controller/index.ts +71 -0
  164. package/src/core/engine/backend-controller/legacy.ts +111 -0
  165. package/src/core/engine/backend-controller/pool.ts +296 -0
  166. package/src/core/engine/backend-controller/rebind.ts +205 -0
  167. package/src/core/engine/backend-controller/state.ts +150 -0
  168. package/src/core/engine/backend-controller/types.ts +51 -0
  169. package/src/core/engine/dispatcher.ts +68 -0
  170. package/src/core/engine/gateway-actions/cron.ts +518 -0
  171. package/src/core/engine/gateway-actions/fetch-url.ts +120 -0
  172. package/src/core/engine/gateway-actions/goals.ts +178 -0
  173. package/src/core/engine/gateway-actions/history.ts +53 -0
  174. package/src/core/engine/gateway-actions/index.ts +60 -0
  175. package/src/core/engine/gateway-actions/models.ts +120 -0
  176. package/src/core/engine/gateway-actions/plugins.ts +83 -0
  177. package/src/core/engine/gateway-actions/scripts.ts +127 -0
  178. package/src/core/engine/gateway-actions/shared.ts +66 -0
  179. package/src/core/engine/gateway-actions/skills.ts +120 -0
  180. package/src/core/engine/gateway-actions/triggers.ts +237 -0
  181. package/src/core/engine/gateway-actions/types.ts +18 -0
  182. package/src/core/{gateway.ts → engine/gateway.ts} +223 -60
  183. package/src/core/engine/index.ts +20 -0
  184. package/src/core/engine/model-audit.ts +121 -0
  185. package/src/core/errors.ts +68 -6
  186. package/src/core/mcp-hub/children.ts +254 -0
  187. package/src/core/mcp-hub/index.ts +335 -0
  188. package/src/core/mcp-hub/proxy-server.ts +45 -0
  189. package/src/core/mcp-hub/talon-server.ts +71 -0
  190. package/src/core/memory/retrieval.ts +90 -0
  191. package/src/core/models/active-model.ts +441 -0
  192. package/src/core/{models.ts → models/catalog.ts} +6 -0
  193. package/src/core/models/index.ts +17 -0
  194. package/src/core/models/reasoning-levels.ts +57 -0
  195. package/src/core/plugin/actions.ts +32 -0
  196. package/src/core/plugin/builtins.ts +162 -0
  197. package/src/core/plugin/index.ts +37 -0
  198. package/src/core/plugin/loader.ts +289 -0
  199. package/src/core/plugin/mcp.ts +86 -0
  200. package/src/core/plugin/registry.ts +124 -0
  201. package/src/core/plugin/types.ts +126 -0
  202. package/src/core/prompt/assemble.ts +273 -0
  203. package/src/core/prompt/disk-prompts.ts +41 -0
  204. package/src/core/prompt/embed.ts +107 -0
  205. package/src/core/prompt/embedded-prompts.ts +85 -0
  206. package/src/core/prompt/index.ts +30 -0
  207. package/src/core/prompt/templates.ts +124 -0
  208. package/src/core/prompt/workspace-listing.ts +91 -0
  209. package/src/core/scripting/lua-runner.ts +210 -0
  210. package/src/core/scripts/runner.ts +125 -0
  211. package/src/core/soul/README.md +110 -0
  212. package/src/core/soul/RESEARCH.md +98 -0
  213. package/src/core/soul/associative.ts +98 -0
  214. package/src/core/soul/centrality.ts +98 -0
  215. package/src/core/soul/cluster.ts +83 -0
  216. package/src/core/soul/compiler.ts +207 -0
  217. package/src/core/soul/consolidate.ts +179 -0
  218. package/src/core/soul/critic.ts +159 -0
  219. package/src/core/soul/dag.ts +265 -0
  220. package/src/core/soul/delta.ts +123 -0
  221. package/src/core/soul/drift.ts +99 -0
  222. package/src/core/soul/embedder.ts +129 -0
  223. package/src/core/soul/emergent-critic.ts +96 -0
  224. package/src/core/soul/forgetting.ts +131 -0
  225. package/src/core/soul/governance.ts +93 -0
  226. package/src/core/soul/hash.ts +97 -0
  227. package/src/core/soul/hdc.ts +154 -0
  228. package/src/core/soul/index.ts +140 -0
  229. package/src/core/soul/kernel.ts +540 -0
  230. package/src/core/soul/lattice.ts +103 -0
  231. package/src/core/soul/lens.ts +110 -0
  232. package/src/core/soul/projector.ts +240 -0
  233. package/src/core/soul/reflect.ts +170 -0
  234. package/src/core/soul/reflex.ts +164 -0
  235. package/src/core/soul/retrieve.ts +146 -0
  236. package/src/core/soul/salience.ts +142 -0
  237. package/src/core/soul/service.ts +204 -0
  238. package/src/core/soul/settings.ts +47 -0
  239. package/src/core/soul/signals.ts +117 -0
  240. package/src/core/soul/talon-embedder.ts +80 -0
  241. package/src/core/soul/taps.ts +199 -0
  242. package/src/core/soul/types.ts +298 -0
  243. package/src/core/soul/valence.ts +83 -0
  244. package/src/core/tools/goals.ts +117 -0
  245. package/src/core/tools/index.ts +10 -0
  246. package/src/core/tools/mcp-env.ts +94 -0
  247. package/src/core/tools/mcp-server.ts +27 -4
  248. package/src/core/tools/messaging.ts +122 -29
  249. package/src/core/tools/models.ts +39 -0
  250. package/src/core/tools/scheduling.ts +133 -14
  251. package/src/core/tools/schemas.ts +16 -4
  252. package/src/core/tools/scripts.ts +78 -0
  253. package/src/core/tools/skills.ts +90 -0
  254. package/src/core/tools/stickers.ts +1 -1
  255. package/src/core/tools/triggers.ts +19 -3
  256. package/src/core/tools/types.ts +6 -6
  257. package/src/core/types.ts +62 -112
  258. package/src/core/update/self-update.ts +269 -0
  259. package/src/core/weaver/index.ts +10 -0
  260. package/src/core/weaver/loom.ts +125 -0
  261. package/src/core/weaver/thread-session.ts +51 -0
  262. package/src/core/weaver/thread.ts +196 -0
  263. package/src/core/weaver/weaver.ts +357 -0
  264. package/src/frontend/discord/actions/chat-info.ts +268 -0
  265. package/src/frontend/discord/actions/index.ts +77 -0
  266. package/src/frontend/discord/actions/media.ts +190 -0
  267. package/src/frontend/discord/actions/messaging.ts +277 -0
  268. package/src/frontend/discord/actions/shared.ts +100 -0
  269. package/src/frontend/discord/actions/types.ts +33 -0
  270. package/src/frontend/discord/admin.ts +13 -23
  271. package/src/frontend/discord/callbacks/autocomplete.ts +55 -0
  272. package/src/frontend/discord/{callbacks.ts → callbacks/components.ts} +150 -190
  273. package/src/frontend/discord/callbacks/index.ts +14 -0
  274. package/src/frontend/discord/callbacks/modals.ts +76 -0
  275. package/src/frontend/discord/callbacks/shared.ts +22 -0
  276. package/src/frontend/discord/commands/admin.ts +88 -0
  277. package/src/frontend/discord/commands/definitions.ts +200 -0
  278. package/src/frontend/discord/commands/index.ts +19 -0
  279. package/src/frontend/discord/commands/info.ts +106 -0
  280. package/src/frontend/discord/commands/router.ts +149 -0
  281. package/src/frontend/discord/commands/session.ts +89 -0
  282. package/src/frontend/discord/commands/settings.ts +405 -0
  283. package/src/frontend/discord/commands/shared.ts +50 -0
  284. package/src/frontend/discord/formatting.ts +8 -34
  285. package/src/frontend/discord/handlers/access.ts +248 -0
  286. package/src/frontend/discord/handlers/context.ts +161 -0
  287. package/src/frontend/discord/handlers/delivery.ts +94 -0
  288. package/src/frontend/discord/handlers/index.ts +34 -0
  289. package/src/frontend/discord/handlers/messages.ts +120 -0
  290. package/src/frontend/discord/handlers/queue.ts +135 -0
  291. package/src/frontend/discord/handlers/registry.ts +29 -0
  292. package/src/frontend/discord/handlers/state.ts +94 -0
  293. package/src/frontend/discord/helpers.ts +46 -57
  294. package/src/frontend/discord/index.ts +10 -7
  295. package/src/frontend/discord/middleware.ts +2 -2
  296. package/src/frontend/native/actions.ts +133 -0
  297. package/src/frontend/native/chats.ts +146 -0
  298. package/src/frontend/native/discovery.ts +50 -0
  299. package/src/frontend/native/index.ts +1227 -0
  300. package/src/frontend/native/logs.ts +95 -0
  301. package/src/frontend/native/protocol.ts +253 -0
  302. package/src/frontend/native/server.ts +612 -0
  303. package/src/frontend/native/settings.ts +205 -0
  304. package/src/frontend/native/turn-meta.ts +43 -0
  305. package/src/frontend/shared/format.ts +51 -0
  306. package/src/frontend/shared/reasoning-levels.ts +46 -0
  307. package/src/frontend/shared/session-status.ts +189 -0
  308. package/src/frontend/shared/status-context.ts +125 -0
  309. package/src/frontend/teams/actions.ts +7 -5
  310. package/src/frontend/teams/formatting.ts +7 -18
  311. package/src/frontend/teams/graph.ts +2 -1
  312. package/src/frontend/teams/index.ts +76 -54
  313. package/src/frontend/telegram/actions/chat-info.ts +323 -0
  314. package/src/frontend/telegram/actions/index.ts +68 -0
  315. package/src/frontend/telegram/actions/media.ts +224 -0
  316. package/src/frontend/telegram/actions/messaging.ts +295 -0
  317. package/src/frontend/telegram/actions/shared.ts +58 -0
  318. package/src/frontend/telegram/actions/types.ts +31 -0
  319. package/src/frontend/telegram/admin.ts +12 -22
  320. package/src/frontend/telegram/callbacks/effort.ts +68 -0
  321. package/src/frontend/telegram/callbacks/index.ts +68 -0
  322. package/src/frontend/telegram/callbacks/model.ts +311 -0
  323. package/src/frontend/telegram/callbacks/pulse.ts +50 -0
  324. package/src/frontend/telegram/callbacks/settings.ts +177 -0
  325. package/src/frontend/telegram/callbacks/shared.ts +71 -0
  326. package/src/frontend/telegram/commands/admin.ts +226 -0
  327. package/src/frontend/telegram/commands/definitions.ts +60 -0
  328. package/src/frontend/telegram/commands/index.ts +39 -0
  329. package/src/frontend/telegram/commands/info.ts +125 -0
  330. package/src/frontend/telegram/commands/session.ts +77 -0
  331. package/src/frontend/telegram/commands/settings.ts +345 -0
  332. package/src/frontend/telegram/commands/state.ts +34 -0
  333. package/src/frontend/telegram/formatting.ts +14 -25
  334. package/src/frontend/telegram/handlers/access.ts +287 -0
  335. package/src/frontend/telegram/handlers/context.ts +210 -0
  336. package/src/frontend/telegram/handlers/delivery.ts +236 -0
  337. package/src/frontend/telegram/handlers/index.ts +39 -0
  338. package/src/frontend/telegram/handlers/messages.ts +477 -0
  339. package/src/frontend/telegram/handlers/queue.ts +241 -0
  340. package/src/frontend/telegram/handlers/state.ts +75 -0
  341. package/src/frontend/telegram/helpers/diagnostics.ts +188 -0
  342. package/src/frontend/telegram/helpers/format.ts +41 -0
  343. package/src/frontend/telegram/helpers/index.ts +13 -0
  344. package/src/frontend/telegram/{helpers.ts → helpers/menu.ts} +209 -210
  345. package/src/frontend/telegram/index.ts +24 -27
  346. package/src/frontend/telegram/middleware.ts +16 -3
  347. package/src/frontend/telegram/model-callbacks.ts +14 -0
  348. package/src/frontend/telegram/model-menu.ts +317 -0
  349. package/src/frontend/telegram/sticker-library.ts +178 -0
  350. package/src/frontend/telegram/userbot.ts +2 -44
  351. package/src/frontend/terminal/commands.ts +47 -41
  352. package/src/frontend/terminal/index.ts +46 -31
  353. package/src/frontend/terminal/input.ts +5 -0
  354. package/src/frontend/terminal/renderer.ts +4 -2
  355. package/src/index.ts +13 -171
  356. package/src/login.ts +3 -2
  357. package/src/native/blake3-wasm-bytes.ts +7 -0
  358. package/src/native/blake3.ts +234 -0
  359. package/src/native/htmlents-wasm-bytes.ts +7 -0
  360. package/src/native/htmlents.ts +56 -0
  361. package/src/native/prelude.d.mts +168 -0
  362. package/src/native/prelude.mjs +1561 -0
  363. package/src/native/registry.ts +142 -0
  364. package/src/native/runtime.ts +164 -0
  365. package/src/native/scheduler-core/gleam.d.mts +2 -0
  366. package/src/native/scheduler-core/gleam.mjs +1 -0
  367. package/src/native/scheduler-core/scheduler_core.d.mts +76 -0
  368. package/src/native/scheduler-core/scheduler_core.mjs +252 -0
  369. package/src/native/scheduler-core.ts +124 -0
  370. package/src/native/sqlguard-wasm-bytes.ts +7 -0
  371. package/src/native/sqlguard.ts +107 -0
  372. package/src/native/strsim-wasm-bytes.ts +7 -0
  373. package/src/native/strsim.ts +98 -0
  374. package/src/native/textops-wasm-bytes.ts +7 -0
  375. package/src/native/textops.ts +83 -0
  376. package/src/native/warden.ts +287 -0
  377. package/src/plugins/github/index.ts +1 -1
  378. package/src/plugins/mempalace/index.ts +1 -1
  379. package/src/plugins/playwright/index.ts +1 -1
  380. package/src/storage/chat-settings.ts +335 -85
  381. package/src/storage/cron-store.ts +266 -109
  382. package/src/storage/daily-log.ts +15 -3
  383. package/src/storage/db.ts +206 -0
  384. package/src/storage/goal-store.ts +186 -0
  385. package/src/storage/history.ts +137 -188
  386. package/src/storage/kv.ts +52 -0
  387. package/src/storage/legacy-import.ts +47 -0
  388. package/src/storage/media-index.ts +118 -61
  389. package/src/storage/repositories/chat-settings-repo.ts +60 -0
  390. package/src/storage/repositories/cron-repo.ts +128 -0
  391. package/src/storage/repositories/goals-repo.ts +122 -0
  392. package/src/storage/repositories/history-repo.ts +207 -0
  393. package/src/storage/repositories/kv-repo.ts +25 -0
  394. package/src/storage/repositories/media-index-repo.ts +147 -0
  395. package/src/storage/repositories/scripts-repo.ts +81 -0
  396. package/src/storage/repositories/sessions-repo.ts +129 -0
  397. package/src/storage/repositories/triggers-repo.ts +158 -0
  398. package/src/storage/repositories/turn-meta-repo.ts +32 -0
  399. package/src/storage/scheduled-store.ts +84 -0
  400. package/src/storage/script-store.ts +198 -0
  401. package/src/storage/sessions.ts +227 -102
  402. package/src/storage/skill-store.ts +325 -0
  403. package/src/storage/sql/README.md +18 -0
  404. package/src/storage/sql/chat-settings.sql +11 -0
  405. package/src/storage/sql/cron.sql +40 -0
  406. package/src/storage/sql/db.sql +11 -0
  407. package/src/storage/sql/embed.ts +118 -0
  408. package/src/storage/sql/goals.sql +41 -0
  409. package/src/storage/sql/history.sql +83 -0
  410. package/src/storage/sql/kv.sql +11 -0
  411. package/src/storage/sql/media-index.sql +45 -0
  412. package/src/storage/sql/schema.sql +233 -0
  413. package/src/storage/sql/scripts.sql +28 -0
  414. package/src/storage/sql/sessions.sql +22 -0
  415. package/src/storage/sql/statements.generated.ts +500 -0
  416. package/src/storage/sql/triggers.sql +69 -0
  417. package/src/storage/sql/turn-meta.sql +24 -0
  418. package/src/storage/sticker-store.ts +141 -0
  419. package/src/storage/trigger-store.ts +104 -126
  420. package/src/storage/turn-meta.ts +118 -0
  421. package/src/util/chat-id.ts +30 -0
  422. package/src/util/config.ts +313 -195
  423. package/src/util/fs-path.ts +32 -0
  424. package/src/util/log.ts +53 -31
  425. package/src/util/mcp-launcher.ts +351 -33
  426. package/src/util/paths.ts +45 -17
  427. package/src/util/tail-file.ts +24 -0
  428. package/src/util/workspace.ts +161 -10
  429. package/tsconfig.json +1 -0
  430. package/src/backend/claude-sdk/models.ts +0 -501
  431. package/src/backend/codex/handler.ts +0 -595
  432. package/src/backend/kilo/handler.ts +0 -707
  433. package/src/backend/kilo/models.ts +0 -762
  434. package/src/backend/openai-agents/handler.ts +0 -539
  435. package/src/backend/openai-agents/mcp.ts +0 -139
  436. package/src/backend/opencode/handler.ts +0 -663
  437. package/src/backend/opencode/models.ts +0 -741
  438. package/src/core/cron.ts +0 -184
  439. package/src/core/dispatcher.ts +0 -144
  440. package/src/core/gateway-actions.ts +0 -603
  441. package/src/core/heartbeat.ts +0 -575
  442. package/src/core/plugin.ts +0 -776
  443. package/src/core/triggers.ts +0 -640
  444. package/src/frontend/discord/actions.ts +0 -729
  445. package/src/frontend/discord/commands.ts +0 -1036
  446. package/src/frontend/discord/handlers.ts +0 -798
  447. package/src/frontend/telegram/actions.ts +0 -731
  448. package/src/frontend/telegram/callbacks.ts +0 -419
  449. package/src/frontend/telegram/commands.ts +0 -642
  450. package/src/frontend/telegram/handlers.ts +0 -1352
  451. package/src/util/mcp-launcher.mjs +0 -140
package/src/app.ts ADDED
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Talon — agentic AI harness.
3
+ * Composition root: loads config, creates frontend + backend, wires dispatcher.
4
+ *
5
+ * Frontends (Telegram, Terminal) and backends (Claude, OpenCode)
6
+ * are loaded dynamically — only the selected platform's dependencies are required.
7
+ */
8
+
9
+ import { getFrontends } from "./util/config.js";
10
+ import { startUploadCleanup, stopUploadCleanup } from "./util/workspace.js";
11
+ import { flushDatabase } from "./storage/db.js";
12
+ import { getActiveCount } from "./core/engine/dispatcher.js";
13
+ import { startPulseTimer, stopPulseTimer } from "./core/background/pulse.js";
14
+ import {
15
+ startHeartbeatTimer,
16
+ stopHeartbeatTimer,
17
+ awaitCurrentRun as awaitHeartbeat,
18
+ } from "./core/background/heartbeat/index.js";
19
+ import {
20
+ startCronTimer,
21
+ stopCronTimer,
22
+ runStartupCatchup,
23
+ } from "./core/background/cron.js";
24
+ import { shutdownTriggers } from "./core/background/triggers/index.js";
25
+ import { startWatchdog, stopWatchdog } from "./util/watchdog.js";
26
+ import { log, logError, logWarn } from "./util/log.js";
27
+ import { bootstrap, initBackendAndDispatcher } from "./bootstrap.js";
28
+ import { Gateway } from "./core/engine/gateway.js";
29
+ import type { Frontend } from "./bootstrap.js";
30
+
31
+ // ── Bootstrap ────────────────────────────────────────────────────────────────
32
+
33
+ import {
34
+ writePidRecord,
35
+ removePidRecordIfOwnedBy,
36
+ } from "./core/daemon/pidfile.js";
37
+
38
+ const { config } = await bootstrap();
39
+
40
+ // Record this process as the daemon. The gateway port is appended once
41
+ // the gateway binds (it may fall back from the default on EADDRINUSE).
42
+ const bootedAt = new Date().toISOString();
43
+ writePidRecord({ pid: process.pid, startedAt: bootedAt });
44
+
45
+ // ── Create gateway + frontend ─────────────────────────────────────────────────
46
+
47
+ const gateway = new Gateway("daemon");
48
+ gateway.onStarted((port) =>
49
+ writePidRecord({ pid: process.pid, port, startedAt: bootedAt }),
50
+ );
51
+ gateway.onShutdownRequest((reason) => void gracefulShutdown(reason));
52
+
53
+ const configuredFrontends = [
54
+ ...new Set(getFrontends(config)),
55
+ ] as Frontend["name"][];
56
+
57
+ async function createFrontend(name: Frontend["name"]): Promise<Frontend> {
58
+ switch (name) {
59
+ case "terminal": {
60
+ const { createTerminalFrontend } =
61
+ await import("./frontend/terminal/index.js");
62
+ return createTerminalFrontend(config, gateway);
63
+ }
64
+ case "teams": {
65
+ const { createTeamsFrontend } = await import("./frontend/teams/index.js");
66
+ return createTeamsFrontend(config, gateway);
67
+ }
68
+ case "discord": {
69
+ const { createDiscordFrontend } =
70
+ await import("./frontend/discord/index.js");
71
+ return createDiscordFrontend(config, gateway);
72
+ }
73
+ case "native": {
74
+ const { createNativeFrontend } =
75
+ await import("./frontend/native/index.js");
76
+ return createNativeFrontend(config, gateway);
77
+ }
78
+ case "telegram":
79
+ default: {
80
+ const { createTelegramFrontend } =
81
+ await import("./frontend/telegram/index.js");
82
+ return createTelegramFrontend(config, gateway);
83
+ }
84
+ }
85
+ }
86
+
87
+ const frontends: Frontend[] = [];
88
+ for (const name of configuredFrontends) {
89
+ const frontend = await createFrontend(name);
90
+ frontends.push(frontend);
91
+ log("bot", `Frontend: ${name[0].toUpperCase()}${name.slice(1)}`);
92
+ }
93
+
94
+ // ── Create backend + wire dispatcher ─────────────────────────────────────────
95
+
96
+ const { backend } = await initBackendAndDispatcher(config, frontends);
97
+ gateway.backend = backend;
98
+
99
+ // Subscribe the gateway to chat-role rebinds so `/model`, `/settings`,
100
+ // shared-action dispatch, etc. all see the new backend the moment a
101
+ // rebind resolves. Heartbeat / dream / per-chat-override rebinds don't
102
+ // touch the gateway field — those roles run from their own getBackend
103
+ // providers (dispatcher routes per chat).
104
+ const { onBackendChange, roleHolder } =
105
+ await import("./core/engine/backend-controller/index.js");
106
+ const CHAT_ROLE_HOLDER = roleHolder("chat");
107
+ onBackendChange((holder, newBackend, info) => {
108
+ if (holder !== CHAT_ROLE_HOLDER) return;
109
+ gateway.backend = newBackend;
110
+ log("bot", `Gateway backend reference updated → ${info.label}`);
111
+ });
112
+
113
+ // ── Graceful shutdown ────────────────────────────────────────────────────────
114
+
115
+ let shuttingDown = false;
116
+
117
+ const SHUTDOWN_TIMEOUT_MS = 15_000;
118
+ const DRAIN_TIMEOUT_MS = 5_000;
119
+
120
+ /**
121
+ * One best-effort teardown step. A failing subsystem (a frontend that
122
+ * won't stop, a plugin that throws in destroy, a dynamic import that
123
+ * fails mid-shutdown) must not abort the rest of the sequence — the
124
+ * WAL checkpoint and pidfile removal below have to run regardless.
125
+ */
126
+ async function shutdownStep(name: string, fn: () => unknown): Promise<void> {
127
+ try {
128
+ await fn();
129
+ } catch (err) {
130
+ logError("shutdown", `${name} failed`, err);
131
+ }
132
+ }
133
+
134
+ async function gracefulShutdown(signal: string): Promise<void> {
135
+ if (shuttingDown) return;
136
+ shuttingDown = true;
137
+ log("shutdown", `${signal} received, shutting down gracefully...`);
138
+
139
+ const forceTimer = setTimeout(() => {
140
+ logError("shutdown", "Timeout exceeded, forcing exit");
141
+ process.exit(1);
142
+ }, SHUTDOWN_TIMEOUT_MS);
143
+ forceTimer.unref();
144
+
145
+ // Drain in-flight queries: poll instead of a fixed sleep, so an idle
146
+ // daemon exits immediately and a busy one gets the full budget.
147
+ if (getActiveCount() > 0) {
148
+ log(
149
+ "shutdown",
150
+ `Waiting for ${getActiveCount()} in-flight queries to drain...`,
151
+ );
152
+ const deadline = Date.now() + DRAIN_TIMEOUT_MS;
153
+ while (getActiveCount() > 0 && Date.now() < deadline) {
154
+ await new Promise((r) => setTimeout(r, 250));
155
+ }
156
+ const remaining = getActiveCount();
157
+ if (remaining > 0) {
158
+ logWarn(
159
+ "shutdown",
160
+ `Drain timed out with ${remaining} queries still in flight`,
161
+ );
162
+ }
163
+ }
164
+
165
+ await shutdownStep("frontends", () =>
166
+ Promise.allSettled(frontends.map((frontend) => frontend.stop())),
167
+ );
168
+ if (config.backend === "opencode") {
169
+ await shutdownStep("opencode server", async () => {
170
+ const { stopOpenCodeServer } =
171
+ await import("./backend/opencode/index.js");
172
+ stopOpenCodeServer();
173
+ });
174
+ }
175
+ // Destroy plugins (cleanup resources)
176
+ if (config.plugins.length > 0) {
177
+ await shutdownStep("plugins", async () => {
178
+ const { destroyPlugins } = await import("./core/plugin/index.js");
179
+ await destroyPlugins();
180
+ });
181
+ }
182
+ await shutdownStep("pulse timer", stopPulseTimer);
183
+ await shutdownStep("heartbeat", async () => {
184
+ stopHeartbeatTimer();
185
+ await awaitHeartbeat();
186
+ });
187
+ await shutdownStep("cron timer", stopCronTimer);
188
+ await shutdownStep("triggers", shutdownTriggers);
189
+ await shutdownStep("watchdog", stopWatchdog);
190
+ await shutdownStep("upload cleanup", stopUploadCleanup);
191
+ await shutdownStep("mcp hub", async () => {
192
+ const { shutdownHub } = await import("./core/mcp-hub/index.js");
193
+ await shutdownHub();
194
+ });
195
+ flushDatabase();
196
+ // Guarded removal: after a /restart handoff the successor has already
197
+ // written its own pid here — deleting unconditionally would orphan it
198
+ // (the bug that made `talon restart` spawn duplicate daemons).
199
+ removePidRecordIfOwnedBy(process.pid);
200
+ log("shutdown", "State saved");
201
+ process.exit(0);
202
+ }
203
+
204
+ process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
205
+ process.on("SIGINT", () => gracefulShutdown("SIGINT"));
206
+
207
+ process.on("uncaughtException", (err) => {
208
+ // EPIPE errors from network sockets (e.g. Telegram MTProto) are transient —
209
+ // gramjs will reconnect; crashing the process here is wrong.
210
+ if ((err as NodeJS.ErrnoException).code === "EPIPE") {
211
+ logWarn("bot", `Suppressed transient EPIPE error: ${err.message}`);
212
+ return;
213
+ }
214
+ logError("bot", "Uncaught exception", err);
215
+ flushDatabase();
216
+ // Same pid-guarded removal as the graceful path — a crashed daemon
217
+ // must not leave a record that makes `talon status` chase a dead or
218
+ // recycled pid.
219
+ removePidRecordIfOwnedBy(process.pid);
220
+ process.exit(1);
221
+ });
222
+
223
+ process.on("unhandledRejection", (reason) => {
224
+ logWarn(
225
+ "bot",
226
+ `Unhandled rejection: ${reason instanceof Error ? reason.message : reason}`,
227
+ );
228
+ });
229
+
230
+ // ── Start ────────────────────────────────────────────────────────────────────
231
+
232
+ async function main(): Promise<void> {
233
+ await Promise.all(frontends.map((frontend) => frontend.init()));
234
+ log("bot", "Starting Talon...");
235
+
236
+ if (config.pulse) startPulseTimer(config.pulseIntervalMs);
237
+ if (config.heartbeat) startHeartbeatTimer(config.heartbeatIntervalMinutes);
238
+ startWatchdog(config.workspace);
239
+ startUploadCleanup(config.workspace);
240
+
241
+ const terminalFrontends = frontends.filter(
242
+ (frontend) => frontend.name === "terminal",
243
+ );
244
+ const blockingFrontends = frontends.filter(
245
+ (frontend) => frontend.name !== "terminal",
246
+ );
247
+ if (terminalFrontends.length > 0 && frontends.length > 1) {
248
+ log(
249
+ "bot",
250
+ "Terminal frontend shares stdin with the other frontends; it will run alongside them without blocking startup.",
251
+ );
252
+ }
253
+ await Promise.all(blockingFrontends.map((frontend) => frontend.start()));
254
+ for (const frontend of terminalFrontends) {
255
+ void frontend
256
+ .start()
257
+ .catch((err) =>
258
+ logError("bot", `Terminal frontend start failed: ${String(err)}`),
259
+ );
260
+ }
261
+
262
+ // Replay any runs that came due while Talon was down (per-job catch-up
263
+ // policy; default skip = fast no-op), THEN start the live cron tick. Kicking
264
+ // catch-up off first gives it the ~60s head start to take each replayed job's
265
+ // in-flight lock before the first scheduled tick, so a replay can't race a
266
+ // scheduled run. Fire-and-forget so a slow replay never blocks startup.
267
+ runStartupCatchup().catch((err) =>
268
+ logError("cron", "startup catch-up failed", err),
269
+ );
270
+ startCronTimer();
271
+ }
272
+
273
+ main().catch((err) => {
274
+ logError("bot", "Fatal startup error", err);
275
+ flushDatabase();
276
+ removePidRecordIfOwnedBy(process.pid);
277
+ process.exit(1);
278
+ });
@@ -1,23 +1,35 @@
1
1
  /**
2
2
  * Claude SDK backend constants — thinking effort, streaming, and
3
- * chat-specific tool restrictions.
3
+ * chat-specific tool whitelist.
4
4
  *
5
- * Core disallowed-tool lists live in core/constants.ts (backend-agnostic).
5
+ * Core whitelist lives in core/constants.ts (kept separate so the chat
6
+ * additions live next to the rest of the chat-handler config).
6
7
  */
7
8
 
8
9
  import {
9
- DISALLOWED_TOOLS_CORE,
10
- DISALLOWED_TOOLS_BACKGROUND,
10
+ ALLOWED_TOOLS_CORE,
11
+ ALLOWED_TOOLS_BACKGROUND,
11
12
  } from "../../core/constants.js";
12
13
 
13
14
  // Re-export so existing backend imports keep working
14
- export { DISALLOWED_TOOLS_CORE, DISALLOWED_TOOLS_BACKGROUND };
15
+ export { ALLOWED_TOOLS_CORE, ALLOWED_TOOLS_BACKGROUND };
15
16
 
16
- /** Disallowed tools for the main chat handler (core + web tools replaced by Brave MCP). */
17
- export const DISALLOWED_TOOLS_CHAT = [
18
- ...DISALLOWED_TOOLS_CORE,
19
- "WebSearch",
20
- "WebFetch",
17
+ /**
18
+ * Whitelist of built-in tools available to the main chat handler.
19
+ *
20
+ * Chat gets two extras on top of the core whitelist:
21
+ * - `Agent`: sub-agent dispatch (Explore / Plan / etc.). Useful for
22
+ * focused subtasks like code-review or codebase audits; the heartbeat
23
+ * path keeps it out because nested agents complicate orphan tracking.
24
+ * - `Skill`: required for `/skill` commands and other skill-driven flows.
25
+ * The SDK auto-includes Skill when `skills` are passed via options, but
26
+ * we list it explicitly so the tool surface is unambiguous from a single
27
+ * constants file.
28
+ */
29
+ export const ALLOWED_TOOLS_CHAT = [
30
+ ...ALLOWED_TOOLS_CORE,
31
+ "Agent",
32
+ "Skill",
21
33
  ] as const;
22
34
 
23
35
  // ── Thinking / effort configuration ────────────────────────────────────────
@@ -4,31 +4,44 @@
4
4
  *
5
5
  * Unlike Kilo/OpenCode (which run a local HTTP server), the Claude SDK
6
6
  * spawns a per-query subprocess. So this factory also wires the
7
- * `refreshMcpServers` hot-swap path used by plugin reload + the
8
- * `evictOrphanSubprocesses` cleanup helper.
7
+ * `tools.refreshTools` hot-swap path used by plugin reload + the
8
+ * `background.evictOrphanSubprocesses` cleanup helper.
9
+ *
10
+ * Returns a composed `Backend` with capability slots for chat,
11
+ * background, models, sessions, tools, and control.
9
12
  */
10
13
 
11
- import { registerBackend } from "../registry.js";
12
- import type { BackendFactory } from "../registry.js";
13
- import type { QueryBackend } from "../../core/types.js";
14
+ import { registerBackend } from "../../core/agent-runtime/backend-registry.js";
15
+ import type { BackendFactory } from "../../core/agent-runtime/backend-registry.js";
14
16
  import { log } from "../../util/log.js";
15
- import { getPluginMcpServers } from "../../core/plugin.js";
17
+ import {
18
+ composeBackend,
19
+ type ChatBackend,
20
+ type BackgroundRunner,
21
+ type ModelCatalog,
22
+ type SessionBackend,
23
+ type SystemControl,
24
+ type ToolRuntime,
25
+ } from "../../core/agent-runtime/capabilities.js";
16
26
 
17
27
  import {
18
28
  initAgent as initClaudeAgent,
19
29
  updateSystemPrompt as claudeUpdateSystemPrompt,
20
- handleMessage as claudeHandleMessage,
21
30
  warmSession as claudeWarmSession,
22
31
  getActiveQuery,
23
32
  buildMcpServers,
33
+ buildPluginMcpServers,
24
34
  runOneShotAgent as claudeRunOneShotAgent,
25
35
  evictOrphanSubprocesses as claudeEvictOrphanSubprocesses,
26
36
  } from "./index.js";
37
+ import {
38
+ runChatTurn as claudeRunChatTurn,
39
+ interruptChatTurn as claudeInterruptChatTurn,
40
+ } from "./handler.js";
41
+ import { waitForMcpServersReady } from "./mcp-ready.js";
27
42
 
28
43
  import * as modelProvider from "./model-provider.js";
29
44
 
30
- // ── Factory ────────────────────────────────────────────────────────────────
31
-
32
45
  const claudeSdkFactory: BackendFactory = {
33
46
  // The config schema uses `"claude"` for backward compatibility with
34
47
  // talon.json files predating the registry. Matching the id here means
@@ -40,12 +53,24 @@ const claudeSdkFactory: BackendFactory = {
40
53
  await initClaudeAgent(config, ctx.getBridgePort);
41
54
  log("bot", "Backend: Claude SDK (@anthropic-ai/claude-agent-sdk)");
42
55
 
43
- const backend: QueryBackend = {
44
- query: (params) => claudeHandleMessage(params),
45
- warmSession: (chatId) => claudeWarmSession(chatId),
46
- updateSystemPrompt: (prompt) => claudeUpdateSystemPrompt(prompt),
47
- resolveModel: (q) => modelProvider.resolveModel(q),
48
- getModelInfo: (id) => modelProvider.getModelInfo(id),
56
+ const chat: ChatBackend = {
57
+ runChatTurn: (params) => claudeRunChatTurn(params),
58
+ interruptChatTurn: (chatId) => claudeInterruptChatTurn(chatId),
59
+ };
60
+
61
+ const background: BackgroundRunner = {
62
+ runOneShotAgent: (p) => claudeRunOneShotAgent(p),
63
+ evictOrphanSubprocesses: (label) => claudeEvictOrphanSubprocesses(label),
64
+ };
65
+
66
+ const models: ModelCatalog = {
67
+ resolveModelInfo: (q) => modelProvider.resolveModel(q),
68
+ // Claude SDK ships a canonical `"default"` alias the runtime
69
+ // resolves to the recommended model. Returning it keeps reset
70
+ // + backend-switch on "Default (recommended)" rather than
71
+ // freezing a specific id that may go stale across SDK upgrades.
72
+ getDefaultModelId: () => "default",
73
+ getRawModelInfo: (id) => modelProvider.getModelInfo(id),
49
74
  getSettingsPresentation: (m, options) =>
50
75
  modelProvider.getSettingsPresentation(m, options),
51
76
  getProviders: () => modelProvider.getProviders(),
@@ -53,25 +78,57 @@ const claudeSdkFactory: BackendFactory = {
53
78
  modelProvider.getProviderModels(p, pg, ps),
54
79
  formatModelError: (q, r) => modelProvider.formatModelError(q, r),
55
80
  listModels: (f) => modelProvider.listModels(f),
56
- backendLabel: "Anthropic",
57
- refreshMcpServers: async (chatId) => {
81
+ };
82
+
83
+ // Claude SDK's per-turn subprocess model has no shared session
84
+ // state to reset; `warmSession` is the only useful hook. The
85
+ // dispatcher's `/reset` clears Talon's stored session id via
86
+ // `storage/sessions.ts:resetSession` regardless.
87
+ const sessions: SessionBackend = {
88
+ warmSession: (chatId) => claudeWarmSession(chatId),
89
+ };
90
+
91
+ const tools: ToolRuntime = {
92
+ refreshTools: async (chatId) => {
58
93
  const qi = getActiveQuery(chatId);
59
94
  if (!qi) return null;
60
95
  // Two-phase teardown: remove all MCP servers first so each
61
96
  // subprocess receives an OS-agnostic shutdown via stdio, then
62
97
  // install the fresh set.
63
98
  await qi.setMcpServers({});
64
- const bridgeUrl = `http://127.0.0.1:${ctx.getBridgePort()}`;
65
99
  const freshServers = {
66
100
  ...buildMcpServers(chatId),
67
- ...getPluginMcpServers(bridgeUrl, chatId),
101
+ ...buildPluginMcpServers(chatId),
68
102
  };
69
- return qi.setMcpServers(freshServers);
103
+ const result = await qi.setMcpServers(freshServers);
104
+ // setMcpServers resolves on REGISTER, not CONNECT — MCP startup is
105
+ // non-blocking. A stdio server that dials a slow remote (e.g. the
106
+ // playwright plugin connecting to the Camoufox websocket) is still
107
+ // 'pending' at this point and its tools are absent from the live
108
+ // registry, so the turn would proceed with mcp__playwright-tools__*
109
+ // stuck "connecting" until the next refresh. Wait (bounded) for the
110
+ // newly-added servers to finish connecting before returning.
111
+ await waitForMcpServersReady(qi, result.added);
112
+ return result;
70
113
  },
71
- runOneShotAgent: (p) => claudeRunOneShotAgent(p),
72
- evictOrphanSubprocesses: (label) => claudeEvictOrphanSubprocesses(label),
73
114
  };
74
115
 
116
+ const control: SystemControl = {
117
+ updateSystemPrompt: (prompt) => claudeUpdateSystemPrompt(prompt),
118
+ };
119
+
120
+ const backend = composeBackend({
121
+ id: "claude",
122
+ label: "Anthropic",
123
+ cacheMetrics: "readwrite",
124
+ chat,
125
+ background,
126
+ models,
127
+ sessions,
128
+ tools,
129
+ control,
130
+ });
131
+
75
132
  return { backend };
76
133
  },
77
134
  };