@mindot/will 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/channels/discord.d.ts +67 -6
  2. package/dist/channels/discord.js +112 -6
  3. package/dist/channels/discord.js.map +1 -1
  4. package/dist/channels/whatsapp.d.ts +1 -1
  5. package/dist/channels/whatsapp.js +4 -1
  6. package/dist/channels/whatsapp.js.map +1 -1
  7. package/dist/cli.js +3174 -867
  8. package/dist/cli.js.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +3236 -1042
  11. package/dist/index.js.map +1 -1
  12. package/dist/mcp/effectors.d.ts +1 -1
  13. package/dist/{will-cS6k4uiJ.d.ts → will-DbDj_TEH.d.ts} +752 -17
  14. package/package.json +1 -1
  15. package/src/channels/discord.ts +189 -11
  16. package/src/channels/types.ts +90 -0
  17. package/src/channels/whatsapp.ts +13 -4
  18. package/src/cli.ts +9 -4
  19. package/src/cognition/agency/consequence.ts +122 -1
  20. package/src/cognition/agency/conversation.aim.ts +260 -0
  21. package/src/cognition/agency/engines/action.selector.ts +83 -2
  22. package/src/cognition/agency/engines/affordance.synthesizer.ts +90 -1
  23. package/src/cognition/agency/engines/motor.schema.executor.ts +152 -10
  24. package/src/cognition/agency/engines/reafference.engine.ts +117 -0
  25. package/src/cognition/agency/proactive.communicator.ts +19 -3
  26. package/src/cognition/agency/restart.ts +66 -0
  27. package/src/cognition/agency/selection.scoring.ts +33 -0
  28. package/src/cognition/agency/types.ts +35 -0
  29. package/src/cognition/cache/composition.ts +232 -0
  30. package/src/cognition/cache/deliberation.cache.ts +219 -0
  31. package/src/cognition/cache/fingerprint.ts +120 -0
  32. package/src/cognition/cache/types.ts +105 -0
  33. package/src/cognition/config.mirror.entities.ts +108 -0
  34. package/src/cognition/event.schemas.ts +22 -0
  35. package/src/cognition/faculties/autobiographical.narrator.ts +5 -10
  36. package/src/cognition/faculties/episodic.consolidator.ts +59 -3
  37. package/src/cognition/faculties/executive.engine/commands.ts +189 -14
  38. package/src/cognition/faculties/executive.engine/context.ts +67 -13
  39. package/src/cognition/faculties/executive.engine/deliberate.reasoning.ts +1 -1
  40. package/src/cognition/faculties/executive.engine/engine.ts +552 -131
  41. package/src/cognition/faculties/executive.engine/escalation.buffer.ts +162 -44
  42. package/src/cognition/faculties/executive.engine/facet.supervisor.ts +310 -65
  43. package/src/cognition/faculties/executive.engine/facet.ts +81 -26
  44. package/src/cognition/faculties/executive.engine/gating.ts +14 -14
  45. package/src/cognition/faculties/executive.engine/parser.ts +21 -1
  46. package/src/cognition/faculties/executive.engine/prompt.factory.ts +167 -19
  47. package/src/cognition/faculties/executive.engine/types.ts +69 -0
  48. package/src/cognition/faculties/goal.manager.ts +94 -14
  49. package/src/cognition/faculties/known.entity.tracker.ts +267 -28
  50. package/src/cognition/faculties/moral.evaluator.ts +8 -3
  51. package/src/cognition/faculties/persona.consolidator.ts +141 -0
  52. package/src/cognition/faculties/reputation.tracker.ts +66 -2
  53. package/src/cognition/faculties/self.model.updater.ts +19 -12
  54. package/src/cognition/faculties/social.perception.ts +47 -3
  55. package/src/cognition/faculties/threat.evaluator.ts +7 -0
  56. package/src/cognition/faculties/working.memory.ts +10 -20
  57. package/src/cognition/identity.entity.ts +205 -0
  58. package/src/cognition/index.ts +7 -0
  59. package/src/cognition/memory/vector.adapter.ts +12 -3
  60. package/src/cognition/memory/vector.embedder.ts +45 -2
  61. package/src/cognition/persona.prior.ts +6 -0
  62. package/src/cognition/senses/audition.engine/engine.ts +404 -46
  63. package/src/cognition/senses/base.sense.engine.ts +1 -1
  64. package/src/cognition/senses/index.ts +12 -0
  65. package/src/cognition/social.identity.ts +273 -0
  66. package/src/cognition/utilities/token.tracker.ts +58 -5
  67. package/src/core/orchestrator.ts +38 -0
  68. package/src/llm/index.ts +25 -8
  69. package/src/llm/routing.ts +6 -0
  70. package/src/llm/summarizer.ts +1 -1
  71. package/src/llm/wire.contracts.ts +19 -0
  72. package/src/pma/index.ts +67 -53
  73. package/src/sdk/will.ts +39 -6
  74. package/src/stem/assembly.audit.ts +1 -0
  75. package/src/stem/guards/identity.coherence.ts +1 -1
  76. package/src/stem/index.ts +79 -2
  77. package/src/stem/mind.ts +172 -55
  78. package/src/stem/tracts/outbox.writer.ts +40 -2
  79. package/src/cognition/faculties/executive.engine/messages.ts +0 -102
@@ -59,6 +59,18 @@ export interface ExecutiveOutputFull {
59
59
  name?: string
60
60
  learned?: string[]
61
61
  feeling?: number
62
+ /**
63
+ * "This is the same someone as that" — another keid I now believe is this
64
+ * same referent, fusing two of my records into one.
65
+ *
66
+ * The mind's own verdict on an identity, and it may do what the recognition
67
+ * heuristic will not: absorb an ESTABLISHED relationship. The heuristic is
68
+ * right to refuse — fusing two real people who share a name would take one of
69
+ * them's whole history — but the mind has evidence a name-match does not,
70
+ * usually because somebody just told it. Without this, the same human
71
+ * well-established on two channels stayed two people permanently.
72
+ */
73
+ sameAs?: string
62
74
  }>
63
75
  newGoals?: Array<{
64
76
  description: string
@@ -70,6 +82,8 @@ export interface ExecutiveOutputFull {
70
82
  goalsToAbandon?: Array<{ goalId: string; reason: string }>
71
83
  goalsToReprioritize?: Array<{ goalId: string; newPriority: number; reason: string }>
72
84
  selfObservations?: string[]
85
+ /** Compound actions the mind is naming as single skills (see ProposedSkill). */
86
+ newSkills?: ProposedSkill[]
73
87
  /**
74
88
  * Plain-text reply from a conversation facet — populated by parseResponse()
75
89
  * from the [REPLY_TEXT]...[/REPLY_TEXT] block.
@@ -77,6 +91,11 @@ export interface ExecutiveOutputFull {
77
91
  * Paragraphs (double-newline separated) map to separate reply bubbles.
78
92
  */
79
93
  replyText?: string
94
+ /**
95
+ * Set when the facet declared it is NOT speaking this cycle, carrying why.
96
+ * Present ⇒ nothing is sent, whatever else the response contains.
97
+ */
98
+ noMessage?: string
80
99
  /**
81
100
  * @deprecated Legacy JSON reply format — no longer emitted by conversation facets.
82
101
  * Kept for backward compatibility with any tests/tooling that inspect parsed output.
@@ -287,6 +306,33 @@ export interface ExecutiveContext {
287
306
  /** planId if this action came from a plan step */
288
307
  planId?: string
289
308
  }>
309
+ /**
310
+ * What the mind has said to people lately, and who has answered.
311
+ *
312
+ * The one thing it could never see about itself. `conversation.sent` has been in
313
+ * state since the beginning — 57 records on the Will this was found on — and
314
+ * reached no prompt at all, so the sole evidence of having spoken was a `✓
315
+ * reach-out` line under Recent Action Outcomes: no words, no person, and a tick
316
+ * mark asserting it had worked. That is why the same question went out eleven
317
+ * times in two and a half minutes; from the inside each one was the first.
318
+ *
319
+ * Newest first. Answered turns are kept alongside open ones deliberately — "I
320
+ * asked and they replied" and "I asked and heard nothing" only mean anything
321
+ * against each other.
322
+ */
323
+ spokenTurns: Array<{
324
+ /** Who it was said to, by name where the mind knows one. */
325
+ target: string
326
+ /** The opening words — enough to recognise a thing already said. */
327
+ preview: string
328
+ /** Ticks since it was said. */
329
+ age: number
330
+ /** Unset while still in the air; the mind is told which. */
331
+ answered: boolean
332
+ /** What they said back, when they did. The fact of an answer without its
333
+ * content is worse than silence — it invites acting as though it is known. */
334
+ answeredWith?: string
335
+ }>
290
336
  /** Behavioral disposition loaded from PMA at session start — stable per session. */
291
337
  behavioralDisposition?: {
292
338
  riskTolerance: number
@@ -309,6 +355,10 @@ export interface ExecutiveContext {
309
355
  * Omitted when the Will knows no one.
310
356
  */
311
357
  knownEntities?: Array<{
358
+ /** Where this referent is reachable, and how each place has gone. */
359
+ handles?: Array<{ keid: string; kind: string; answeredAgo?: number }>
360
+ /** Names of referents this one may be the same as — an unsettled identity. */
361
+ mayBeSameAs?: string[]
312
362
  keid: string
313
363
  kind: 'sentient' | 'thing'
314
364
  name?: string
@@ -336,6 +386,25 @@ export interface ExecutiveContext {
336
386
 
337
387
  // ── Pending message ──────────────────────────────────────────
338
388
 
389
+ /**
390
+ * A compound action the mind names as one thing it does — "when I do A then B,
391
+ * that is <name>". Registered into the SchemaRepertoire as a composite, after
392
+ * which it competes as a single affordance and can proceduralize into a habit.
393
+ *
394
+ * This is the creation seam for the instrumental→habitual gradient. Before it,
395
+ * `agency.composite.proposed` was subscribed by ReafferenceEngine — whose handler
396
+ * is the only caller of `registerComposite()` anywhere — and published by nothing,
397
+ * so no Will could ever hold a skill beyond the innate floor (#114).
398
+ */
399
+ export interface ProposedSkill {
400
+ /** What the mind calls it. Becomes the schema id. */
401
+ id: string
402
+ /** The sub-schemas it is made of, in order. Two or more, or it is not compound. */
403
+ composedOf: string[]
404
+ tags?: string[]
405
+ cost?: number
406
+ }
407
+
339
408
  export interface PendingMessage {
340
409
  id: string
341
410
  content: string
@@ -71,6 +71,21 @@ const DRIVE_TAGS = new Set([ 'energy', 'sleep', 'stress', 'survival', 'wellbeing
71
71
  // conscientiousness-developable baseSwitchCost, #28). Recomputed fresh each tick from
72
72
  // basePriority — never accumulates. This is what makes the focus mechanically "stick":
73
73
  // the focused goal stays top for goal selection, the executive, and planning.
74
+ /**
75
+ * Schema ids and effector names that mean "the mind said something to someone".
76
+ *
77
+ * `reach-out` is the innate schema; `text`/`talk`/`gesture`/`broadcast` are the
78
+ * effectors it resolves to. Both spellings appear as an `action.outcome`'s
79
+ * `actionType` depending on which path emitted it, and only the second set was
80
+ * ever recognised here. Mirrors `COMM_SCHEMAS` in agency/execution.primitives.
81
+ */
82
+ const COMMUNICATIVE_SCHEMAS = new Set([
83
+ 'reach-out', 'reach_out', 'communicate', 'talk', 'text', 'broadcast', 'gesture',
84
+ ])
85
+
86
+ /** Progress an action goal gains when the person it concerns actually answers. */
87
+ const ANSWER_PROGRESS_STEP = 0.12
88
+
74
89
  const FOCUS_COMMITMENT_RAMP = 30 // ticks of focus to reach full commitment weight
75
90
  const COMMITMENT_GAIN = 0.3 // scales switchCost × commitment × plan-sunk-cost
76
91
  const MAX_COMMITMENT_BOOST = 0.2 // cap — a clearly higher-priority goal still wins
@@ -88,6 +103,10 @@ export interface GoalState {
88
103
  activatedAt: Tick
89
104
  deadline?: Tick
90
105
  tags: string[]
106
+ /** Why this goal was abandoned, when it was. Set only on status 'abandoned'.
107
+ * The reason used to be pushed onto `tags`, which threw once the goal had
108
+ * been rehydrated from a deep-frozen state entity. */
109
+ abandonedReason?: string
91
110
  /** Snapshot of memory.beliefs_total when this goal was activated.
92
111
  * Used to compute epistemic progress: (currentBeliefs - baseline) / threshold. */
93
112
  beliefsAtActivation: number
@@ -199,6 +218,7 @@ export class GoalManager implements SimulationEngine, CognitiveEngine {
199
218
  'executive.facet.progress',
200
219
  'plan.completed',
201
220
  'action.outcome', // 4.1: advance action-type goals when matching outcomes fire
221
+ 'social.responsiveness', // somebody answered — the only progress a message can make
202
222
  ]
203
223
  }
204
224
  publishes(): CognitiveEventSchema[] {
@@ -298,6 +318,13 @@ export class GoalManager implements SimulationEngine, CognitiveEngine {
298
318
  this._nudgeActionGoals( p.domain, p.actionType, p.outcomeQuality )
299
319
  break
300
320
  }
321
+ // A communicative act only advances a goal once somebody answers it. The
322
+ // send itself is not progress — see _nudgeActionGoals.
323
+ case 'social.responsiveness': {
324
+ const p = e.payload as { keid: string; answered: boolean }
325
+ if( p.answered === true && p.keid ) this._nudgeAnsweredGoals( p.keid )
326
+ break
327
+ }
301
328
  }
302
329
  }
303
330
 
@@ -565,8 +592,11 @@ export class GoalManager implements SimulationEngine, CognitiveEngine {
565
592
  const goal = this._goals.get( goalId )
566
593
  if( goal && goal.status === 'active'){
567
594
  goal.status = 'abandoned'
568
- // Optionally store the reason (if GoalState had a reason field; we can add it or store in tags)
569
- reason && goal.tags.push(`abandoned:${reason.slice(0,50)}`)
595
+ // On its own field, not pushed onto `tags`. A goal rehydrated from a state
596
+ // entity holds that entity's deep-frozen arrays by reference, so the push
597
+ // threw and the goal stayed active forever — still competing for salience,
598
+ // with the rest of the deferred-effects flush for that tick lost with it.
599
+ if( reason ) goal.abandonedReason = reason.slice( 0, 200 )
570
600
 
571
601
  this._sessionLogger?.write({
572
602
  type: 'goal.abandoned',
@@ -618,13 +648,18 @@ export class GoalManager implements SimulationEngine, CognitiveEngine {
618
648
  progress: ( meta.progress as number ) ?? 0,
619
649
  status,
620
650
  parentGoalId: meta.parentGoalId as string | undefined,
621
- subGoals: ( meta.subGoals as string[] ) ?? [],
651
+ // COPY, never adopt. `meta` belongs to a state entity, and the state
652
+ // manager deep-freezes those — adopting the array by reference gives the
653
+ // goal a frozen `tags`/`subGoals`, and the next push (abandonGoal, or
654
+ // addGoal appending to a parent) throws TypeError mid-tick.
655
+ subGoals: [ ...( ( meta.subGoals as string[] ) ?? [] ) ],
622
656
  activatedAt: ( meta.activatedAt as Tick ) ?? tick,
623
657
  deadline: meta.deadline as Tick | undefined,
624
- tags: ( meta.tags as string[] ) ?? [],
658
+ tags: [ ...( ( meta.tags as string[] ) ?? [] ) ],
625
659
  beliefsAtActivation: ( meta.beliefsAtActivation as number ) ?? this._currentBeliefCount,
626
660
  completionType: ( meta.completionType as GoalState['completionType'] ) ?? 'epistemic',
627
661
  completionCondition: meta.completionCondition as string | undefined,
662
+ abandonedReason: meta.abandonedReason as string | undefined,
628
663
  })
629
664
  }
630
665
  }
@@ -852,11 +887,26 @@ export class GoalManager implements SimulationEngine, CognitiveEngine {
852
887
  const dLow = domain.toLowerCase()
853
888
  const aLow = actionType.toLowerCase()
854
889
 
855
- // Communication actions 'talk' and 'text' are always treated as
856
- // matching the 'communication' and 'reply' tag families so goals created
857
- // in response to incoming messages get their progress nudged.
858
- const isCommunicationAction = aLow === 'talk' || aLow === 'text'
859
- || dLow === 'communication'
890
+ // A communicative act makes NO progress by being sent.
891
+ //
892
+ // This is the whole shape of the repetition failure, seen from the goal side.
893
+ // `action.outcome` for a message fires the moment the outbox accepts it, with
894
+ // `outcomeQuality` describing the delivery — so crediting it here would have a
895
+ // goal like "get a clear answer to one operational question" complete itself
896
+ // after nine unanswered messages, and the mind would be right to keep sending
897
+ // because sending was visibly working.
898
+ //
899
+ // The answer is progress. It arrives later, through `social.responsiveness`,
900
+ // and lands in _nudgeAnsweredGoals.
901
+ //
902
+ // (Before this the question was moot in the worst way: `actionType` for an
903
+ // outreach is the SCHEMA id, `reach-out`, and the old test looked only for
904
+ // 'talk'/'text', so no communicative act ever reached a goal at all. Measured
905
+ // on a live Will: 8 goals, 28 reach-outs, and `lastActionAttemptTick` unset on
906
+ // every single goal. The bridge was not miscalibrated, it was disconnected —
907
+ // which is why fixing the match alone would have turned a silent failure into
908
+ // a loud one.)
909
+ if( COMMUNICATIVE_SCHEMAS.has( aLow ) || dLow === 'communication') return
860
910
 
861
911
  for( const goal of this._goals.values() ){
862
912
  if( goal.status !== 'active' && goal.status !== 'blocked') continue
@@ -868,9 +918,7 @@ export class GoalManager implements SimulationEngine, CognitiveEngine {
868
918
  || t === aLow
869
919
  || dLow.includes( t ) || t.includes( dLow )
870
920
  || aLow.includes( t ) || t.includes( aLow )
871
- }) || ( isCommunicationAction && goal.tags.some( t =>
872
- t === 'communication' || t === 'reply' || t === 'conversation'
873
- ) )
921
+ })
874
922
 
875
923
  if( hasMatch ){
876
924
  goal.progress = Math.min( 1, goal.progress + outcomeQuality * 0.12 )
@@ -880,6 +928,33 @@ export class GoalManager implements SimulationEngine, CognitiveEngine {
880
928
  }
881
929
  }
882
930
 
931
+ /**
932
+ * Somebody answered. Advance the action goals that were about reaching them.
933
+ *
934
+ * Linked the way every other goal→person link in the system is linked: the
935
+ * `keid:<id>` tag (selection.scoring's `collectGoalTargets` reads the same one
936
+ * to lift a reach-out's goal relevance) or `requestingEntityId`, set when a
937
+ * conversation escalation created the goal. Nothing here guesses from wording.
938
+ *
939
+ * Unmatched by design: a goal with no link to this person gets nothing, even if
940
+ * it is tagged 'communication'. Being answered by one person is not progress on
941
+ * wanting to talk to another.
942
+ */
943
+ private _nudgeAnsweredGoals( keid: string ): void {
944
+ const tag = `keid:${ keid }`.toLowerCase()
945
+
946
+ for( const goal of this._goals.values() ){
947
+ if( goal.status !== 'active' && goal.status !== 'blocked') continue
948
+ if( goal.completionType !== 'action') continue
949
+ if( goal.requestingEntityId !== keid
950
+ && !goal.tags.some( t => t.toLowerCase() === tag ) ) continue
951
+
952
+ goal.progress = Math.min( 1, goal.progress + ANSWER_PROGRESS_STEP )
953
+ goal.lastActionAttemptTick = this._currentTick
954
+ goal.lastActionType = 'answered'
955
+ }
956
+ }
957
+
883
958
  /** True when a metric completionCondition (e.g. "emotion.boredom < 40") is already met. */
884
959
  private _isConditionMet( condition: string | undefined, state: ReadonlySimulationState ): boolean {
885
960
  if( !condition ) return false
@@ -994,9 +1069,14 @@ export class GoalManager implements SimulationEngine, CognitiveEngine {
994
1069
  progress: goal.progress,
995
1070
  status: goal.status,
996
1071
  parentGoalId: goal.parentGoalId,
997
- subGoals: goal.subGoals,
1072
+ // COPY on the way out too. The state manager deep-freezes what it
1073
+ // stores, so handing it these arrays by reference freezes the
1074
+ // manager's OWN copies — a goal created this session, never
1075
+ // rehydrated, still ends up with an unpushable `tags`.
1076
+ subGoals: [ ...goal.subGoals ],
998
1077
  deadline: goal.deadline,
999
- tags: goal.tags,
1078
+ tags: [ ...goal.tags ],
1079
+ abandonedReason: goal.abandonedReason,
1000
1080
  beliefsAtActivation: goal.beliefsAtActivation,
1001
1081
  completionType: goal.completionType,
1002
1082
  completionCondition: goal.completionCondition,