@mindot/will 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -22
- package/dist/channels/discord.d.ts +67 -6
- package/dist/channels/discord.js +112 -6
- package/dist/channels/discord.js.map +1 -1
- package/dist/channels/whatsapp.d.ts +1 -1
- package/dist/channels/whatsapp.js +4 -1
- package/dist/channels/whatsapp.js.map +1 -1
- package/dist/cli.js +13733 -11057
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3729 -1199
- package/dist/index.js.map +1 -1
- package/dist/mcp/effectors.d.ts +1 -1
- package/dist/{will-DAW0l-lY.d.ts → will-DbDj_TEH.d.ts} +1214 -93
- package/package.json +1 -1
- package/src/channels/discord.ts +189 -11
- package/src/channels/types.ts +90 -0
- package/src/channels/whatsapp.ts +13 -4
- package/src/cli.ts +9 -4
- package/src/cognition/agency/consequence.ts +122 -1
- package/src/cognition/agency/conversation.aim.ts +260 -0
- package/src/cognition/agency/engines/action.selector.ts +85 -3
- package/src/cognition/agency/engines/affordance.synthesizer.ts +90 -1
- package/src/cognition/agency/engines/motor.schema.executor.ts +152 -10
- package/src/cognition/agency/engines/reafference.engine.ts +129 -2
- package/src/cognition/agency/proactive.communicator.ts +19 -3
- package/src/cognition/agency/reconcile.learning.ts +16 -2
- package/src/cognition/agency/restart.ts +66 -0
- package/src/cognition/agency/schemas/repertoire.ts +12 -5
- package/src/cognition/agency/selection.scoring.ts +33 -0
- package/src/cognition/agency/types.ts +35 -0
- package/src/cognition/cache/composition.ts +232 -0
- package/src/cognition/cache/deliberation.cache.ts +219 -0
- package/src/cognition/cache/fingerprint.ts +120 -0
- package/src/cognition/cache/types.ts +105 -0
- package/src/cognition/config.mirror.entities.ts +109 -1
- package/src/cognition/event.schemas.ts +22 -0
- package/src/cognition/faculties/autobiographical.narrator.ts +5 -10
- package/src/cognition/faculties/episodic.consolidator.ts +59 -3
- package/src/cognition/faculties/executive.engine/commands.ts +189 -14
- package/src/cognition/faculties/executive.engine/context.ts +67 -13
- package/src/cognition/faculties/executive.engine/deliberate.reasoning.ts +1 -1
- package/src/cognition/faculties/executive.engine/engine.ts +686 -187
- package/src/cognition/faculties/executive.engine/escalation.buffer.ts +162 -44
- package/src/cognition/faculties/executive.engine/facet.supervisor.ts +310 -65
- package/src/cognition/faculties/executive.engine/facet.ts +89 -26
- package/src/cognition/faculties/executive.engine/gating.ts +14 -14
- package/src/cognition/faculties/executive.engine/parser.ts +21 -1
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +169 -20
- package/src/cognition/faculties/executive.engine/types.ts +69 -0
- package/src/cognition/faculties/goal.manager.ts +94 -14
- package/src/cognition/faculties/known.entity.tracker.ts +267 -28
- package/src/cognition/faculties/moral.evaluator.ts +8 -3
- package/src/cognition/faculties/persona.consolidator.ts +141 -0
- package/src/cognition/faculties/reputation.tracker.ts +66 -2
- package/src/cognition/faculties/self.model.updater.ts +19 -12
- package/src/cognition/faculties/social.perception.ts +47 -3
- package/src/cognition/faculties/threat.evaluator.ts +7 -0
- package/src/cognition/faculties/working.memory.ts +10 -20
- package/src/cognition/identity.entity.ts +205 -0
- package/src/cognition/index.ts +11 -0
- package/src/cognition/memory/vector.adapter.ts +12 -3
- package/src/cognition/memory/vector.embedder.ts +54 -7
- package/src/cognition/persona.prior.ts +6 -0
- package/src/cognition/senses/audition.engine/engine.ts +404 -46
- package/src/cognition/senses/base.sense.engine.ts +1 -1
- package/src/cognition/senses/index.ts +12 -0
- package/src/cognition/social.identity.ts +273 -0
- package/src/cognition/utilities/token.tracker.ts +246 -98
- package/src/core/orchestrator.ts +38 -0
- package/src/host/boot.ts +78 -22
- package/src/index.ts +35 -0
- package/src/llm/index.ts +415 -97
- package/src/llm/routing.ts +204 -0
- package/src/llm/summarizer.ts +5 -1
- package/src/llm/wire.contracts.ts +19 -0
- package/src/pma/index.ts +67 -53
- package/src/runners/thin-shim.runner.ts +18 -6
- package/src/sdk/will.ts +121 -22
- package/src/stem/assembly.audit.ts +1 -0
- package/src/stem/guards/identity.coherence.ts +17 -6
- package/src/stem/index.ts +82 -5
- package/src/stem/mind.ts +327 -79
- package/src/stem/policy/arbiter.ts +49 -14
- package/src/stem/policy/rule.table.ts +2 -2
- package/src/stem/tracts/effector.controller.ts +56 -9
- package/src/stem/tracts/outbox.writer.ts +40 -2
- package/src/cognition/faculties/executive.engine/messages.ts +0 -102
|
@@ -53,6 +53,18 @@ export interface FacetReport {
|
|
|
53
53
|
contextId?: string
|
|
54
54
|
/** Optional dynamic instructions to append to the user message */
|
|
55
55
|
instructions?: string
|
|
56
|
+
/**
|
|
57
|
+
* Attend to something else for THIS report only, leaving the facet's standing
|
|
58
|
+
* focus untouched.
|
|
59
|
+
*
|
|
60
|
+
* A facet's focus was a single mutable field, so anything that wanted a live
|
|
61
|
+
* facet to consider one different thing had to `setFocus()` first — clobbering
|
|
62
|
+
* whatever the facet was already set up for, and racing with any report already
|
|
63
|
+
* queued behind it. That is why a self-initiated message to someone the mind was
|
|
64
|
+
* ALREADY talking to had to be composed by a separate, transient facet that could
|
|
65
|
+
* not see the live conversation at all.
|
|
66
|
+
*/
|
|
67
|
+
focus?: FocusSection
|
|
56
68
|
}
|
|
57
69
|
|
|
58
70
|
export interface FacetDecision {
|
|
@@ -63,6 +75,16 @@ export interface FacetDecision {
|
|
|
63
75
|
decision: unknown
|
|
64
76
|
reasoning: string
|
|
65
77
|
confidence: number
|
|
78
|
+
/**
|
|
79
|
+
* Sim tick this decision was reasoned at.
|
|
80
|
+
*
|
|
81
|
+
* The facet has always known it and never passed it on, so a subscriber writing
|
|
82
|
+
* state in response had no deterministic clock and reached for a process-local
|
|
83
|
+
* counter instead — which resets on restart and collides. Never wall-clock: this
|
|
84
|
+
* reaches ids that live in state, and a wall-clock id makes recorded and replayed
|
|
85
|
+
* runs diverge (R2).
|
|
86
|
+
*/
|
|
87
|
+
tick: number
|
|
66
88
|
}
|
|
67
89
|
|
|
68
90
|
export type FacetEventListener = ( decision: FacetDecision ) => void
|
|
@@ -134,6 +156,19 @@ export class ExecutiveFacet {
|
|
|
134
156
|
private _facetReasoningHistory: string[] = []
|
|
135
157
|
private _masterSyncHistory: string[] = []
|
|
136
158
|
|
|
159
|
+
/**
|
|
160
|
+
* This facet's own prior reasoning, for the supervisor to carry to whichever
|
|
161
|
+
* facet takes over the same keyed thread. Continuity belongs to the thread, not
|
|
162
|
+
* to the instance holding it: a facet reaped mid-conversation used to take the
|
|
163
|
+
* mind's private thinking about that person with it.
|
|
164
|
+
*/
|
|
165
|
+
get reasoningHistory(): string[] { return [ ...this._facetReasoningHistory ] }
|
|
166
|
+
|
|
167
|
+
/** Resume a thread's reasoning on spawn (supervisor-only; see FacetSpawnDeps.key). */
|
|
168
|
+
restoreReasoningHistory( history: string[] ): void {
|
|
169
|
+
this._facetReasoningHistory = [ ...history ]
|
|
170
|
+
}
|
|
171
|
+
|
|
137
172
|
/** Confidence of this facet's *previous* decision — a dual-process gate signal. */
|
|
138
173
|
private _lastConfidence = 0.5
|
|
139
174
|
|
|
@@ -260,9 +295,7 @@ export class ExecutiveFacet {
|
|
|
260
295
|
private _launchReason( report: FacetReport ): void {
|
|
261
296
|
this._inflight++
|
|
262
297
|
this._reason( report )
|
|
263
|
-
.catch( err =>
|
|
264
|
-
logger.error(`[executive.facet] ${this.facetId} reasoning error:`, err )
|
|
265
|
-
)
|
|
298
|
+
.catch( err => logger.error(`[executive.facet] ${this.facetId} reasoning error:`, err ) )
|
|
266
299
|
.finally( () => {
|
|
267
300
|
this._inflight--
|
|
268
301
|
this.markActive( ( this._currentStateRef?.tick as number ) ?? this._lastActiveTick )
|
|
@@ -322,9 +355,14 @@ export class ExecutiveFacet {
|
|
|
322
355
|
|
|
323
356
|
logger.info(`[executive.facet] ${this.facetId} synced from master (tick=${payload.tick})`)
|
|
324
357
|
|
|
325
|
-
// Store
|
|
358
|
+
// Store the wider reasoning for context in the next report().
|
|
359
|
+
//
|
|
360
|
+
// Rendered in the FIRST PERSON and with no mention of a "master": this is the
|
|
361
|
+
// same mind's thinking arriving from where the rest of its attention has been,
|
|
362
|
+
// not a report from a superior. Naming it "Master sync" gave the facet a second
|
|
363
|
+
// party to address — and it addressed it, out loud, on the outbound channel.
|
|
326
364
|
if( payload.reasoning )
|
|
327
|
-
this._masterSyncHistory.push(`[
|
|
365
|
+
this._masterSyncHistory.push(`[tick ${payload.tick}] ${payload.reasoning.slice( 0, 400 )}`)
|
|
328
366
|
|
|
329
367
|
// Keep only last 5 sync entries
|
|
330
368
|
if( this._masterSyncHistory.length > 5 )
|
|
@@ -338,7 +376,11 @@ export class ExecutiveFacet {
|
|
|
338
376
|
if( !this._currentStateRef )
|
|
339
377
|
throw new Error(`[executive.facet] ${this.facetId} no state reference available`)
|
|
340
378
|
|
|
341
|
-
if
|
|
379
|
+
// This report's focus: its own if it carried one, else the facet's standing
|
|
380
|
+
// one. A per-report focus never mutates `_currentFocus`, so a live thread can
|
|
381
|
+
// be asked to attend to one different thing and come straight back.
|
|
382
|
+
const reportFocus = report.focus ?? this._currentFocus
|
|
383
|
+
if( !reportFocus )
|
|
342
384
|
throw new Error(`[executive.facet] ${this.facetId} no focus set. Call setFocus() before report().`)
|
|
343
385
|
|
|
344
386
|
const currentState = this._currentStateRef
|
|
@@ -346,7 +388,7 @@ export class ExecutiveFacet {
|
|
|
346
388
|
// Build fresh context from current state
|
|
347
389
|
// A focus may supply a recall query (e.g. the live conversation message) to
|
|
348
390
|
// drive the single "## Relevant Memories" section — one recall surface (§5).
|
|
349
|
-
const execContext = await PromptFactory.buildFreshContext( this._contextDeps, currentState,
|
|
391
|
+
const execContext = await PromptFactory.buildFreshContext( this._contextDeps, currentState, reportFocus.recallQuery )
|
|
350
392
|
|
|
351
393
|
const qualityModulation = PromptFactory.computeQualityModulation( currentState )
|
|
352
394
|
const epistemicUncertainty = PromptFactory.computeEpistemicUncertainty( execContext, currentState )
|
|
@@ -355,10 +397,10 @@ export class ExecutiveFacet {
|
|
|
355
397
|
// the appropriate content via setFocus()
|
|
356
398
|
const focus: FocusSection = this._masterSyncHistory.length > 0
|
|
357
399
|
? {
|
|
358
|
-
...
|
|
359
|
-
content: `${
|
|
400
|
+
...reportFocus,
|
|
401
|
+
content: `${reportFocus.content}\n\n## What I've Been Turning Over\n${this._masterSyncHistory.join('\n')}`
|
|
360
402
|
}
|
|
361
|
-
:
|
|
403
|
+
: reportFocus
|
|
362
404
|
|
|
363
405
|
// Build system prompt using PromptFactory — same schema as master, [REPLY] gated out.
|
|
364
406
|
const systemPrompt = PromptFactory.buildSystemPrompt( {
|
|
@@ -377,7 +419,7 @@ export class ExecutiveFacet {
|
|
|
377
419
|
// isn't cold on each cycle. Injected before the caller's instructions so the
|
|
378
420
|
// caller content always comes last (highest recency bias from the LLM).
|
|
379
421
|
const continuityBlock = this._facetReasoningHistory.length > 0
|
|
380
|
-
? `## My
|
|
422
|
+
? `## Where My Thinking Had Got To\n${this._facetReasoningHistory.join('\n')}`
|
|
381
423
|
: ''
|
|
382
424
|
|
|
383
425
|
const reportContent = [
|
|
@@ -399,7 +441,7 @@ export class ExecutiveFacet {
|
|
|
399
441
|
stressLoad: currentState.metrics.get('stress.load') ?? 0,
|
|
400
442
|
// A facet's "stakes-bearing moment" is a live message awaiting reply (conversation
|
|
401
443
|
// facets set focus.recallQuery to it); planning/other facets rely on uncertainty.
|
|
402
|
-
hasPendingMessage: !!
|
|
444
|
+
hasPendingMessage: !!reportFocus.recallQuery,
|
|
403
445
|
}, deliberateThreshold )
|
|
404
446
|
|
|
405
447
|
let ideationCandidates: IdeationCandidate[] | undefined
|
|
@@ -410,7 +452,6 @@ export class ExecutiveFacet {
|
|
|
410
452
|
state: currentState,
|
|
411
453
|
qualityModulation,
|
|
412
454
|
epistemicUncertainty,
|
|
413
|
-
pendingMessages: [],
|
|
414
455
|
focus,
|
|
415
456
|
deps: this._promptDeps,
|
|
416
457
|
recentActionTypes: [],
|
|
@@ -424,7 +465,14 @@ export class ExecutiveFacet {
|
|
|
424
465
|
ideationUserMessage,
|
|
425
466
|
tick: currentState.tick,
|
|
426
467
|
proposeTemperature,
|
|
427
|
-
meta: {
|
|
468
|
+
meta: {
|
|
469
|
+
category: 'executive',
|
|
470
|
+
attribute: 'facet',
|
|
471
|
+
process: 'ideation',
|
|
472
|
+
function: reportFocus.function ?? '-',
|
|
473
|
+
scope: this.facetId,
|
|
474
|
+
demand: processSelection.effortScore
|
|
475
|
+
},
|
|
428
476
|
} )
|
|
429
477
|
logger.info(
|
|
430
478
|
`[executive.facet] ${this.facetId} ◆ deliberate propose tick=${currentState.tick} ` +
|
|
@@ -437,7 +485,6 @@ export class ExecutiveFacet {
|
|
|
437
485
|
state: currentState,
|
|
438
486
|
qualityModulation,
|
|
439
487
|
epistemicUncertainty,
|
|
440
|
-
pendingMessages: [],
|
|
441
488
|
focus,
|
|
442
489
|
deps: this._promptDeps,
|
|
443
490
|
recentActionTypes: [],
|
|
@@ -465,11 +512,20 @@ export class ExecutiveFacet {
|
|
|
465
512
|
// Use streaming call when a per-facet chunk handler is registered —
|
|
466
513
|
// this enables entity-scoped token delivery (e.g. AuditionEngine SSE).
|
|
467
514
|
// Falls back to regular call when no handler is present.
|
|
515
|
+
// MODEL_ROUTING W0 — same effort gate as master, so a facet's demand is
|
|
516
|
+
// measured on the identical scale (a live message awaiting reply is this
|
|
517
|
+
// focus's stakes-bearing moment, and already weighs into the score).
|
|
468
518
|
const facetMeta: LLMCallMeta = {
|
|
469
519
|
category: 'executive',
|
|
470
520
|
attribute: 'facet',
|
|
471
|
-
|
|
521
|
+
process: 'decision',
|
|
522
|
+
// A focus that declares no function is making its decision call, the
|
|
523
|
+
// facet's analogue of master's 'decision'. This previously fell back to
|
|
524
|
+
// 'facet' — an *attribute* value, which quietly created a bogus bucket
|
|
525
|
+
// in the by-function cost breakdown. The typed axes caught it.
|
|
526
|
+
function: reportFocus.function ?? '-',
|
|
472
527
|
scope: this.facetId,
|
|
528
|
+
demand: processSelection.effortScore,
|
|
473
529
|
}
|
|
474
530
|
const result = this._chunkHandler
|
|
475
531
|
? await this._llmDirector.callStream( systemPrompt, userMessage, currentState.tick, this._chunkHandler, undefined, facetMeta )
|
|
@@ -547,7 +603,8 @@ export class ExecutiveFacet {
|
|
|
547
603
|
respondingToType: report.type,
|
|
548
604
|
decision: this._extractDecisionPayload( output, focus ),
|
|
549
605
|
reasoning: output.reasoning,
|
|
550
|
-
confidence: output.confidence
|
|
606
|
+
confidence: output.confidence,
|
|
607
|
+
tick: currentState.tick as unknown as number
|
|
551
608
|
}
|
|
552
609
|
|
|
553
610
|
// Promote subscriber-visible fields from the decision object to the event payload
|
|
@@ -558,7 +615,7 @@ export class ExecutiveFacet {
|
|
|
558
615
|
? decision.decision as Record<string, unknown>
|
|
559
616
|
: {}
|
|
560
617
|
|
|
561
|
-
this._bus.publish(
|
|
618
|
+
this._bus.publish({
|
|
562
619
|
type: 'executive.facet.progress',
|
|
563
620
|
version: 1,
|
|
564
621
|
sourceEngine: `executive-facet-${this.facetId}`,
|
|
@@ -579,7 +636,7 @@ export class ExecutiveFacet {
|
|
|
579
636
|
contextId: report.contextId,
|
|
580
637
|
tick: currentState.tick
|
|
581
638
|
}
|
|
582
|
-
}
|
|
639
|
+
})
|
|
583
640
|
|
|
584
641
|
// Conscious learning about others — route name/feeling to known.entity.tracker (the
|
|
585
642
|
// dossier owner) the same way the master does, so routine (un-escalated) conversation
|
|
@@ -587,15 +644,17 @@ export class ExecutiveFacet {
|
|
|
587
644
|
const keUpdates = dec[ 'knownEntityUpdates' ] as ExecutiveOutputFull['knownEntityUpdates'] | undefined
|
|
588
645
|
if( keUpdates )
|
|
589
646
|
for( const u of keUpdates )
|
|
590
|
-
if( u.keid && u.keid !== 'agent-self' && ( u.name || u.feeling != null ) )
|
|
591
|
-
this._bus.publish(
|
|
592
|
-
type: 'known.entity.learned',
|
|
647
|
+
if( u.keid && u.keid !== 'agent-self' && ( u.name || u.feeling != null || u.sameAs ) )
|
|
648
|
+
this._bus.publish({
|
|
649
|
+
type: 'known.entity.learned',
|
|
650
|
+
version: 1,
|
|
593
651
|
sourceEngine: `executive-facet-${this.facetId}`,
|
|
594
|
-
salience:
|
|
595
|
-
|
|
652
|
+
salience: u.sameAs ? 0.7 : 0.5,
|
|
653
|
+
payload: { keid: u.keid, name: u.name, feeling: u.feeling, sameAs: u.sameAs }
|
|
654
|
+
})
|
|
596
655
|
|
|
597
656
|
// Sync back to master
|
|
598
|
-
this._bus.publish(
|
|
657
|
+
this._bus.publish({
|
|
599
658
|
type: 'executive.facet.sync',
|
|
600
659
|
version: 1,
|
|
601
660
|
sourceEngine: `executive-facet-${this.facetId}`,
|
|
@@ -605,9 +664,13 @@ export class ExecutiveFacet {
|
|
|
605
664
|
reasoning: output.reasoning,
|
|
606
665
|
confidence: output.confidence,
|
|
607
666
|
actionTypes: output.actions.map( a => a.type ),
|
|
667
|
+
// WHO this facet is engaged with (FocusSection.subject*). The master keeps
|
|
668
|
+
// the singular seat, so it needs the person, not just the facet number.
|
|
669
|
+
...( focus.subjectEntityId ? { subjectEntityId: focus.subjectEntityId } : {} ),
|
|
670
|
+
...( focus.subjectName ? { subjectName: focus.subjectName } : {} ),
|
|
608
671
|
tick: currentState.tick
|
|
609
672
|
}
|
|
610
|
-
}
|
|
673
|
+
})
|
|
611
674
|
|
|
612
675
|
// Notify all listeners (PlanningEngine, AuditionEngine, etc.).
|
|
613
676
|
//
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// src/cognition/faculties/executive.engine/gating.ts
|
|
3
3
|
// ─────────────────────────────────────────────────────────────
|
|
4
4
|
|
|
5
|
-
import type { PendingMessage } from '#faculties/executive.engine/types'
|
|
6
5
|
import type { Tick, ReadonlySimulationState } from '#core/types'
|
|
7
6
|
import type { GenerativeModel } from '#cognition/generative.model'
|
|
8
7
|
import {
|
|
@@ -11,23 +10,28 @@ import {
|
|
|
11
10
|
} from '#faculties/executive.engine/config'
|
|
12
11
|
import type { CognitiveEvent } from '#cognition/bus'
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Something in the world is loud enough to wake a resting mind.
|
|
15
|
+
*
|
|
16
|
+
* Percept salience is the whole test now. Two other wake sources used to sit here
|
|
17
|
+
* and neither could ever fire: an unprocessed `communication` entity (a type
|
|
18
|
+
* nothing has ever written) and a non-empty pending-message queue (never pushed
|
|
19
|
+
* to, and the current design forbids it — inbound reaches a facet, and the master
|
|
20
|
+
* learns of it through `executive.facet.handoff` → a high-salience percept, which
|
|
21
|
+
* this catches). Both removed with the queue itself (#114).
|
|
22
|
+
*/
|
|
23
|
+
function hasPendingInstructions( state: ReadonlySimulationState ): boolean {
|
|
24
|
+
for( const entity of state.entities.values() )
|
|
16
25
|
if( entity.type === 'percept' || entity.type === 'percept.social'){
|
|
17
26
|
const salience = (entity.metadata?.salience as number) ?? 0
|
|
18
27
|
if( salience > 0.7 ) return true
|
|
19
28
|
}
|
|
20
29
|
|
|
21
|
-
|
|
22
|
-
return true
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return pendingMessages.length > 0
|
|
30
|
+
return false
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
export interface GatingDependencies {
|
|
29
34
|
generativeModel: GenerativeModel
|
|
30
|
-
pendingMessages: PendingMessage[]
|
|
31
35
|
hasPendingWork: boolean
|
|
32
36
|
}
|
|
33
37
|
|
|
@@ -110,7 +114,7 @@ export function evaluateGating(
|
|
|
110
114
|
if( isResting > 0 || isSleeping > 0 ){
|
|
111
115
|
const
|
|
112
116
|
significantEvent = novelty > 0.8,
|
|
113
|
-
hasPending = hasPendingInstructions( state
|
|
117
|
+
hasPending = hasPendingInstructions( state )
|
|
114
118
|
|
|
115
119
|
if( significantEvent || hasPending )
|
|
116
120
|
return {
|
|
@@ -142,10 +146,6 @@ export function evaluateGating(
|
|
|
142
146
|
if( energy < 15 )
|
|
143
147
|
return { shouldActivate: true, reason: 'energy_critical', cleanedBuffer }
|
|
144
148
|
|
|
145
|
-
// ── Pending messages — always fire ────────────────────────
|
|
146
|
-
if( deps.pendingMessages.length > 0 )
|
|
147
|
-
return { shouldActivate: true, reason: 'pending_message', cleanedBuffer }
|
|
148
|
-
|
|
149
149
|
// ── Normal interval scheduling ────────────────────────────
|
|
150
150
|
if( tick - gs.lastExecutiveTick >= gs.executiveInterval ){
|
|
151
151
|
// Prediction-error gating — uses GenerativeModel.observe() which returns { gated }
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// ─────────────────────────────────────────────────────────────
|
|
4
4
|
|
|
5
5
|
import { logger } from '#core/logger'
|
|
6
|
-
import { REPLY_TEXT_TAG } from '#llm/wire.contracts'
|
|
6
|
+
import { REPLY_TEXT_TAG, NO_MESSAGE_TAG, NO_MESSAGE_OPEN } from '#llm/wire.contracts'
|
|
7
7
|
import type { ReadonlySimulationState } from '#core/types'
|
|
8
8
|
import type { ExecutiveOutputFull, ExecutiveOutputMinimal, IdeationCandidate, IdeationOutput } from '#faculties/executive.engine/types'
|
|
9
9
|
|
|
@@ -68,6 +68,18 @@ export function parseResponse(
|
|
|
68
68
|
const replyText = extractTextBlock( responseText, REPLY_TEXT_TAG )
|
|
69
69
|
if( replyText ) full.replyText = replyText
|
|
70
70
|
|
|
71
|
+
// A declared decision not to speak. Its own field rather than an empty
|
|
72
|
+
// replyText, because "I chose silence" and "the facet produced nothing" are
|
|
73
|
+
// different events: one is a decision worth recording, the other a failure worth
|
|
74
|
+
// noticing, and collapsing them hides both.
|
|
75
|
+
// Presence of the MARKER is the decision — not the content, which may legitimately
|
|
76
|
+
// be empty. `extractTextBlock` returns null for an absent tag AND for a present
|
|
77
|
+
// but empty one, so it cannot tell them apart; testing it for undefined (as this
|
|
78
|
+
// first did) is true in every case and made the mind mute on every path. The
|
|
79
|
+
// integration suite caught it; a live boot would have caught it as total silence.
|
|
80
|
+
if( responseText.includes( NO_MESSAGE_OPEN ) )
|
|
81
|
+
full.noMessage = extractTextBlock( responseText, NO_MESSAGE_TAG ) ?? '(no reason given)'
|
|
82
|
+
|
|
71
83
|
return full
|
|
72
84
|
}
|
|
73
85
|
|
|
@@ -193,6 +205,7 @@ function parseTaggedBlocks(
|
|
|
193
205
|
'GOALS_REPRIORITIZE',
|
|
194
206
|
'EFFECTORS',
|
|
195
207
|
'SELF_OBS',
|
|
208
|
+
'SKILLS',
|
|
196
209
|
],
|
|
197
210
|
found = taggedTypes.filter( t => text.includes(`[${t}]`) )
|
|
198
211
|
if( found.length > 0 ){
|
|
@@ -299,6 +312,13 @@ function parseTaggedBlocks(
|
|
|
299
312
|
}
|
|
300
313
|
catch { /* ignore */ }
|
|
301
314
|
|
|
315
|
+
// Named compound skills — the creation seam for learned composites (#114).
|
|
316
|
+
try {
|
|
317
|
+
const skillsData = parseJsonBlock('SKILLS') as { newSkills?: ExecutiveOutputFull['newSkills'] } | null
|
|
318
|
+
if( skillsData?.newSkills ) full.newSkills = skillsData.newSkills
|
|
319
|
+
}
|
|
320
|
+
catch { /* ignore */ }
|
|
321
|
+
|
|
302
322
|
// [ACK] and legacy [REPLY] blocks are no longer emitted by any engine.
|
|
303
323
|
// [ACK] — removed with the legacy master communication path (Phase 13.8).
|
|
304
324
|
// [REPLY] — replaced by [REPLY_TEXT] plain-text block in conversation facets.
|