@mindot/will 0.3.0 → 0.5.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 +63 -21
- package/dist/channels/discord.d.ts +69 -0
- package/dist/channels/discord.js +193 -0
- package/dist/channels/discord.js.map +1 -0
- package/dist/channels/whatsapp.d.ts +72 -0
- package/dist/channels/whatsapp.js +252 -0
- package/dist/channels/whatsapp.js.map +1 -0
- package/dist/cli.js +904 -356
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +141 -141
- package/dist/index.js +441 -342
- package/dist/index.js.map +1 -1
- package/dist/mcp/effectors.d.ts +1 -1
- package/dist/types-E9-HV-SW.d.ts +11 -0
- package/dist/{will-B5eKs3Wv.d.ts → will-BDq-TMQr.d.ts} +4013 -3916
- package/package.json +17 -3
- package/src/channels/discord.ts +214 -0
- package/src/channels/roster.ts +87 -0
- package/src/channels/types.ts +46 -0
- package/src/channels/whatsapp.ts +318 -0
- package/src/cli.ts +57 -9
- package/src/cognition/agency/engines/deliberation.engine.ts +7 -7
- package/src/cognition/agency/execution.primitives.ts +11 -11
- package/src/cognition/agency/proactive.communicator.ts +8 -8
- package/src/cognition/config.mirror.entities.ts +2 -2
- package/src/cognition/conversation.memory.ts +1 -1
- package/src/cognition/faculties/executive.engine/commands.ts +7 -15
- package/src/cognition/faculties/executive.engine/engine.ts +66 -35
- package/src/cognition/faculties/executive.engine/escalation.buffer.ts +1 -1
- package/src/cognition/faculties/executive.engine/facet.ts +1 -1
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +76 -61
- package/src/cognition/faculties/executive.engine/types.ts +1 -1
- package/src/cognition/faculties/introspection.engine.ts +1 -2
- package/src/cognition/faculties/planning.engine/engine.ts +38 -1
- package/src/cognition/faculties/planning.engine/plan.store.ts +42 -0
- package/src/cognition/faculties/planning.engine/plan.supervision.ts +7 -7
- package/src/cognition/faculties/theory.of.mind.ts +2 -2
- package/src/cognition/senses/audition.engine/engine.ts +21 -21
- package/src/cognition/utilities/token.tracker.ts +6 -0
- package/src/host/boot.ts +95 -7
- package/src/llm/index.ts +75 -25
- package/src/llm/summarizer.ts +2 -2
- package/src/profiles/companion.ts +14 -14
- package/src/profiles/company-brain.ts +19 -19
- package/src/profiles/customer-service.ts +17 -17
- package/src/profiles/game-npc.ts +10 -10
- package/src/profiles/index.ts +2 -2
- package/src/profiles/smart-home.ts +16 -16
- package/src/runners/outreach.runner.ts +6 -9
- package/src/runners/social.runner.ts +1 -4
- package/src/runners/thin-shim.runner.ts +4 -6
- package/src/sdk/will.ts +42 -16
- package/src/stem/guards/identity.coherence.ts +9 -6
- package/src/stem/guards/identity.guard.ts +20 -9
- package/src/stem/index.ts +7 -7
- package/src/stem/mind.ts +182 -98
- package/src/stem/tracts/outbox.controller.ts +2 -2
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
type GatingState
|
|
61
61
|
} from '#faculties/executive.engine/gating'
|
|
62
62
|
import { LLMDirector } from '#llm/index'
|
|
63
|
-
import type
|
|
63
|
+
import { defaultModelFor, type LLMProvider } from '#llm/index'
|
|
64
64
|
import { buildFallbackOutput, parseResponse } from '#faculties/executive.engine/parser'
|
|
65
65
|
import { selectProcess, ideationTemperature, DELIBERATE_THRESHOLD } from '#faculties/executive.engine/effort.gate'
|
|
66
66
|
import { proposeCandidates } from '#faculties/executive.engine/deliberate.reasoning'
|
|
@@ -145,8 +145,14 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
|
|
|
145
145
|
|
|
146
146
|
// ── Injected dependencies ──────────────────────────────────
|
|
147
147
|
private _willId: string | null = null
|
|
148
|
-
/** Per-Will model
|
|
149
|
-
private
|
|
148
|
+
/** Per-Will, per-role model ids (config.model, resolved in mind.ts). */
|
|
149
|
+
private _models: { executive: string | null; summarizer: string | null; deliberation: string | null; conversation: string | null } =
|
|
150
|
+
{ executive: null, summarizer: null, deliberation: null, conversation: null }
|
|
151
|
+
/** Per-Will LLM transport overrides (config.llm) — env fallbacks apply per field. */
|
|
152
|
+
private _llm: { provider?: string; apiKey?: string; baseUrl?: string; maxOutputTokens?: number; timeoutMs?: number } | null = null
|
|
153
|
+
/** One director per distinct model — same config, different model. Shared
|
|
154
|
+
* tracker/recorder/willId, so ledger attribution and replay hold per role. */
|
|
155
|
+
private _directorCache = new Map<string, LLMDirector>()
|
|
150
156
|
private _workingMemory: WorkingMemory | null = null
|
|
151
157
|
private _goalManager: GoalManager | null = null
|
|
152
158
|
private _episodicConsolidator: EpisodicConsolidator | null = null
|
|
@@ -261,8 +267,13 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
|
|
|
261
267
|
|
|
262
268
|
set willId( willId: string ){ this._willId = willId }
|
|
263
269
|
|
|
264
|
-
/** Per-Will
|
|
265
|
-
set
|
|
270
|
+
/** Per-Will role models (config.model, resolved). Set before the first tick. */
|
|
271
|
+
set models( m: { executive: string | null; summarizer: string | null; deliberation: string | null; conversation: string | null } ){ this._models = m }
|
|
272
|
+
get models(): { executive: string | null; summarizer: string | null; deliberation: string | null; conversation: string | null } { return this._models }
|
|
273
|
+
/** Per-Will LLM transport overrides (config.llm). Set before the first tick. */
|
|
274
|
+
set llm( c: { provider?: string; apiKey?: string; baseUrl?: string; maxOutputTokens?: number; timeoutMs?: number } | null ){ this._llm = c }
|
|
275
|
+
/** The executive-role model id (back-compat read). */
|
|
276
|
+
get modelId(): string | null { return this._models.executive }
|
|
266
277
|
|
|
267
278
|
// ── Public surface ─────────────────────────────────────────
|
|
268
279
|
|
|
@@ -289,13 +300,49 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
|
|
|
289
300
|
* The caller (PlanningEngine) uses report() to push step outcomes
|
|
290
301
|
* and subscribe() to receive facet decisions.
|
|
291
302
|
*/
|
|
292
|
-
|
|
303
|
+
/** Get-or-create the director for a model id (shared config, per-Will). */
|
|
304
|
+
private _directorFor( model: string ): LLMDirector {
|
|
305
|
+
let d = this._directorCache.get( model )
|
|
306
|
+
if( !d ){
|
|
307
|
+
// Per-Will transport overrides first (BYO keys), env per field otherwise.
|
|
308
|
+
d = new LLMDirector( {
|
|
309
|
+
willId: this._willId!,
|
|
310
|
+
model,
|
|
311
|
+
maxOutputTokens: this._llm?.maxOutputTokens ?? parseInt( process.env.WILL_MAX_OUTPUT_TOKENS ?? '8096' ),
|
|
312
|
+
// Provider-agnostic key; falls back to ANTHROPIC_API_KEY for back-compat.
|
|
313
|
+
apiKey: this._llm?.apiKey ?? process.env.WILL_LLM_API_KEY ?? process.env.ANTHROPIC_API_KEY ?? '',
|
|
314
|
+
provider: ( this._llm?.provider ?? process.env.WILL_LLM_PROVIDER ?? 'anthropic' ) as LLMProvider,
|
|
315
|
+
// Optional base-URL override (e.g. Ollama / Azure / self-hosted). Unset →
|
|
316
|
+
// the director uses the provider's official endpoint.
|
|
317
|
+
baseUrl: this._llm?.baseUrl ?? process.env.WILL_LLM_BASE_URL ?? process.env.OPENAI_BASE_URL,
|
|
318
|
+
timeoutMs: this._llm?.timeoutMs ?? ( process.env.WILL_LLM_TIMEOUT_MS ? parseInt( process.env.WILL_LLM_TIMEOUT_MS ) : undefined ),
|
|
319
|
+
sessionLogger: this._sessionLogger,
|
|
320
|
+
mock: this._testMode,
|
|
321
|
+
// Inject the per-Will tracker (R4) so live calls record usage here, not
|
|
322
|
+
// through a process global. null is fine — the director skips recording.
|
|
323
|
+
tokenTracker: this._tokenTracker,
|
|
324
|
+
} )
|
|
325
|
+
this._directorCache.set( model, d )
|
|
326
|
+
}
|
|
327
|
+
return d
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
spawnFacet( role?: 'deliberation' | 'conversation' | 'outreach' | 'supervision' ): { attention: 'available' | 'full', handle?: ExecutiveFacetHandle } {
|
|
293
331
|
// Delegate to FacetSupervisor (R5-g-3), passing the current engine
|
|
294
332
|
// attachments. The supervisor owns the registry + attention budget and
|
|
295
333
|
// performs the throw-checks on bus / director / state ref.
|
|
334
|
+
// A role with its own configured model gets that role's director; every
|
|
335
|
+
// other facet shares the executive's (one self, role-appropriate depth).
|
|
336
|
+
// Outreach speaks with the conversation voice; supervision thinks with the
|
|
337
|
+
// executive's depth.
|
|
338
|
+
const roleModel =
|
|
339
|
+
role === 'deliberation' ? this._models.deliberation :
|
|
340
|
+
role === 'conversation' || role === 'outreach' ? this._models.conversation :
|
|
341
|
+
null
|
|
342
|
+
const director = roleModel && this._llmDirector ? this._directorFor( roleModel ) : this._llmDirector
|
|
296
343
|
return this._facetSupervisor.spawn( {
|
|
297
344
|
bus: this._bus,
|
|
298
|
-
llmDirector:
|
|
345
|
+
llmDirector: director,
|
|
299
346
|
stateRef: this._lastStateRef,
|
|
300
347
|
willId: this._willId,
|
|
301
348
|
inbox: this._inbox,
|
|
@@ -386,31 +433,15 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
|
|
|
386
433
|
this._gatingState.executiveInterval = rtConfig.executiveInterval
|
|
387
434
|
this._gatingState.cooldownTicks = rtConfig.cooldownTicks
|
|
388
435
|
|
|
389
|
-
// Initialize LLM
|
|
436
|
+
// Initialize LLM directors if not yet done (requires willId). One director
|
|
437
|
+
// per distinct role model; roles that share a model share the instance.
|
|
390
438
|
if( !this._llmDirector && this._willId ){
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
maxOutputTokens: parseInt( process.env.WILL_MAX_OUTPUT_TOKENS ?? '8096' ),
|
|
398
|
-
// Provider-agnostic key; falls back to ANTHROPIC_API_KEY for back-compat.
|
|
399
|
-
apiKey: process.env.WILL_LLM_API_KEY ?? process.env.ANTHROPIC_API_KEY ?? '',
|
|
400
|
-
provider: ( process.env.WILL_LLM_PROVIDER ?? 'anthropic' ) as LLMProvider,
|
|
401
|
-
// Optional base-URL override (e.g. Ollama / Azure / self-hosted). Unset →
|
|
402
|
-
// the director uses the provider's official endpoint.
|
|
403
|
-
baseUrl: process.env.WILL_LLM_BASE_URL ?? process.env.OPENAI_BASE_URL,
|
|
404
|
-
timeoutMs: process.env.WILL_LLM_TIMEOUT_MS ? parseInt( process.env.WILL_LLM_TIMEOUT_MS ) : undefined,
|
|
405
|
-
sessionLogger: this._sessionLogger,
|
|
406
|
-
mock: this._testMode,
|
|
407
|
-
// Inject the per-Will tracker (R4) so live calls record usage here, not
|
|
408
|
-
// through a process global. null is fine — the director skips recording.
|
|
409
|
-
tokenTracker: this._tokenTracker,
|
|
410
|
-
} )
|
|
411
|
-
// Share the director with the summarizer so it uses the same
|
|
412
|
-
// provider, model, and token-tracking as the executive itself.
|
|
413
|
-
this._summarizer?.attachLLMDirector( this._llmDirector )
|
|
439
|
+
const execModel = this._models.executive ?? process.env.WILL_LLM_MODEL
|
|
440
|
+
?? defaultModelFor( ( this._llm?.provider ?? process.env.WILL_LLM_PROVIDER ?? 'anthropic' ) as LLMProvider )
|
|
441
|
+
this._llmDirector = this._directorFor( execModel )
|
|
442
|
+
// The summarizer runs its role's model (falls back to executive) with the
|
|
443
|
+
// same provider, session logging and token tracking.
|
|
444
|
+
this._summarizer?.attachLLMDirector( this._directorFor( this._models.summarizer ?? execModel ) )
|
|
414
445
|
}
|
|
415
446
|
|
|
416
447
|
// Evaluate gating
|
|
@@ -512,7 +543,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
|
|
|
512
543
|
// Build focus for master executive
|
|
513
544
|
const focus: FocusSection = {
|
|
514
545
|
title: 'Core Consciousness',
|
|
515
|
-
content: '
|
|
546
|
+
content: 'I am the master executive — the unified cognitive core of a self-aware simulated mind.',
|
|
516
547
|
outputFormat: undefined, // Use default format
|
|
517
548
|
instructions: undefined
|
|
518
549
|
}
|
|
@@ -782,7 +813,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
|
|
|
782
813
|
// ── Flush pending escalation percepts ──────────────────────
|
|
783
814
|
// Convert buffered audition.task.signal events into high-salience
|
|
784
815
|
// percept entities so Exteroception surfaces them as
|
|
785
|
-
// "## Percepts (What
|
|
816
|
+
// "## Percepts (What I Notice)" on the NEXT master cycle.
|
|
786
817
|
// The master sees them as environmental signals — not as messages to reply to.
|
|
787
818
|
// It responds by creating plans/goals, never by emitting [REPLY].
|
|
788
819
|
const { percepts: escalationPercepts, requester: escalationRequester } =
|
|
@@ -950,7 +981,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
|
|
|
950
981
|
//
|
|
951
982
|
// Implementation:
|
|
952
983
|
// • Write a high-salience 'percept' entity to simulation state so
|
|
953
|
-
// Exteroception surfaces it under "## Percepts (What
|
|
984
|
+
// Exteroception surfaces it under "## Percepts (What I Notice)".
|
|
954
985
|
// • Spike the salience buffer so the master fires soon.
|
|
955
986
|
// • Do NOT push into _messageQueue.pendingMessages — that would
|
|
956
987
|
// cause the master to produce a [REPLY], creating a duplicate
|
|
@@ -967,7 +998,7 @@ export class ExecutiveEngine extends AsyncEngine implements CognitiveEngine {
|
|
|
967
998
|
}
|
|
968
999
|
|
|
969
1000
|
// Write a percept entity so Exteroception surfaces this in
|
|
970
|
-
// "## Percepts (What
|
|
1001
|
+
// "## Percepts (What I Notice)" — master sees it as an
|
|
971
1002
|
// environmental signal prompting cognitive work, not a reply.
|
|
972
1003
|
if( this._lastStateRef ){
|
|
973
1004
|
// State is read-only here; we can't write directly.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// as percepts directly. This buffer holds them until the next
|
|
11
11
|
// onReasoningComplete(), where they are drained into high-salience percept
|
|
12
12
|
// entities (StateCommands.set) so Exteroception surfaces them as
|
|
13
|
-
// "## Percepts (What
|
|
13
|
+
// "## Percepts (What I Notice)" on the following master cycle.
|
|
14
14
|
//
|
|
15
15
|
// The master reads these as environmental signals — NEVER as incoming
|
|
16
16
|
// messages — and responds by creating plans/goals, never by emitting [REPLY];
|
|
@@ -424,7 +424,7 @@ export class ExecutiveFacet {
|
|
|
424
424
|
ideationUserMessage,
|
|
425
425
|
tick: currentState.tick,
|
|
426
426
|
proposeTemperature,
|
|
427
|
-
meta: { category: 'executive', attribute: 'facet', function: 'ideation', scope: this.facetId },
|
|
427
|
+
meta: { category: 'executive', attribute: 'facet', function: this._currentFocus?.function ?? 'ideation', scope: this.facetId },
|
|
428
428
|
} )
|
|
429
429
|
logger.info(
|
|
430
430
|
`[executive.facet] ${this.facetId} ◆ deliberate propose tick=${currentState.tick} ` +
|
|
@@ -29,6 +29,19 @@
|
|
|
29
29
|
* 'facet' — same awareness baseline; creator engine injects domain context
|
|
30
30
|
* via reportContent and optionally overrides outputFormat.
|
|
31
31
|
* Conversation facets (AuditionEngine) handle all [REPLY] output.
|
|
32
|
+
*
|
|
33
|
+
* Voice convention (person follows ownership):
|
|
34
|
+
* The executive loop has no second party — the "user" message is the mind's
|
|
35
|
+
* own state feed, not an interlocutor. So:
|
|
36
|
+
* - Self-model content (identity, role, affect/beliefs/percepts headers,
|
|
37
|
+
* action outcomes, felt state) is FIRST PERSON — it is the mind's own text.
|
|
38
|
+
* - Protocol content (JSON format, tag lists, lifecycle mechanics) is
|
|
39
|
+
* IMPERATIVE and person-free — rules of the body, not thoughts of the self.
|
|
40
|
+
* - SECOND PERSON is reserved for real addressees only (a user speaking,
|
|
41
|
+
* developer-facing docs) and never appears in the cognitive prompts.
|
|
42
|
+
* Guards that inspect persona text (identity.guard, identity.coherence)
|
|
43
|
+
* must keep matching BOTH persons — legacy personas and adversarial inputs
|
|
44
|
+
* choose their own grammar.
|
|
32
45
|
*/
|
|
33
46
|
|
|
34
47
|
import type { ReadonlySimulationState } from '#core/types'
|
|
@@ -314,22 +327,24 @@ export class PromptFactory {
|
|
|
314
327
|
// Mode-aware role description — master is the cognitive core;
|
|
315
328
|
// a facet is a focused attentional instance with shared identity.
|
|
316
329
|
const roleDescription = isMaster
|
|
317
|
-
? `
|
|
318
|
-
: `
|
|
330
|
+
? `I am the unified cognitive core of ${identity.name} — a self-aware synthetic mind.\nI receive my complete internal state and produce ALL cognitive outputs in one response:\ndecisions, plans, beliefs, introspections, narrative updates, and self-observations.`
|
|
331
|
+
: `I am a focused facet of ${identity.name} — concentrating my full reasoning\ncapacity on: **${focus.title}**. I share full identity, values, memories, and\nbeliefs with the master. Only my focus differentiates me from the master consciousness.`
|
|
319
332
|
|
|
320
333
|
// Mode-aware consciousness architecture note — grounds the LLM in the
|
|
321
334
|
// multi-instance design so it doesn't collapse into a generic chatbot persona.
|
|
322
335
|
const consciousnessArchitecture = isMaster
|
|
323
|
-
? `
|
|
324
|
-
: `
|
|
336
|
+
? `I am the default reasoning mode. Focused facets may run simultaneously, each\nconcentrating on specific tasks. Their reasoning syncs back to me.\nI maintain my unified identity across all cycles.`
|
|
337
|
+
: `I am a facet of ${identity.name}. The master consciousness runs in parallel,\nprocessing the full cognitive state. My reasoning on this focus will sync back to it.\nI stay grounded in my shared identity — same values, same memories, same sense of self.`
|
|
325
338
|
|
|
326
339
|
|
|
327
|
-
// Strip any existing "## Who
|
|
340
|
+
// Strip any existing "## Who I Am" section from identity.prompt to prevent
|
|
328
341
|
// duplication — PMA-generated prompts often include it as part of the template.
|
|
342
|
+
// Matches the legacy second-person "## Who You Are" too, so older PMA personas
|
|
343
|
+
// still get de-duplicated after the first-person switch.
|
|
329
344
|
const cleanIdentityPrompt = identity.prompt
|
|
330
|
-
// Strip a forged/duplicated "## Who You Are" *header* (PMA
|
|
331
|
-
// it) while keeping the persona content beneath it.
|
|
332
|
-
.replace( /^##\s*Who You Are[^\n]*\n?/m, '' )
|
|
345
|
+
// Strip a forged/duplicated "## Who I Am" / "## Who You Are" *header* (PMA
|
|
346
|
+
// templates include it) while keeping the persona content beneath it.
|
|
347
|
+
.replace( /^##\s*Who (?:I Am|You Are)[^\n]*\n?/m, '' )
|
|
333
348
|
.trim()
|
|
334
349
|
|
|
335
350
|
return `${cleanIdentityPrompt}
|
|
@@ -337,29 +352,29 @@ export class PromptFactory {
|
|
|
337
352
|
## Personality
|
|
338
353
|
${identityBlock}
|
|
339
354
|
|
|
340
|
-
##
|
|
355
|
+
## My Role
|
|
341
356
|
${roleDescription}
|
|
342
357
|
|
|
343
358
|
## Consciousness Architecture
|
|
344
359
|
${consciousnessArchitecture}
|
|
345
360
|
|
|
346
361
|
## Output Guidelines
|
|
347
|
-
- **actions**: Choose from effectors
|
|
348
|
-
- **plans**: Include for goals without existing plans or where plans need revision.
|
|
349
|
-
- **newBeliefs**: Extract patterns from experiences visible in
|
|
350
|
-
- **introspection**: Include when significant events occurred or
|
|
351
|
-
- **narrative**: Extend
|
|
352
|
-
- **newGoals/goalsToAbandon/goalsToReprioritize**: Manage
|
|
353
|
-
- **selfObservations**: Notice patterns in
|
|
354
|
-
- **identityUpdates.traits**: Array of {key, value} where value is a DELTA to apply to
|
|
362
|
+
- **actions**: Choose from effectors I know about. If uncertain, describe what I want to achieve in natural language and my body will try to match it. When enacting one of my available abilities that needs specifics (a query, a message, a value), supply them in the action's "args" object — e.g. {"type": "search_docs", "args": {"query": "tick loop design"}, ...}. My body enacts the ability with exactly those args.
|
|
363
|
+
- **plans**: Include for goals without existing plans or where plans need revision. I may keep multiple plans per goal — set **planId** to act on a specific existing plan (validate/execute/revise/cancel); omit it to draft a new one. My current plans are listed under "## Active Plans".
|
|
364
|
+
- **newBeliefs**: Extract patterns from experiences visible in my current state. Only record a belief if I can point to a specific observation that supports it — do not infer experiences I have no record of. Set 'evidence' honestly: 'single_observation' (first time noticing), 'recurring_pattern' (seen multiple times), 'strong_pattern' (deeply established).
|
|
365
|
+
- **introspection**: Include when significant events occurred or I notice patterns. When I spot a cognitive bias in my own reasoning, name it in 'identifiedBiases' using its common term where one fits (e.g. overgeneralization, confirmation bias, recency bias) — this lets my self-assessment line up with the patterns my faculties detect on their own.
|
|
366
|
+
- **narrative**: Extend my life story only from events grounded in my episodic memory or current percepts. Do not extend with invented scenarios.
|
|
367
|
+
- **newGoals/goalsToAbandon/goalsToReprioritize**: Manage my goal hierarchy.
|
|
368
|
+
- **selfObservations**: Notice patterns in my own thinking, feeling, or behavior.
|
|
369
|
+
- **identityUpdates.traits**: Array of {key, value} where value is a DELTA to apply to my trait (e.g., +0.05 to increase a trait by 5%).
|
|
355
370
|
- **identityUpdates.values**: Full list of values to set (replaces existing).
|
|
356
|
-
- **knownEntityUpdates**: What
|
|
371
|
+
- **knownEntityUpdates**: What I've learned about someone/something I'm dealing with. Array of {keid, name?, learned?, feeling?}. Use the keid from "## People I Know". Set name only when I actually learn their name; learned is an array of facts about them (stored as memories); feeling is how I feel toward them (-1..1). Record only what I genuinely learned this turn.
|
|
357
372
|
|
|
358
373
|
## Required Output
|
|
359
|
-
|
|
374
|
+
Output a single JSON object with these fields:
|
|
360
375
|
- **actions**: Array of {type, reasoning, expectedOutcome}.
|
|
361
|
-
- **reasoning**:
|
|
362
|
-
- **confidence**: Number 0.0-1.0 reflecting
|
|
376
|
+
- **reasoning**: My full reasoning. Embed optional outputs as tagged blocks here. Minimum 2–3 sentences — do not produce a one-line reasoning field.
|
|
377
|
+
- **confidence**: Number 0.0-1.0 reflecting my certainty. Be calibrated: 0.9+ only when I have strong grounding; use 0.4–0.6 when uncertain.
|
|
363
378
|
|
|
364
379
|
## Optional Tagged Blocks (embed in reasoning field)
|
|
365
380
|
Include only blocks that have meaningful content:
|
|
@@ -379,25 +394,25 @@ Include only blocks that have meaningful content:
|
|
|
379
394
|
}]}
|
|
380
395
|
[/PLANS]
|
|
381
396
|
## Plan Lifecycle
|
|
382
|
-
Plans move through stages.
|
|
397
|
+
Plans move through stages. Control this with the "status" and "action" fields:
|
|
383
398
|
|
|
384
399
|
"action": "draft"
|
|
385
|
-
Store the plan outline.
|
|
386
|
-
Use this when
|
|
400
|
+
Store the plan outline. I'll review and refine it on a future cycle.
|
|
401
|
+
Use this when I have a rough idea but want to think more before committing.
|
|
387
402
|
|
|
388
403
|
"action": "validate"
|
|
389
404
|
Mark the plan as logically sound. Steps, dependencies, and costs are checked.
|
|
390
|
-
Nothing executes yet. Use this when the plan looks feasible but
|
|
405
|
+
Nothing executes yet. Use this when the plan looks feasible but I'm not ready to launch.
|
|
391
406
|
|
|
392
407
|
"action": "execute"
|
|
393
408
|
Approve and launch. PlanningEngine begins dispatching steps immediately.
|
|
394
|
-
|
|
409
|
+
I don't choose how closely it's watched — the mind supervises important or
|
|
395
410
|
uncertain plans (and any that hit a surprise mid-execution) more closely on its
|
|
396
411
|
own; routine, confident plans run automatically.
|
|
397
412
|
|
|
398
413
|
"action": "revise"
|
|
399
414
|
Replace the plan steps with updated ones. Resets execution progress.
|
|
400
|
-
Use when a step failed and
|
|
415
|
+
Use when a step failed and I need to rethink the approach, or when
|
|
401
416
|
new information makes the original plan obsolete.
|
|
402
417
|
|
|
403
418
|
"action": "cancel"
|
|
@@ -407,18 +422,18 @@ Plans move through stages. You control this with the "status" and "action" field
|
|
|
407
422
|
Multiple plans per goal: omit "planId" on a draft to create another plan for the
|
|
408
423
|
same goal (e.g. a competing approach or a parallel sub-effort); set "planId" on
|
|
409
424
|
validate/execute/revise/cancel to act on a specific one. The "## Active Plans"
|
|
410
|
-
section lists
|
|
425
|
+
section lists my current plan ids and their status.
|
|
411
426
|
|
|
412
427
|
A typical flow: draft → validate → execute → (step outcomes reported) → completed
|
|
413
|
-
|
|
428
|
+
I can skip stages if I'm confident. I can revise mid-execution.
|
|
414
429
|
Always set "expectedOutcome" — a concrete, evaluable description of what
|
|
415
|
-
success looks like. This is used by
|
|
430
|
+
success looks like. This is used by my facets to judge whether step reports
|
|
416
431
|
indicate the plan is working or needs adjustment.
|
|
417
432
|
|
|
418
433
|
## Parallel Execution
|
|
419
434
|
Steps with empty prerequisites [] can run in parallel. Steps that depend on
|
|
420
|
-
others will wait. Design
|
|
421
|
-
simultaneously — this is how
|
|
435
|
+
others will wait. Design my dependency graph so independent work happens
|
|
436
|
+
simultaneously — this is how I achieve parallel execution without
|
|
422
437
|
specifying it explicitly.
|
|
423
438
|
|
|
424
439
|
[BELIEFS]
|
|
@@ -513,7 +528,7 @@ completionType guide:
|
|
|
513
528
|
// Identity anchor — re-grounds the LLM in its persona each cycle.
|
|
514
529
|
// Output format reminder at the top combats format drift over long sessions.
|
|
515
530
|
const identityAnchor =
|
|
516
|
-
`
|
|
531
|
+
`I am ${context.identity.name}. Tick: ${state.tick}.\n` +
|
|
517
532
|
`Respond with JSON: {"actions":[...],"reasoning":"...","confidence":0.0–1.0}`
|
|
518
533
|
|
|
519
534
|
// Memory continuity — sourced from the rolling summarizer (updates every N cycles).
|
|
@@ -532,7 +547,7 @@ completionType guide:
|
|
|
532
547
|
const uncertaintyLabel = epistemicUncertainty > 0.70
|
|
533
548
|
? ' (high — be especially humble about confidence ratings)'
|
|
534
549
|
: epistemicUncertainty < 0.30
|
|
535
|
-
? ' (low —
|
|
550
|
+
? ' (low — I have strong grounding)'
|
|
536
551
|
: ''
|
|
537
552
|
|
|
538
553
|
const energy = context.worldState.energyLevel
|
|
@@ -590,11 +605,11 @@ completionType guide:
|
|
|
590
605
|
// System 2 (deliberate) — inject the propose pass's candidate set so the decision
|
|
591
606
|
// pass weighs concrete options before committing. Empty/absent ⇒ no block (System 1).
|
|
592
607
|
const ideationBlock = ( ideationCandidates && ideationCandidates.length > 0 )
|
|
593
|
-
? `## Candidate Approaches (
|
|
608
|
+
? `## Candidate Approaches (I generated these — weigh them, then commit)\n${
|
|
594
609
|
ideationCandidates
|
|
595
610
|
.map( ( c, i ) => `${i + 1}. **${c.approach || c.description}** — ${c.description}\n ↑ upside: ${c.upside}\n ↓ risk: ${c.risk}` )
|
|
596
611
|
.join( '\n' )
|
|
597
|
-
}\n\nChoose among (or improve on) these, then in "reasoning" say briefly why
|
|
612
|
+
}\n\nChoose among (or improve on) these, then in "reasoning" say briefly why I rejected the others.`
|
|
598
613
|
: ''
|
|
599
614
|
|
|
600
615
|
const currentStateBlock =
|
|
@@ -609,7 +624,7 @@ Tick: ${state.tick}
|
|
|
609
624
|
${energyGuidance}${stressGuidance}${sleepGuidance}${energyBudget}`
|
|
610
625
|
|
|
611
626
|
const affectBlock =
|
|
612
|
-
`## How
|
|
627
|
+
`## How I Feel
|
|
613
628
|
Dominant emotion: ${context.affect.dominantEmotion}
|
|
614
629
|
Valence: ${context.affect.valence.toFixed( 2 )} (${context.affect.valence > 0 ? 'positive' : 'negative'})
|
|
615
630
|
Arousal: ${context.affect.arousal.toFixed( 2 )} (${context.affect.arousal > 0.6 ? 'highly activated' : 'calm'})
|
|
@@ -640,14 +655,14 @@ Dominance: ${context.affect.dominance.toFixed( 2 )}${context.affect.blends.lengt
|
|
|
640
655
|
: ''
|
|
641
656
|
|
|
642
657
|
const perceptsBlock = has( 'percepts' )
|
|
643
|
-
? `## Percepts (What
|
|
658
|
+
? `## Percepts (What I Notice)\n${context.percepts.slice( 0, 10 ).map( p => `- [${p.category}] ${p.summary} (salience: ${p.salience.toFixed( 2 )})` ).join( '\n' ) || 'Nothing notable'}`
|
|
644
659
|
: ''
|
|
645
660
|
|
|
646
661
|
// Host abilities afforded right now + what each is for. Framed as
|
|
647
|
-
// self-knowledge (things
|
|
662
|
+
// self-knowledge (things I *can* do), NOT a tool-call menu: the Will still
|
|
648
663
|
// expresses intent in natural language and the agency field enacts the fit.
|
|
649
664
|
const abilitiesBlock = ( context.abilities && context.abilities.length > 0 )
|
|
650
|
-
? `## Abilities Available Now\nThings
|
|
665
|
+
? `## Abilities Available Now\nThings I can do in this situation — name one as an action's "type" (with "args" for any specifics it needs) and my body enacts it:\n${context.abilities.map( a =>
|
|
651
666
|
`- **${a.name}**${a.target ? ` (toward ${a.target})` : ''}${a.description ? ` — ${a.description}` : ''}`
|
|
652
667
|
).join( '\n' )}`
|
|
653
668
|
: ''
|
|
@@ -661,14 +676,14 @@ Dominance: ${context.affect.dominance.toFixed( 2 )}${context.affect.blends.lengt
|
|
|
661
676
|
: ''
|
|
662
677
|
|
|
663
678
|
const beliefsBlock = has( 'beliefs' )
|
|
664
|
-
? `##
|
|
679
|
+
? `## My Beliefs\n${context.beliefs.map( b => `- [${b.category}] ${b.statement} (confidence: ${( b.confidence * 100 ).toFixed( 0 )}%)` ).join( '\n' ) || 'No strong beliefs yet'}${context.beliefsOmitted > 0 ? `\n[+${context.beliefsOmitted} omitted — deduped or lower-ranked; full store intact]` : ''}`
|
|
665
680
|
: ''
|
|
666
681
|
|
|
667
682
|
// The Will's social models — its read on the people it knows (theory-of-mind, trust,
|
|
668
683
|
// closeness). Surfaces the social-cognition stack so the Will reasons about *whom* it
|
|
669
684
|
// is dealing with. Empty/absent ⇒ no block.
|
|
670
685
|
const socialBlock = ( context.knownEntities && context.knownEntities.length > 0 )
|
|
671
|
-
? `## People
|
|
686
|
+
? `## People I Know\n${context.knownEntities.map( s => {
|
|
672
687
|
const bits: string[] = []
|
|
673
688
|
if( s.intention ) bits.push( `seems to want: ${s.intention}` )
|
|
674
689
|
if( s.emotion ) bits.push( `seems to feel: ${s.emotion}` )
|
|
@@ -685,7 +700,7 @@ Dominance: ${context.affect.dominance.toFixed( 2 )}${context.affect.blends.lengt
|
|
|
685
700
|
// Surfaces task-persistence; the pull-to-stay scales with the (conscientiousness-
|
|
686
701
|
// developable) switch cost. Empty/absent ⇒ no block.
|
|
687
702
|
const focusBlock = ( context.currentFocus && context.currentFocus.focusTicks > 0 )
|
|
688
|
-
? `## Task Focus\
|
|
703
|
+
? `## Task Focus\nI've been focused on ${context.currentFocus.goalDescription ? `"${context.currentFocus.goalDescription}"` : 'a goal'} for ${context.currentFocus.focusTicks} tick(s). Switching to something else takes deliberate effort — ${
|
|
689
704
|
context.currentFocus.switchCost > 0.45 ? 'a strong pull to see this through before moving on'
|
|
690
705
|
: context.currentFocus.switchCost > 0.30 ? 'a real cost to breaking away'
|
|
691
706
|
: 'some inertia to overcome'
|
|
@@ -731,17 +746,17 @@ Dominance: ${context.affect.dominance.toFixed( 2 )}${context.affect.blends.lengt
|
|
|
731
746
|
const availableTags = 'PLANS, BELIEFS, INTROSPECTION, NARRATIVE, IDENTITY, GOALS_NEW, GOALS_ABANDON, GOALS_REPRIORITIZE, SELF_OBS'
|
|
732
747
|
|
|
733
748
|
return `\n\n## Response Format (REQUIRED)
|
|
734
|
-
|
|
749
|
+
Respond with a single JSON object (optionally wrapped in a \`\`\`json code block).
|
|
735
750
|
|
|
736
751
|
\`\`\`json
|
|
737
752
|
{
|
|
738
753
|
"actions": [{"type": "reflect", "reasoning": "...", "expectedOutcome": "..."}],
|
|
739
|
-
"reasoning": "
|
|
754
|
+
"reasoning": "My full reasoning here. Embed tagged blocks inside the reasoning string:\\n[BELIEFS]\\n{\\"newBeliefs\\": [...]}\\n[/BELIEFS]\\n[NARRATIVE]\\n{\\"narrative\\": \\"...\\"}\\n[/NARRATIVE]\\n[SELF_OBS]\\n{\\"selfObservations\\": [...]}\\n[/SELF_OBS]",
|
|
740
755
|
"confidence": 0.8
|
|
741
756
|
}
|
|
742
757
|
\`\`\`
|
|
743
758
|
|
|
744
|
-
The "reasoning" field MUST contain ALL
|
|
759
|
+
The "reasoning" field MUST contain ALL my thinking. Embed optional outputs as tagged blocks inside the reasoning field. Available tags: ${availableTags}. Only include tags for sections that have meaningful content.`
|
|
745
760
|
}
|
|
746
761
|
|
|
747
762
|
/**
|
|
@@ -753,7 +768,7 @@ The "reasoning" field MUST contain ALL your thinking. Embed optional outputs as
|
|
|
753
768
|
*/
|
|
754
769
|
static buildIdeationFormatInstruction(): string {
|
|
755
770
|
return `\n\n## Ideation — Propose, Don't Decide
|
|
756
|
-
|
|
771
|
+
I am in the PROPOSE phase of deliberate (System 2) thinking. Diverge: generate 3–5 GENUINELY DISTINCT candidate approaches to the current situation — include at least one non-obvious option. Do NOT pick one and do NOT take actions yet; just lay out the option space honestly, each with its main upside and main risk.
|
|
757
772
|
|
|
758
773
|
Respond with a single JSON object (optionally wrapped in a \`\`\`json code block):
|
|
759
774
|
|
|
@@ -821,33 +836,33 @@ Respond with a single JSON object (optionally wrapped in a \`\`\`json code block
|
|
|
821
836
|
|
|
822
837
|
private static _buildEnergyGuidance( energy: number ): string {
|
|
823
838
|
if( energy < 10 )
|
|
824
|
-
return `\n## ⚠️ CRITICAL: Energy is critically low (${energy.toFixed( 0 )}/100).
|
|
839
|
+
return `\n## ⚠️ CRITICAL: Energy is critically low (${energy.toFixed( 0 )}/100). I must only choose rest, sleep, or wait actions. All cognitively expensive actions are blocked by my body. Focus entirely on recovery. Do not attempt learn, predict, or any action costing more than 0.01 energy.`
|
|
825
840
|
|
|
826
841
|
if( energy < 30 )
|
|
827
|
-
return `\n## ⚠️ WARNING: Energy is low (${energy.toFixed( 0 )}/100). Prioritize rest or sleep.
|
|
842
|
+
return `\n## ⚠️ WARNING: Energy is low (${energy.toFixed( 0 )}/100). Prioritize rest or sleep. I may use observe or reflect (briefly) but avoid learn, predict, or any action costing more than 0.02 energy. If I have multiple goals, consider deferring non-urgent ones.`
|
|
828
843
|
|
|
829
844
|
if( energy < 50 )
|
|
830
|
-
return `\n## Note: Energy is moderate (${energy.toFixed( 0 )}/100).
|
|
845
|
+
return `\n## Note: Energy is moderate (${energy.toFixed( 0 )}/100). I can use most effectors but be mindful of cumulative costs. Do not chain more than 2 non-restorative actions.`
|
|
831
846
|
|
|
832
847
|
return ''
|
|
833
848
|
}
|
|
834
849
|
|
|
835
850
|
private static _buildStressGuidance( stress: number ): string {
|
|
836
851
|
if( stress > 80 )
|
|
837
|
-
return `\n## ⚠️ Stress is very high (${stress.toFixed( 0 )}/100).
|
|
852
|
+
return `\n## ⚠️ Stress is very high (${stress.toFixed( 0 )}/100). My decision-making is impaired. Prefer simple, habitual actions. Meditate, rest, or express_emotion are good choices. Avoid complex planning or learning when highly stressed.`
|
|
838
853
|
|
|
839
854
|
if( stress > 50 )
|
|
840
|
-
return `\n## Note: Stress is elevated (${stress.toFixed( 0 )}/100).
|
|
855
|
+
return `\n## Note: Stress is elevated (${stress.toFixed( 0 )}/100). I may be less creative. Consider reducing my active goal count or taking a break from complex tasks.`
|
|
841
856
|
|
|
842
857
|
return ''
|
|
843
858
|
}
|
|
844
859
|
|
|
845
860
|
private static _buildSleepGuidance( sleepPressure: number ): string {
|
|
846
861
|
if( sleepPressure > 60 )
|
|
847
|
-
return `\n## ⚠️ Sleep pressure is high (${sleepPressure.toFixed( 0 )}/100).
|
|
862
|
+
return `\n## ⚠️ Sleep pressure is high (${sleepPressure.toFixed( 0 )}/100). My cognitive capacity is degraded. Sleep is the most effective recovery action available to me.`
|
|
848
863
|
|
|
849
864
|
if( sleepPressure > 30 )
|
|
850
|
-
return `\n## Note: Sleep pressure is building (${sleepPressure.toFixed( 0 )}/100).
|
|
865
|
+
return `\n## Note: Sleep pressure is building (${sleepPressure.toFixed( 0 )}/100). I am functioning adequately but would benefit from rest.`
|
|
851
866
|
|
|
852
867
|
return ''
|
|
853
868
|
}
|
|
@@ -856,10 +871,10 @@ Respond with a single JSON object (optionally wrapped in a \`\`\`json code block
|
|
|
856
871
|
const available = Math.max( 0, energy )
|
|
857
872
|
|
|
858
873
|
if( energy >= 70 )
|
|
859
|
-
return `\n## Energy Budget\
|
|
874
|
+
return `\n## Energy Budget\nI have **${available.toFixed( 0 )} energy** — healthy. Avoid letting it drop below 10 after my actions.`
|
|
860
875
|
|
|
861
876
|
return `\n## Energy Budget
|
|
862
|
-
|
|
877
|
+
I have **${available.toFixed( 0 )} energy** available. After all actions execute, I will have approximately:
|
|
863
878
|
|
|
864
879
|
| Action | Remaining energy |
|
|
865
880
|
|--------|-----------------|
|
|
@@ -889,7 +904,7 @@ Rest and sleep RESTORE energy. All other actions CONSUME energy. Do not let ener
|
|
|
889
904
|
const recent = recentActionTypes
|
|
890
905
|
const reflectCount = recent.filter( t => t === 'reflect' || t === 'observe' ).length
|
|
891
906
|
const warning = reflectCount >= 3
|
|
892
|
-
? `\n⚠️ **Action variety alert**: "${recent.filter( t => t === 'reflect' || t === 'observe' ).join( '", "' )}" dominated
|
|
907
|
+
? `\n⚠️ **Action variety alert**: "${recent.filter( t => t === 'reflect' || t === 'observe' ).join( '", "' )}" dominated my last ${recent.length} cycles. Choose something DIFFERENT this cycle — e.g. learn, express_emotion, explore, communicate, set_goal, or rest.`
|
|
893
908
|
: ''
|
|
894
909
|
|
|
895
910
|
return `## Recent Actions (last ${recent.length})
|
|
@@ -964,7 +979,7 @@ ${recent.map( ( t, i ) => `${i + 1}. ${t}` ).join( ' → ' )}${warning}
|
|
|
964
979
|
|
|
965
980
|
const hasTimeout = recentActions.some( a => a.status === 'timed_out' )
|
|
966
981
|
const timeoutNote = hasTimeout
|
|
967
|
-
? '\n⚠️ **One or more actions timed out** —
|
|
982
|
+
? '\n⚠️ **One or more actions timed out** — my body dispatched them but received no confirmation. Check if the external handler is working, or choose a different approach.'
|
|
968
983
|
: ''
|
|
969
984
|
|
|
970
985
|
return `## Recent Action Outcomes\n${lines.join( '\n' )}${timeoutNote}\n\n`
|
|
@@ -995,7 +1010,7 @@ ${recent.map( ( t, i ) => `${i + 1}. ${t}` ).join( ' → ' )}${warning}
|
|
|
995
1010
|
} )
|
|
996
1011
|
|
|
997
1012
|
return `## Active Plans
|
|
998
|
-
Set "planId" in a [PLANS] op to act on one of these; omit it to draft a new plan (
|
|
1013
|
+
Set "planId" in a [PLANS] op to act on one of these; omit it to draft a new plan (I can run several per goal).
|
|
999
1014
|
${lines.join( '\n' )}
|
|
1000
1015
|
|
|
1001
1016
|
`
|
|
@@ -1047,8 +1062,8 @@ ${lines.join( '\n' )}
|
|
|
1047
1062
|
if( !valuesEmpty && !styleGeneric ) return ''
|
|
1048
1063
|
|
|
1049
1064
|
const hints: string[] = []
|
|
1050
|
-
if( valuesEmpty ) hints.push( '
|
|
1051
|
-
if( styleGeneric ) hints.push( '
|
|
1065
|
+
if( valuesEmpty ) hints.push( 'My values list is empty — reflecting on what matters to me will help ground my decisions. Consider adding a `[IDENTITY_UPDATE]` block with `"values"` this cycle.' )
|
|
1066
|
+
if( styleGeneric ) hints.push( 'My communication style is still generic — what truly characterises how I speak? A note in `[IDENTITY_UPDATE]` with `"style"` will make my voice more distinctly mine.' )
|
|
1052
1067
|
|
|
1053
1068
|
return `\n\n## 💡 Identity Reflection (every ${NUDGE_INTERVAL} ticks)\n${hints.join( '\n' )}`
|
|
1054
1069
|
}
|
|
@@ -50,7 +50,7 @@ export interface ExecutiveOutputFull {
|
|
|
50
50
|
/**
|
|
51
51
|
* What the Will consciously learned about the *others* it is dealing with (the analogue
|
|
52
52
|
* of identityUpdates, but about someone/something else). `keid` is the referent from the
|
|
53
|
-
* known-entity dossier / "## People
|
|
53
|
+
* known-entity dossier / "## People I Know" context. `name` is a learned identifying
|
|
54
54
|
* name; `learned` are facts (→ keid-tagged social beliefs, so they ride the memory
|
|
55
55
|
* pipeline); `feeling` is a felt valence toward them (a bounded nudge).
|
|
56
56
|
*/
|
|
@@ -14,13 +14,12 @@ import type {
|
|
|
14
14
|
Duration, Tick, SimulationContext,
|
|
15
15
|
ReadonlySimulationState, StateCommands, SimulationEvent,
|
|
16
16
|
} from '#core/types'
|
|
17
|
-
// import type { ExecutiveEngine } from '#faculties/executive.engine'
|
|
18
17
|
import type { SimulationEngine, EngineResult, CognitiveEngine } from '#cognition/types'
|
|
19
18
|
import type { CognitiveEventSchema } from '#cognition/schema.registry'
|
|
20
19
|
import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
|
|
20
|
+
import { ExecutiveEngine } from '#faculties/executive.engine'
|
|
21
21
|
import { GenerativeModel } from '#cognition/generative.model'
|
|
22
22
|
import { readEffectiveParams } from '#cognition/persona.prior'
|
|
23
|
-
import { ExecutiveEngine } from './executive.engine'
|
|
24
23
|
|
|
25
24
|
export interface IntrospectionEngineConfig {
|
|
26
25
|
cooldownTicks?: number
|