@mindot/will 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -11
- package/dist/index.d.ts +188 -141
- package/dist/index.js +16660 -15206
- package/dist/index.js.map +1 -1
- package/dist/{channels → surface/channels}/discord.d.ts +50 -3
- package/dist/{channels → surface/channels}/discord.js +102 -7
- package/dist/surface/channels/discord.js.map +1 -0
- package/dist/{channels → surface/channels}/whatsapp.d.ts +2 -2
- package/dist/{channels → surface/channels}/whatsapp.js +7 -4
- package/dist/surface/channels/whatsapp.js.map +1 -0
- package/dist/{cli.js → surface/cli.js} +4406 -2904
- package/dist/surface/cli.js.map +1 -0
- package/dist/{mcp → surface/mcp}/effectors.d.ts +1 -1
- package/dist/{mcp → surface/mcp}/effectors.js +10 -4
- package/dist/surface/mcp/effectors.js.map +1 -0
- package/dist/{will-DbDj_TEH.d.ts → will-evj9_vrd.d.ts} +5699 -4854
- package/package.json +11 -12
- package/src/cognition/agency/consequence.ts +237 -3
- package/src/cognition/agency/conversation.aim.ts +32 -0
- package/src/cognition/agency/engines/action.selector.ts +59 -3
- package/src/cognition/agency/engines/affordance.synthesizer.ts +114 -10
- package/src/cognition/agency/engines/deliberation.engine.ts +76 -3
- package/src/cognition/agency/engines/motor.schema.executor.ts +362 -27
- package/src/cognition/agency/engines/reafference.engine.ts +43 -4
- package/src/cognition/agency/execution.primitives.ts +17 -4
- package/src/cognition/agency/reconcile.learning.ts +5 -4
- package/src/cognition/agency/schemas/innate.ts +96 -1
- package/src/cognition/agency/schemas/repertoire.ts +19 -1
- package/src/cognition/agency/selection.scoring.ts +16 -0
- package/src/cognition/agency/settlement.ts +203 -0
- package/src/cognition/agency/types.ts +38 -1
- package/src/cognition/config.mirror.entities.ts +0 -1
- package/src/cognition/event.schemas.ts +0 -8
- package/src/cognition/faculties/affective.blender.ts +21 -4
- package/src/cognition/faculties/circadian.oscillator.ts +36 -7
- package/src/cognition/faculties/executive.engine/action.record.ts +129 -0
- package/src/cognition/faculties/executive.engine/context.ts +41 -35
- package/src/cognition/faculties/executive.engine/engine.ts +270 -113
- package/src/cognition/faculties/executive.engine/escalation.buffer.ts +126 -59
- package/src/cognition/faculties/executive.engine/facet.supervisor.ts +10 -0
- package/src/cognition/faculties/executive.engine/parser.ts +100 -38
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +168 -23
- package/src/cognition/faculties/executive.engine/types.ts +18 -15
- package/src/cognition/faculties/exteroception.ts +99 -98
- package/src/cognition/faculties/goal.manager.ts +50 -2
- package/src/cognition/faculties/known.entity.tracker.ts +22 -3
- package/src/cognition/faculties/planning.engine/engine.ts +4 -4
- package/src/cognition/faculties/planning.engine/plan.frontier.ts +1 -1
- package/src/cognition/faculties/semantic.engine/integrator.ts +1 -1
- package/src/cognition/faculties/working.memory.ts +6 -1
- package/src/cognition/instruction.handler.ts +1 -1
- package/src/cognition/memory/vector.embedder.ts +1 -3
- package/src/cognition/percept.entity.ts +122 -0
- package/src/cognition/sense.boundary.ts +176 -0
- package/src/cognition/senses/audition.engine/engine.ts +97 -16
- package/src/cognition/senses/base.sense.engine.ts +104 -6
- package/src/cognition/senses/index.ts +71 -13
- package/src/cognition/senses/provenance.ts +128 -0
- package/src/cognition/senses/somatosensation.engine.ts +117 -9
- package/src/cognition/social.identity.ts +23 -0
- package/src/cognition/utilities/token.tracker.ts +36 -5
- package/src/core/orchestrator.ts +13 -0
- package/src/index.ts +39 -5
- package/src/llm/gate.ts +48 -0
- package/src/llm/index.ts +102 -25
- package/src/llm/wire.contracts.ts +38 -0
- package/src/pma/index.ts +1 -1
- package/src/stem/index.ts +92 -21
- package/src/stem/mind.ts +26 -2
- package/src/stem/policy/arbiter.ts +10 -0
- package/src/stem/profiles/built-in.ts +7 -0
- package/src/{profiles → stem/profiles}/companion.ts +1 -1
- package/src/{profiles → stem/profiles}/company-brain.ts +1 -1
- package/src/{profiles → stem/profiles}/customer-service.ts +1 -1
- package/src/{profiles → stem/profiles}/game-npc.ts +1 -1
- package/src/{profiles → stem/profiles}/index.ts +1 -1
- package/src/{profiles → stem/profiles}/smart-home.ts +1 -1
- package/src/stem/tracts/effector/escalation.lifecycle.ts +239 -0
- package/src/stem/tracts/effector/policy.enforcement.ts +261 -0
- package/src/stem/tracts/effector/types.ts +110 -0
- package/src/stem/tracts/effector.controller.ts +112 -401
- package/src/stem/tracts/outbox.controller.ts +30 -17
- package/src/stem/tracts/sensory.controller.ts +6 -6
- package/src/stem/tracts/session.logger.ts +6 -1
- package/src/stem/tracts/transport/types.ts +20 -1
- package/src/stem/tracts/transport.controller.ts +33 -9
- package/src/{channels → surface/channels}/discord.ts +224 -7
- package/src/{channels → surface/channels}/roster.ts +1 -1
- package/src/{channels → surface/channels}/types.ts +1 -1
- package/src/{channels → surface/channels}/whatsapp.ts +9 -6
- package/src/{cli.ts → surface/cli.ts} +6 -6
- package/src/{host → surface/host}/boot.ts +3 -3
- package/src/{host → surface/host}/utterances.ts +2 -2
- package/src/{mcp → surface/mcp}/effectors.ts +19 -6
- package/src/{mcp → surface/mcp}/server.ts +19 -5
- package/src/{sdk → surface/sdk}/will.ts +156 -28
- package/src/{serve → surface/serve}/server.ts +11 -4
- package/src/types.ts +24 -3
- package/dist/channels/discord.js.map +0 -1
- package/dist/channels/whatsapp.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/mcp/effectors.js.map +0 -1
- package/src/extensions/livestream.ext.ts +0 -570
- package/src/extensions/time.ext.ts +0 -339
- package/src/profiles/built-in.ts +0 -7
- package/src/runners/coherence.runner.ts +0 -49
- package/src/runners/outreach.runner.ts +0 -155
- package/src/runners/social.runner.ts +0 -179
- package/src/runners/thin-shim.runner.ts +0 -205
- /package/dist/{cli.d.ts → surface/cli.d.ts} +0 -0
|
@@ -47,6 +47,21 @@ const ACP_CONFIDENCE = 0.4
|
|
|
47
47
|
* Numeric encoding for dominant emotion metric.
|
|
48
48
|
* Consumers decode using DOMINANT_EMOTION_LABELS[code].
|
|
49
49
|
*/
|
|
50
|
+
/**
|
|
51
|
+
* The entity carrying the non-numeric side of affect — what the mind is feeling,
|
|
52
|
+
* by name.
|
|
53
|
+
*
|
|
54
|
+
* Exported as a CONSTANT because the id is a contract between two files and it
|
|
55
|
+
* silently broke: `context.ts` read `state.entities.get('affective-state')`, an
|
|
56
|
+
* id nothing has ever written, so `dominantEmotion` fell back to 'neutral' in
|
|
57
|
+
* every prompt ever rendered. Measured live: a COO sitting at frustration 1.000
|
|
58
|
+
* and boredom 1.000 was told "Dominant emotion: neutral".
|
|
59
|
+
*
|
|
60
|
+
* Two string literals in two files cannot disagree if there is only one.
|
|
61
|
+
*/
|
|
62
|
+
export const AFFECT_STATE_ID = 'affect-blends'
|
|
63
|
+
export const AFFECT_STATE_TYPE = 'affect.blends'
|
|
64
|
+
|
|
50
65
|
const DOMINANT_EMOTION_CODES: Record<string, number> = {
|
|
51
66
|
'neutral': 0,
|
|
52
67
|
'fear': 1,
|
|
@@ -381,11 +396,13 @@ export class AffectiveBlender implements SimulationEngine, CognitiveEngine {
|
|
|
381
396
|
const dominantCode = DOMINANT_EMOTION_CODES[ dominant ?? 'neutral' ] ?? 0
|
|
382
397
|
commands.metrics!.push([ 'affect.dominant_emotion', dominantCode ])
|
|
383
398
|
|
|
384
|
-
//
|
|
399
|
+
// The mind's own read on what it is feeling, as an entity the executive can
|
|
400
|
+
// render. `dominantEmotion` is written as the LABEL, not the code: the code
|
|
401
|
+
// goes to metrics for telemetry, and a prompt cannot say "I feel 20".
|
|
385
402
|
commands.set!.push({
|
|
386
|
-
id:
|
|
387
|
-
type:
|
|
388
|
-
metadata: { blends },
|
|
403
|
+
id: AFFECT_STATE_ID,
|
|
404
|
+
type: AFFECT_STATE_TYPE,
|
|
405
|
+
metadata: { dominantEmotion: dominant ?? 'neutral', blends },
|
|
389
406
|
})
|
|
390
407
|
|
|
391
408
|
// 8. Track emotion history for blending detection
|
|
@@ -41,7 +41,22 @@ export interface CircadianConfig {
|
|
|
41
41
|
/** Whether external light signals entrain the oscillator */
|
|
42
42
|
entrainable?: boolean
|
|
43
43
|
/** Current simulated time of day in hours (0-24). If not provided, derived from tick. */
|
|
44
|
-
|
|
44
|
+
/**
|
|
45
|
+
* The hour of day, 0–24. A NUMBER freezes it; a FUNCTION is read every tick,
|
|
46
|
+
* which is what a host with a real clock should pass.
|
|
47
|
+
*
|
|
48
|
+
* WHY THIS IS THE HOST'S TO SUPPLY. Left unset, the oscillator derives the
|
|
49
|
+
* hour from the tick count (1 tick = 1 second), which makes it *hours since
|
|
50
|
+
* tick zero, mod 24* — and after a snapshot restore, tick zero is an
|
|
51
|
+
* arbitrary point in a previous life. A mind reasoning about whether anyone
|
|
52
|
+
* is awake right now was reasoning from that.
|
|
53
|
+
*
|
|
54
|
+
* A circadian oscillator is a BODY RHYTHM, not a clock. It models what a body
|
|
55
|
+
* does over a day; it cannot know what day it is or where on Earth it runs.
|
|
56
|
+
* What time it is, is a fact about the world — afference — and arrives the
|
|
57
|
+
* way `environment.light_level` already does: from whoever can see it.
|
|
58
|
+
*/
|
|
59
|
+
timeOfDayHours?: number | ( () => number )
|
|
45
60
|
bus?: CognitiveBus
|
|
46
61
|
}
|
|
47
62
|
|
|
@@ -51,7 +66,7 @@ export class CircadianOscillator implements SimulationEngine, CognitiveEngine {
|
|
|
51
66
|
private _periodHours: number
|
|
52
67
|
private _phaseOffsetHours: number
|
|
53
68
|
private _entrainable: boolean
|
|
54
|
-
private _timeOfDayHours?: number
|
|
69
|
+
private _timeOfDayHours?: number | ( () => number )
|
|
55
70
|
|
|
56
71
|
private _bus: CognitiveBus | null = null
|
|
57
72
|
|
|
@@ -100,8 +115,11 @@ export class CircadianOscillator implements SimulationEngine, CognitiveEngine {
|
|
|
100
115
|
events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = [],
|
|
101
116
|
commands: StateCommands = { metrics: [] }
|
|
102
117
|
|
|
103
|
-
// Determine current time of day
|
|
104
|
-
|
|
118
|
+
// Determine current time of day. A function is re-read every tick — a host
|
|
119
|
+
// clock moves; a config value does not.
|
|
120
|
+
let timeOfDay = typeof this._timeOfDayHours === 'function'
|
|
121
|
+
? normalizeHour( this._timeOfDayHours() )
|
|
122
|
+
: this._timeOfDayHours
|
|
105
123
|
|
|
106
124
|
if( timeOfDay === undefined ){
|
|
107
125
|
// Derive from tick, assuming 1 tick = 1 second
|
|
@@ -278,17 +296,28 @@ export class CircadianOscillator implements SimulationEngine, CognitiveEngine {
|
|
|
278
296
|
* Set the current time of day explicitly (for scenarios with controlled time).
|
|
279
297
|
*/
|
|
280
298
|
setTimeOfDay( hours: number ): void {
|
|
281
|
-
this._timeOfDayHours = ( hours
|
|
299
|
+
this._timeOfDayHours = normalizeHour( hours )
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Read a live clock every tick instead of holding a fixed hour. */
|
|
303
|
+
setClock( clock: ( () => number ) | null ): void {
|
|
304
|
+
this._timeOfDayHours = clock ?? undefined
|
|
282
305
|
}
|
|
283
306
|
|
|
284
307
|
/**
|
|
285
308
|
* Get the current circadian phase.
|
|
286
309
|
*/
|
|
287
310
|
getPhase(): CircadianPhase {
|
|
288
|
-
const h = this._timeOfDayHours
|
|
311
|
+
const h = typeof this._timeOfDayHours === 'function'
|
|
312
|
+
? normalizeHour( this._timeOfDayHours() )
|
|
313
|
+
: this._timeOfDayHours ?? 12
|
|
289
314
|
return h >= 6 && h < 12 ? 'morning'
|
|
290
315
|
: h >= 12 && h < 17 ? 'afternoon'
|
|
291
316
|
: h >= 17 && h < 21 ? 'evening'
|
|
292
317
|
: 'night'
|
|
293
318
|
}
|
|
294
|
-
}
|
|
319
|
+
}
|
|
320
|
+
/** 0–24, wrapping — a host clock that hands over 25 or −1 must not poison the rhythm. */
|
|
321
|
+
function normalizeHour( h: number ): number {
|
|
322
|
+
return Number.isFinite( h ) ? ( ( h % 24 ) + 24 ) % 24 : 12
|
|
323
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────
|
|
2
|
+
// src/cognition/faculties/executive.engine/action.record.ts
|
|
3
|
+
// ─────────────────────────────────────────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// What became of what I did.
|
|
6
|
+
//
|
|
7
|
+
// The executive's prompt has a `## What Became Of What I Did` section (called
|
|
8
|
+
// `## Recent Action Outcomes` until P3 renamed it after what it renders), a builder
|
|
9
|
+
// for it, and a type for its data. `context.ts` fills it by scanning
|
|
10
|
+
// `decision.record` entities that carry an `actionStatus`. Nothing in the engine
|
|
11
|
+
// has ever written `actionStatus` — it is read in exactly one place and set in
|
|
12
|
+
// none — so the section has never had a single row. Measured across every
|
|
13
|
+
// prompt a live COO received over two runs: that section appears
|
|
14
|
+
// 0 times, while `## What I've Said Lately` appears in all of them.
|
|
15
|
+
//
|
|
16
|
+
// So the mind could see what it had SAID and never what it had DONE. Its only
|
|
17
|
+
// other record of its own doing is `## What I Have Been Choosing` (`## Recent
|
|
18
|
+
// Actions` at the time), which is fed from
|
|
19
|
+
// `output.actions` — the executive's DECISIONS — and is therefore a list of
|
|
20
|
+
// intentions wearing the name of a history.
|
|
21
|
+
//
|
|
22
|
+
// A mind whose record of acting contains only intentions cannot tell an
|
|
23
|
+
// intention from an act. Live, asked directly "have you completed that?", a COO
|
|
24
|
+
// answered "Yes — it's done. I drafted the full v0.1 spec: user stories, command
|
|
25
|
+
// surface, integration points, success metrics. Posted it to FKEM." She had
|
|
26
|
+
// posted nothing; she had no effectors at all and could not have drafted
|
|
27
|
+
// anything anywhere. Her deliberation history said "I produce the scoping doc
|
|
28
|
+
// now" across twenty cycles, and nothing in her state said whether she had.
|
|
29
|
+
//
|
|
30
|
+
// This is the same distinction `pending` draws for utterances — attempting to
|
|
31
|
+
// speak is not speaking (#124) — carried to acts in general. It is written from
|
|
32
|
+
// the `action.outcome` the executive ALREADY receives (it subscribes to `*`) and
|
|
33
|
+
// from an explicit withheld signal, and it is an ordinary entity, so it
|
|
34
|
+
// snapshots and replays with the rest of the mind.
|
|
35
|
+
// ─────────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
import type { EntityInput, Tick } from '#core/types'
|
|
38
|
+
|
|
39
|
+
export const ACTION_RECORD_TYPE = 'action.record'
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* How many outcomes the mind carries.
|
|
43
|
+
*
|
|
44
|
+
* Matches the cap `context.ts` already applies when rendering, so the state
|
|
45
|
+
* holds what the prompt shows and no more — an unbounded history of everything
|
|
46
|
+
* ever done is a memory system, not a working record, and this is the latter.
|
|
47
|
+
*/
|
|
48
|
+
export const ACTION_RECORD_KEEP = 6
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* `withheld` is a first-class outcome, not a flavour of failure.
|
|
52
|
+
*
|
|
53
|
+
* The mind considered an act, formed it, and chose not to complete it. Folding
|
|
54
|
+
* that into `failed` is the mistake #123 was written to correct — it taught a
|
|
55
|
+
* COO it was bad at speaking from the times it decided not to speak.
|
|
56
|
+
*/
|
|
57
|
+
export type ActionStatus = 'completed' | 'failed' | 'withheld'
|
|
58
|
+
|
|
59
|
+
export interface ActionRecord {
|
|
60
|
+
type: string
|
|
61
|
+
status: ActionStatus
|
|
62
|
+
tick: Tick
|
|
63
|
+
targetEntityId?: string
|
|
64
|
+
/** The mind's own account of what happened, in its words where it has any. */
|
|
65
|
+
outcome: string
|
|
66
|
+
planId?: string
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Stable id — one record per (tick, act), so two acts on a tick both survive. */
|
|
70
|
+
export function actionRecordId( tick: Tick, type: string, targetEntityId?: string ): string {
|
|
71
|
+
return `action-record-${ tick }-${ type }${ targetEntityId ? `-${ targetEntityId }` : '' }`
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function actionRecordEntity( r: ActionRecord ): EntityInput {
|
|
75
|
+
return {
|
|
76
|
+
id: actionRecordId( r.tick, r.type, r.targetEntityId ),
|
|
77
|
+
type: ACTION_RECORD_TYPE,
|
|
78
|
+
metadata: { ...r },
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Read a record back off entity metadata — every field, including the ones it is easy to forget. */
|
|
83
|
+
export function readActionRecord(
|
|
84
|
+
m: ReadonlyMap<string, unknown> | Record<string, unknown> | undefined,
|
|
85
|
+
): ActionRecord | null {
|
|
86
|
+
const meta = ( m instanceof Map ? Object.fromEntries( m ) : m ?? {} ) as Record<string, unknown>
|
|
87
|
+
const type = typeof meta['type'] === 'string' ? meta['type'] as string : undefined
|
|
88
|
+
const status = meta['status']
|
|
89
|
+
if( !type || ( status !== 'completed' && status !== 'failed' && status !== 'withheld') ) return null
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
type, status,
|
|
93
|
+
tick: typeof meta['tick'] === 'number' ? meta['tick'] as number : 0,
|
|
94
|
+
targetEntityId: typeof meta['targetEntityId'] === 'string' ? meta['targetEntityId'] as string : undefined,
|
|
95
|
+
outcome: typeof meta['outcome'] === 'string' ? meta['outcome'] as string : '',
|
|
96
|
+
planId: typeof meta['planId'] === 'string' ? meta['planId'] as string : undefined,
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** The mind's recent acts, newest first. */
|
|
101
|
+
export function recentActionRecords(
|
|
102
|
+
entities: ReadonlyMap<string, { type: string; metadata?: ReadonlyMap<string, unknown> | Record<string, unknown> }>,
|
|
103
|
+
keep: number = ACTION_RECORD_KEEP,
|
|
104
|
+
): ActionRecord[] {
|
|
105
|
+
const out: ActionRecord[] = []
|
|
106
|
+
for( const [ , e ] of entities ){
|
|
107
|
+
if( e.type !== ACTION_RECORD_TYPE ) continue
|
|
108
|
+
const r = readActionRecord( e.metadata )
|
|
109
|
+
if( r ) out.push( r )
|
|
110
|
+
}
|
|
111
|
+
// Newest first, ties broken by act name so a run and its replay agree.
|
|
112
|
+
out.sort( ( a, b ) => b.tick - a.tick || ( a.type < b.type ? -1 : a.type > b.type ? 1 : 0 ) )
|
|
113
|
+
return out.slice( 0, keep )
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Records that have fallen off the end of the window — swept by the writer. */
|
|
117
|
+
export function staleActionRecordIds(
|
|
118
|
+
entities: ReadonlyMap<string, { type: string; metadata?: ReadonlyMap<string, unknown> | Record<string, unknown> }>,
|
|
119
|
+
keep: number = ACTION_RECORD_KEEP,
|
|
120
|
+
): string[] {
|
|
121
|
+
const all: Array<{ id: string; r: ActionRecord }> = []
|
|
122
|
+
for( const [ id, e ] of entities ){
|
|
123
|
+
if( e.type !== ACTION_RECORD_TYPE ) continue
|
|
124
|
+
const r = readActionRecord( e.metadata )
|
|
125
|
+
if( r ) all.push({ id, r })
|
|
126
|
+
}
|
|
127
|
+
all.sort( ( a, b ) => b.r.tick - a.r.tick || ( a.r.type < b.r.type ? -1 : a.r.type > b.r.type ? 1 : 0 ) )
|
|
128
|
+
return all.slice( keep ).map( x => x.id )
|
|
129
|
+
}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// src/cognition/faculties/executive.engine/context.ts
|
|
3
3
|
// ─────────────────────────────────────────────────────────────
|
|
4
4
|
|
|
5
|
+
import { recentActionRecords } from '#faculties/executive.engine/action.record'
|
|
6
|
+
import { AFFECT_STATE_ID } from '#faculties/affective.blender'
|
|
5
7
|
import type { ReadonlySimulationState } from '#core/types'
|
|
6
8
|
import type { GoalManager } from '#faculties/goal.manager'
|
|
7
9
|
import type { WorkingMemory } from '#faculties/working.memory'
|
|
@@ -53,7 +55,7 @@ export async function buildExecutiveContext(
|
|
|
53
55
|
|
|
54
56
|
// Working memory — getItems() returns WMItem[] sorted by activation descending.
|
|
55
57
|
// Filter types that are already rendered elsewhere in the prompt:
|
|
56
|
-
// conversation.exchange → shown in
|
|
58
|
+
// conversation.exchange → shown in What Became Of What I Did
|
|
57
59
|
// goal → shown in Active Goals
|
|
58
60
|
const WM_FILTER_TYPES = new Set([ 'conversation.exchange', 'goal' ])
|
|
59
61
|
const wmItems = ( deps.workingMemory?.getItems() ?? [] )
|
|
@@ -61,7 +63,12 @@ export async function buildExecutiveContext(
|
|
|
61
63
|
const workingMemory = wmItems.map( item => ({
|
|
62
64
|
type: item.type,
|
|
63
65
|
summary: extractSummary( item.content ),
|
|
64
|
-
activation: item.activation
|
|
66
|
+
activation: item.activation,
|
|
67
|
+
// Storing the evidence in memory and then rendering only the label would
|
|
68
|
+
// lose it just as completely, one step later. A percept entity is swept
|
|
69
|
+
// after 2 ticks and the executive fires on its own schedule, so memory is
|
|
70
|
+
// often where the mind meets an observation at all.
|
|
71
|
+
...( itemData( item.content ) !== undefined ? { data: itemData( item.content ) } : {} ),
|
|
65
72
|
}))
|
|
66
73
|
|
|
67
74
|
// Episodic memory — semantic query for relevant memories based on current goals
|
|
@@ -256,33 +263,15 @@ export async function buildExecutiveContext(
|
|
|
256
263
|
impulsivity: execParams.impulsivity ?? 0.3,
|
|
257
264
|
} : undefined
|
|
258
265
|
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
for( const entity of state.entities.values() ){
|
|
269
|
-
if( entity.type !== 'decision.record') continue
|
|
270
|
-
const actionStatus = entity.metadata?.actionStatus as string | undefined
|
|
271
|
-
if( !actionStatus ) continue
|
|
272
|
-
if( !( [ 'completed', 'failed', 'awaiting_host', 'timed_out' ] as string[] ).includes( actionStatus ) ) continue
|
|
273
|
-
|
|
274
|
-
recentActions.push({
|
|
275
|
-
type: ( entity.metadata?.actionType as string ) ?? 'unknown',
|
|
276
|
-
status: actionStatus as 'completed' | 'failed' | 'awaiting_host' | 'timed_out',
|
|
277
|
-
tick: ( entity.metadata?.executionTick as number ) ?? ( entity.metadata?.dispatchedAt as number ) ?? 0,
|
|
278
|
-
outcome: String( entity.metadata?.outcome ?? '').slice( 0, 120 ),
|
|
279
|
-
planId: entity.metadata?.planId as string | undefined,
|
|
280
|
-
})
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Sort newest-first, cap at 5
|
|
284
|
-
recentActions.sort( ( a, b ) => b.tick - a.tick )
|
|
285
|
-
const recentActionsCapped = recentActions.slice( 0, 5 )
|
|
266
|
+
// What became of what I did — this is what closes the Act → Confirm → Perceive
|
|
267
|
+
// loop the prompt's `## What Became Of What I Did` section was written for.
|
|
268
|
+
//
|
|
269
|
+
// It used to scan `decision.record` for an `actionStatus`, a field READ here
|
|
270
|
+
// and written nowhere in the engine. The section therefore rendered zero times
|
|
271
|
+
// across every prompt a live COO ever received, while `## What I've Said
|
|
272
|
+
// Lately` rendered in all of them — the mind could see what it had said and
|
|
273
|
+
// never what it had done. See `action.record.ts` for what that cost.
|
|
274
|
+
const recentActionsCapped = recentActionRecords( state.entities as never )
|
|
286
275
|
|
|
287
276
|
// Current best name for a person, from the known-entity roster.
|
|
288
277
|
const nameOf = ( keid: string ): string | undefined => {
|
|
@@ -353,7 +342,11 @@ export async function buildExecutiveContext(
|
|
|
353
342
|
sleepPressure: state.metrics.get('sleep.pressure') ?? 0,
|
|
354
343
|
stressLoad: state.metrics.get('stress.load') ?? 0,
|
|
355
344
|
circadianPhase: state.metrics.get('circadian.phase') ?? 0,
|
|
356
|
-
|
|
345
|
+
// `circadian.time_of_day`, not `time.of_day`. The oscillator has always
|
|
346
|
+
// written the first and this has always read the second, so the fallback
|
|
347
|
+
// fired on EVERY tick a Will has ever run: the prompt said `Time: 12.0h`
|
|
348
|
+
// — noon, permanently — beside a phase label that disagreed with it.
|
|
349
|
+
timeOfDay: state.metrics.get('circadian.time_of_day') ?? 12,
|
|
357
350
|
// Tonic threat representation — survives event habituation (guardrail).
|
|
358
351
|
threatLevel: state.metrics.get('threat.level') ?? 0
|
|
359
352
|
},
|
|
@@ -623,6 +616,13 @@ function mapEpisodeToMemory( ep: {
|
|
|
623
616
|
}
|
|
624
617
|
}
|
|
625
618
|
|
|
619
|
+
/** A working-memory item's host payload, when it carries one. */
|
|
620
|
+
function itemData( content: unknown ): unknown {
|
|
621
|
+
if( content && typeof content === 'object')
|
|
622
|
+
return ( content as Record<string, unknown> )['data']
|
|
623
|
+
return undefined
|
|
624
|
+
}
|
|
625
|
+
|
|
626
626
|
function extractSummary( content: unknown ): string {
|
|
627
627
|
if( typeof content === 'string')
|
|
628
628
|
return content.slice( 0, 120 )
|
|
@@ -638,8 +638,8 @@ function extractSummary( content: unknown ): string {
|
|
|
638
638
|
return String( content ?? '').slice( 0, 120 )
|
|
639
639
|
}
|
|
640
640
|
|
|
641
|
-
function extractPercepts( state: ReadonlySimulationState ): Array<{ category: string; summary: string; salience: number }> {
|
|
642
|
-
const percepts: Array<{ category: string; summary: string; salience: number }> = []
|
|
641
|
+
function extractPercepts( state: ReadonlySimulationState ): Array<{ category: string; summary: string; salience: number; data?: unknown }> {
|
|
642
|
+
const percepts: Array<{ category: string; summary: string; salience: number; data?: unknown }> = []
|
|
643
643
|
|
|
644
644
|
for( const entity of state.entities.values() ){
|
|
645
645
|
if( entity.type !== 'percept' && entity.type !== 'percept.social') continue
|
|
@@ -652,6 +652,10 @@ function extractPercepts( state: ReadonlySimulationState ): Array<{ category: st
|
|
|
652
652
|
percepts.push({
|
|
653
653
|
category: (entity.metadata?.category as string) ?? 'general',
|
|
654
654
|
summary,
|
|
655
|
+
// What the host actually sent, beside the label the engine wrote. A mind
|
|
656
|
+
// reasoning only from labels is reasoning from somebody else's summary of
|
|
657
|
+
// the evidence.
|
|
658
|
+
...( entity.metadata?.data !== undefined ? { data: entity.metadata.data } : {} ),
|
|
655
659
|
salience: (entity.metadata?.salience as number) ?? 0
|
|
656
660
|
})
|
|
657
661
|
}
|
|
@@ -672,12 +676,14 @@ function extractAffect( state: ReadonlySimulationState ): ExecutiveContext['affe
|
|
|
672
676
|
const arousal = state.metrics.get('affect.arousal') ?? 0.5
|
|
673
677
|
const dominance = state.metrics.get('affect.dominance') ?? 0.5
|
|
674
678
|
|
|
675
|
-
// Non-numeric affect data — read from the
|
|
676
|
-
//
|
|
679
|
+
// Non-numeric affect data — read from the entity AffectiveBlender writes each
|
|
680
|
+
// tick. The id comes from the writer rather than being spelled again here: this
|
|
681
|
+
// read used to look for 'affective-state', which nothing has ever written, so
|
|
682
|
+
// both values silently took their fallbacks in every prompt ever rendered.
|
|
677
683
|
let dominantEmotion = 'neutral'
|
|
678
684
|
let blends: string[] = []
|
|
679
685
|
|
|
680
|
-
const affectEntity = state.entities.get(
|
|
686
|
+
const affectEntity = state.entities.get( AFFECT_STATE_ID )
|
|
681
687
|
if( affectEntity ){
|
|
682
688
|
dominantEmotion = (affectEntity.metadata?.dominantEmotion as string) ?? 'neutral'
|
|
683
689
|
blends = (affectEntity.metadata?.blends as string[]) ?? []
|