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,110 +0,0 @@
1
- # Soul Kernel
2
-
3
- Talon's compiled identity. Not a markdown prompt, not a JSON blob — a
4
- **content-addressed Merkle DAG** of typed identity nodes, learned **mechanically**
5
- from behavioral telemetry and projected into the system prompt by **selection**.
6
-
7
- > The model is the brain. Talon is the body. The Soul is the persistent identity
8
- > artifact that tells the brain how to be Talon.
9
-
10
- ## The thesis: the model never writes its own soul
11
-
12
- There are two jobs — _being the self_ (the reasoning model reads the soul and
13
- acts) and _writing the self_ (turning experience into identity). If the reasoning
14
- model does the second, it can rationalize, flatter itself, and confabulate a
15
- coherent self-story that isn't true. So **writing the self is strictly
16
- model-free**: continuous, deterministic, evidence-grounded. The reasoning model is
17
- a _reader_ of the soul, never its author. That is the safety property, not just a
18
- cost saving.
19
-
20
- The only neural component anywhere is an optional **local embedder** (for
21
- clustering/dedup/contradiction-distance) — a frozen fixed function, not an agent.
22
- Everything else is counters, exponential decay, dot products, and selection.
23
-
24
- ## The substrate
25
-
26
- A node's identity is the sha-256 of its canonical content. The single most
27
- important decision is the split between:
28
-
29
- - **Content** (hashed, immutable) — a node's semantic identity: kind + verbatim
30
- payload + referenced child hashes. A change of content is a new node.
31
- - **State** (mutable, keyed by hash) — salience, evidence weight, activation
32
- counts. Churns every tick; lives _outside_ the Merkle structure.
33
-
34
- So reinforcing a value a thousand times never churns a single content hash.
35
- Versioning, provenance, dedup, and partial recompilation fall out structurally;
36
- learning and decay live in the state layer.
37
-
38
- ## The five structures
39
-
40
- | Structure | Node kind | What it is |
41
- | --------- | --------------- | ------------------------------------------------------------------------------------------- |
42
- | Spine | `spine` | append-only causal narrative — _why_ Talon became Talon |
43
- | Lattice | `value` + edges | values as evidence clusters; tension/affinity edges self-organize via Hebbian co-activation |
44
- | Reflexes | `reflex` | `trigger → guard → action` rules the harness _enforces_ |
45
- | Holograph | `lens` | identity refracted per interlocutor (selection + reweighting) |
46
- | Critic | (classifiers) | frozen feature-based gates over failure modes |
47
-
48
- The atoms under all of it are `evidence` nodes — verbatim ground truth. The kernel
49
- never paraphrases; it only ever quotes.
50
-
51
- ## The model-free pipeline
52
-
53
- ```
54
- telemetry ──▶ signals ──▶ compiler ──▶ DAG (+ salience/Hebbian) ──▶ projector ──▶ runtime.md
55
- (harness) (structured) (arithmetic) (content + state) (selection) (injected)
56
- ```
57
-
58
- - **Signals** (`signals.ts`) — structured harness events (reaction, engagement,
59
- correction, reflex-fire). Interpretation already happened; no transcript reading.
60
- - **Compiler** (`compiler.ts`) — routes each signal to pure update rules. Outcome
61
- signals reinforce/penalize the values that were live in that turn's projection
62
- and Hebbian-coactivate them; corrections store verbatim evidence + a Spine event.
63
- - **Salience** (`salience.ts`) — lazy exponential decay, reinforcement, Hebbian
64
- edges, predictive-coding delta rule. The whole "learning" is here, all arithmetic.
65
- - **Projector** (`projector.ts`) — selects verbatim evidence, salience-ordered
66
- under a token budget. Reflexes are never budgeted away. The soul cannot
67
- hallucinate itself.
68
- - **Critic** (`critic.ts`) — frozen classifiers for wall-of-text, sycophancy,
69
- emoji-overload.
70
- - **Kernel** (`kernel.ts`) — orchestrator: genesis → ingest → commit → project,
71
- with a git-like commit chain and JSON persistence.
72
-
73
- ## File map
74
-
75
- ```
76
- types.ts node payloads, edges, activation state, commits, config
77
- hash.ts canonical serialization + content addressing + Merkle root
78
- dag.ts the DAG store: integrity, dirty propagation, snapshot/restore
79
- salience.ts decay / reinforce / coactivate / prediction-error (the math)
80
- reflex.ts predicate registry + enforcer + the three seed reflexes
81
- signals.ts structured telemetry types + emoji→valence
82
- compiler.ts signal → arithmetic update routing (writing the self)
83
- projector.ts DAG → runtime surface by selection (reading the self)
84
- critic.ts frozen failure-mode classifiers
85
- kernel.ts orchestrator: lifecycle, commits, persistence
86
- index.ts public surface
87
- ```
88
-
89
- ## Status
90
-
91
- Implemented and tested (150+ tests, model-free end to end):
92
-
93
- - **Substrate** — content-addressed Merkle DAG, dirty-tracking, commits, persistence.
94
- - **Learning** — salience decay/reinforce, Hebbian edges, predictive-coding updates.
95
- - **Emergence** — value clustering (`crystallize`), self-reorganizing `consolidate`
96
- ("dream") with adaptive thresholds + state migration, reflection into `theme`s.
97
- - **Embedding** — our own `TalonEmbedder` (model-free) behind a pluggable seam.
98
- - **Adaptation** — learned valence (meaning from outcomes), FSRS/DSR forgetting,
99
- ADWIN drift → Spine epochs, emergent failure modes.
100
- - **Recall** — Generative-Agents context retrieval, PageRank centrality, modern
101
- Hopfield associative recall, VSA/HDC compositional episodic memory.
102
- - **Refraction** — relational holograph lens compilation.
103
- - **Surfaces** — projector (selection), delta stream, mechanical Critic.
104
- - **Governance** — protected-node approval queue; runtime gate (off by default).
105
-
106
- See `RESEARCH.md` for the literature behind each mechanism.
107
-
108
- Remaining: **harness wiring** — telemetry taps (reactions/engagement/corrections →
109
- signals), prompt injection of the projected surface, and live reflex enforcement.
110
- This touches the live Talon runtime and is gated behind `TALON_SOUL_ENABLED`.
@@ -1,98 +0,0 @@
1
- # Soul Kernel — research grounding
2
-
3
- Every mechanism in the kernel is model-free, but few are invented. This maps the
4
- load-bearing ideas to the literature they come from, and notes where each lives.
5
-
6
- ## Implemented
7
-
8
- ### Content-addressed Merkle DAG — `hash.ts`, `dag.ts`
9
-
10
- - Merkle, "A Digital Signature Based on a Conventional Encryption Function" (1987);
11
- the git object model (Torvalds/Hamano, 2005).
12
- - Why: content addressing makes dedup, provenance, versioning, and partial
13
- recompilation structural rather than bolted on.
14
-
15
- ### Hebbian association — `salience.coactivate`, `lattice.ts`
16
-
17
- - Hebb, _The Organization of Behavior_ (1949): "cells that fire together wire
18
- together."
19
- - Why: the value lattice's affinity/tension edges self-organize from
20
- co-activation counts; no model decides what relates.
21
-
22
- ### Predictive-coding / free-energy updates — `salience.applyPredictionError`
23
-
24
- - Rao & Ballard (1999); Friston, free-energy principle (2010).
25
- - Why: the soul is a predictive model of its own behavior; a correction is a
26
- large prediction error and updates salience proportionally.
27
-
28
- ### Complementary Learning Systems / systems consolidation — `consolidate.ts`
29
-
30
- - McClelland, McNaughton & O'Reilly (1995); memory replay during sleep
31
- (Wilson & McNaughton, 1994).
32
- - Why: fast intake (crystallize) vs. slow reorganization (the "dream" pass that
33
- merges drifted-together values and migrates learned state) mirrors the
34
- fast-hippocampal / slow-neocortical split.
35
-
36
- ### Feature hashing embedder — `talon-embedder.ts`
37
-
38
- - Weinberger et al., "Feature Hashing for Large Scale Multitask Learning" (2009);
39
- signed hashing to debias collisions.
40
- - Why: a deterministic, dependency-free, model-free encoder we own — robust to
41
- typos via shared character n-grams; a real sentence encoder drops in behind the
42
- same interface.
43
-
44
- ### Generative-Agents retrieval — `retrieve.ts`
45
-
46
- - Park et al., "Generative Agents: Interactive Simulacra of Human Behavior" (2023).
47
- - Score = normalized(recency) + normalized(importance) + normalized(relevance),
48
- each min-max'd to [0,1] before summation, exactly as in the paper. Makes the
49
- projected soul _relevant to the current moment_, not just globally salient.
50
-
51
- ### FSRS / DSR adaptive forgetting — `forgetting.ts`
52
-
53
- - Wozniak's DSR model; FSRS (open-spaced-repetition); power-law forgetting
54
- (Wickelgren, 1974) which fits human retention better than an exponential.
55
- - Retrievability R(t) = (1 + FACTOR·t/S)^DECAY with R(S) ≈ 0.9; stability S grows
56
- on spaced successful recall and shrinks on a lapse. Core traits become durable,
57
- fads evaporate — emergently.
58
-
59
- ### Modern Hopfield associative recall — `associative.ts`
60
-
61
- - Ramsauer et al., "Hopfield Networks is All You Need" (2020); Krotov & Hopfield
62
- (2016, 2020). Continuous Hopfield retrieval is one softmax step — the same
63
- operation as attention.
64
- - Recall from a cue = softmax over Hebbian edge weights, p ∝ exp(β·w); `prime`
65
- applies the update to the lattice so the soul recalls in constellations.
66
-
67
- ### Reflection — `reflect.ts`
68
-
69
- - Park et al. (2023): synthesize higher-level inferences over time. Done
70
- structurally — themes form over values that are coherent AND co-active. The one
71
- optional, gated model pass (a label-only `synthesize` hook) lives here and can
72
- never change which values group.
73
-
74
- ### Concept-drift detection — `drift.ts`
75
-
76
- - Bifet & Gavaldà, "Learning from Time-Changing Data with Adaptive Windowing"
77
- (ADWIN, 2007). Detects shifts in interaction-outcome distribution and opens a
78
- developmental epoch in the Spine.
79
-
80
- ### Personalized PageRank centrality — `centrality.ts`
81
-
82
- - Page, Brin, Motwani & Winograd (1999). Structural importance over the
83
- co-activation graph; personalizable to a context.
84
-
85
- ### Hyperdimensional / Vector-Symbolic memory — `hdc.ts`
86
-
87
- - Kanerva, "Hyperdimensional Computing" (2009). bind/bundle/permute/cleanup over
88
- high-dim bipolar vectors give a compositional, model-free episodic memory:
89
- context⊗value bound and bundled, recalled by unbinding — "in a situation like
90
- this, what do I do?"
91
-
92
- ## Future directions (researched, not yet built)
93
-
94
- - **Holographic Reduced Representations** (Plate, 1995) as a circular-convolution
95
- alternative to elementwise binding, for graceful capacity scaling.
96
- - **Sparse distributed memory** (Kanerva, 1988) as an alternative episodic store.
97
- - **Active-inference planning** (Friston et al.) atop the existing predictive-
98
- coding updates, to _select_ behavior, not just learn from it.
@@ -1,98 +0,0 @@
1
- /**
2
- * Soul Kernel — associative recall (modern Hopfield / attention).
3
- *
4
- * Grounded in Ramsauer et al., "Hopfield Networks is All You Need" (2020), which
5
- * showed that a continuous modern Hopfield network retrieves a stored pattern in
6
- * ONE update via a softmax over similarities — the very operation at the heart of
7
- * attention. We apply the same rule to the lattice: the Hebbian coactivation
8
- * edges are the stored associations, and recalling from a cue is a one-step
9
- * softmax over the edge weights.
10
- *
11
- * p(neighbor) ∝ exp(β · w(cue → neighbor))
12
- *
13
- * `prime` then performs the Hopfield update against the lattice itself: it nudges
14
- * the salience of the associatively-bound partners. The behavioral effect is what
15
- * you would want from a self — thinking of one value brings its companions to
16
- * mind ("push back" primes "be direct"), so the soul recalls in coherent
17
- * constellations rather than isolated points. Still model-free: a softmax over
18
- * counts.
19
- */
20
-
21
- import type { SoulDag } from "./dag.js";
22
- import type { Hash } from "./types.js";
23
-
24
- export interface RecallResult {
25
- readonly node: Hash;
26
- /** Softmax weight in (0, 1]; the constellation sums to 1. */
27
- readonly weight: number;
28
- }
29
-
30
- export interface RecallOptions {
31
- /** Inverse temperature; higher β sharpens recall toward the strongest bond. */
32
- readonly beta?: number;
33
- /** Keep only the top-K partners (default: all). */
34
- readonly topK?: number;
35
- }
36
-
37
- /**
38
- * One-step associative retrieval from one or more cue nodes. Aggregates
39
- * coactivation edge weights to each neighbor, then softmaxes. Cues are excluded
40
- * from their own recall.
41
- */
42
- export function associativeRecall(
43
- dag: SoulDag,
44
- cues: readonly Hash[],
45
- opts: RecallOptions = {},
46
- ): RecallResult[] {
47
- const beta = opts.beta ?? 1;
48
- const cueSet = new Set(cues);
49
- const score = new Map<Hash, number>();
50
- for (const cue of cues) {
51
- for (const e of dag.edgesFrom(cue, "coactivation")) {
52
- if (cueSet.has(e.to)) continue;
53
- score.set(e.to, (score.get(e.to) ?? 0) + e.weight);
54
- }
55
- }
56
- if (score.size === 0) return [];
57
-
58
- // Numerically-stable softmax over β·score.
59
- const entries = [...score.entries()];
60
- const max = Math.max(...entries.map(([, w]) => w));
61
- const exps = entries.map(
62
- ([h, w]) => [h, Math.exp(beta * (w - max))] as const,
63
- );
64
- const z = exps.reduce((s, [, e]) => s + e, 0);
65
-
66
- const out = exps
67
- .map(([node, e]) => ({ node, weight: e / z }))
68
- .sort((a, b) => b.weight - a.weight || a.node.localeCompare(b.node));
69
- return opts.topK ? out.slice(0, opts.topK) : out;
70
- }
71
-
72
- export interface PrimeOptions extends RecallOptions {
73
- readonly now: number;
74
- /** Salience injected, distributed across the recalled constellation. */
75
- readonly gain: number;
76
- }
77
-
78
- /**
79
- * The Hopfield update applied to the lattice: recall from the cues and add
80
- * salience to the bound partners in proportion to their recall weight. Returns
81
- * the primed nodes. Caller commits.
82
- */
83
- export function prime(
84
- dag: SoulDag,
85
- cues: readonly Hash[],
86
- opts: PrimeOptions,
87
- ): Hash[] {
88
- const recalled = associativeRecall(dag, cues, opts);
89
- const primed: Hash[] = [];
90
- for (const { node, weight } of recalled) {
91
- const s = dag.stateOf(node);
92
- s.salience += opts.gain * weight;
93
- s.lastActivatedAt = opts.now;
94
- dag.touch(node);
95
- primed.push(node);
96
- }
97
- return primed;
98
- }
@@ -1,98 +0,0 @@
1
- /**
2
- * Soul Kernel — graph centrality (Personalized PageRank).
3
- *
4
- * Degree centrality ("how many strong bonds does this value have") is a crude
5
- * importance signal. PageRank (Page, Brin, Motwani & Winograd, 1999) is the
6
- * principled one: a value is important if it is bonded to OTHER important values.
7
- * We run it over the Hebbian co-activation graph so structural importance
8
- * reflects the whole association network, not just local degree.
9
- *
10
- * The "personalized" variant biases the teleport distribution toward a set of
11
- * seed nodes, yielding importance *relative to a context* — central with respect
12
- * to whatever is currently active. Pure power iteration; model-free.
13
- */
14
-
15
- import type { SoulDag } from "./dag.js";
16
- import type { Hash } from "./types.js";
17
-
18
- export interface PageRankOptions {
19
- readonly damping?: number;
20
- readonly iterations?: number;
21
- readonly epsilon?: number;
22
- /**
23
- * Optional personalization: teleport mass distribution over nodes. Values are
24
- * normalized internally. Absent ⇒ uniform (classic PageRank).
25
- */
26
- readonly personalization?: ReadonlyMap<Hash, number>;
27
- }
28
-
29
- /**
30
- * Weighted Personalized PageRank over the value co-activation graph. Returns a
31
- * score per live value summing to 1. Dangling nodes (no outbound bonds)
32
- * redistribute their mass via the teleport vector, keeping it a proper
33
- * distribution.
34
- */
35
- export function pagerank(
36
- dag: SoulDag,
37
- opts: PageRankOptions = {},
38
- ): Map<Hash, number> {
39
- const damping = opts.damping ?? 0.85;
40
- const iterations = opts.iterations ?? 100;
41
- const epsilon = opts.epsilon ?? 1e-9;
42
-
43
- const nodes = dag.nodesOfKind("value").map((n) => n.hash);
44
- const n = nodes.length;
45
- const out = new Map<Hash, number>();
46
- if (n === 0) return out;
47
-
48
- const idx = new Map(nodes.map((h, i) => [h, i]));
49
-
50
- // Weighted out-adjacency over coactivation edges (only among value nodes).
51
- const outWeight = Array.from({ length: n }, () => 0);
52
- const edges: { from: number; to: number; w: number }[] = [];
53
- for (const from of nodes) {
54
- for (const e of dag.edgesFrom(from, "coactivation")) {
55
- const j = idx.get(e.to);
56
- if (j === undefined || e.weight <= 0) continue;
57
- const i = idx.get(from)!;
58
- edges.push({ from: i, to: j, w: e.weight });
59
- outWeight[i]! += e.weight;
60
- }
61
- }
62
-
63
- // Teleport / personalization vector.
64
- const teleport = Array.from({ length: n }, () => 1 / n);
65
- if (opts.personalization && opts.personalization.size > 0) {
66
- let total = 0;
67
- for (const [, w] of opts.personalization) total += Math.max(0, w);
68
- if (total > 0) {
69
- for (let i = 0; i < n; i++) teleport[i] = 0;
70
- for (const [h, w] of opts.personalization) {
71
- const i = idx.get(h);
72
- if (i !== undefined) teleport[i]! += Math.max(0, w) / total;
73
- }
74
- }
75
- }
76
-
77
- let rank = Array.from({ length: n }, () => 1 / n);
78
- for (let it = 0; it < iterations; it++) {
79
- const next = teleport.map((t) => (1 - damping) * t);
80
-
81
- // Dangling mass (nodes with no out-edges) flows to the teleport vector.
82
- let dangling = 0;
83
- for (let i = 0; i < n; i++) if (outWeight[i] === 0) dangling += rank[i]!;
84
- for (let i = 0; i < n; i++) next[i]! += damping * dangling * teleport[i]!;
85
-
86
- for (const e of edges) {
87
- next[e.to]! += (damping * rank[e.from]! * e.w) / outWeight[e.from]!;
88
- }
89
-
90
- let delta = 0;
91
- for (let i = 0; i < n; i++) delta += Math.abs(next[i]! - rank[i]!);
92
- rank = next;
93
- if (delta < epsilon) break;
94
- }
95
-
96
- for (let i = 0; i < n; i++) out.set(nodes[i]!, rank[i]!);
97
- return out;
98
- }
@@ -1,83 +0,0 @@
1
- /**
2
- * Soul Kernel — emergent value clustering.
3
- *
4
- * This is where values *come from*: not authored, not seeded by a model, but
5
- * discovered as clusters of evidence embeddings. The model never names a value —
6
- * the cluster's medoid (its most central real fragment) is its label.
7
- *
8
- * The algorithm is single-pass leader/threshold clustering: each item joins the
9
- * nearest existing cluster if it is within `threshold` cosine distance of that
10
- * cluster's centroid, otherwise it founds a new cluster. Leader clustering is
11
- * order-sensitive, so items are processed in a stable hash order to keep the
12
- * output deterministic and reproducible across runs.
13
- */
14
-
15
- import { centroid, cosineDistance, medoidIndex } from "./embedder.js";
16
- import type { Hash } from "./types.js";
17
-
18
- export interface Embedded {
19
- readonly hash: Hash;
20
- readonly vector: readonly number[];
21
- }
22
-
23
- export interface EvidenceCluster {
24
- /** Evidence hashes in the cluster, in stable order. */
25
- readonly members: Hash[];
26
- /** The medoid evidence hash — the value's verbatim label. */
27
- readonly medoid: Hash;
28
- /** Cluster centroid, for downstream distance comparisons. */
29
- readonly centroid: number[];
30
- }
31
-
32
- interface MutableCluster {
33
- members: Hash[];
34
- vectors: number[][];
35
- centroid: number[];
36
- }
37
-
38
- /**
39
- * Cluster embedded evidence into emergent groups. `threshold` is the maximum
40
- * cosine distance for an item to join a cluster (smaller = tighter, more
41
- * clusters). Processing order is stabilized by hash so results are deterministic.
42
- */
43
- export function clusterEvidence(
44
- items: readonly Embedded[],
45
- threshold: number,
46
- ): EvidenceCluster[] {
47
- const sorted = [...items].sort((a, b) => a.hash.localeCompare(b.hash));
48
- const clusters: MutableCluster[] = [];
49
-
50
- for (const item of sorted) {
51
- let nearest = -1;
52
- let nearestDist = Infinity;
53
- for (let c = 0; c < clusters.length; c++) {
54
- const d = cosineDistance(item.vector, clusters[c]!.centroid);
55
- if (d < nearestDist) {
56
- nearestDist = d;
57
- nearest = c;
58
- }
59
- }
60
-
61
- if (nearest >= 0 && nearestDist <= threshold) {
62
- const cl = clusters[nearest]!;
63
- cl.members.push(item.hash);
64
- cl.vectors.push([...item.vector]);
65
- cl.centroid = centroid(cl.vectors);
66
- } else {
67
- clusters.push({
68
- members: [item.hash],
69
- vectors: [[...item.vector]],
70
- centroid: [...item.vector],
71
- });
72
- }
73
- }
74
-
75
- return clusters.map((cl) => {
76
- const mi = medoidIndex(cl.vectors);
77
- return {
78
- members: cl.members,
79
- medoid: cl.members[mi]!,
80
- centroid: cl.centroid,
81
- };
82
- });
83
- }
@@ -1,207 +0,0 @@
1
- /**
2
- * Soul Kernel — the compiler. Maps structured signals to arithmetic updates.
3
- *
4
- * This is the "writing the self" process, and it contains no model call. Each
5
- * signal routes to the pure update rules in salience.ts:
6
- *
7
- * reaction / engagement → reinforce or penalize the active values + Hebbian
8
- * co-activation of the set that fired together.
9
- * correction → store the verbatim text as evidence, append a Spine
10
- * event (corrections are formative), penalize whatever
11
- * values were live when it landed.
12
- * directive → store the verbatim instruction as evidence for later
13
- * clustering into a value (embedder phase).
14
- * reflex-fire (block) → record the near-miss in the Spine.
15
- * activation → co-activate the live set; a faint reinforcement.
16
- *
17
- * Evidence is always verbatim ground truth; the compiler never paraphrases.
18
- */
19
-
20
- import { SoulDag } from "./dag.js";
21
- import { coactivate, reinforce } from "./salience.js";
22
- import { reinforceFsrs } from "./forgetting.js";
23
- import { emojiValence } from "./signals.js";
24
- import type { CorrectionSignal, DirectiveSignal, Signal } from "./signals.js";
25
- import type { EvidencePayload, Hash, SoulConfig } from "./types.js";
26
- import { halfLifeForKind } from "./types.js";
27
-
28
- export interface IngestResult {
29
- /** Evidence node created from a correction/directive, if any. */
30
- readonly evidenceAdded?: Hash;
31
- /** Spine event appended, if any. */
32
- readonly spineAdded?: Hash;
33
- /** Nodes whose state was touched. */
34
- readonly touched: readonly Hash[];
35
- }
36
-
37
- /** Find the most recent spine node to chain a new event onto. */
38
- function latestSpine(dag: SoulDag): Hash | undefined {
39
- let best: Hash | undefined;
40
- let bestAt = -Infinity;
41
- for (const node of dag.nodesOfKind("spine")) {
42
- if (node.payload.kind === "spine" && node.payload.at > bestAt) {
43
- bestAt = node.payload.at;
44
- best = node.hash;
45
- }
46
- }
47
- return best;
48
- }
49
-
50
- /** Append a developmental-narrative event, chained to the prior spine node. */
51
- export function appendSpine(
52
- dag: SoulDag,
53
- event: string,
54
- at: number,
55
- affects: readonly Hash[] = [],
56
- ): Hash {
57
- return dag.addNode({
58
- kind: "spine",
59
- event,
60
- at,
61
- affects: [...affects],
62
- prev: latestSpine(dag),
63
- });
64
- }
65
-
66
- function addEvidence(
67
- dag: SoulDag,
68
- text: string,
69
- at: number,
70
- origin: EvidencePayload["source"]["origin"],
71
- actor?: string,
72
- ref?: string,
73
- ): Hash {
74
- return dag.addNode({
75
- kind: "evidence",
76
- text,
77
- observedAt: at,
78
- source: { origin, ...(actor ? { actor } : {}), ...(ref ? { ref } : {}) },
79
- });
80
- }
81
-
82
- function reinforceNode(
83
- dag: SoulDag,
84
- hash: Hash,
85
- cfg: SoulConfig,
86
- amount: number,
87
- valence: number,
88
- at: number,
89
- ): void {
90
- const kind = dag.getNode(hash)?.payload.kind;
91
- if (cfg.adaptiveForgetting) {
92
- reinforceFsrs(dag.stateOf(hash), {
93
- now: at,
94
- cfg,
95
- amount,
96
- valence,
97
- ...(kind !== undefined ? { kind } : {}),
98
- });
99
- dag.touch(hash);
100
- return;
101
- }
102
- reinforce(dag, hash, {
103
- now: at,
104
- halfLifeMs: halfLifeForKind(cfg, kind),
105
- amount,
106
- valence,
107
- });
108
- }
109
-
110
- function ingestOutcome(
111
- dag: SoulDag,
112
- nodes: readonly Hash[],
113
- valence: number,
114
- cfg: SoulConfig,
115
- at: number,
116
- ): Hash[] {
117
- const present = nodes.filter((h) => dag.hasNode(h));
118
- for (const h of present) {
119
- reinforceNode(dag, h, cfg, cfg.reinforce, valence, at);
120
- }
121
- if (present.length > 1) {
122
- coactivate(dag, present, { now: at, increment: cfg.hebbIncrement });
123
- }
124
- return present;
125
- }
126
-
127
- function ingestCorrection(
128
- dag: SoulDag,
129
- sig: CorrectionSignal,
130
- cfg: SoulConfig,
131
- ): IngestResult {
132
- const evidence = addEvidence(
133
- dag,
134
- sig.text,
135
- sig.at,
136
- "correction",
137
- sig.actor,
138
- sig.ref,
139
- );
140
- const spine = appendSpine(dag, `Correction: ${sig.text}`, sig.at, [evidence]);
141
- // Penalize values that were live when the correction landed.
142
- const penalized = ingestOutcome(dag, sig.activeNodes ?? [], -2, cfg, sig.at);
143
- return { evidenceAdded: evidence, spineAdded: spine, touched: penalized };
144
- }
145
-
146
- function ingestDirective(dag: SoulDag, sig: DirectiveSignal): IngestResult {
147
- const evidence = addEvidence(
148
- dag,
149
- sig.text,
150
- sig.at,
151
- "directive",
152
- sig.actor,
153
- sig.ref,
154
- );
155
- return { evidenceAdded: evidence, touched: [] };
156
- }
157
-
158
- /** Apply one signal to the kernel. Pure arithmetic + verbatim evidence.
159
- *
160
- * `valenceOf` resolves a cue's valence; pass a learned ValenceModel.valence to
161
- * let meaning come from data, or omit to use the static emoji prior. */
162
- export function ingest(
163
- dag: SoulDag,
164
- signal: Signal,
165
- cfg: SoulConfig,
166
- valenceOf: (cue: string) => number = emojiValence,
167
- ): IngestResult {
168
- switch (signal.kind) {
169
- case "reaction": {
170
- const v = valenceOf(signal.emoji);
171
- const touched = ingestOutcome(dag, signal.activeNodes, v, cfg, signal.at);
172
- return { touched };
173
- }
174
- case "engagement": {
175
- const v = signal.continued ? 1 : -1;
176
- const touched = ingestOutcome(dag, signal.activeNodes, v, cfg, signal.at);
177
- return { touched };
178
- }
179
- case "correction":
180
- return ingestCorrection(dag, signal, cfg);
181
- case "directive":
182
- return ingestDirective(dag, signal);
183
- case "reflex-fire": {
184
- if (signal.severity !== "block") return { touched: [] };
185
- const spine = appendSpine(
186
- dag,
187
- `Reflex blocked a misstep: ${signal.name}`,
188
- signal.at,
189
- );
190
- return { spineAdded: spine, touched: [] };
191
- }
192
- case "activation": {
193
- const touched = ingestOutcome(dag, signal.activeNodes, 0, cfg, signal.at);
194
- return { touched };
195
- }
196
- }
197
- }
198
-
199
- /** Apply a batch of signals in order. */
200
- export function ingestAll(
201
- dag: SoulDag,
202
- signals: readonly Signal[],
203
- cfg: SoulConfig,
204
- valenceOf: (cue: string) => number = emojiValence,
205
- ): IngestResult[] {
206
- return signals.map((s) => ingest(dag, s, cfg, valenceOf));
207
- }