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
@@ -1,146 +0,0 @@
1
- /**
2
- * Soul Kernel — context-conditioned retrieval.
3
- *
4
- * Grounded in Park et al., "Generative Agents: Interactive Simulacra of Human
5
- * Behavior" (2023), whose memory retrieval scores each record by a normalized
6
- * sum of three signals: recency, importance, and relevance to the current
7
- * moment. We adapt it to value retrieval so the projected soul is the part of
8
- * identity that is *relevant right now*, not just globally salient:
9
- *
10
- * recency — decayed salience (already the kernel's "weather").
11
- * importance — how core the value is: confidence magnitude + how connected it
12
- * is in the Hebbian lattice (degree centrality). Central,
13
- * well-evidenced values matter regardless of the moment.
14
- * relevance — cosine similarity between the value's medoid and the current
15
- * context embedding (0 when no context is supplied).
16
- *
17
- * Each component is min-max normalized to [0,1] across the candidate set (as in
18
- * the paper) before the weighted sum, so no single signal's scale dominates.
19
- * Still model-free: scores are arithmetic over embeddings and counts.
20
- */
21
-
22
- import type { SoulDag } from "./dag.js";
23
- import { isSuperseded } from "./consolidate.js";
24
- import { cosineSimilarity, type Embedder } from "./embedder.js";
25
- import { confidence, effectiveSalience } from "./salience.js";
26
- import type { Hash, SoulConfig, ValuePayload } from "./types.js";
27
- import { halfLifeForKind } from "./types.js";
28
-
29
- export interface RetrievalWeights {
30
- readonly recency: number;
31
- readonly importance: number;
32
- readonly relevance: number;
33
- }
34
-
35
- const DEFAULT_RETRIEVAL_WEIGHTS: RetrievalWeights = {
36
- recency: 1,
37
- importance: 1,
38
- relevance: 1,
39
- };
40
-
41
- export interface RetrievedValue {
42
- readonly hash: Hash;
43
- readonly score: number;
44
- readonly recency: number;
45
- readonly importance: number;
46
- readonly relevance: number;
47
- }
48
-
49
- export interface RetrieveOptions {
50
- readonly now: number;
51
- readonly config: SoulConfig;
52
- /** Current-moment text; its embedding drives the relevance term. */
53
- readonly context?: string;
54
- readonly weights?: RetrievalWeights;
55
- /**
56
- * Optional precomputed centrality (e.g. PageRank) used for the importance
57
- * term. When absent, importance falls back to log-degree centrality.
58
- */
59
- readonly centrality?: ReadonlyMap<Hash, number>;
60
- }
61
-
62
- function medoidText(dag: SoulDag, valueHash: Hash): string | undefined {
63
- const node = dag.getNode(valueHash);
64
- if (node?.payload.kind !== "value") return undefined;
65
- const medoid = dag.getNode((node.payload as ValuePayload).medoid);
66
- return medoid?.payload.kind === "evidence" ? medoid.payload.text : undefined;
67
- }
68
-
69
- /** Degree centrality: total coactivation edge weight incident to a node. */
70
- function centrality(dag: SoulDag, hash: Hash): number {
71
- let sum = 0;
72
- for (const e of dag.edgesFrom(hash, "coactivation")) sum += e.weight;
73
- return sum;
74
- }
75
-
76
- function minMax(values: number[]): (x: number) => number {
77
- const lo = Math.min(...values);
78
- const hi = Math.max(...values);
79
- const span = hi - lo;
80
- return (x) => (span <= 0 ? 0 : (x - lo) / span);
81
- }
82
-
83
- /**
84
- * Rank live values by the Generative-Agents composite score. Async because the
85
- * relevance term embeds the medoids and the context together.
86
- */
87
- export async function retrieveValues(
88
- dag: SoulDag,
89
- embedder: Embedder,
90
- opts: RetrieveOptions,
91
- ): Promise<RetrievedValue[]> {
92
- const weights = opts.weights ?? DEFAULT_RETRIEVAL_WEIGHTS;
93
- const values = dag
94
- .nodesOfKind("value")
95
- .filter((n) => !isSuperseded(dag, n.hash));
96
-
97
- const rows = values
98
- .map((n) => ({ hash: n.hash, text: medoidText(dag, n.hash) }))
99
- .filter((r): r is { hash: Hash; text: string } => !!r.text);
100
- if (rows.length === 0) return [];
101
-
102
- const rawRecency = rows.map((r) =>
103
- effectiveSalience(
104
- dag.stateOf(r.hash),
105
- opts.now,
106
- halfLifeForKind(opts.config, "value"),
107
- ),
108
- );
109
- const rawImportance = rows.map((r) => {
110
- const conf = Math.abs(confidence(dag.stateOf(r.hash)));
111
- const struct = opts.centrality
112
- ? (opts.centrality.get(r.hash) ?? 0)
113
- : Math.log1p(centrality(dag, r.hash));
114
- return conf + struct;
115
- });
116
-
117
- // Relevance via one embed call over [context, ...medoids].
118
- let rawRelevance = rows.map(() => 0);
119
- if (opts.context) {
120
- const vecs = await embedder.embed([
121
- opts.context,
122
- ...rows.map((r) => r.text),
123
- ]);
124
- const ctx = vecs[0]!;
125
- rawRelevance = rows.map((_, i) =>
126
- Math.max(0, cosineSimilarity(ctx, vecs[i + 1]!)),
127
- );
128
- }
129
-
130
- const nR = minMax(rawRecency);
131
- const nI = minMax(rawImportance);
132
- const nV = minMax(rawRelevance);
133
-
134
- return rows
135
- .map((r, i) => {
136
- const recency = nR(rawRecency[i]!);
137
- const importance = nI(rawImportance[i]!);
138
- const relevance = nV(rawRelevance[i]!);
139
- const score =
140
- weights.recency * recency +
141
- weights.importance * importance +
142
- weights.relevance * relevance;
143
- return { hash: r.hash, score, recency, importance, relevance };
144
- })
145
- .sort((a, b) => b.score - a.score || a.hash.localeCompare(b.hash));
146
- }
@@ -1,146 +0,0 @@
1
- /**
2
- * Soul Kernel — salience dynamics. "The soul has weather."
3
- *
4
- * This is the entire learning mechanism, and it is pure arithmetic — no model,
5
- * no embedder, just counters, exponential decay, and a delta rule. Four forces:
6
- *
7
- * - decay salience halves over a half-life of disuse, so stale
8
- * fixations fade from projection without being deleted.
9
- * - reinforce activation under a positive signal raises salience and
10
- * accumulates signed evidence.
11
- * - coactivate Hebbian: nodes that fire together in a successful interaction
12
- * strengthen their mutual edge ("fire together, wire together").
13
- * - prediction the soul predicts how loud a node should be; a correction is
14
- * error a large prediction error and updates proportionally.
15
- *
16
- * Decay is applied LAZILY: stored salience is always "salience as of
17
- * lastActivatedAt", and the effective value at any later instant is computed on
18
- * read. This means no global sweep is ever required — reading the soul is O(1)
19
- * per node, and writing only touches the nodes actually involved.
20
- */
21
-
22
- import type { SoulDag } from "./dag.js";
23
- import { retrievability } from "./forgetting.js";
24
- import type { ActivationState, Hash } from "./types.js";
25
-
26
- /** Exponential decay multiplier for an elapsed interval given a half-life. */
27
- export function decayFactor(elapsedMs: number, halfLifeMs: number): number {
28
- if (elapsedMs <= 0 || halfLifeMs <= 0) return elapsedMs <= 0 ? 1 : 0;
29
- return Math.pow(0.5, elapsedMs / halfLifeMs);
30
- }
31
-
32
- /**
33
- * Salience as it stands *now*, after lazy time-decay from its last activation.
34
- * When the node carries an FSRS stability, decay follows the power-law
35
- * retrievability curve; otherwise it is the fixed-half-life exponential. An
36
- * infinite half-life (a no-decay node kind, e.g. reflexes) short-circuits both
37
- * paths: the stored salience is returned untouched.
38
- */
39
- export function effectiveSalience(
40
- state: ActivationState,
41
- now: number,
42
- halfLifeMs: number,
43
- ): number {
44
- if (!Number.isFinite(halfLifeMs)) return state.salience;
45
- if (state.stability !== undefined) {
46
- return (
47
- state.salience *
48
- retrievability(now - state.lastActivatedAt, state.stability)
49
- );
50
- }
51
- return state.salience * decayFactor(now - state.lastActivatedAt, halfLifeMs);
52
- }
53
-
54
- /**
55
- * Confidence in a node, squashed from its net evidence into (-1, 1). Positive
56
- * means behavior expressing it has been rewarded; negative means corrected.
57
- * tanh keeps a runaway counter from ever dominating.
58
- */
59
- export function confidence(state: ActivationState): number {
60
- return Math.tanh(state.evidence / 4);
61
- }
62
-
63
- export interface ReinforceOptions {
64
- readonly now: number;
65
- readonly halfLifeMs: number;
66
- /** Salience increment for this activation (>= 0). */
67
- readonly amount: number;
68
- /** Signed evidence delta: positive for reward, negative for a correction. */
69
- readonly valence: number;
70
- }
71
-
72
- /**
73
- * Activation under a behavioral signal. Decays the stored salience to `now`
74
- * first (so the additive bump composes correctly with time), then adds the
75
- * increment and accumulates signed evidence.
76
- */
77
- export function reinforce(
78
- dag: SoulDag,
79
- hash: Hash,
80
- opts: ReinforceOptions,
81
- ): void {
82
- const s = dag.stateOf(hash);
83
- s.salience = effectiveSalience(s, opts.now, opts.halfLifeMs) + opts.amount;
84
- s.evidence += opts.valence;
85
- s.activations += 1;
86
- s.lastActivatedAt = opts.now;
87
- dag.touch(hash);
88
- }
89
-
90
- /**
91
- * Hebbian co-activation over the set of nodes active in one interaction.
92
- * Strengthens a symmetric coactivation edge for every unordered pair. The
93
- * Lattice's affinity/tension structure self-organizes from these counts — no
94
- * model decides which values relate, the statistics do.
95
- */
96
- export function coactivate(
97
- dag: SoulDag,
98
- hashes: readonly Hash[],
99
- opts: { now: number; increment: number },
100
- ): void {
101
- const list = [...new Set(hashes)];
102
- for (let i = 0; i < list.length; i++) {
103
- for (let j = i + 1; j < list.length; j++) {
104
- const a = list[i]!;
105
- const b = list[j]!;
106
- for (const [from, to] of [
107
- [a, b],
108
- [b, a],
109
- ] as const) {
110
- const e = dag.edge(from, "coactivation", to, opts.now);
111
- e.weight += opts.increment;
112
- e.updatedAt = opts.now;
113
- }
114
- }
115
- }
116
- }
117
-
118
- export interface PredictionErrorOptions {
119
- readonly now: number;
120
- readonly halfLifeMs: number;
121
- /** How strongly the observed signal corrects the prediction, in (0, 1]. */
122
- readonly learningRate: number;
123
- }
124
-
125
- /**
126
- * Predictive-coding update. The soul holds a prediction of how salient a node
127
- * should be (its decayed salience); the realized `observed` signal yields an
128
- * error, and salience moves a learningRate-fraction of the way toward it.
129
- * Returns the error so callers can route large surprises into the Spine as
130
- * developmental events. Salience is floored at 0.
131
- */
132
- export function applyPredictionError(
133
- dag: SoulDag,
134
- hash: Hash,
135
- observed: number,
136
- opts: PredictionErrorOptions,
137
- ): number {
138
- const s = dag.stateOf(hash);
139
- const predicted = effectiveSalience(s, opts.now, opts.halfLifeMs);
140
- const error = observed - predicted;
141
- s.salience = Math.max(0, predicted + opts.learningRate * error);
142
- s.activations += 1;
143
- s.lastActivatedAt = opts.now;
144
- dag.touch(hash);
145
- return error;
146
- }
@@ -1,204 +0,0 @@
1
- /**
2
- * Soul Kernel — runtime service (the harness integration seam).
3
- *
4
- * A single gated entry point the rest of Talon talks to, so the kernel's
5
- * internals stay decoupled from the frontend/runtime. The service is OFF unless
6
- * the deployment opts in (`TALON_SOUL_ENABLED`); when off, every method is an
7
- * inert no-op and nothing about Talon's behavior changes.
8
- *
9
- * Construction is synchronous and race-free: the kernel loads from disk (or
10
- * genesis) with `readFileSync`, and the static projection used in the system
11
- * prompt is synchronous too. Only the maintenance `dream` (which embeds) is
12
- * async, so it runs off the hot path on a schedule.
13
- *
14
- * Responsibilities:
15
- * - render the projected identity surface for the system prompt,
16
- * - accept behavioral signals (reactions today; more taps to follow),
17
- * - evaluate reflexes for the turn-end guard,
18
- * - run the periodic `dream` and persist.
19
- */
20
-
21
- import { existsSync } from "node:fs";
22
- import { files } from "../../util/paths.js";
23
- import { log, logError } from "../../util/log.js";
24
- import { SoulKernel } from "./kernel.js";
25
- import { TalonEmbedder } from "./talon-embedder.js";
26
- import { resolveSoulSettings, type SoulSettings } from "./settings.js";
27
- import {
28
- evaluateReflexes,
29
- isBlocked,
30
- type ReflexContext,
31
- type ReflexVerdict,
32
- } from "./reflex.js";
33
- import { explainDelta } from "./delta.js";
34
- import type { Embedder } from "./embedder.js";
35
- import type { Hash, ReflexPayload } from "./types.js";
36
-
37
- export class SoulService {
38
- readonly enabled: boolean;
39
- private readonly embedder: Embedder = new TalonEmbedder();
40
- private lastActive: Hash[] = [];
41
-
42
- private constructor(
43
- private readonly kernel: SoulKernel | null,
44
- private readonly path: string,
45
- ) {
46
- this.enabled = kernel !== null;
47
- }
48
-
49
- /**
50
- * Build the service from settings. Disabled deployments get an inert instance;
51
- * enabled ones load the persisted kernel (or genesis a fresh one). A corrupt
52
- * store degrades to genesis rather than crashing the bot.
53
- */
54
- static create(override?: Partial<SoulSettings>): SoulService {
55
- const settings = resolveSoulSettings(override);
56
- const path = settings.path ?? files.soul;
57
- if (!settings.enabled) return new SoulService(null, path);
58
-
59
- let kernel: SoulKernel;
60
- try {
61
- kernel = existsSync(path) ? SoulKernel.load(path) : SoulKernel.genesis();
62
- log("soul", `loaded kernel (${existsSync(path) ? "disk" : "genesis"})`);
63
- } catch (err) {
64
- logError("soul", `kernel load failed, starting fresh: ${String(err)}`);
65
- kernel = SoulKernel.genesis();
66
- }
67
- return new SoulService(kernel, path);
68
- }
69
-
70
- // ── Prompt surface ───────────────────────────────────────────────────────────
71
-
72
- /**
73
- * The projected identity surface to inject into the system prompt, or "" when
74
- * disabled. Records the surfaced values as "active" so a later reaction can be
75
- * credited to exactly what was on stage.
76
- */
77
- renderPromptSection(): string {
78
- if (!this.kernel) return "";
79
- const projection = this.kernel.project();
80
- this.lastActive = [...projection.includedValues];
81
- return projection.text;
82
- }
83
-
84
- // ── Signal taps ──────────────────────────────────────────────────────────────
85
-
86
- /** A reaction to Talon's message → reinforce/penalize the values on stage. */
87
- recordReaction(emoji: string, at = Date.now()): void {
88
- if (!this.kernel) return;
89
- this.kernel.ingest({
90
- kind: "reaction",
91
- at,
92
- emoji,
93
- activeNodes: this.lastActive,
94
- });
95
- this.persist();
96
- }
97
-
98
- /** An explicit instruction about how to be → stored as verbatim evidence. */
99
- recordDirective(text: string, actor?: string, at = Date.now()): void {
100
- if (!this.kernel) return;
101
- this.kernel.ingest({
102
- kind: "directive",
103
- at,
104
- text,
105
- ...(actor ? { actor } : {}),
106
- });
107
- this.persist();
108
- }
109
-
110
- /** A correction → verbatim evidence + Spine event + penalize active values. */
111
- recordCorrection(text: string, actor?: string, at = Date.now()): void {
112
- if (!this.kernel) return;
113
- this.kernel.ingest({
114
- kind: "correction",
115
- at,
116
- text,
117
- activeNodes: this.lastActive,
118
- ...(actor ? { actor } : {}),
119
- });
120
- this.persist();
121
- }
122
-
123
- // ── Reflex guard ─────────────────────────────────────────────────────────────
124
-
125
- /** Evaluate the kernel's reflexes for a decision point. Empty when disabled. */
126
- reflexCheck(ctx: ReflexContext): ReflexVerdict[] {
127
- if (!this.kernel) return [];
128
- const reflexes = this.kernel
129
- .graph()
130
- .nodesOfKind("reflex")
131
- .map((n) => n.payload as ReflexPayload);
132
- return evaluateReflexes(reflexes, ctx);
133
- }
134
-
135
- /** Convenience: does any reflex block this decision point? */
136
- isBlocked(ctx: ReflexContext): boolean {
137
- return isBlocked(this.reflexCheck(ctx));
138
- }
139
-
140
- // ── Maintenance ──────────────────────────────────────────────────────────────
141
-
142
- /** The periodic organic pass: crystallize → consolidate → reflect, then persist. */
143
- async dream(): Promise<void> {
144
- if (!this.kernel) return;
145
- try {
146
- const summary = await this.kernel.dream(this.embedder);
147
- this.kernel.commit("dream");
148
- this.persist();
149
- log(
150
- "soul",
151
- `dream: +${summary.crystallized} values, ${summary.consolidated.created.length} merged, ${summary.themes} themes`,
152
- );
153
- } catch (err) {
154
- logError("soul", `dream failed: ${String(err)}`);
155
- }
156
- }
157
-
158
- // ── Introspection (/soul) ────────────────────────────────────────────────────
159
-
160
- /** Human-readable current identity + last delta, for the `/soul` command. */
161
- introspect(): string {
162
- if (!this.kernel) return "Soul is disabled.";
163
- const head = this.kernel.head();
164
- const projection = this.kernel.project();
165
- const lines = [
166
- projection.text,
167
- "",
168
- `_version ${this.kernel.history().length}, ${this.kernel.graph().size} nodes_`,
169
- ];
170
- if (head) lines.push(`_last change: ${head.summary}_`);
171
- const delta = explainDelta(this.kernel.delta());
172
- if (delta !== "no structural change")
173
- lines.push("", "Recent changes:", delta);
174
- return lines.join("\n");
175
- }
176
-
177
- private persist(): void {
178
- if (!this.kernel) return;
179
- try {
180
- this.kernel.save(this.path);
181
- } catch (err) {
182
- logError("soul", `persist failed: ${String(err)}`);
183
- }
184
- }
185
- }
186
-
187
- // ── Module singleton ─────────────────────────────────────────────────────────
188
-
189
- let instance: SoulService | null = null;
190
-
191
- /** The process-wide soul service (lazily created from env settings). */
192
- export function getSoul(): SoulService {
193
- return (instance ??= SoulService.create());
194
- }
195
-
196
- /** Replace the singleton (tests / explicit settings). */
197
- export function setSoul(service: SoulService): void {
198
- instance = service;
199
- }
200
-
201
- /** Drop the singleton so the next getSoul() rebuilds it. */
202
- export function resetSoul(): void {
203
- instance = null;
204
- }
@@ -1,47 +0,0 @@
1
- /**
2
- * Soul Kernel — runtime gate.
3
- *
4
- * The soul is OFF by default. It is an experimental identity substrate; no
5
- * deployment should grow one unless it explicitly opts in. Our own Talon flips
6
- * `enabled` on (so the kernel accumulates from day one, ready for when the
7
- * harness wiring lands); every other deployment stays inert.
8
- *
9
- * Resolution order: explicit settings argument → env (`TALON_SOUL_ENABLED`) →
10
- * default false. When the harness config system grows a `soul` block, it should
11
- * feed it through `resolveSoulSettings`, keeping this the single gate.
12
- */
13
-
14
- export interface SoulSettings {
15
- /** Master switch. Default false everywhere except our Talon. */
16
- readonly enabled: boolean;
17
- /** Path to the persisted kernel; defaults under the workspace when wired. */
18
- readonly path?: string;
19
- }
20
-
21
- export const DEFAULT_SOUL_SETTINGS: SoulSettings = { enabled: false };
22
-
23
- function envFlag(name: string): boolean | undefined {
24
- const v = process.env[name];
25
- if (v === undefined) return undefined;
26
- return /^(1|true|yes|on)$/i.test(v.trim());
27
- }
28
-
29
- /**
30
- * Resolve effective settings. An explicit `enabled` always wins; otherwise the
31
- * env flag; otherwise disabled. Keeping this pure makes it trivially testable and
32
- * keeps the "default off" guarantee in one place.
33
- */
34
- export function resolveSoulSettings(
35
- override?: Partial<SoulSettings>,
36
- ): SoulSettings {
37
- const enabled = override?.enabled ?? envFlag("TALON_SOUL_ENABLED") ?? false;
38
- return {
39
- enabled,
40
- ...(override?.path ? { path: override.path } : {}),
41
- };
42
- }
43
-
44
- /** True when the soul should run in this deployment. */
45
- export function soulEnabled(override?: Partial<SoulSettings>): boolean {
46
- return resolveSoulSettings(override).enabled;
47
- }
@@ -1,117 +0,0 @@
1
- /**
2
- * Soul Kernel — behavioral signals: the fuel.
3
- *
4
- * The compiler never reads a transcript and forms an opinion. It consumes
5
- * *structured* events the harness already emits — reactions, whether a
6
- * conversation continued or died, corrections, reflex fires. Interpretation has
7
- * already happened by the time a signal exists, so turning experience into
8
- * identity stays mechanical.
9
- *
10
- * Each outcome signal carries the `activeNodes` that were surfaced in the
11
- * projection for that turn. That is what closes the loop: project → which values
12
- * were live → what happened → reinforce or penalize exactly those values.
13
- */
14
-
15
- import type { Hash } from "./types.js";
16
-
17
- interface ReactionSignal {
18
- readonly kind: "reaction";
19
- readonly at: number;
20
- readonly emoji: string;
21
- /** Value nodes that were live in the projection for the reacted-to turn. */
22
- readonly activeNodes: readonly Hash[];
23
- }
24
-
25
- interface EngagementSignal {
26
- readonly kind: "engagement";
27
- readonly at: number;
28
- /** Did the conversation continue after Talon's message, or die? */
29
- readonly continued: boolean;
30
- readonly activeNodes: readonly Hash[];
31
- /**
32
- * Categorical cues observed in the interaction (e.g. emojis used). When
33
- * present, the outcome teaches each cue's learned valence — meaning comes from
34
- * data, not a hardcoded table.
35
- */
36
- readonly cues?: readonly string[];
37
- }
38
-
39
- export interface CorrectionSignal {
40
- readonly kind: "correction";
41
- readonly at: number;
42
- /** The verbatim correction — stored as ground-truth evidence. */
43
- readonly text: string;
44
- readonly actor?: string;
45
- readonly ref?: string;
46
- /** Values that were live when the correction landed (penalized). */
47
- readonly activeNodes?: readonly Hash[];
48
- }
49
-
50
- export interface DirectiveSignal {
51
- readonly kind: "directive";
52
- readonly at: number;
53
- /** Verbatim instruction about how to be — stored as evidence. */
54
- readonly text: string;
55
- readonly actor?: string;
56
- readonly ref?: string;
57
- }
58
-
59
- interface ReflexFireSignal {
60
- readonly kind: "reflex-fire";
61
- readonly at: number;
62
- readonly name: string;
63
- readonly severity: "block" | "warn" | "advise";
64
- }
65
-
66
- interface ActivationSignal {
67
- readonly kind: "activation";
68
- readonly at: number;
69
- readonly activeNodes: readonly Hash[];
70
- }
71
-
72
- export type Signal =
73
- | ReactionSignal
74
- | EngagementSignal
75
- | CorrectionSignal
76
- | DirectiveSignal
77
- | ReflexFireSignal
78
- | ActivationSignal;
79
-
80
- const POSITIVE = new Set([
81
- "👍",
82
- "❤",
83
- "❤️",
84
- "🔥",
85
- "🎉",
86
- "💯",
87
- "🥰",
88
- "👏",
89
- "😁",
90
- "🤩",
91
- "🙏",
92
- "👌",
93
- "🤝",
94
- "🫡",
95
- "😍",
96
- "🆒",
97
- "💘",
98
- ]);
99
- const NEGATIVE = new Set([
100
- "👎",
101
- "😡",
102
- "🤬",
103
- "💩",
104
- "🤮",
105
- "😢",
106
- "🖕",
107
- "🥱",
108
- "🥴",
109
- "😴",
110
- ]);
111
-
112
- /** Map an emoji reaction to a signed valence in {-1, 0, +1}. */
113
- export function emojiValence(emoji: string): number {
114
- if (POSITIVE.has(emoji)) return 1;
115
- if (NEGATIVE.has(emoji)) return -1;
116
- return 0;
117
- }