@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.
- package/LICENSE +202 -0
- package/README.md +777 -0
- package/dist/index.d.ts +8144 -0
- package/dist/index.js +26231 -0
- package/dist/index.js.map +1 -0
- package/package.json +73 -0
- package/src/cognition/agency/access.grants.ts +59 -0
- package/src/cognition/agency/competence.codec.ts +89 -0
- package/src/cognition/agency/engines/action.selector.ts +462 -0
- package/src/cognition/agency/engines/affordance.synthesizer.ts +384 -0
- package/src/cognition/agency/engines/deliberation.engine.ts +241 -0
- package/src/cognition/agency/engines/instruction.intake.ts +54 -0
- package/src/cognition/agency/engines/motor.schema.executor.ts +532 -0
- package/src/cognition/agency/engines/reafference.engine.ts +241 -0
- package/src/cognition/agency/execution.primitives.ts +118 -0
- package/src/cognition/agency/index.ts +58 -0
- package/src/cognition/agency/proactive.communicator.ts +274 -0
- package/src/cognition/agency/reconcile.learning.ts +82 -0
- package/src/cognition/agency/schemas/external.ts +59 -0
- package/src/cognition/agency/schemas/innate.ts +111 -0
- package/src/cognition/agency/schemas/repertoire.ts +246 -0
- package/src/cognition/agency/selection.scoring.ts +191 -0
- package/src/cognition/agency/types.ts +165 -0
- package/src/cognition/bus.ts +391 -0
- package/src/cognition/completion.inbox.ts +86 -0
- package/src/cognition/config.mirror.entities.ts +475 -0
- package/src/cognition/conversation.memory.ts +81 -0
- package/src/cognition/event.log.ts +116 -0
- package/src/cognition/event.schemas.ts +568 -0
- package/src/cognition/faculties/aesthetic.evaluator.ts +313 -0
- package/src/cognition/faculties/affective.blender.ts +562 -0
- package/src/cognition/faculties/attachment.evaluator.ts +432 -0
- package/src/cognition/faculties/attention.allocator.ts +422 -0
- package/src/cognition/faculties/autobiographical.narrator.ts +300 -0
- package/src/cognition/faculties/bias.detector.ts +363 -0
- package/src/cognition/faculties/circadian.oscillator.ts +294 -0
- package/src/cognition/faculties/confidence.calibrator.ts +324 -0
- package/src/cognition/faculties/dream.simulator.ts +251 -0
- package/src/cognition/faculties/empathy.simulator.ts +253 -0
- package/src/cognition/faculties/energy.regulator.ts +320 -0
- package/src/cognition/faculties/episodic.consolidator.ts +728 -0
- package/src/cognition/faculties/executive.engine/commands.ts +459 -0
- package/src/cognition/faculties/executive.engine/config.ts +46 -0
- package/src/cognition/faculties/executive.engine/context.ts +605 -0
- package/src/cognition/faculties/executive.engine/deferred.effects.ts +104 -0
- package/src/cognition/faculties/executive.engine/deliberate.reasoning.ts +60 -0
- package/src/cognition/faculties/executive.engine/effort.gate.ts +114 -0
- package/src/cognition/faculties/executive.engine/engine.ts +1028 -0
- package/src/cognition/faculties/executive.engine/escalation.buffer.ts +90 -0
- package/src/cognition/faculties/executive.engine/facet.supervisor.ts +271 -0
- package/src/cognition/faculties/executive.engine/facet.ts +628 -0
- package/src/cognition/faculties/executive.engine/gating.ts +222 -0
- package/src/cognition/faculties/executive.engine/index.ts +6 -0
- package/src/cognition/faculties/executive.engine/messages.ts +102 -0
- package/src/cognition/faculties/executive.engine/parser.ts +380 -0
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +1053 -0
- package/src/cognition/faculties/executive.engine/types.ts +323 -0
- package/src/cognition/faculties/exteroception.ts +338 -0
- package/src/cognition/faculties/forgetting.curve.ts +202 -0
- package/src/cognition/faculties/frustration.evaluator.ts +280 -0
- package/src/cognition/faculties/goal.manager.ts +1008 -0
- package/src/cognition/faculties/inhibition.controller.ts +351 -0
- package/src/cognition/faculties/interoception.ts +417 -0
- package/src/cognition/faculties/introspection.engine.ts +246 -0
- package/src/cognition/faculties/known.entity.tracker.ts +439 -0
- package/src/cognition/faculties/loss.evaluator.ts +224 -0
- package/src/cognition/faculties/moral.evaluator.ts +437 -0
- package/src/cognition/faculties/novelty.detector.ts +254 -0
- package/src/cognition/faculties/persona.consolidator.ts +845 -0
- package/src/cognition/faculties/planning.engine/engine.ts +859 -0
- package/src/cognition/faculties/planning.engine/plan.frontier.ts +83 -0
- package/src/cognition/faculties/planning.engine/plan.store.ts +174 -0
- package/src/cognition/faculties/planning.engine/plan.supervision.ts +494 -0
- package/src/cognition/faculties/planning.engine/types.ts +143 -0
- package/src/cognition/faculties/reputation.tracker.ts +294 -0
- package/src/cognition/faculties/reward.evaluator.ts +304 -0
- package/src/cognition/faculties/self.model.updater.ts +677 -0
- package/src/cognition/faculties/semantic.engine/clustering.ts +673 -0
- package/src/cognition/faculties/semantic.engine/index.ts +6 -0
- package/src/cognition/faculties/semantic.engine/integrator.ts +750 -0
- package/src/cognition/faculties/semantic.engine/types.ts +53 -0
- package/src/cognition/faculties/sleep.pressure.regulator.ts +262 -0
- package/src/cognition/faculties/social.perception.ts +333 -0
- package/src/cognition/faculties/spaced.repetition.ts +605 -0
- package/src/cognition/faculties/stress.regulator.ts +375 -0
- package/src/cognition/faculties/task.switcher.ts +239 -0
- package/src/cognition/faculties/theory.of.mind.ts +333 -0
- package/src/cognition/faculties/threat.evaluator.ts +312 -0
- package/src/cognition/faculties/working.memory.ts +406 -0
- package/src/cognition/generative.model.ts +344 -0
- package/src/cognition/heartbeat.ts +70 -0
- package/src/cognition/index.ts +291 -0
- package/src/cognition/instruction.handler.ts +146 -0
- package/src/cognition/memory/index.ts +35 -0
- package/src/cognition/memory/vector.adapter.ts +316 -0
- package/src/cognition/memory/vector.content.ts +47 -0
- package/src/cognition/memory/vector.embedder.ts +212 -0
- package/src/cognition/memory/vector.index.ts +459 -0
- package/src/cognition/memory/vector.types.ts +65 -0
- package/src/cognition/orchestrator.ts +142 -0
- package/src/cognition/persona.prior.ts +265 -0
- package/src/cognition/schema.registry.ts +145 -0
- package/src/cognition/senses/audition.engine/engine.ts +976 -0
- package/src/cognition/senses/audition.engine/salience.ts +59 -0
- package/src/cognition/senses/base.sense.engine.ts +117 -0
- package/src/cognition/senses/gustation.engine.ts +24 -0
- package/src/cognition/senses/index.ts +172 -0
- package/src/cognition/senses/olfaction.engine.ts +24 -0
- package/src/cognition/senses/somatosensation.engine.ts +23 -0
- package/src/cognition/senses/vision.engine.ts +23 -0
- package/src/cognition/types.ts +63 -0
- package/src/cognition/utilities/token.tracker.ts +492 -0
- package/src/core/abstracts.ts +60 -0
- package/src/core/async.engine.ts +539 -0
- package/src/core/clock.ts +196 -0
- package/src/core/completion.recorder.ts +122 -0
- package/src/core/conflict.detector.ts +140 -0
- package/src/core/distributed.ts +626 -0
- package/src/core/event.bus.ts +292 -0
- package/src/core/inbound.recorder.ts +100 -0
- package/src/core/index.ts +167 -0
- package/src/core/logger.ts +85 -0
- package/src/core/metrics.ts +107 -0
- package/src/core/orchestrator.ts +625 -0
- package/src/core/replay.ts +589 -0
- package/src/core/scenario.ts +120 -0
- package/src/core/serialization.ts +448 -0
- package/src/core/simulation.ts +197 -0
- package/src/core/snapshot.manager.ts +293 -0
- package/src/core/state.manager.ts +283 -0
- package/src/core/types.ts +274 -0
- package/src/core/utils.ts +82 -0
- package/src/core/wall.clock.ts +23 -0
- package/src/extensions/livestream.ext.ts +570 -0
- package/src/extensions/time.ext.ts +339 -0
- package/src/index.ts +91 -0
- package/src/llm/gate.ts +140 -0
- package/src/llm/index.ts +716 -0
- package/src/llm/summarizer.ts +170 -0
- package/src/llm/wire.contracts.ts +67 -0
- package/src/pma/eval.ts +651 -0
- package/src/pma/index.ts +1082 -0
- package/src/profiles/built-in.ts +7 -0
- package/src/profiles/companion.ts +28 -0
- package/src/profiles/company-brain.ts +54 -0
- package/src/profiles/customer-service.ts +30 -0
- package/src/profiles/game-npc.ts +20 -0
- package/src/profiles/index.ts +42 -0
- package/src/profiles/smart-home.ts +34 -0
- package/src/runners/coherence.runner.ts +49 -0
- package/src/runners/outreach.runner.ts +158 -0
- package/src/runners/social.runner.ts +182 -0
- package/src/runners/thin-shim.runner.ts +195 -0
- package/src/sdk/will.ts +334 -0
- package/src/stem/assembly.audit.ts +88 -0
- package/src/stem/distribution.ts +203 -0
- package/src/stem/guards/identity.coherence.ts +152 -0
- package/src/stem/guards/identity.guard.ts +227 -0
- package/src/stem/index.ts +1145 -0
- package/src/stem/mind.ts +1090 -0
- package/src/stem/tracts/ack.reconciler.ts +55 -0
- package/src/stem/tracts/biography.writer.ts +190 -0
- package/src/stem/tracts/effector.controller.ts +143 -0
- package/src/stem/tracts/health.reporter.ts +113 -0
- package/src/stem/tracts/inbound.queue.ts +54 -0
- package/src/stem/tracts/outbox.controller.ts +167 -0
- package/src/stem/tracts/outbox.writer.ts +133 -0
- package/src/stem/tracts/pma.controller.ts +109 -0
- package/src/stem/tracts/replay.controller.ts +177 -0
- package/src/stem/tracts/sensory.controller.ts +168 -0
- package/src/stem/tracts/session.logger.ts +157 -0
- package/src/stem/tracts/transport/index.ts +38 -0
- package/src/stem/tracts/transport/loopback.transport.ts +86 -0
- package/src/stem/tracts/transport/socketio.transport.ts +200 -0
- package/src/stem/tracts/transport/stream.transport.ts +152 -0
- package/src/stem/tracts/transport/types.ts +193 -0
- package/src/stem/tracts/transport.controller.ts +380 -0
- 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
|
+
}
|