@mindot/will 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -22
- package/dist/channels/discord.d.ts +1 -1
- package/dist/channels/whatsapp.d.ts +1 -1
- package/dist/cli.js +10823 -10454
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +562 -226
- package/dist/index.js.map +1 -1
- package/dist/mcp/effectors.d.ts +1 -1
- package/dist/{will-DAW0l-lY.d.ts → will-cS6k4uiJ.d.ts} +470 -84
- package/package.json +1 -1
- package/src/cognition/agency/engines/action.selector.ts +2 -1
- package/src/cognition/agency/engines/reafference.engine.ts +12 -2
- package/src/cognition/agency/reconcile.learning.ts +16 -2
- package/src/cognition/agency/schemas/repertoire.ts +12 -5
- package/src/cognition/config.mirror.entities.ts +1 -1
- package/src/cognition/faculties/executive.engine/engine.ts +136 -58
- package/src/cognition/faculties/executive.engine/facet.ts +10 -2
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +2 -1
- package/src/cognition/index.ts +4 -0
- package/src/cognition/memory/vector.embedder.ts +9 -5
- package/src/cognition/utilities/token.tracker.ts +191 -96
- package/src/host/boot.ts +78 -22
- package/src/index.ts +35 -0
- package/src/llm/index.ts +397 -96
- package/src/llm/routing.ts +198 -0
- package/src/llm/summarizer.ts +5 -1
- package/src/runners/thin-shim.runner.ts +18 -6
- package/src/sdk/will.ts +82 -16
- package/src/stem/guards/identity.coherence.ts +17 -6
- package/src/stem/index.ts +3 -3
- package/src/stem/mind.ts +155 -24
- package/src/stem/policy/arbiter.ts +49 -14
- package/src/stem/policy/rule.table.ts +2 -2
- package/src/stem/tracts/effector.controller.ts +56 -9
package/README.md
CHANGED
|
@@ -74,8 +74,10 @@ ANTHROPIC_API_KEY=sk-ant-… \
|
|
|
74
74
|
bun run examples/with-anthropic.ts # a real executive: genuine reasoning + replies
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
Requires [Bun](https://bun.sh) ≥ 1.1. For a real executive set
|
|
78
|
-
|
|
77
|
+
Requires [Bun](https://bun.sh) ≥ 1.1. For a real executive set a provider, a model and a
|
|
78
|
+
key — `WILL_LLM_PROVIDER=anthropic` + `WILL_LLM_MODEL=claude-sonnet-4-5-20250929` +
|
|
79
|
+
`ANTHROPIC_API_KEY`. All three are required and none is guessed: [a dozen providers are
|
|
80
|
+
first-class](#llm-provider), and a default here would send your key to the wrong one. The dev
|
|
79
81
|
runner (`bun dev`) starts a long-lived Will: engines step every `WILL_TICK_MS` on the
|
|
80
82
|
deterministic clock; the ExecutiveEngine fires an LLM call every `WILL_EXECUTIVE_INTERVAL`
|
|
81
83
|
ticks — or earlier when physiology demands it.
|
|
@@ -107,7 +109,9 @@ import { Will } from '@mindot/will'
|
|
|
107
109
|
const will = await Will.create({
|
|
108
110
|
name: 'Aria',
|
|
109
111
|
identity: { prompt: 'I am Aria, a calm, precise research assistant.' },
|
|
110
|
-
//
|
|
112
|
+
// Keyless by default: a deterministic mock executive. Set any provider's own
|
|
113
|
+
// key (ANTHROPIC_API_KEY, ZAI_API_KEY, MOONSHOT_API_KEY, …) plus
|
|
114
|
+
// WILL_LLM_MODEL to raise a live mind — or pass `llmConfig` explicitly.
|
|
111
115
|
})
|
|
112
116
|
|
|
113
117
|
// Hear the Will (replies arrive asynchronously — it reasons on its own tick cycle).
|
|
@@ -160,7 +164,7 @@ Host a Will over the [Model Context Protocol](https://modelcontextprotocol.io)
|
|
|
160
164
|
}
|
|
161
165
|
```
|
|
162
166
|
|
|
163
|
-
The surface keeps the paradigm: `perceive` delivers a stimulus (it returns when *delivered*, not answered), `next_utterance` awaits the mind's next words (**silence is a valid outcome**, reported — never an error), `state` reads its inner life, and `save` checkpoints it without stopping it. There is deliberately no `ask()`-shaped tool. Config via env: `WILL_ANATOMY` (mind|reflex — reflex is the no-LLM shell), `WILL_LLM_MODEL` (concrete model id), `WILL_LLM` (mock
|
|
167
|
+
The surface keeps the paradigm: `perceive` delivers a stimulus (it returns when *delivered*, not answered), `next_utterance` awaits the mind's next words (**silence is a valid outcome**, reported — never an error), `state` reads its inner life, and `save` checkpoints it without stopping it. There is deliberately no `ask()`-shaped tool. Config via env: `WILL_ANATOMY` (mind|reflex — reflex is the no-LLM shell), `WILL_LLM_MODEL` (concrete model id — required for a live mind), `WILL_LLM` (`mock` or [any provider name](#llm-provider) — defaults to the zero-key mock unless some provider's own key is set), `WILL_TICK_MS`, `WILL_PMA_PATH`.
|
|
164
168
|
|
|
165
169
|
### Employing MCP tools — the mind gets abilities
|
|
166
170
|
|
|
@@ -220,7 +224,9 @@ const config: WillConfig = {
|
|
|
220
224
|
traits: { conscientiousness: 0.9, neuroticism: 0.4 },
|
|
221
225
|
style: 'measured and warm',
|
|
222
226
|
},
|
|
223
|
-
|
|
227
|
+
// Provider + model ride together on `llm`. Both are required for a live mind
|
|
228
|
+
// and neither is guessed; omit the whole field for the zero-key mock.
|
|
229
|
+
llm: { provider: 'anthropic', model: 'claude-sonnet-4-5-20250929' },
|
|
224
230
|
allowedGenericEffectors: ['listen', 'talk', 'text'], // opt in to communication
|
|
225
231
|
persistentMemory: true,
|
|
226
232
|
snapshotInterval: 10,
|
|
@@ -555,7 +561,11 @@ Traits seed the PersonaPrior as a *starting disposition*, not a fixed personalit
|
|
|
555
561
|
| `name` | ✅ | — | Human-readable display name |
|
|
556
562
|
| `identity` | ✅ | — | Persona: `{ prompt, values[], traits{}, style }` (Layer 2) |
|
|
557
563
|
| `anatomy` | — | `'mind'` | `'mind' \| 'reflex'` — the only structural variant. `mind` runs the whole architecture; `reflex` is a no-LLM shell (regulatory + senses + agency heuristics) for embedded use. Faculties are not a pricing axis — budgets are. |
|
|
558
|
-
| `
|
|
564
|
+
| `llm.provider` | ✅ *(live)* | — | Which provider to speak to. No default: see [LLM provider](#llm-provider). `WILL_LLM_PROVIDER` env fills in |
|
|
565
|
+
| `llm.model` | ✅ *(live)* | — | A concrete model id (`'claude-sonnet-4-5-20250929'`), **or** a per-role map `{ executive, summarizer, deliberation, conversation, embedding }`. Unset roles fall back to `executive`. `WILL_LLM_MODEL` pins every thinking role. Product tier labels resolve to a concrete id host-side, before the engine |
|
|
566
|
+
| `llm.apiKey` / `llm.baseUrl` | — | env | Credential + endpoint for the default provider. Held in memory only — never state, logs, or PMA |
|
|
567
|
+
| `llm.providers` | — | — | Everything the host knows per provider: `{ apiKey, baseUrl?, wire?, prices? }`. Needed to route *across* vendors, and the only place prices live — the engine ships none |
|
|
568
|
+
| `llm.router` | — | `NULL_ROUTER` | A `ModelRouter` choosing a model per call from the call's attribution and `demand`. Chains ahead of the compiled role map. See [Different models for different thinking](#different-models-for-different-thinking) |
|
|
559
569
|
| `persistentMemory` | ✅ | — | Persist snapshots so beliefs/goals/narrative survive restarts |
|
|
560
570
|
| `snapshotInterval` | ✅ | — | Ticks between in-memory snapshots |
|
|
561
571
|
| `profile` | — | `null` | World profile preset (effectors + environment context). Merged with `allowedGenericEffectors` |
|
|
@@ -741,15 +751,22 @@ src/
|
|
|
741
751
|
│ │ └── access.grants.ts · proactive.communicator.ts
|
|
742
752
|
│ └── memory/ # in-house vector index + embedder (semantic recall)
|
|
743
753
|
│
|
|
744
|
-
├── llm/ # in-house provider client
|
|
754
|
+
├── llm/ # in-house multi-provider client — no ai-sdk/Mastra runtime dep
|
|
755
|
+
│ ├── index.ts # wire dialects (anthropic·openai·google), provider table, director
|
|
756
|
+
│ ├── routing.ts # which model serves which call — ModelRouter, TableRouter, chainRouters
|
|
757
|
+
│ ├── gate.ts # global concurrency semaphore + 429 backoff
|
|
758
|
+
│ └── summarizer.ts · wire.contracts.ts
|
|
745
759
|
├── pma/ # PMADistiller, PMALoader + reconstruction-fidelity eval
|
|
746
760
|
├── profiles/ # world profile presets (companion, game-npc, customer-service, …)
|
|
747
761
|
├── eval/ · extensions/ · runners/
|
|
748
762
|
├── types.ts # public API types (OutboxMessage, EffectorInvocation, …)
|
|
749
763
|
│
|
|
750
764
|
└── stem/
|
|
751
|
-
├── mind.ts # assembleMind() — engine graph factory
|
|
765
|
+
├── mind.ts # assembleMind() — engine graph factory; compiles the role
|
|
766
|
+
│ # model map into routing rules
|
|
752
767
|
├── index.ts # WillStem — lifecycle, tick loop, outbox, acks
|
|
768
|
+
├── policy/ # what a Will MAY enact — arbiter seam, rule table, verdict tape
|
|
769
|
+
├── guards/ # identity coherence — the self a drifting output is checked against
|
|
753
770
|
└── tracts/ # lifecycle controllers: outbox, effector, sensory, transport,
|
|
754
771
|
# replay, pma, health, biography, ack, session log
|
|
755
772
|
```
|
|
@@ -779,17 +796,16 @@ cd will && bun run build
|
|
|
779
796
|
|
|
780
797
|
| Variable | Default | Description |
|
|
781
798
|
|---|---|---|
|
|
782
|
-
| `WILL_LLM_PROVIDER` |
|
|
783
|
-
| `WILL_LLM_MODEL` |
|
|
784
|
-
| `WILL_LLM_API_KEY` | — |
|
|
785
|
-
| `ZAI_API_KEY` | — |
|
|
799
|
+
| `WILL_LLM_PROVIDER` | **required** | Which provider to speak to — see [the table below](#llm-provider). No default: a guess here sends your key to the wrong vendor |
|
|
800
|
+
| `WILL_LLM_MODEL` | **required** | Concrete model id (`claude-sonnet-4-5-20250929` / `glm-5.2`). No default — pins *every* thinking role, so set it only for single-model deployments |
|
|
801
|
+
| `WILL_LLM_API_KEY` | — | Provider-agnostic key. Wins over the provider's own env var below. Setting it without `WILL_LLM_PROVIDER` is an error, not a guess |
|
|
802
|
+
| `ANTHROPIC_API_KEY` · `ZAI_API_KEY` · `OPENAI_API_KEY` · … | — | The provider's own key. Its presence alone selects that provider. Only ever read for the provider it belongs to |
|
|
786
803
|
| `WILL_LLM_BASE_URL` | *(provider default)* | Override the provider API base URL (e.g. a self-hosted GLM at `http://localhost:8000/anthropic`). Falls back to `OPENAI_BASE_URL` |
|
|
787
804
|
| `WILL_LLM_TIMEOUT_MS` | `90000` | LLM timeout. On the Anthropic-wire providers (`anthropic`, `glm` — both streaming) this is a *first-byte*/TTFT deadline — long completions aren't aborted mid-generation |
|
|
788
805
|
| `WILL_LLM_CONCURRENCY` | `3` | Max concurrent LLM calls (min 3: executive + conversation + summary) |
|
|
789
806
|
| `WILL_TICK_MS` | `1000` | Milliseconds between ticks |
|
|
790
807
|
| `WILL_MAX_TICKS` | `0` | Stop after N ticks. `0` = run forever |
|
|
791
808
|
| `WILL_LOG_INTERVAL` | `10` | Print status to console every N ticks |
|
|
792
|
-
| `WILL_MODEL_TIER` | `sonnet` | Which model the executive recruits: `haiku` · `sonnet` · `opus` |
|
|
793
809
|
| `WILL_EXECUTIVE_INTERVAL` | *(cadence preset)* | Ticks between executive (LLM) calls — responsive 30 / balanced 60 / economy 90 |
|
|
794
810
|
| `WILL_THREAD_HISTORY` | `2` | `lastMessages` for the executive conversation thread |
|
|
795
811
|
| `WILL_CONVERSATION_HISTORY` | `50` | `lastMessages` for entity conversation threads |
|
|
@@ -815,29 +831,78 @@ cd will && bun run build
|
|
|
815
831
|
|
|
816
832
|
## LLM provider
|
|
817
833
|
|
|
818
|
-
|
|
834
|
+
A provider is named, never guessed. The engine has no default vendor, no default model, and no key fallback that crosses vendors — every one of those was a way for a Will to talk to someone you did not configure.
|
|
819
835
|
|
|
820
|
-
|
|
836
|
+
What the engine branches on is the **wire** (the request dialect), not the provider. So the table below is convenience data — base URLs you would otherwise look up — and *any* provider works once it declares its own:
|
|
837
|
+
|
|
838
|
+
```ts
|
|
839
|
+
llm: {
|
|
840
|
+
provider: 'together', model: 'Qwen/Qwen3-235B',
|
|
841
|
+
providers: { together: { apiKey, wire: 'openai', baseUrl: 'https://api.together.xyz/v1' } },
|
|
842
|
+
}
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
| Provider | `WILL_LLM_PROVIDER` | Key env | Wire |
|
|
821
846
|
|---|---|---|---|
|
|
822
|
-
| Anthropic | `anthropic` | `ANTHROPIC_API_KEY` |
|
|
823
|
-
| **Z.ai — GLM** | `glm` | `ZAI_API_KEY` |
|
|
824
|
-
| OpenAI
|
|
847
|
+
| Anthropic | `anthropic` | `ANTHROPIC_API_KEY` | Anthropic — streaming, prompt cache, TTFT deadline |
|
|
848
|
+
| **Z.ai — GLM** | `glm` | `ZAI_API_KEY` | Anthropic — full path, via Z.ai's compatible endpoint |
|
|
849
|
+
| OpenAI | `openai` | `OPENAI_API_KEY` | OpenAI |
|
|
850
|
+
| Google — Gemini | `google` | `GOOGLE_API_KEY` · `GEMINI_API_KEY` | Google (native) |
|
|
851
|
+
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | OpenAI |
|
|
852
|
+
| Moonshot — Kimi | `moonshot` | `MOONSHOT_API_KEY` | OpenAI |
|
|
853
|
+
| Alibaba — Qwen | `qwen` | `DASHSCOPE_API_KEY` | OpenAI |
|
|
854
|
+
| xAI — Grok | `xai` | `XAI_API_KEY` | OpenAI |
|
|
855
|
+
| MiniMax | `minimax` | `MINIMAX_API_KEY` | OpenAI |
|
|
856
|
+
| Mistral | `mistral` | `MISTRAL_API_KEY` | OpenAI |
|
|
857
|
+
| Ollama · vLLM (local) | `ollama` · `vllm` | *(none)* | OpenAI — `localhost` defaults, override with `WILL_LLM_BASE_URL` |
|
|
858
|
+
|
|
859
|
+
The two Anthropic-wire providers get token streaming, prompt-cache breakpoints and the first-byte (TTFT) deadline; the OpenAI wire is non-streaming today. **Name your actual vendor** even when it speaks a borrowed wire — calling Kimi `openai` because it talks that dialect puts a false provider on the completion tape and in the cost breakdown.
|
|
860
|
+
|
|
861
|
+
`moonshot`, `qwen` and `minimax` also run separate mainland-China hosts. The international endpoint is the default; a key issued on the other one authenticates nowhere, so set `baseUrl` explicitly.
|
|
862
|
+
|
|
863
|
+
### Different models for different thinking
|
|
864
|
+
|
|
865
|
+
A mind does several kinds of work, and they do not all deserve the same model. Give roles their own:
|
|
866
|
+
|
|
867
|
+
```ts
|
|
868
|
+
llm: { provider: 'glm', model: { executive: 'glm-5.2', summarizer: 'glm-5' } }
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
For anything finer, supply a router — it sees what *kind* of call this is and how much the moment demands, and answers with a model:
|
|
872
|
+
|
|
873
|
+
```ts
|
|
874
|
+
import { TableRouter } from '@mindot/will'
|
|
875
|
+
|
|
876
|
+
llm: {
|
|
877
|
+
provider: 'anthropic', model: 'claude-sonnet-4-5-20250929',
|
|
878
|
+
providers: { deepseek: { apiKey: process.env.DEEPSEEK_API_KEY! } },
|
|
879
|
+
router: new TableRouter( [
|
|
880
|
+
{ category: 'summarizer', route: { model: 'claude-haiku-4-5' } },
|
|
881
|
+
{ function: 'deliberation', minDemand: 0.7, route: { model: 'claude-opus-4-1' } },
|
|
882
|
+
{ attribute: 'guard', route: { provider: 'deepseek', model: 'deepseek-v4-flash' } },
|
|
883
|
+
] ),
|
|
884
|
+
}
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
The role map is sugar for exactly this — it compiles into rules and joins your router in one chain, yours first. A router that throws, or names a provider you hold no credential for, falls back to the default model: a routing mistake never kills a running mind.
|
|
888
|
+
|
|
889
|
+
The engine carries the mechanism and none of the policy. A router sees the call's attribution and its `demand` — a *cognitive* measure of how consequential the moment is — and never who is paying or what anything costs. Prices, if you want costed telemetry, are yours to supply per provider (`providers.<name>.prices`); the engine ships none, because a price table inside an npm release is stale the week after it publishes.
|
|
825
890
|
|
|
826
891
|
### Running a mind on GLM
|
|
827
892
|
|
|
828
893
|
```bash
|
|
829
|
-
ZAI_API_KEY=… WILL_NAME=Aria npx -y @mindot/will discord
|
|
894
|
+
ZAI_API_KEY=… WILL_LLM_MODEL=glm-5.2 WILL_NAME=Aria npx -y @mindot/will discord
|
|
830
895
|
```
|
|
831
896
|
|
|
832
|
-
|
|
897
|
+
The provider auto-detects from the key present and the endpoint comes with it; the **model is yours to name** — the engine carries no default, and the CLI says so plainly rather than guessing one. Pin the 1M-context variant with `WILL_LLM_MODEL=glm-5.2[1m]`.
|
|
833
898
|
|
|
834
899
|
Why it matters for a Will specifically: a mind is **always on**. It reasons every N ticks whether or not anyone spoke, so the executive is a standing cost, not a per-request one — the arithmetic that makes a cheaper capable model matter more here than in a request/response agent. GLM-5.2 runs about **$1.40 / $4.40** per Mtok against Claude Sonnet's $3 / $15, with a 1M context.
|
|
835
900
|
|
|
836
|
-
`WILL_LLM_BASE_URL` points `glm` at any **Anthropic-compatible** endpoint — a gateway (LiteLLM, claude-code-router), or one fronting the open weights (GLM-5.2 is MIT-licensed). Note the wire, not just the model: vLLM/SGLang serve an *OpenAI*-shaped API, so a bare self-host belongs on `WILL_LLM_PROVIDER=
|
|
901
|
+
`WILL_LLM_BASE_URL` points `glm` at any **Anthropic-compatible** endpoint — a gateway (LiteLLM, claude-code-router), or one fronting the open weights (GLM-5.2 is MIT-licensed). Note the wire, not just the model: vLLM/SGLang serve an *OpenAI*-shaped API, so a bare self-host belongs on `WILL_LLM_PROVIDER=vllm` (non-streaming) until an Anthropic-compatible shim sits in front.
|
|
837
902
|
|
|
838
903
|
A Will's identity survives the swap either way: the [PMA](#pma--the-persistent-mind-artifact) carries the self across a model change, and `runPMAEval` scores how faithfully — continuity across providers is measurable, not asserted.
|
|
839
904
|
|
|
840
|
-
The provider layer is an in-house `fetch` client (`src/llm/index.ts`) with a global concurrency gate (`src/llm/gate.ts`) — no Mastra / ai-sdk runtime dependency.
|
|
905
|
+
The provider layer is an in-house `fetch` client (`src/llm/index.ts`) with a global concurrency gate (`src/llm/gate.ts`) and a per-call router (`src/llm/routing.ts`) — no Mastra / ai-sdk runtime dependency.
|
|
841
906
|
|
|
842
907
|
---
|
|
843
908
|
|