@mindot/will 0.1.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 (178) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +777 -0
  3. package/dist/index.d.ts +8144 -0
  4. package/dist/index.js +26231 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +73 -0
  7. package/src/cognition/agency/access.grants.ts +59 -0
  8. package/src/cognition/agency/competence.codec.ts +89 -0
  9. package/src/cognition/agency/engines/action.selector.ts +462 -0
  10. package/src/cognition/agency/engines/affordance.synthesizer.ts +384 -0
  11. package/src/cognition/agency/engines/deliberation.engine.ts +241 -0
  12. package/src/cognition/agency/engines/instruction.intake.ts +54 -0
  13. package/src/cognition/agency/engines/motor.schema.executor.ts +532 -0
  14. package/src/cognition/agency/engines/reafference.engine.ts +241 -0
  15. package/src/cognition/agency/execution.primitives.ts +118 -0
  16. package/src/cognition/agency/index.ts +58 -0
  17. package/src/cognition/agency/proactive.communicator.ts +274 -0
  18. package/src/cognition/agency/reconcile.learning.ts +82 -0
  19. package/src/cognition/agency/schemas/external.ts +59 -0
  20. package/src/cognition/agency/schemas/innate.ts +111 -0
  21. package/src/cognition/agency/schemas/repertoire.ts +246 -0
  22. package/src/cognition/agency/selection.scoring.ts +191 -0
  23. package/src/cognition/agency/types.ts +165 -0
  24. package/src/cognition/bus.ts +391 -0
  25. package/src/cognition/completion.inbox.ts +86 -0
  26. package/src/cognition/config.mirror.entities.ts +475 -0
  27. package/src/cognition/conversation.memory.ts +81 -0
  28. package/src/cognition/event.log.ts +116 -0
  29. package/src/cognition/event.schemas.ts +568 -0
  30. package/src/cognition/faculties/aesthetic.evaluator.ts +313 -0
  31. package/src/cognition/faculties/affective.blender.ts +562 -0
  32. package/src/cognition/faculties/attachment.evaluator.ts +432 -0
  33. package/src/cognition/faculties/attention.allocator.ts +422 -0
  34. package/src/cognition/faculties/autobiographical.narrator.ts +300 -0
  35. package/src/cognition/faculties/bias.detector.ts +363 -0
  36. package/src/cognition/faculties/circadian.oscillator.ts +294 -0
  37. package/src/cognition/faculties/confidence.calibrator.ts +324 -0
  38. package/src/cognition/faculties/dream.simulator.ts +251 -0
  39. package/src/cognition/faculties/empathy.simulator.ts +253 -0
  40. package/src/cognition/faculties/energy.regulator.ts +320 -0
  41. package/src/cognition/faculties/episodic.consolidator.ts +728 -0
  42. package/src/cognition/faculties/executive.engine/commands.ts +459 -0
  43. package/src/cognition/faculties/executive.engine/config.ts +46 -0
  44. package/src/cognition/faculties/executive.engine/context.ts +605 -0
  45. package/src/cognition/faculties/executive.engine/deferred.effects.ts +104 -0
  46. package/src/cognition/faculties/executive.engine/deliberate.reasoning.ts +60 -0
  47. package/src/cognition/faculties/executive.engine/effort.gate.ts +114 -0
  48. package/src/cognition/faculties/executive.engine/engine.ts +1028 -0
  49. package/src/cognition/faculties/executive.engine/escalation.buffer.ts +90 -0
  50. package/src/cognition/faculties/executive.engine/facet.supervisor.ts +271 -0
  51. package/src/cognition/faculties/executive.engine/facet.ts +628 -0
  52. package/src/cognition/faculties/executive.engine/gating.ts +222 -0
  53. package/src/cognition/faculties/executive.engine/index.ts +6 -0
  54. package/src/cognition/faculties/executive.engine/messages.ts +102 -0
  55. package/src/cognition/faculties/executive.engine/parser.ts +380 -0
  56. package/src/cognition/faculties/executive.engine/prompt.factory.ts +1053 -0
  57. package/src/cognition/faculties/executive.engine/types.ts +323 -0
  58. package/src/cognition/faculties/exteroception.ts +338 -0
  59. package/src/cognition/faculties/forgetting.curve.ts +202 -0
  60. package/src/cognition/faculties/frustration.evaluator.ts +280 -0
  61. package/src/cognition/faculties/goal.manager.ts +1008 -0
  62. package/src/cognition/faculties/inhibition.controller.ts +351 -0
  63. package/src/cognition/faculties/interoception.ts +417 -0
  64. package/src/cognition/faculties/introspection.engine.ts +246 -0
  65. package/src/cognition/faculties/known.entity.tracker.ts +439 -0
  66. package/src/cognition/faculties/loss.evaluator.ts +224 -0
  67. package/src/cognition/faculties/moral.evaluator.ts +437 -0
  68. package/src/cognition/faculties/novelty.detector.ts +254 -0
  69. package/src/cognition/faculties/persona.consolidator.ts +845 -0
  70. package/src/cognition/faculties/planning.engine/engine.ts +859 -0
  71. package/src/cognition/faculties/planning.engine/plan.frontier.ts +83 -0
  72. package/src/cognition/faculties/planning.engine/plan.store.ts +174 -0
  73. package/src/cognition/faculties/planning.engine/plan.supervision.ts +494 -0
  74. package/src/cognition/faculties/planning.engine/types.ts +143 -0
  75. package/src/cognition/faculties/reputation.tracker.ts +294 -0
  76. package/src/cognition/faculties/reward.evaluator.ts +304 -0
  77. package/src/cognition/faculties/self.model.updater.ts +677 -0
  78. package/src/cognition/faculties/semantic.engine/clustering.ts +673 -0
  79. package/src/cognition/faculties/semantic.engine/index.ts +6 -0
  80. package/src/cognition/faculties/semantic.engine/integrator.ts +750 -0
  81. package/src/cognition/faculties/semantic.engine/types.ts +53 -0
  82. package/src/cognition/faculties/sleep.pressure.regulator.ts +262 -0
  83. package/src/cognition/faculties/social.perception.ts +333 -0
  84. package/src/cognition/faculties/spaced.repetition.ts +605 -0
  85. package/src/cognition/faculties/stress.regulator.ts +375 -0
  86. package/src/cognition/faculties/task.switcher.ts +239 -0
  87. package/src/cognition/faculties/theory.of.mind.ts +333 -0
  88. package/src/cognition/faculties/threat.evaluator.ts +312 -0
  89. package/src/cognition/faculties/working.memory.ts +406 -0
  90. package/src/cognition/generative.model.ts +344 -0
  91. package/src/cognition/heartbeat.ts +70 -0
  92. package/src/cognition/index.ts +291 -0
  93. package/src/cognition/instruction.handler.ts +146 -0
  94. package/src/cognition/memory/index.ts +35 -0
  95. package/src/cognition/memory/vector.adapter.ts +316 -0
  96. package/src/cognition/memory/vector.content.ts +47 -0
  97. package/src/cognition/memory/vector.embedder.ts +212 -0
  98. package/src/cognition/memory/vector.index.ts +459 -0
  99. package/src/cognition/memory/vector.types.ts +65 -0
  100. package/src/cognition/orchestrator.ts +142 -0
  101. package/src/cognition/persona.prior.ts +265 -0
  102. package/src/cognition/schema.registry.ts +145 -0
  103. package/src/cognition/senses/audition.engine/engine.ts +976 -0
  104. package/src/cognition/senses/audition.engine/salience.ts +59 -0
  105. package/src/cognition/senses/base.sense.engine.ts +117 -0
  106. package/src/cognition/senses/gustation.engine.ts +24 -0
  107. package/src/cognition/senses/index.ts +172 -0
  108. package/src/cognition/senses/olfaction.engine.ts +24 -0
  109. package/src/cognition/senses/somatosensation.engine.ts +23 -0
  110. package/src/cognition/senses/vision.engine.ts +23 -0
  111. package/src/cognition/types.ts +63 -0
  112. package/src/cognition/utilities/token.tracker.ts +492 -0
  113. package/src/core/abstracts.ts +60 -0
  114. package/src/core/async.engine.ts +539 -0
  115. package/src/core/clock.ts +196 -0
  116. package/src/core/completion.recorder.ts +122 -0
  117. package/src/core/conflict.detector.ts +140 -0
  118. package/src/core/distributed.ts +626 -0
  119. package/src/core/event.bus.ts +292 -0
  120. package/src/core/inbound.recorder.ts +100 -0
  121. package/src/core/index.ts +167 -0
  122. package/src/core/logger.ts +85 -0
  123. package/src/core/metrics.ts +107 -0
  124. package/src/core/orchestrator.ts +625 -0
  125. package/src/core/replay.ts +589 -0
  126. package/src/core/scenario.ts +120 -0
  127. package/src/core/serialization.ts +448 -0
  128. package/src/core/simulation.ts +197 -0
  129. package/src/core/snapshot.manager.ts +293 -0
  130. package/src/core/state.manager.ts +283 -0
  131. package/src/core/types.ts +274 -0
  132. package/src/core/utils.ts +82 -0
  133. package/src/core/wall.clock.ts +23 -0
  134. package/src/extensions/livestream.ext.ts +570 -0
  135. package/src/extensions/time.ext.ts +339 -0
  136. package/src/index.ts +91 -0
  137. package/src/llm/gate.ts +140 -0
  138. package/src/llm/index.ts +716 -0
  139. package/src/llm/summarizer.ts +170 -0
  140. package/src/llm/wire.contracts.ts +67 -0
  141. package/src/pma/eval.ts +651 -0
  142. package/src/pma/index.ts +1082 -0
  143. package/src/profiles/built-in.ts +7 -0
  144. package/src/profiles/companion.ts +28 -0
  145. package/src/profiles/company-brain.ts +54 -0
  146. package/src/profiles/customer-service.ts +30 -0
  147. package/src/profiles/game-npc.ts +20 -0
  148. package/src/profiles/index.ts +42 -0
  149. package/src/profiles/smart-home.ts +34 -0
  150. package/src/runners/coherence.runner.ts +49 -0
  151. package/src/runners/outreach.runner.ts +158 -0
  152. package/src/runners/social.runner.ts +182 -0
  153. package/src/runners/thin-shim.runner.ts +195 -0
  154. package/src/sdk/will.ts +334 -0
  155. package/src/stem/assembly.audit.ts +88 -0
  156. package/src/stem/distribution.ts +203 -0
  157. package/src/stem/guards/identity.coherence.ts +152 -0
  158. package/src/stem/guards/identity.guard.ts +227 -0
  159. package/src/stem/index.ts +1145 -0
  160. package/src/stem/mind.ts +1090 -0
  161. package/src/stem/tracts/ack.reconciler.ts +55 -0
  162. package/src/stem/tracts/biography.writer.ts +190 -0
  163. package/src/stem/tracts/effector.controller.ts +143 -0
  164. package/src/stem/tracts/health.reporter.ts +113 -0
  165. package/src/stem/tracts/inbound.queue.ts +54 -0
  166. package/src/stem/tracts/outbox.controller.ts +167 -0
  167. package/src/stem/tracts/outbox.writer.ts +133 -0
  168. package/src/stem/tracts/pma.controller.ts +109 -0
  169. package/src/stem/tracts/replay.controller.ts +177 -0
  170. package/src/stem/tracts/sensory.controller.ts +168 -0
  171. package/src/stem/tracts/session.logger.ts +157 -0
  172. package/src/stem/tracts/transport/index.ts +38 -0
  173. package/src/stem/tracts/transport/loopback.transport.ts +86 -0
  174. package/src/stem/tracts/transport/socketio.transport.ts +200 -0
  175. package/src/stem/tracts/transport/stream.transport.ts +152 -0
  176. package/src/stem/tracts/transport/types.ts +193 -0
  177. package/src/stem/tracts/transport.controller.ts +380 -0
  178. package/src/types.ts +116 -0
@@ -0,0 +1,494 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/planning.engine/plan.supervision.ts — the judgment faculty
3
+ // ─────────────────────────────────────────────────────────────
4
+ //
5
+ // Deliberate-tier supervision: a facet of the executive consciousness watches a
6
+ // plan's execution, judges each step outcome against the plan's expectedOutcome,
7
+ // and issues a supervisory directive (continue / retry / skip / pause / replan /
8
+ // escalate / abandon / complete). This module owns:
9
+ //
10
+ // • emergent-tier inference — important/uncertain plans start deliberate
11
+ // (top-down); an automatic plan escalates on a surprising outcome (bottom-up);
12
+ // • the facet lifecycle (spawn via the ExecutiveEngine, reap-degradation,
13
+ // teardown) and the plan-focus that defines the judgment vocabulary;
14
+ // • step reporting (facts only — the facet IS the executive's cognition; the
15
+ // engine reports state, never prescribes the decision);
16
+ // • directive dispatch — effects flow back into the engine through the narrow
17
+ // SupervisionHost interface, keeping the dependency one-directional.
18
+ //
19
+ // Extracted verbatim from planning.engine.ts — prompt strings byte-identical
20
+ // (the replay-equivalence capstone gates this: any drift breaks byte-identity).
21
+ // ─────────────────────────────────────────────────────────────
22
+
23
+ import { logger } from '#core/logger'
24
+ import type { ExecutiveFacetHandle, FacetReport, FacetDecision } from '#faculties/executive.engine/facet'
25
+ import type { FocusSection } from '#faculties/executive.engine/prompt.factory'
26
+ import type { ExecutiveOutputFull } from '#faculties/executive.engine/types'
27
+ import type { ExecutiveEngine } from '#faculties/executive.engine'
28
+ import type { GoalManager } from '#faculties/goal.manager'
29
+ import type { Plan, PlanStep, PlanContext, PlanningDispositions } from '#faculties/planning.engine/types'
30
+
31
+ /**
32
+ * The engine-side effects a supervisory directive can trigger. Narrow by design:
33
+ * the supervisor judges and directs; the engine executes and owns plan lifecycle.
34
+ */
35
+ export interface SupervisionHost {
36
+ /** Re-run the execution pass (advance the frontier after a directive). */
37
+ executePlans(): void
38
+ /** Terminal transitions — the engine owns status, terminal bookkeeping + bus events. */
39
+ planCompleted( plan: Plan ): void
40
+ planFailed( plan: Plan, reason: string ): void
41
+ /** Publish a planning bus event (plan.escalated / plan.replanned). */
42
+ publish( event: { type: string; version: number; salience: number; payload: Record<string, unknown> } ): void
43
+ }
44
+
45
+ export class PlanSupervisor {
46
+ private _activeFacets = new Map<string, ExecutiveFacetHandle>()
47
+
48
+ /**
49
+ * Cumulative count of each supervisory directive the facet has issued
50
+ * (continue/retry/skip/pause/replan/escalate/abandon/complete). Pure observability —
51
+ * surfaced as `planning.supervision.*` metrics so the planning-quality eval harness
52
+ * can measure how the mind supervises execution (how often it corrects course). Not
53
+ * restored from snapshot; re-accrues deterministically as the same decisions replay.
54
+ */
55
+ private _supervisionCounts = new Map<string, number>()
56
+
57
+ constructor(
58
+ private readonly _host: SupervisionHost,
59
+ private readonly _dispositions: PlanningDispositions,
60
+ ){}
61
+
62
+ private _executiveEngine: ExecutiveEngine | null = null
63
+ private _goalManager: GoalManager | null = null
64
+
65
+ attachExecutiveEngine( oe: ExecutiveEngine ): void { this._executiveEngine = oe }
66
+ attachGoalManager( gm: GoalManager ): void { this._goalManager = gm }
67
+
68
+ // ── Observability ──────────────────────────────────────────
69
+
70
+ get activeFacetCount(): number { return this._activeFacets.size }
71
+ supervisionCount( directive: string ): number { return this._supervisionCounts.get( directive ) ?? 0 }
72
+ hasFacet( planId: string ): boolean { return this._activeFacets.has( planId ) }
73
+
74
+ // ── Supervision inference (emergent tier) ──────────────────
75
+
76
+ /**
77
+ * Top-down initial supervision mode for a plan being launched. Important
78
+ * (high-priority goal) or uncertain (low-confidence) plans are supervised from
79
+ * the first step; everything else runs automatically. Pure + deterministic.
80
+ */
81
+ inferInitialTier( plan: Plan ): 'automatic' | 'deliberate' {
82
+ const priority = this._goalManager?.getGoal( plan.goalId )?.priority ?? 0
83
+ if( priority >= this._dispositions.deliberateGoalPriority ) return 'deliberate'
84
+ if( plan.confidence < this._dispositions.lowPlanConfidence ) return 'deliberate'
85
+ return 'automatic'
86
+ }
87
+
88
+ /**
89
+ * Bottom-up: should an AUTOMATIC plan recruit deliberate supervision on this step
90
+ * outcome? Surprise (failure / outcome well below expectation) captures attention.
91
+ * EXTENSION POINT — add triggers here (timeouts, prediction error, repeated
92
+ * retries, threat/stress spikes, …) as more edge cases surface.
93
+ */
94
+ shouldEscalate(
95
+ _plan: Plan, _step: PlanStep, outcome: { success: boolean; outcomeQuality: number }
96
+ ): boolean {
97
+ if( !outcome.success ) return true // a failure always demands attention
98
+ if( outcome.outcomeQuality < this._dispositions.surpriseOutcomeQuality ) return true // succeeded, but well below expectation
99
+ return false
100
+ }
101
+
102
+ // ── Facet lifecycle ────────────────────────────────────────
103
+
104
+ activateFacet( plan: Plan, prime: boolean = true ): void {
105
+ if( !this._executiveEngine ) return
106
+
107
+ try {
108
+ const { attention, handle: facet } = this._executiveEngine.spawnFacet()
109
+ if( !facet || attention === 'full' ){
110
+ plan.executionTier = 'automatic'
111
+ logger.info( `[planning] attention full — plan ${plan.id} stays automatic (no facet)` )
112
+ return
113
+ }
114
+
115
+ // Build the plan-specific focus section for the facet
116
+ const planFocus = this._buildPlanFocusSection( plan )
117
+ facet.setFocus( planFocus )
118
+
119
+ facet.subscribe( ( decision: FacetDecision ) => this._onFacetDecision( plan, decision ) )
120
+ this._activeFacets.set( plan.id, facet )
121
+
122
+ // If the supervisor reaps this facet out from under us (idle TTL or LRU
123
+ // eviction under attention pressure), drop the now-dead handle and degrade
124
+ // the plan to autonomous completion — otherwise it stalls on a destroyed
125
+ // facet whose report() silently no-ops. (P2)
126
+ facet.onReaped( () => {
127
+ this._activeFacets.delete( plan.id )
128
+ if( plan.status === 'executing' || plan.status === 'ready' )
129
+ plan.executionTier = 'automatic'
130
+ logger.info(
131
+ `[planning] facet for plan ${plan.id} reaped — degraded to automatic`
132
+ )
133
+ } )
134
+
135
+ // Prime the facet with initial context. Skipped on lazy escalation (prime=
136
+ // false), where the triggering step report follows immediately.
137
+ if( prime ){
138
+ const initialReport: FacetReport = {
139
+ type: 'plan.initialized',
140
+ contextId: plan.id,
141
+ instructions: this._buildDecisionGuidance( 'plan.initialized', undefined ),
142
+ payload: {
143
+ planId: plan.id,
144
+ goalId: plan.goalId,
145
+ totalSteps: plan.steps.length,
146
+ expectedOutcome: plan.expectedOutcome,
147
+ executionTier: plan.executionTier
148
+ }
149
+ }
150
+ facet.report( initialReport )
151
+ }
152
+
153
+ logger.info( `[planning] facet activated: plan=${plan.id} facetId=${facet.facetId}` )
154
+ }
155
+ catch( err ){
156
+ logger.error( `[planning] facet failed for plan ${plan.id}:`, err )
157
+ plan.executionTier = 'automatic'
158
+ }
159
+ }
160
+
161
+ cleanupFacet( planId: string ): void {
162
+ const facet = this._activeFacets.get( planId )
163
+ if( facet ){
164
+ facet.destroy()
165
+ this._activeFacets.delete( planId )
166
+ }
167
+ }
168
+
169
+ // ── Focus + guidance (the judgment vocabulary) ─────────────
170
+
171
+ /**
172
+ * Build the plan-specific focus section for the facet.
173
+ * Provided to the facet via setFocus() before any reports.
174
+ *
175
+ * Uses the STANDARD executive output format (no custom outputFormat).
176
+ * The facet LLM expresses its directive as the FIRST action type
177
+ * (e.g. { type: "continue" }), which the extractDecision callback reads.
178
+ * A [PLANS] tagged block in reasoning carries revised steps for "replan".
179
+ */
180
+ private _buildPlanFocusSection( plan: Plan ): FocusSection {
181
+ const goalDescription = this._goalManager
182
+ ?.getActiveGoals()
183
+ .find( g => g.id === plan.goalId )
184
+ ?.description ?? plan.goalId
185
+
186
+ const stepList = plan.steps.map( s => {
187
+ const marker = s.status === 'completed' ? '✓' :
188
+ s.status === 'failed' ? '✗' :
189
+ s.status === 'active' ? '→' : '○'
190
+ return `${marker} [${s.id}] ${s.action}: ${s.description}`
191
+ } ).join( '\n' )
192
+
193
+ const completedCount = plan.steps.filter(
194
+ s => s.status === 'completed' || s.status === 'skipped'
195
+ ).length
196
+
197
+ const focusContent =
198
+ `Goal: ${goalDescription} (${plan.goalId})\n` +
199
+ `Expected Outcome: ${plan.expectedOutcome || 'Not specified'}\n` +
200
+ `Progress: ${completedCount}/${plan.steps.length} steps\n\n` +
201
+ `## Plan Steps\n${stepList}`
202
+
203
+ return {
204
+ title: 'Plan Execution',
205
+ function: 'planning',
206
+ content: focusContent,
207
+ outputFormat: undefined, // use standard executive output format
208
+ instructions:
209
+ `You are monitoring plan "${plan.id}" for goal "${plan.goalId}".\n`+
210
+ `Your ONLY role: evaluate step outcomes and decide what happens next.\n`+
211
+ `Do not create new goals or beliefs unless directly relevant to this plan.\n\n`+
212
+ `## Decision Vocabulary\n`+
213
+ `Express your decision as the FIRST action in your actions array:\n`+
214
+ `- { "type": "continue" } — proceed to the next step\n`+
215
+ `- { "type": "retry" } — re-attempt the failed step (capped)\n`+
216
+ `- { "type": "skip" } — skip the failed step and move on\n`+
217
+ `- { "type": "pause" } — hold the plan; resume it later (no progress now)\n`+
218
+ `- { "type": "replan" } — include a [PLANS] block with revised steps\n`+
219
+ `- { "type": "escalate" } — hand the decision up to your master self\n`+
220
+ `- { "type": "abandon" } — plan is unrecoverable; give up entirely\n`+
221
+ `- { "type": "complete" } — all meaningful work is done; close the plan\n\n`+
222
+ `For "replan", include a [PLANS] block inside your reasoning with new steps.\n`+
223
+ `The plan's expectedOutcome tells you what success looks like — use it to judge step reports.`,
224
+ extractDecision: ( rawOutput: unknown ) => {
225
+ const output = rawOutput as ExecutiveOutputFull
226
+
227
+ // Directive comes from the first action type the facet chose
228
+ const actionType = output.actions[ 0 ]?.type ?? 'continue'
229
+ const DIRECTIVES = [ 'continue', 'retry', 'skip', 'pause', 'replan', 'escalate', 'abandon', 'complete' ] as const
230
+ const directive = DIRECTIVES.includes( actionType as typeof DIRECTIVES[number] )
231
+ ? actionType
232
+ : 'continue'
233
+
234
+ // goalProgress: complete → 1.0, otherwise ratio of finished steps
235
+ const total = plan.steps.length
236
+ const done = plan.steps.filter(
237
+ s => s.status === 'completed' || s.status === 'skipped'
238
+ ).length
239
+ const goalProgress = directive === 'complete'
240
+ ? 1.0
241
+ : total > 0 ? done / total : 0
242
+
243
+ // updatedSteps: present only for replan (facet emits a [PLANS] block)
244
+ const updatedSteps = directive === 'replan'
245
+ ? output.plans?.[ 0 ]?.steps?.map( s => ( {
246
+ action: s.action,
247
+ description: s.description,
248
+ expectedOutcome: s.expectedOutcome,
249
+ prerequisites: s.prerequisites ?? []
250
+ } ) )
251
+ : undefined
252
+
253
+ return {
254
+ directive,
255
+ goalId: plan.goalId,
256
+ goalProgress,
257
+ updatedSteps,
258
+ newGoals: output.newGoals,
259
+ goalsToAbandon: output.goalsToAbandon,
260
+ newBeliefs: output.newBeliefs
261
+ }
262
+ }
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Per-report status for the facet: FACTS ONLY — what happened — not coaching on
268
+ * which directive to pick. The facet IS the executive's cognition and already has
269
+ * the decision vocabulary from its focus instructions; the engine's job is to
270
+ * report state, not prescribe the decision. (Lean guidance — the engine no longer
271
+ * does the mind's thinking for it.)
272
+ */
273
+ private _buildDecisionGuidance( statusType: string, step?: PlanStep ): string {
274
+ switch( statusType ){
275
+ case 'step_completed':
276
+ return `## Report\nStep ${step?.id} completed. Outcome: ${step?.outcome?.description ?? 'ok'}`
277
+
278
+ case 'step_failed':
279
+ return `## Report\nStep ${step?.id} failed. Outcome: ${step?.outcome?.description ?? 'unknown'}`
280
+
281
+ case 'plan_completed':
282
+ return `## Report\nAll steps are complete or skipped.`
283
+
284
+ case 'plan_failed':
285
+ return `## Report\nThe plan can no longer progress — one or more steps failed with no remaining path.`
286
+
287
+ case 'plan.initialized':
288
+ return `## Report\nPlan initialized and ready for execution.`
289
+
290
+ default:
291
+ return `## Report\nProgress update.`
292
+ }
293
+ }
294
+
295
+ // ── Step reporting ─────────────────────────────────────────
296
+
297
+ reportToFacet(
298
+ plan: Plan,
299
+ step: PlanStep,
300
+ outcome: { success: boolean; description: string; outcomeQuality: number }
301
+ ): boolean {
302
+ const facet = this._activeFacets.get( plan.id )
303
+ if( !facet ) return false
304
+
305
+ const allDone = plan.steps.every( s => s.status === 'completed' || s.status === 'skipped' )
306
+ const anyFailed = plan.steps.some( s => s.status === 'failed' )
307
+ const pendingCount = plan.steps.filter( s => s.status !== 'completed' && s.status !== 'skipped' ).length
308
+
309
+ let statusType: string
310
+ if( allDone && !anyFailed ) statusType = 'plan_completed'
311
+ else if( anyFailed && pendingCount === 0 ) statusType = 'plan_failed'
312
+ else if( outcome.success ) statusType = 'step_completed'
313
+ else statusType = 'step_failed'
314
+
315
+ // Update step outcome for guidance generation
316
+ step.outcome = outcome
317
+
318
+ const report: FacetReport = {
319
+ type: statusType,
320
+ contextId: plan.id,
321
+ instructions: this._buildDecisionGuidance( statusType, step ),
322
+ payload: {
323
+ planId: plan.id,
324
+ stepId: step.id,
325
+ outcome: {
326
+ success: outcome.success,
327
+ description: outcome.description,
328
+ outcomeQuality: outcome.outcomeQuality
329
+ },
330
+ planContext: this._buildFacetPlanContext( plan )
331
+ }
332
+ }
333
+
334
+ facet.report( report )
335
+ return true
336
+ }
337
+
338
+ private _buildFacetPlanContext( plan: Plan ): PlanContext {
339
+ return {
340
+ goalId: plan.goalId,
341
+ goalDescription: this._goalManager?.getActiveGoals()
342
+ .find( g => g.id === plan.goalId )?.description ?? plan.goalId,
343
+ expectedOutcome: plan.expectedOutcome,
344
+ steps: plan.steps.map( s => ( {
345
+ id: s.id,
346
+ action: s.action,
347
+ description: s.description,
348
+ expectedOutcome: s.expectedOutcome,
349
+ status: s.status,
350
+ prerequisites: s.prerequisites,
351
+ } ) ),
352
+ totalSteps: plan.steps.length,
353
+ completedSteps: plan.steps.filter( s => s.status === 'completed' || s.status === 'skipped' ).length,
354
+ skippedSteps: plan.steps.filter( s => s.status === 'skipped' ).map( s => s.id ),
355
+ executionTier: plan.executionTier
356
+ }
357
+ }
358
+
359
+ // ── Directive dispatch ─────────────────────────────────────
360
+
361
+ private _onFacetDecision( plan: Plan, decision: FacetDecision ): void {
362
+ // The decision payload structure is defined by the focus.outputFormat
363
+ const payload = decision.decision as {
364
+ directive?: string
365
+ updatedSteps?: Array<{ action: string; description: string; expectedOutcome: string; prerequisites: string[] }>
366
+ goalProgress?: number
367
+ newGoals?: Array<{ description: string; priority: number; tags: string[]; completionType: string; completionCondition?: string }>
368
+ goalsToAbandon?: Array<{ goalId: string; reason: string }>
369
+ newBeliefs?: Array<{ statement: string; category: string; confidence: number; evidence: 'single_observation' | 'recurring_pattern' | 'strong_pattern'; tags: string[] }>
370
+ }
371
+
372
+ const directive = payload.directive ?? 'continue'
373
+
374
+ // Measure: tally the supervisory decision (surfaced as planning.supervision.*).
375
+ this._supervisionCounts.set( directive, ( this._supervisionCounts.get( directive ) ?? 0 ) + 1 )
376
+
377
+ logger.info(
378
+ `[planning] facet decision: plan=${plan.id} ` +
379
+ `${directive} (confidence=${decision.confidence.toFixed( 2 )})`
380
+ )
381
+
382
+ switch( directive ){
383
+ case 'continue':
384
+ this._host.executePlans()
385
+ break
386
+
387
+ case 'skip': {
388
+ const failedStep = plan.steps.find( s => s.status === 'failed' )
389
+ if( failedStep ) failedStep.status = 'skipped'
390
+ this._host.executePlans()
391
+ break
392
+ }
393
+
394
+ case 'abandon': {
395
+ this._host.planFailed( plan, `Facet abandoned: ${decision.reasoning.slice( 0, 100 )}` )
396
+ this.cleanupFacet( plan.id )
397
+ break
398
+ }
399
+
400
+ case 'replan': {
401
+ if( payload.updatedSteps && payload.updatedSteps.length > 0 ){
402
+ plan.steps = payload.updatedSteps.map( ( s, i ) => ( {
403
+ id: `step-${i}`,
404
+ order: i,
405
+ action: s.action,
406
+ description: s.description,
407
+ expectedOutcome: s.expectedOutcome,
408
+ prerequisites: s.prerequisites,
409
+ estimatedDuration: 5,
410
+ status: 'pending' as const,
411
+ } ) )
412
+
413
+ logger.info( `[planning] plan ${plan.id} replanned (${plan.steps.length} steps)` )
414
+
415
+ // Surface: the mind rewrote the plan mid-flight — a course-correction the
416
+ // master should be aware of (mirrors plan.escalated). Only fires when steps
417
+ // actually changed, not on an empty replan directive.
418
+ this._host.publish( {
419
+ type: 'plan.replanned', version: 1,
420
+ salience: 0.7,
421
+ payload: {
422
+ planId: plan.id,
423
+ goalId: plan.goalId,
424
+ reason: decision.reasoning.slice( 0, 120 ),
425
+ stepCount: plan.steps.length,
426
+ requestingEntityId: plan.requestingEntityId,
427
+ requestingThreadId: plan.requestingThreadId,
428
+ }
429
+ } )
430
+ }
431
+ this._host.executePlans()
432
+ break
433
+ }
434
+
435
+ case 'complete': {
436
+ this._host.planCompleted( plan )
437
+ this.cleanupFacet( plan.id )
438
+ break
439
+ }
440
+
441
+ case 'retry': {
442
+ // Re-attempt failed step(s) — reset to pending so computeReadySet
443
+ // re-activates it on the frontier; capped per step so a stuck step can't loop forever.
444
+ let retried = 0
445
+ for( const s of plan.steps ){
446
+ if( s.status !== 'failed' ) continue
447
+ const n = s.retries ?? 0
448
+ if( n >= this._dispositions.maxStepRetries ){
449
+ logger.info( `[planning] step ${s.id} retry exhausted (${n}/${this._dispositions.maxStepRetries}); left failed` )
450
+ continue
451
+ }
452
+ s.retries = n + 1
453
+ s.status = 'pending'
454
+ s.outcome = undefined
455
+ retried++
456
+ }
457
+ logger.info( `[planning] plan ${plan.id} retrying ${retried} step(s)` )
458
+ this._host.executePlans()
459
+ break
460
+ }
461
+
462
+ case 'pause': {
463
+ // Hold the plan without failing/abandoning it (resumes when re-executed).
464
+ // Free the facet's attention while held.
465
+ plan.status = 'paused'
466
+ this.cleanupFacet( plan.id )
467
+ logger.info( `[planning] plan ${plan.id} paused by facet` )
468
+ break
469
+ }
470
+
471
+ case 'escalate': {
472
+ // The facet defers to the master self: hold the plan + cleanup, and raise a
473
+ // high-salience signal the master notices (alongside its Active Plans
474
+ // awareness, which shows the paused plan) so it can re-decide.
475
+ plan.status = 'paused'
476
+ this.cleanupFacet( plan.id )
477
+ this._host.publish( {
478
+ type: 'plan.escalated', version: 1,
479
+ salience: 0.85,
480
+ payload: {
481
+ planId: plan.id,
482
+ goalId: plan.goalId,
483
+ reason: decision.reasoning.slice( 0, 120 ),
484
+ requestingEntityId: plan.requestingEntityId,
485
+ requestingThreadId: plan.requestingThreadId,
486
+ }
487
+ } )
488
+ logger.info( `[planning] plan ${plan.id} escalated to master` )
489
+ break
490
+ }
491
+ }
492
+ }
493
+ }
494
+
@@ -0,0 +1,143 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/planning.engine/types.ts — shared planning types
3
+ // ─────────────────────────────────────────────────────────────
4
+ //
5
+ // Extracted verbatim from planning.engine.ts (the 1,500-line file split along
6
+ // its natural seams: types / store / frontier / supervision / engine shell).
7
+ // All names are re-exported by planning.engine.ts — external imports unchanged.
8
+ // ─────────────────────────────────────────────────────────────
9
+
10
+ import type { Tick } from '#core/types'
11
+ import type { CognitiveBus } from '#cognition/bus'
12
+
13
+ export interface Plan {
14
+ id: string
15
+ goalId: string
16
+ steps: PlanStep[]
17
+ estimatedCost: number
18
+ confidence: number
19
+ /** Full lifecycle: draft → validated → approved → ready → executing → completed/failed/rejected */
20
+ status: 'draft' | 'validated' | 'approved' | 'ready' | 'executing' | 'paused' | 'completed' | 'failed' | 'rejected' | 'revised'
21
+ executionTier: 'deliberate' | 'automatic'
22
+ /** Concrete description of what successful completion looks like — set by executive */
23
+ expectedOutcome: string
24
+ createdAt: Tick
25
+ /**
26
+ * Causal link — the entity whose message triggered the goal that spawned this plan.
27
+ * Copied from GoalState.requestingEntityId at plan-creation time.
28
+ * Stamped on all bus events so the activity SSE stream can filter by entity.
29
+ */
30
+ requestingEntityId?: string
31
+ /** Matching thread ID for reply correlation. */
32
+ requestingThreadId?: string
33
+ }
34
+
35
+ export interface PlanStep {
36
+ id: string
37
+ order: number
38
+ /**
39
+ * Advisory suggested schema — the action this step would LIKE to recruit. It is
40
+ * projected as a `plan.prior` that biases the competition toward this schema; it
41
+ * is NOT dispatched. If the schema does not resolve in the repertoire the prior
42
+ * cannot surface and the plan waits / replans (no forced execution of a string).
43
+ */
44
+ action: string
45
+ description: string
46
+ expectedOutcome: string
47
+ prerequisites: string[]
48
+ estimatedDuration: number
49
+ /** `active` = on the frontier, biasing the competition this tick (was `dispatched`). */
50
+ status: 'pending' | 'active' | 'completed' | 'failed' | 'skipped'
51
+ /** Optional entity the step's action is directed at — biases goal-relevance + binds the affordance. */
52
+ targetEntityId?: string
53
+ /** Optional schema tags to route the prior (currently unused by projection; reserved). */
54
+ tags?: string[]
55
+ /** Re-attempt count (the `retry` directive); capped by maxStepRetries. */
56
+ retries?: number
57
+ /** The outcome from ActionExecutor when the step completes */
58
+ outcome?: {
59
+ success: boolean
60
+ description: string
61
+ outcomeQuality: number
62
+ }
63
+ }
64
+
65
+ export interface PlanContext {
66
+ goalId: string
67
+ goalDescription: string
68
+ /** Concrete description of what successful completion looks like */
69
+ expectedOutcome: string
70
+ steps: Array<{
71
+ id: string
72
+ action: string
73
+ description: string
74
+ expectedOutcome: string
75
+ status: 'pending' | 'active' | 'completed' | 'failed' | 'skipped'
76
+ prerequisites: string[]
77
+ }>
78
+ totalSteps: number
79
+ completedSteps: number
80
+ skippedSteps: string[] // stepIds that were skipped, not completed
81
+ executionTier: 'deliberate' | 'automatic'
82
+ }
83
+
84
+ /**
85
+ * A normalised activity event forwarded to activity-stream listeners.
86
+ * Maps 1-to-1 onto the SSE event types emitted by GET /wills/:id/activity.
87
+ */
88
+ export interface ActivityEvent {
89
+ /** SSE event type name. */
90
+ type: 'plan_started' | 'step_activated' | 'step_outcome' | 'plan_complete' | 'plan_failed' | 'plan_cancelled'
91
+ planId: string
92
+ goalId?: string
93
+ requestingEntityId?: string
94
+ requestingThreadId?: string
95
+ /** Additional per-event fields (steps, outcomes, etc.). */
96
+ [key: string]: unknown
97
+ }
98
+
99
+ export type ActivityEventHandler = ( event: ActivityEvent ) => void
100
+
101
+ export interface PlanningEngineConfig {
102
+ bus?: CognitiveBus
103
+ /**
104
+ * Ticks a terminal (completed/failed/rejected) plan is retained before it and
105
+ * its state entity are GC'd. Bounds unbounded plan accretion on long-lived
106
+ * minds. Default 300.
107
+ */
108
+ planRetentionTicks?: number
109
+ /**
110
+ * Emergent-supervision thresholds. The executive no longer sets the tier; the
111
+ * engine starts a plan `deliberate` when its goal is important (top-down) or the
112
+ * plan is uncertain, and escalates an `automatic` plan to `deliberate` on a
113
+ * surprising step outcome (bottom-up). All extensible in _inferInitialTier /
114
+ * _shouldEscalate.
115
+ */
116
+ deliberateGoalPriority?: number // goal priority ≥ this → start deliberate (default 0.7)
117
+ lowPlanConfidence?: number // plan confidence < this → start deliberate (default 0.5)
118
+ surpriseOutcomeQuality?: number // step outcomeQuality < this → escalate (default 0.25)
119
+ maxStepRetries?: number // cap on the `retry` directive per step (default 3)
120
+ }
121
+
122
+ /**
123
+ * Trait-driven dispositions, refreshed from the persona-prior mirror each tick
124
+ * (Channel A) and read LIVE by the store/frontier/supervisor. One mutable object
125
+ * owned by the engine — a single source of truth instead of copies drifting
126
+ * across the split modules.
127
+ */
128
+ export interface PlanningDispositions {
129
+ deliberateGoalPriority: number
130
+ lowPlanConfidence: number
131
+ surpriseOutcomeQuality: number
132
+ maxStepRetries: number
133
+ /** Channel A: how hard the plan asserts its frontier in the action competition
134
+ * (base 1 ⊕ conscientiousness prior). Multiplies the projected plan-prior bias. */
135
+ planBiasGain: number
136
+ }
137
+
138
+ /** Terminal plan statuses — never change again once entered. */
139
+ export const TERMINAL_STATUSES: readonly string[] = [ 'completed', 'failed', 'rejected' ]
140
+
141
+ export function clamp01( n: number ): number {
142
+ return n < 0 ? 0 : n > 1 ? 1 : n
143
+ }