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.
- package/README.md +3 -3
- package/package.json +2 -1
- package/prompts/README.md +2 -2
- package/prompts/system/memory-recall.md +16 -0
- package/src/app.ts +22 -7
- package/src/backend/claude-sdk/factory.ts +21 -41
- package/src/backend/claude-sdk/handler.ts +28 -7
- package/src/backend/claude-sdk/host/in-process.ts +147 -0
- package/src/backend/claude-sdk/one-shot.ts +1 -1
- package/src/backend/claude-sdk/options.ts +7 -6
- package/src/backend/claude-sdk/stream.ts +30 -3
- package/src/backend/claude-sdk/warm.ts +1 -1
- package/src/backend/codex/constants.ts +1 -1
- package/src/backend/codex/factory.ts +2 -2
- package/src/backend/codex/handler/events.ts +1 -1
- package/src/backend/codex/handler/message.ts +26 -12
- package/src/backend/codex/handler/rollout-accounting.ts +1 -1
- package/src/backend/codex/init.ts +1 -1
- package/src/backend/codex/mcp-config.ts +2 -2
- package/src/backend/codex/one-shot.ts +1 -1
- package/src/backend/kilo/handler/message.ts +4 -1
- package/src/backend/openai-agents/constants.ts +1 -1
- package/src/backend/openai-agents/factory.ts +2 -2
- package/src/backend/openai-agents/handler/events.ts +1 -1
- package/src/backend/openai-agents/handler/message.ts +8 -4
- package/src/backend/openai-agents/init.ts +1 -1
- package/src/backend/openai-agents/mcp-pool.ts +2 -2
- package/src/backend/opencode/handler/message.ts +4 -1
- package/src/backend/remote-server/chat-turn.ts +31 -23
- package/src/backend/remote-server/events.ts +3 -3
- package/src/backend/remote-server/factory.ts +6 -3
- package/src/backend/remote-server/index.ts +1 -1
- package/src/backend/remote-server/mcp.ts +1 -1
- package/src/backend/remote-server/one-shot.ts +1 -1
- package/src/backend/remote-server/server-bindings.ts +1 -1
- package/src/backend/remote-server/turn.ts +1 -1
- package/src/backend/runtime/cache/cache-metrics.ts +126 -0
- package/src/backend/{shared → runtime/cache}/cache-telemetry.ts +22 -2
- package/src/backend/{shared → runtime}/index.ts +34 -25
- package/src/backend/{shared → runtime/prompt}/delivery-contract.ts +1 -1
- package/src/backend/{shared → runtime/prompt}/prompt-format.ts +46 -2
- package/src/backend/{shared → runtime/prompt}/system-prompt.ts +4 -4
- package/src/backend/{shared → runtime/turn}/delivered-text.ts +1 -1
- package/src/backend/{shared → runtime/turn}/delivery.ts +3 -3
- package/src/backend/{shared → runtime/turn}/handle-retry.ts +5 -5
- package/src/backend/{shared → runtime/turn}/handler-to-events.ts +24 -10
- package/src/backend/{shared → runtime/turn}/handler-types.ts +7 -1
- package/src/backend/{shared → runtime/turn}/model-retry.ts +2 -2
- package/src/backend/{shared → runtime/turn}/result-events.ts +2 -2
- package/src/backend/{shared → runtime/turn}/stream-state.ts +2 -2
- package/src/backend/{shared → runtime/turn}/turn-interrupt.ts +2 -2
- package/src/backend/{shared → runtime/turn}/turn-phases.ts +6 -6
- package/src/bootstrap.ts +6 -21
- package/src/cli.ts +6 -3
- package/src/core/agent-runtime/README.md +15 -0
- package/src/core/agent-runtime/agent-host.ts +387 -0
- package/src/core/agent-runtime/capabilities.ts +11 -0
- package/src/core/agent-runtime/contract-tests.ts +92 -1
- package/src/core/agent-runtime/events.ts +1 -1
- package/src/core/background/{isolated-agent.ts → cron/isolated-agent.ts} +3 -3
- package/src/core/background/{job-health.ts → cron/job-health.ts} +1 -1
- package/src/core/background/{job-oneshot.ts → cron/job-oneshot.ts} +5 -5
- package/src/core/background/{job-prompt.ts → cron/job-prompt.ts} +1 -1
- package/src/core/background/{cron.ts → cron/scheduler.ts} +6 -6
- package/src/core/background/{cron-spec.ts → cron/spec.ts} +1 -1
- package/src/core/background/{dream.ts → dream/index.ts} +10 -15
- package/src/core/background/{plan-alerts.ts → pulse/plan-alerts.ts} +3 -3
- package/src/core/background/{pulse.ts → pulse/pulse.ts} +8 -5
- package/src/core/background/triggers/command.ts +2 -2
- package/src/{util → core/config}/harden.ts +1 -1
- package/src/core/config/index.ts +16 -12
- package/src/{util → core/daemon}/boot-timer.ts +15 -1
- package/src/core/daemon/pidfile.ts +1 -1
- package/src/core/daemon/resource-sampler.ts +121 -0
- package/src/{util → core/daemon}/respawn.ts +1 -1
- package/src/core/doctor/index.ts +1 -1
- package/src/core/engine/dispatcher.ts +16 -0
- package/src/core/engine/gateway-actions/cron.ts +2 -2
- package/src/core/engine/gateway-actions/fetch-url.ts +1 -1
- package/src/core/engine/gateway-actions/index.ts +4 -1
- package/src/core/engine/gateway-actions/memory.ts +335 -0
- package/src/core/engine/gateway-actions/native/exec-background.ts +129 -0
- package/src/core/engine/gateway-actions/native/exec-remote.ts +85 -0
- package/src/core/engine/gateway-actions/native/exec.ts +182 -0
- package/src/core/engine/gateway-actions/native/index.ts +46 -0
- package/src/core/engine/gateway-actions/native/params.ts +46 -0
- package/src/core/engine/gateway-actions/native/read.ts +182 -0
- package/src/core/engine/gateway-actions/native/results.ts +34 -0
- package/src/core/engine/gateway-actions/native/search.ts +212 -0
- package/src/core/engine/gateway-actions/native/shell.ts +39 -0
- package/src/core/engine/gateway-actions/native/teleport.ts +55 -0
- package/src/core/engine/gateway-actions/native/write.ts +170 -0
- package/src/core/engine/gateway.ts +0 -6
- package/src/core/frontend-runtime/builtins.ts +2 -2
- package/src/{util → core/frontend-runtime}/chat-id.ts +30 -0
- package/src/core/mcp-hub/index.ts +1 -1
- package/src/core/mcp-hub/talon-server.ts +1 -1
- package/src/core/memory/import.ts +3 -2
- package/src/core/memory/taps.ts +199 -0
- package/src/core/memory/turn-retrieval.ts +222 -0
- package/src/core/plugin/mcp.ts +1 -1
- package/src/core/prompt/assemble.ts +2 -12
- package/src/core/prompt/index.ts +2 -2
- package/src/core/prompt/invalidation.ts +1 -1
- package/src/core/{scripting/lua-runner.ts → scripts/lua.ts} +1 -1
- package/src/core/tasks/index.ts +1 -1
- package/src/core/tools/{chat.ts → chat/chat.ts} +1 -1
- package/src/core/tools/{cross-send.ts → chat/cross-send.ts} +1 -1
- package/src/core/tools/{history.ts → chat/history.ts} +2 -2
- package/src/core/tools/{media.ts → chat/media.ts} +1 -1
- package/src/core/tools/{members.ts → chat/members.ts} +2 -2
- package/src/core/tools/{messaging.ts → chat/messaging.ts} +2 -2
- package/src/core/tools/{moderation.ts → chat/moderation.ts} +2 -2
- package/src/core/tools/{stickers.ts → chat/stickers.ts} +2 -2
- package/src/core/tools/{whatsapp.ts → chat/whatsapp.ts} +1 -1
- package/src/core/tools/content/memory.ts +128 -0
- package/src/core/tools/{web.ts → content/web.ts} +1 -1
- package/src/core/tools/index.ts +21 -19
- package/src/core/tools/{admin.ts → ops/admin.ts} +1 -1
- package/src/core/tools/{bridge.ts → ops/bridge.ts} +2 -2
- package/src/core/tools/{goals.ts → ops/goals.ts} +2 -2
- package/src/core/tools/{mesh.ts → ops/mesh.ts} +1 -1
- package/src/core/tools/{models.ts → ops/models.ts} +1 -1
- package/src/core/tools/{native.ts → ops/native.ts} +1 -1
- package/src/core/tools/{scheduling.ts → ops/scheduling.ts} +1 -1
- package/src/core/tools/{scripts.ts → ops/scripts.ts} +1 -1
- package/src/core/tools/{skills.ts → ops/skills.ts} +1 -1
- package/src/core/tools/{triggers.ts → ops/triggers.ts} +1 -1
- package/src/core/tools/types.ts +1 -0
- package/src/{util → core/vfs}/workspace.ts +2 -2
- package/src/core/weaver/turn-cpu.ts +32 -0
- package/src/core/weaver/weaver.ts +36 -0
- package/src/frontend/discord/admin.ts +1 -1
- package/src/frontend/discord/callbacks/components/backend-select.ts +1 -1
- package/src/frontend/discord/callbacks/components/effort.ts +1 -1
- package/src/frontend/discord/callbacks/components/index.ts +1 -1
- package/src/frontend/discord/callbacks/components/pulse.ts +1 -1
- package/src/frontend/discord/callbacks/components/settings.ts +2 -2
- package/src/frontend/discord/callbacks/modals.ts +4 -1
- package/src/frontend/discord/commands/admin.ts +2 -36
- package/src/frontend/discord/commands/definitions.ts +0 -11
- package/src/frontend/discord/commands/info.ts +1 -1
- package/src/frontend/discord/commands/interaction.ts +1 -1
- package/src/frontend/discord/commands/router.ts +0 -3
- package/src/frontend/discord/commands/session.ts +8 -2
- package/src/frontend/discord/commands/settings.ts +2 -2
- package/src/frontend/discord/handlers/messages.ts +1 -1
- package/src/frontend/discord/handlers/state.ts +1 -1
- package/src/frontend/discord/middleware.ts +2 -26
- package/src/frontend/discord/ready.ts +1 -1
- package/src/frontend/discord/render.ts +41 -259
- package/src/frontend/discord/runtime.ts +1 -2
- package/src/frontend/native/{auth.ts → bridge/auth.ts} +2 -2
- package/src/frontend/native/{discovery.ts → bridge/discovery.ts} +3 -3
- package/src/frontend/native/{routes → bridge/routes}/chats.ts +1 -1
- package/src/frontend/native/{routes → bridge/routes}/daemon.ts +1 -1
- package/src/frontend/native/{routes → bridge/routes}/host.ts +6 -3
- package/src/frontend/native/{routes → bridge/routes}/pre-auth.ts +1 -1
- package/src/frontend/native/{server.ts → bridge/server.ts} +3 -3
- package/src/frontend/native/{tls.ts → bridge/tls.ts} +2 -2
- package/src/frontend/native/{chat-lifecycle.ts → chats/chat-lifecycle.ts} +3 -3
- package/src/frontend/native/{chat-wire.ts → chats/chat-wire.ts} +4 -4
- package/src/frontend/native/{chats.ts → chats/chats.ts} +4 -4
- package/src/frontend/native/{empty-chat-sweep.ts → chats/empty-chat-sweep.ts} +4 -4
- package/src/frontend/native/{history.ts → chats/history.ts} +7 -7
- package/src/frontend/native/{reset.ts → chats/reset.ts} +7 -7
- package/src/frontend/native/index.ts +13 -10
- package/src/frontend/native/{media.ts → media/media.ts} +3 -3
- package/src/frontend/native/runtime.ts +1 -1
- package/src/frontend/native/{control.ts → surface/control.ts} +4 -4
- package/src/frontend/native/{extensions.ts → surface/extensions.ts} +12 -9
- package/src/frontend/native/{handlers.ts → surface/handlers.ts} +19 -14
- package/src/frontend/native/{logs.ts → surface/logs.ts} +2 -2
- package/src/frontend/native/{memory.ts → surface/memory.ts} +2 -2
- package/src/frontend/native/{models.ts → surface/models.ts} +17 -10
- package/src/frontend/native/{settings.ts → surface/settings.ts} +9 -9
- package/src/frontend/native/{status.ts → surface/status.ts} +3 -3
- package/src/frontend/native/{actions.ts → turn/actions.ts} +7 -4
- package/src/frontend/native/{context.ts → turn/context.ts} +8 -8
- package/src/frontend/native/{emit.ts → turn/emit.ts} +7 -7
- package/src/frontend/native/{queue.ts → turn/queue.ts} +3 -3
- package/src/frontend/native/{turn-meta.ts → turn/turn-meta.ts} +2 -2
- package/src/frontend/native/{turn.ts → turn/turn.ts} +9 -9
- package/src/frontend/{shared → presentation}/format.ts +4 -3
- package/src/frontend/{shared → presentation}/model-commands.ts +1 -1
- package/src/frontend/{shared → presentation}/reasoning-levels.ts +12 -0
- package/src/frontend/presentation/reports.ts +493 -0
- package/src/frontend/{shared → presentation}/session-status.ts +36 -9
- package/src/frontend/{shared → presentation}/status-context.ts +101 -2
- package/src/frontend/teams/commands.ts +2 -2
- package/src/frontend/teams/turn.ts +1 -1
- package/src/frontend/telegram/admin/background.ts +1 -1
- package/src/frontend/telegram/admin/health.ts +1 -1
- package/src/frontend/telegram/admin/sessions.ts +1 -1
- package/src/frontend/telegram/callbacks/effort.ts +2 -2
- package/src/frontend/telegram/callbacks/metrics.ts +1 -1
- package/src/frontend/telegram/callbacks/model/backend.ts +1 -1
- package/src/frontend/telegram/callbacks/model/views.ts +1 -1
- package/src/frontend/telegram/callbacks/pulse.ts +1 -1
- package/src/frontend/telegram/callbacks/query.ts +1 -1
- package/src/frontend/telegram/callbacks/settings.ts +3 -3
- package/src/frontend/telegram/commands/admin.ts +6 -41
- package/src/frontend/telegram/commands/index.ts +1 -1
- package/src/frontend/telegram/commands/info.ts +2 -2
- package/src/frontend/telegram/commands/session.ts +9 -3
- package/src/frontend/telegram/commands/settings.ts +5 -3
- package/src/frontend/telegram/handlers/messages.ts +0 -10
- package/src/frontend/telegram/handlers/state.ts +1 -1
- package/src/frontend/telegram/index.ts +1 -5
- package/src/frontend/telegram/middleware.ts +1 -15
- package/src/frontend/telegram/model-menu.ts +1 -1
- package/src/frontend/telegram/render/html.ts +30 -0
- package/src/frontend/telegram/{helpers → render}/menu.ts +46 -19
- package/src/frontend/telegram/render/reports.ts +182 -0
- package/src/frontend/terminal/builtins/context.ts +2 -2
- package/src/frontend/terminal/builtins/session.ts +1 -1
- package/src/frontend/terminal/builtins/status.ts +2 -2
- package/src/frontend/terminal/index.ts +2 -2
- package/src/frontend/terminal/renderer.ts +1 -1
- package/src/frontend/whatsapp/access.ts +2 -2
- package/src/frontend/whatsapp/actions/history.ts +2 -2
- package/src/frontend/whatsapp/actions/messaging.ts +2 -2
- package/src/frontend/whatsapp/actions/moderation.ts +1 -1
- package/src/frontend/whatsapp/actions/send.ts +1 -1
- package/src/frontend/whatsapp/commands.ts +12 -6
- package/src/frontend/whatsapp/{connection.ts → connection/connection.ts} +5 -5
- package/src/frontend/whatsapp/{pairing-service.ts → connection/pairing-service.ts} +3 -3
- package/src/frontend/whatsapp/{wa-logger.ts → connection/wa-logger.ts} +2 -2
- package/src/frontend/whatsapp/index.ts +4 -4
- package/src/frontend/whatsapp/{inbound.ts → messages/inbound.ts} +15 -15
- package/src/frontend/whatsapp/{media-store.ts → messages/media-store.ts} +4 -4
- package/src/frontend/whatsapp/{message-store.ts → messages/message-store.ts} +1 -1
- package/src/frontend/whatsapp/{turn-recovery.ts → messages/turn-recovery.ts} +4 -4
- package/src/frontend/whatsapp/registry.ts +2 -2
- package/src/frontend/whatsapp/runtime.ts +1 -1
- package/src/index.ts +6 -3
- package/src/storage/db.ts +6 -1
- package/src/storage/memory.ts +59 -8
- package/src/storage/metrics.ts +38 -0
- package/src/storage/repositories/sessions-repo.ts +6 -0
- package/src/storage/session-record.ts +13 -2
- package/src/storage/sessions.ts +12 -0
- package/src/storage/sql/db.sql +5 -0
- package/src/storage/sql/schema.sql +4 -0
- package/src/storage/sql/sessions.sql +3 -3
- package/src/storage/sql/statements.generated.ts +10 -3
- package/src/storage/sql/turn-meta.sql +1 -1
- package/src/util/log.ts +1 -1
- package/src/util/paths.ts +0 -2
- package/src/util/runtime.ts +1 -1
- package/src/core/engine/gateway-actions/native.ts +0 -1035
- package/src/core/soul/README.md +0 -110
- package/src/core/soul/RESEARCH.md +0 -98
- package/src/core/soul/associative.ts +0 -98
- package/src/core/soul/centrality.ts +0 -98
- package/src/core/soul/cluster.ts +0 -83
- package/src/core/soul/compiler.ts +0 -207
- package/src/core/soul/consolidate.ts +0 -179
- package/src/core/soul/critic.ts +0 -162
- package/src/core/soul/dag.ts +0 -265
- package/src/core/soul/delta.ts +0 -123
- package/src/core/soul/drift.ts +0 -99
- package/src/core/soul/embedder.ts +0 -129
- package/src/core/soul/emergent-critic.ts +0 -96
- package/src/core/soul/forgetting.ts +0 -131
- package/src/core/soul/governance.ts +0 -93
- package/src/core/soul/hash.ts +0 -97
- package/src/core/soul/hdc.ts +0 -154
- package/src/core/soul/kernel.ts +0 -540
- package/src/core/soul/lattice.ts +0 -103
- package/src/core/soul/lens.ts +0 -110
- package/src/core/soul/projector.ts +0 -240
- package/src/core/soul/reflect.ts +0 -170
- package/src/core/soul/reflex.ts +0 -164
- package/src/core/soul/retrieve.ts +0 -146
- package/src/core/soul/salience.ts +0 -146
- package/src/core/soul/service.ts +0 -204
- package/src/core/soul/settings.ts +0 -47
- package/src/core/soul/signals.ts +0 -117
- package/src/core/soul/talon-embedder.ts +0 -80
- package/src/core/soul/taps.ts +0 -199
- package/src/core/soul/types.ts +0 -298
- package/src/core/soul/valence.ts +0 -83
- package/src/frontend/telegram/helpers/diagnostics.ts +0 -428
- package/src/frontend/telegram/helpers/format.ts +0 -42
- package/src/frontend/telegram/helpers/index.ts +0 -13
- package/src/util/cleanup-registry.ts +0 -36
- /package/src/backend/{shared → runtime}/frontends.ts +0 -0
- /package/src/backend/{shared → runtime}/metrics.ts +0 -0
- /package/src/backend/{shared → runtime}/sleep.ts +0 -0
- /package/src/backend/{shared → runtime/turn}/flow-violation.ts +0 -0
- /package/src/backend/{shared → runtime}/usage.ts +0 -0
- /package/src/{util/mcp-launcher.ts → core/mcp-hub/launcher.ts} +0 -0
- /package/src/{util → core/tools/content}/web-content.ts +0 -0
- /package/src/core/tools/{mcp-env.ts → ops/mcp-env.ts} +0 -0
- /package/src/{util → core/weaver}/session-name.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/index.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/memory.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/mesh.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/models.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/params.ts +0 -0
- /package/src/frontend/native/{routes → bridge/routes}/table.ts +0 -0
- /package/src/frontend/native/{tool-result.ts → turn/tool-result.ts} +0 -0
- /package/src/frontend/{shared → presentation}/access.ts +0 -0
- /package/src/frontend/{shared → presentation}/plan-usage-report.ts +0 -0
- /package/src/frontend/whatsapp/{auth-state.ts → connection/auth-state.ts} +0 -0
- /package/src/frontend/whatsapp/{identity.ts → connection/identity.ts} +0 -0
- /package/src/frontend/whatsapp/{pairing-lock.ts → connection/pairing-lock.ts} +0 -0
- /package/src/frontend/whatsapp/{pairing.ts → connection/pairing.ts} +0 -0
- /package/src/frontend/whatsapp/{pins.ts → messages/pins.ts} +0 -0
package/src/core/soul/README.md
DELETED
|
@@ -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
|
-
}
|
package/src/core/soul/cluster.ts
DELETED
|
@@ -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
|
-
}
|