@mindot/will 0.4.0 → 0.6.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 +32 -12
- package/dist/channels/discord.d.ts +2 -11
- package/dist/channels/discord.js.map +1 -1
- 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 +837 -91
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +620 -79
- package/dist/index.js.map +1 -1
- package/dist/mcp/effectors.d.ts +1 -1
- package/dist/mcp/effectors.js.map +1 -1
- package/dist/types-E9-HV-SW.d.ts +11 -0
- package/dist/{will-D-slky1N.d.ts → will-Bikuk4s2.d.ts} +56 -12
- package/package.json +12 -3
- package/src/channels/discord.ts +11 -11
- package/src/channels/roster.ts +1 -1
- package/src/channels/types.ts +1 -1
- package/src/channels/whatsapp.ts +318 -0
- package/src/cli.ts +46 -23
- package/src/cognition/acp.ts +28 -0
- package/src/cognition/agency/consequence.ts +174 -0
- package/src/cognition/agency/engines/action.selector.ts +301 -48
- package/src/cognition/agency/engines/affordance.synthesizer.ts +26 -16
- package/src/cognition/agency/engines/deliberation.engine.ts +28 -14
- package/src/cognition/agency/engines/motor.schema.executor.ts +86 -14
- package/src/cognition/agency/engines/reafference.engine.ts +122 -18
- package/src/cognition/agency/execution.primitives.ts +13 -13
- package/src/cognition/agency/proactive.communicator.ts +1 -1
- package/src/cognition/agency/reconcile.learning.ts +1 -1
- package/src/cognition/agency/revocation.ts +79 -0
- package/src/cognition/agency/schemas/repertoire.ts +2 -2
- package/src/cognition/agency/selection.scoring.ts +25 -9
- package/src/cognition/bus.ts +2 -2
- package/src/cognition/completion.inbox.ts +1 -1
- package/src/cognition/config.mirror.entities.ts +5 -5
- package/src/cognition/event.log.ts +2 -2
- package/src/cognition/event.schemas.ts +67 -67
- package/src/cognition/faculties/aesthetic.evaluator.ts +6 -6
- package/src/cognition/faculties/affective.blender.ts +36 -4
- package/src/cognition/faculties/attachment.evaluator.ts +6 -6
- package/src/cognition/faculties/attention.allocator.ts +63 -8
- package/src/cognition/faculties/autobiographical.narrator.ts +3 -3
- package/src/cognition/faculties/bias.detector.ts +7 -7
- package/src/cognition/faculties/circadian.oscillator.ts +3 -3
- package/src/cognition/faculties/confidence.calibrator.ts +7 -7
- package/src/cognition/faculties/dream.simulator.ts +5 -5
- package/src/cognition/faculties/empathy.simulator.ts +7 -7
- package/src/cognition/faculties/energy.regulator.ts +4 -4
- package/src/cognition/faculties/episodic.consolidator.ts +6 -6
- package/src/cognition/faculties/executive.engine/commands.ts +6 -6
- package/src/cognition/faculties/executive.engine/context.ts +42 -42
- package/src/cognition/faculties/executive.engine/deferred.effects.ts +2 -2
- package/src/cognition/faculties/executive.engine/engine.ts +27 -26
- package/src/cognition/faculties/executive.engine/facet.supervisor.ts +12 -12
- package/src/cognition/faculties/executive.engine/facet.ts +18 -18
- package/src/cognition/faculties/executive.engine/gating.ts +2 -2
- package/src/cognition/faculties/executive.engine/messages.ts +3 -3
- package/src/cognition/faculties/executive.engine/parser.ts +11 -11
- package/src/cognition/faculties/executive.engine/prompt.factory.ts +55 -55
- package/src/cognition/faculties/exteroception.ts +99 -5
- package/src/cognition/faculties/forgetting.curve.ts +3 -3
- package/src/cognition/faculties/frustration.evaluator.ts +6 -6
- package/src/cognition/faculties/goal.manager.ts +15 -15
- package/src/cognition/faculties/inhibition.controller.ts +3 -3
- package/src/cognition/faculties/interoception.ts +3 -3
- package/src/cognition/faculties/introspection.engine.ts +3 -3
- package/src/cognition/faculties/known.entity.tracker.ts +15 -15
- package/src/cognition/faculties/loss.evaluator.ts +2 -2
- package/src/cognition/faculties/moral.evaluator.ts +4 -4
- package/src/cognition/faculties/novelty.detector.ts +4 -4
- package/src/cognition/faculties/persona.consolidator.ts +12 -12
- package/src/cognition/faculties/planning.engine/engine.ts +47 -47
- package/src/cognition/faculties/planning.engine/plan.frontier.ts +5 -5
- package/src/cognition/faculties/planning.engine/plan.store.ts +1 -1
- package/src/cognition/faculties/planning.engine/plan.supervision.ts +20 -20
- package/src/cognition/faculties/reputation.tracker.ts +6 -6
- package/src/cognition/faculties/reward.evaluator.ts +4 -4
- package/src/cognition/faculties/self.model.updater.ts +8 -8
- package/src/cognition/faculties/semantic.engine/integrator.ts +15 -15
- package/src/cognition/faculties/sleep.pressure.regulator.ts +4 -4
- package/src/cognition/faculties/social.perception.ts +3 -3
- package/src/cognition/faculties/spaced.repetition.ts +2 -2
- package/src/cognition/faculties/stress.regulator.ts +27 -4
- package/src/cognition/faculties/task.switcher.ts +11 -6
- package/src/cognition/faculties/theory.of.mind.ts +6 -6
- package/src/cognition/faculties/threat.evaluator.ts +3 -3
- package/src/cognition/faculties/working.memory.ts +8 -8
- package/src/cognition/generative.model.ts +2 -2
- package/src/cognition/memory/vector.adapter.ts +5 -5
- package/src/cognition/memory/vector.content.ts +4 -4
- package/src/cognition/memory/vector.embedder.ts +9 -9
- package/src/cognition/persona.prior.ts +1 -1
- package/src/cognition/schema.registry.ts +2 -2
- package/src/cognition/senses/audition.engine/engine.ts +2 -2
- package/src/cognition/senses/base.sense.engine.ts +1 -1
- package/src/cognition/utilities/token.tracker.ts +11 -5
- package/src/core/abstracts.ts +1 -1
- package/src/core/completion.recorder.ts +2 -2
- package/src/core/serialization.ts +3 -3
- package/src/core/snapshot.manager.ts +1 -1
- package/src/core/state.manager.ts +1 -1
- package/src/core/utils.ts +1 -1
- package/src/host/boot.ts +59 -37
- package/src/host/utterances.ts +1 -1
- package/src/llm/index.ts +84 -34
- package/src/llm/summarizer.ts +4 -4
- package/src/llm/wire.contracts.ts +1 -1
- package/src/mcp/effectors.ts +10 -10
- package/src/mcp/server.ts +11 -11
- package/src/pma/eval.ts +1 -1
- package/src/pma/index.ts +21 -21
- package/src/runners/outreach.runner.ts +3 -3
- package/src/runners/social.runner.ts +1 -1
- package/src/runners/thin-shim.runner.ts +1 -1
- package/src/sdk/will.ts +20 -11
- package/src/serve/server.ts +12 -12
- package/src/stem/assembly.audit.ts +3 -3
- package/src/stem/guards/identity.coherence.ts +13 -12
- package/src/stem/guards/identity.guard.ts +22 -22
- package/src/stem/index.ts +11 -11
- package/src/stem/mind.ts +12 -12
- package/src/stem/tracts/biography.writer.ts +3 -3
- package/src/stem/tracts/effector.controller.ts +4 -4
- package/src/stem/tracts/health.reporter.ts +1 -1
- package/src/stem/tracts/outbox.controller.ts +4 -0
- package/src/stem/tracts/outbox.writer.ts +4 -4
- package/src/stem/tracts/pma.controller.ts +1 -1
- package/src/stem/tracts/replay.controller.ts +10 -10
- package/src/stem/tracts/sensory.controller.ts +2 -2
- package/src/stem/tracts/session.logger.ts +4 -4
- package/src/stem/tracts/transport/socketio.transport.ts +7 -7
- package/src/stem/tracts/transport/stream.transport.ts +2 -2
- package/src/stem/tracts/transport.controller.ts +15 -15
package/src/llm/index.ts
CHANGED
|
@@ -12,7 +12,68 @@ import type { LLMCompletionRecord } from '#core/completion.recorder'
|
|
|
12
12
|
import { withGate } from '#llm/gate'
|
|
13
13
|
import { matchConversationFocus, wrapReplyText } from '#llm/wire.contracts'
|
|
14
14
|
|
|
15
|
-
export type LLMProvider = 'anthropic' | 'deepseek' | 'openai' | 'google'
|
|
15
|
+
export type LLMProvider = 'anthropic' | 'glm' | 'deepseek' | 'openai' | 'google'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Providers that speak the Anthropic Messages wire.
|
|
19
|
+
*
|
|
20
|
+
* Z.ai ships a real Anthropic-compatible endpoint for GLM — it is what Claude
|
|
21
|
+
* Code itself targets — so GLM rides this path rather than the OpenAI scaffold.
|
|
22
|
+
* That buys it everything the path already has: token streaming, the first-byte
|
|
23
|
+
* deadline, prompt-cache breakpoints, and the structured-output contract. GLM is
|
|
24
|
+
* therefore a second *production* provider, not a fifth scaffold.
|
|
25
|
+
*/
|
|
26
|
+
const ANTHROPIC_WIRE = new Set<LLMProvider>( [ 'anthropic', 'glm' ] )
|
|
27
|
+
|
|
28
|
+
/** Does this provider accept Anthropic-shaped requests? */
|
|
29
|
+
export function speaksAnthropicWire( provider: LLMProvider ): boolean {
|
|
30
|
+
return ANTHROPIC_WIRE.has( provider )
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Official API base URL (including version segment) for a provider. */
|
|
34
|
+
export function defaultBaseFor( provider: LLMProvider ): string {
|
|
35
|
+
switch( provider ){
|
|
36
|
+
case 'anthropic': return 'https://api.anthropic.com/v1'
|
|
37
|
+
// Z.ai documents the base as `…/api/anthropic` because the Anthropic SDK
|
|
38
|
+
// appends `/v1/messages`; this client appends `/messages`, so the version
|
|
39
|
+
// segment belongs here — verified against the live endpoint.
|
|
40
|
+
case 'glm': return 'https://api.z.ai/api/anthropic/v1'
|
|
41
|
+
case 'openai': return 'https://api.openai.com/v1'
|
|
42
|
+
case 'deepseek': return 'https://api.deepseek.com/v1'
|
|
43
|
+
case 'google': return 'https://generativelanguage.googleapis.com/v1beta'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The model the executive recruits when none is pinned.
|
|
49
|
+
*
|
|
50
|
+
* Provider-specific because the default is *sent* — a GLM Will with no
|
|
51
|
+
* `WILL_LLM_MODEL` would otherwise ask Z.ai for a Claude id and get a 404 it
|
|
52
|
+
* could do nothing with. The scaffolded providers (openai/deepseek/google) keep
|
|
53
|
+
* today's value: they need an explicit `WILL_LLM_MODEL` to work at all, and
|
|
54
|
+
* inventing ids for them here would look like support that does not exist.
|
|
55
|
+
*/
|
|
56
|
+
export function defaultModelFor( provider: LLMProvider ): string {
|
|
57
|
+
return provider === 'glm' ? 'glm-5.2' : 'claude-sonnet-4-5-20250929'
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Auth + version headers for the Anthropic wire.
|
|
62
|
+
*
|
|
63
|
+
* Anthropic authenticates with `x-api-key`. Z.ai's compat endpoint accepts
|
|
64
|
+
* either that or the `Authorization: Bearer` its own docs describe (both were
|
|
65
|
+
* probed against the live endpoint; each is read and validated). GLM sends both
|
|
66
|
+
* — same secret, same host — so the mind keeps working whichever one Z.ai
|
|
67
|
+
* eventually settles on.
|
|
68
|
+
*/
|
|
69
|
+
export function anthropicWireHeaders( provider: LLMProvider, apiKey: string ): Record<string, string> {
|
|
70
|
+
return {
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
'anthropic-version': '2023-06-01',
|
|
73
|
+
'x-api-key': apiKey,
|
|
74
|
+
...( provider === 'glm' ? { Authorization: `Bearer ${ apiKey }` } : {} ),
|
|
75
|
+
}
|
|
76
|
+
}
|
|
16
77
|
export interface LLMDirectorConfig {
|
|
17
78
|
willId: string
|
|
18
79
|
model: string
|
|
@@ -126,7 +187,7 @@ export class LLMDirector {
|
|
|
126
187
|
* {"actions":[{"type":"...","reasoning":"...","expectedOutcome":"..."}],...}
|
|
127
188
|
* Strategy 1 (JSON.parse) handles this directly.
|
|
128
189
|
*/
|
|
129
|
-
private _mockResponse( tick: number, userMessage: string = ''
|
|
190
|
+
private _mockResponse( tick: number, userMessage: string = ''): LLMCallResult {
|
|
130
191
|
// ── Conversation facet turn ────────────────────────────────
|
|
131
192
|
// Detect the AuditionEngine facet focus via the SHARED contract (see
|
|
132
193
|
// llm/wire.contracts.ts) — the render/match pair whose earlier drift
|
|
@@ -216,7 +277,7 @@ export class LLMDirector {
|
|
|
216
277
|
return result
|
|
217
278
|
}
|
|
218
279
|
|
|
219
|
-
const result = this._provider
|
|
280
|
+
const result = speaksAnthropicWire( this._provider )
|
|
220
281
|
? await this._callAnthropicStream( systemPrompt, userMessage, onChunk, temperature )
|
|
221
282
|
: await ( async () => {
|
|
222
283
|
// Other providers: fall back to regular call, emit whole response as one chunk
|
|
@@ -328,11 +389,7 @@ export class LLMDirector {
|
|
|
328
389
|
try {
|
|
329
390
|
res = await fetch(`${this._resolvedBase()}/messages`, {
|
|
330
391
|
method: 'POST',
|
|
331
|
-
headers:
|
|
332
|
-
'Content-Type': 'application/json',
|
|
333
|
-
'anthropic-version': '2023-06-01',
|
|
334
|
-
'x-api-key': this._apiKey,
|
|
335
|
-
},
|
|
392
|
+
headers: anthropicWireHeaders( this._provider, this._apiKey ),
|
|
336
393
|
body: JSON.stringify({
|
|
337
394
|
model: this._model,
|
|
338
395
|
max_tokens: this._maxOutputTokens,
|
|
@@ -347,7 +404,7 @@ export class LLMDirector {
|
|
|
347
404
|
catch( err ){
|
|
348
405
|
clearTimeout( timer )
|
|
349
406
|
if( controller.signal.aborted )
|
|
350
|
-
throw new Error(
|
|
407
|
+
throw new Error(`LLM stream to ${this._provider} timed out after ${this._timeoutMs}ms (no response)`)
|
|
351
408
|
throw err
|
|
352
409
|
}
|
|
353
410
|
|
|
@@ -377,7 +434,7 @@ export class LLMDirector {
|
|
|
377
434
|
for( const line of lines ){
|
|
378
435
|
if( !line.startsWith('data: ') ) continue
|
|
379
436
|
const raw = line.slice(6).trim()
|
|
380
|
-
if( raw === '[DONE]'
|
|
437
|
+
if( raw === '[DONE]') break
|
|
381
438
|
|
|
382
439
|
try {
|
|
383
440
|
const ev = JSON.parse( raw ) as {
|
|
@@ -438,13 +495,14 @@ export class LLMDirector {
|
|
|
438
495
|
return result
|
|
439
496
|
}
|
|
440
497
|
|
|
441
|
-
// Anthropic
|
|
442
|
-
// (TTFT), not whole-request: a long-but-healthy
|
|
443
|
-
// 20–40s on Sonnet) no longer trips the timeout
|
|
444
|
-
// no-op here — call() returns the full
|
|
445
|
-
// through callStream(). Other
|
|
498
|
+
// The Anthropic-wire providers route through the streaming path so the
|
|
499
|
+
// deadline is first-byte (TTFT), not whole-request: a long-but-healthy
|
|
500
|
+
// executive completion (often 20–40s on Sonnet) no longer trips the timeout
|
|
501
|
+
// mid-generation. onChunk is a no-op here — call() returns the full
|
|
502
|
+
// accumulated text; live token chunks go through callStream(). Other
|
|
503
|
+
// providers keep the whole-request deadline.
|
|
446
504
|
const result = await withGate(
|
|
447
|
-
() => this._provider
|
|
505
|
+
() => speaksAnthropicWire( this._provider )
|
|
448
506
|
? this._callAnthropicStream( systemPrompt, userMessage, () => {}, temperature )
|
|
449
507
|
: this._callProvider( systemPrompt, userMessage, temperature ),
|
|
450
508
|
'executive/direct',
|
|
@@ -465,6 +523,7 @@ export class LLMDirector {
|
|
|
465
523
|
): Promise<LLMCallResult> {
|
|
466
524
|
switch( this._provider ){
|
|
467
525
|
case 'anthropic': return this._callAnthropic( systemPrompt, userMessage, temperature )
|
|
526
|
+
case 'glm': return this._callAnthropic( systemPrompt, userMessage, temperature )
|
|
468
527
|
case 'deepseek': return this._callOpenAI( systemPrompt, userMessage, temperature )
|
|
469
528
|
case 'openai': return this._callOpenAI( systemPrompt, userMessage, temperature )
|
|
470
529
|
case 'google': return this._callGoogle( systemPrompt, userMessage, temperature )
|
|
@@ -474,12 +533,7 @@ export class LLMDirector {
|
|
|
474
533
|
|
|
475
534
|
/** Default API base URL (including version segment) for a provider. */
|
|
476
535
|
private _baseFor( provider: LLMProvider ): string {
|
|
477
|
-
|
|
478
|
-
case 'anthropic': return 'https://api.anthropic.com/v1'
|
|
479
|
-
case 'openai': return 'https://api.openai.com/v1'
|
|
480
|
-
case 'deepseek': return 'https://api.deepseek.com/v1'
|
|
481
|
-
case 'google': return 'https://generativelanguage.googleapis.com/v1beta'
|
|
482
|
-
}
|
|
536
|
+
return defaultBaseFor( provider )
|
|
483
537
|
}
|
|
484
538
|
|
|
485
539
|
/** Resolved API base: explicit override wins, else the provider default. */
|
|
@@ -498,8 +552,8 @@ export class LLMDirector {
|
|
|
498
552
|
}
|
|
499
553
|
catch( err ){
|
|
500
554
|
// AbortSignal.timeout rejects with a DOMException named 'TimeoutError'.
|
|
501
|
-
if( err instanceof Error && err.name === 'TimeoutError'
|
|
502
|
-
throw new Error(
|
|
555
|
+
if( err instanceof Error && err.name === 'TimeoutError')
|
|
556
|
+
throw new Error(`LLM request to ${this._provider} timed out after ${this._timeoutMs}ms`)
|
|
503
557
|
throw err
|
|
504
558
|
}
|
|
505
559
|
}
|
|
@@ -526,23 +580,19 @@ export class LLMDirector {
|
|
|
526
580
|
|
|
527
581
|
const res = await this._fetchWithTimeout(`${this._resolvedBase()}/messages`, {
|
|
528
582
|
method: 'POST',
|
|
529
|
-
headers:
|
|
530
|
-
'Content-Type': 'application/json',
|
|
531
|
-
'anthropic-version': '2023-06-01',
|
|
532
|
-
'x-api-key': this._apiKey
|
|
533
|
-
},
|
|
583
|
+
headers: anthropicWireHeaders( this._provider, this._apiKey ),
|
|
534
584
|
body: JSON.stringify( body )
|
|
535
585
|
})
|
|
536
586
|
|
|
537
587
|
if( !res.ok )
|
|
538
|
-
throw new Error(
|
|
588
|
+
throw new Error(`${this._provider} API ${res.status}: ${( await res.text() ).slice(0, 300)}`)
|
|
539
589
|
|
|
540
590
|
const
|
|
541
591
|
data = await res.json() as {
|
|
542
592
|
content: Array<{ type: string; text: string }>
|
|
543
593
|
usage: { input_tokens: number; output_tokens: number; cache_read_input_tokens?: number; cache_creation_input_tokens?: number }
|
|
544
594
|
},
|
|
545
|
-
text = data.content.find( b => b.type === 'text'
|
|
595
|
+
text = data.content.find( b => b.type === 'text')?.text ?? ''
|
|
546
596
|
|
|
547
597
|
return {
|
|
548
598
|
text,
|
|
@@ -623,7 +673,7 @@ export class LLMDirector {
|
|
|
623
673
|
}
|
|
624
674
|
|
|
625
675
|
const text = ( data.candidates?.[ 0 ]?.content?.parts ?? [] )
|
|
626
|
-
.map( p => p.text ?? ''
|
|
676
|
+
.map( p => p.text ?? '')
|
|
627
677
|
.join('')
|
|
628
678
|
|
|
629
679
|
return {
|
|
@@ -665,7 +715,7 @@ export class LLMDirector {
|
|
|
665
715
|
userMessage,
|
|
666
716
|
].join('\n')
|
|
667
717
|
|
|
668
|
-
const filepath = `${debugDir}/prompt-tick-${String( tick ).padStart( 6, '0'
|
|
718
|
+
const filepath = `${debugDir}/prompt-tick-${String( tick ).padStart( 6, '0')}.txt`
|
|
669
719
|
writeFileSync( filepath, content )
|
|
670
720
|
|
|
671
721
|
logger.info(`[executive] Debug prompt written → ${filepath} (~${estimatedTokens} tok estimated)`)
|
|
@@ -705,7 +755,7 @@ export class LLMDirector {
|
|
|
705
755
|
responseText,
|
|
706
756
|
].join('\n')
|
|
707
757
|
|
|
708
|
-
const filepath = `${debugDir}/response-tick-${String( tick ).padStart( 6, '0'
|
|
758
|
+
const filepath = `${debugDir}/response-tick-${String( tick ).padStart( 6, '0')}.txt`
|
|
709
759
|
writeFileSync( filepath, content )
|
|
710
760
|
}
|
|
711
761
|
catch {
|
package/src/llm/summarizer.ts
CHANGED
|
@@ -130,7 +130,7 @@ export class ExecutiveSummarizer {
|
|
|
130
130
|
|
|
131
131
|
private async _run(): Promise<void> {
|
|
132
132
|
if( !this._llmDirector ){
|
|
133
|
-
logger.warn(
|
|
133
|
+
logger.warn('[summarizer] skipping — LLMDirector not attached yet')
|
|
134
134
|
return
|
|
135
135
|
}
|
|
136
136
|
|
|
@@ -139,8 +139,8 @@ export class ExecutiveSummarizer {
|
|
|
139
139
|
|
|
140
140
|
try {
|
|
141
141
|
const userMessage = snapshot
|
|
142
|
-
.map( ( r, i ) => `[Cycle ${i + 1}]\n${r}`
|
|
143
|
-
.join(
|
|
142
|
+
.map( ( r, i ) => `[Cycle ${i + 1}]\n${r}`)
|
|
143
|
+
.join('\n\n---\n\n')
|
|
144
144
|
|
|
145
145
|
// Use _callCount as the tick value — it's only used for token tracking/logging
|
|
146
146
|
const result = await this._llmDirector.call(
|
|
@@ -161,7 +161,7 @@ export class ExecutiveSummarizer {
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
catch( err ){
|
|
164
|
-
logger.warn(
|
|
164
|
+
logger.warn('[summarizer] failed:', err instanceof Error ? err.message : err )
|
|
165
165
|
}
|
|
166
166
|
finally {
|
|
167
167
|
this._summarizing = false
|
|
@@ -36,7 +36,7 @@ export const REPLY_TEXT_CLOSE = `[/${REPLY_TEXT_TAG}]`
|
|
|
36
36
|
|
|
37
37
|
/** Wrap a reply body in the block markers (the mock's emission shape). */
|
|
38
38
|
export function wrapReplyText( body: string ): string {
|
|
39
|
-
return [ REPLY_TEXT_OPEN, body, REPLY_TEXT_CLOSE ].join(
|
|
39
|
+
return [ REPLY_TEXT_OPEN, body, REPLY_TEXT_CLOSE ].join('\n')
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// ── Conversation-facet focus — render ↔ match pair ────────────
|
package/src/mcp/effectors.ts
CHANGED
|
@@ -67,10 +67,10 @@ export function describeMcpTool( tool: McpToolInfo ): string {
|
|
|
67
67
|
const props = tool.inputSchema?.properties ?? {}
|
|
68
68
|
const required = new Set( tool.inputSchema?.required ?? [] )
|
|
69
69
|
const argHints = Object.entries( props ).map( ( [ key, p ] ) =>
|
|
70
|
-
`${ key }${ required.has( key ) ? '' : '?' }${ p.description ? `: ${ p.description }` : '' }`
|
|
70
|
+
`${ key }${ required.has( key ) ? '' : '?' }${ p.description ? `: ${ p.description }` : '' }`)
|
|
71
71
|
|
|
72
|
-
const base = ( tool.description ?? `The ${ tool.name } tool.`
|
|
73
|
-
const hint = argHints.length > 0 ? ` (args — ${ argHints.join(
|
|
72
|
+
const base = ( tool.description ?? `The ${ tool.name } tool.`).trim().replace( /\s+/g, ' ')
|
|
73
|
+
const hint = argHints.length > 0 ? ` (args — ${ argHints.join('; ') })` : ''
|
|
74
74
|
const full = `${ base }${ hint }`
|
|
75
75
|
return full.length > MEANING_CAP ? `${ full.slice( 0, MEANING_CAP - 1 ) }…` : full
|
|
76
76
|
}
|
|
@@ -90,21 +90,21 @@ export function buildMcpHandler( client: Client, tool: McpToolInfo ): EffectorHa
|
|
|
90
90
|
if( !props || k in props ) filtered[ k ] = v
|
|
91
91
|
|
|
92
92
|
const missing = ( tool.inputSchema?.required ?? [] ).filter(
|
|
93
|
-
k => filtered[ k ] === undefined || filtered[ k ] === ''
|
|
93
|
+
k => filtered[ k ] === undefined || filtered[ k ] === '')
|
|
94
94
|
if( missing.length > 0 )
|
|
95
95
|
return {
|
|
96
96
|
success: false,
|
|
97
|
-
description: `${ tool.name } needs ${ missing.join(
|
|
97
|
+
description: `${ tool.name } needs ${ missing.join(', ') } — enact it deliberately, supplying them in the action's args.`,
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
try {
|
|
101
101
|
const res = await client.callTool( { name: tool.name, arguments: filtered } ) as
|
|
102
102
|
{ content?: Array<{ type: string; text?: string }>; isError?: boolean }
|
|
103
103
|
const text = ( res.content ?? [] )
|
|
104
|
-
.filter( c => c.type === 'text' && typeof c.text === 'string'
|
|
104
|
+
.filter( c => c.type === 'text' && typeof c.text === 'string')
|
|
105
105
|
.map( c => c.text as string )
|
|
106
|
-
.join(
|
|
107
|
-
.trim() || ( res.isError ? 'The tool reported an error.' : 'Done (no output).'
|
|
106
|
+
.join('\n')
|
|
107
|
+
.trim() || ( res.isError ? 'The tool reported an error.' : 'Done (no output).')
|
|
108
108
|
const bounded = text.length > RESULT_DESCRIPTION_CAP ? `${ text.slice( 0, RESULT_DESCRIPTION_CAP - 1 ) }…` : text
|
|
109
109
|
return { success: !res.isError, description: bounded }
|
|
110
110
|
}
|
|
@@ -115,10 +115,10 @@ export function buildMcpHandler( client: Client, tool: McpToolInfo ): EffectorHa
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
async function connect( source: McpToolsSource ): Promise<{ client: Client; owned: boolean }> {
|
|
118
|
-
if(
|
|
118
|
+
if('client' in source ) return { client: source.client, owned: false }
|
|
119
119
|
|
|
120
120
|
const client = new Client( { name: 'mindot-will', version: '0' } )
|
|
121
|
-
if(
|
|
121
|
+
if('url' in source )
|
|
122
122
|
await client.connect( new StreamableHTTPClientTransport( new URL( source.url ) ) )
|
|
123
123
|
else
|
|
124
124
|
await client.connect( new StdioClientTransport( {
|
package/src/mcp/server.ts
CHANGED
|
@@ -35,7 +35,7 @@ export interface WillMcpOptions {
|
|
|
35
35
|
function serverVersion(): string {
|
|
36
36
|
// Same relative depth from src/mcp/ and dist/mcp/ — resolves in both.
|
|
37
37
|
try {
|
|
38
|
-
return JSON.parse( readFileSync( new URL(
|
|
38
|
+
return JSON.parse( readFileSync( new URL('../../package.json', import.meta.url ), 'utf8') ).version ?? '0.0.0'
|
|
39
39
|
}
|
|
40
40
|
catch { return '0.0.0' }
|
|
41
41
|
}
|
|
@@ -54,7 +54,7 @@ export function buildWillMcpServer( will: Will, opts: WillMcpOptions = {} ): Mcp
|
|
|
54
54
|
|
|
55
55
|
// ── Tools ─────────────────────────────────────────────────
|
|
56
56
|
|
|
57
|
-
server.registerTool(
|
|
57
|
+
server.registerTool('perceive', {
|
|
58
58
|
title: 'Perceive',
|
|
59
59
|
description:
|
|
60
60
|
`Deliver a stimulus (something said or observed) into ${ will.name }'s sensory field. ` +
|
|
@@ -62,9 +62,9 @@ export function buildWillMcpServer( will: Will, opts: WillMcpOptions = {} ): Mcp
|
|
|
62
62
|
`NOT when it has responded. Its response — if it chooses to give one — arrives as its next ` +
|
|
63
63
|
`utterance (use the next_utterance tool). Staying silent is a valid choice, not an error.`,
|
|
64
64
|
inputSchema: {
|
|
65
|
-
text: z.string().describe(
|
|
65
|
+
text: z.string().describe('What is said or observed.'),
|
|
66
66
|
from: z.string().optional().describe( "Who it's from (entity id, default 'user'). Use a stable id per person." ),
|
|
67
|
-
speaker: z.string().optional().describe(
|
|
67
|
+
speaker: z.string().optional().describe('Display name of the speaker.'),
|
|
68
68
|
},
|
|
69
69
|
}, async ( { text, from, speaker } ) => {
|
|
70
70
|
await will.perceive( { text, ...( from ? { from } : {} ), ...( speaker ? { speaker } : {} ) } )
|
|
@@ -77,15 +77,15 @@ export function buildWillMcpServer( will: Will, opts: WillMcpOptions = {} ): Mcp
|
|
|
77
77
|
}
|
|
78
78
|
} )
|
|
79
79
|
|
|
80
|
-
server.registerTool(
|
|
80
|
+
server.registerTool('next_utterance', {
|
|
81
81
|
title: 'Next utterance',
|
|
82
82
|
description:
|
|
83
83
|
`Await ${ will.name }'s next spontaneous utterance. Returns what it says next, or reports ` +
|
|
84
84
|
`that it chose silence within the wait window — silence is a real outcome, not a failure. ` +
|
|
85
85
|
`Call after perceive to hear the response, or on its own to listen for unprompted speech.`,
|
|
86
86
|
inputSchema: {
|
|
87
|
-
within_ms: z.number().optional().describe(
|
|
88
|
-
from: z.string().optional().describe(
|
|
87
|
+
within_ms: z.number().optional().describe('How long to wait before accepting silence (default 15000, max 120000).'),
|
|
88
|
+
from: z.string().optional().describe('Only accept an utterance addressed to this entity id.'),
|
|
89
89
|
},
|
|
90
90
|
}, async ( { within_ms, from } ) => {
|
|
91
91
|
const within = Math.min( Math.max( within_ms ?? 15_000, 100 ), 120_000 )
|
|
@@ -101,7 +101,7 @@ export function buildWillMcpServer( will: Will, opts: WillMcpOptions = {} ): Mcp
|
|
|
101
101
|
}
|
|
102
102
|
} )
|
|
103
103
|
|
|
104
|
-
server.registerTool(
|
|
104
|
+
server.registerTool('state', {
|
|
105
105
|
title: 'Inner state',
|
|
106
106
|
description:
|
|
107
107
|
`Read a snapshot of ${ will.name }'s current inner life: tick, body/affect metrics ` +
|
|
@@ -112,7 +112,7 @@ export function buildWillMcpServer( will: Will, opts: WillMcpOptions = {} ): Mcp
|
|
|
112
112
|
{ content: [ { type: 'text', text: JSON.stringify( will.state(), null, 2 ) } ] }
|
|
113
113
|
) )
|
|
114
114
|
|
|
115
|
-
server.registerTool(
|
|
115
|
+
server.registerTool('save', {
|
|
116
116
|
title: 'Save (checkpoint)',
|
|
117
117
|
description:
|
|
118
118
|
`Checkpoint ${ will.name } into a portable PMA artifact on disk — non-destructive, it keeps ` +
|
|
@@ -130,12 +130,12 @@ export function buildWillMcpServer( will: Will, opts: WillMcpOptions = {} ): Mcp
|
|
|
130
130
|
|
|
131
131
|
// ── Resources (read-only projections) ─────────────────────
|
|
132
132
|
|
|
133
|
-
server.registerResource(
|
|
133
|
+
server.registerResource('state', 'will://state',
|
|
134
134
|
{ title: `${ will.name } — inner state`, description: 'Live snapshot of the mind: metrics, goals, beliefs, narrative.', mimeType: 'application/json' },
|
|
135
135
|
async uri => ( { contents: [ { uri: uri.href, mimeType: 'application/json', text: JSON.stringify( will.state(), null, 2 ) } ] } ),
|
|
136
136
|
)
|
|
137
137
|
|
|
138
|
-
server.registerResource(
|
|
138
|
+
server.registerResource('narrative', 'will://narrative',
|
|
139
139
|
{ title: `${ will.name } — self-narrative`, description: 'The story the mind currently tells about itself.', mimeType: 'text/plain' },
|
|
140
140
|
async uri => ( { contents: [ { uri: uri.href, mimeType: 'text/plain', text: will.state().narrative || '(no narrative formed yet)' } ] } ),
|
|
141
141
|
)
|
package/src/pma/eval.ts
CHANGED
|
@@ -368,7 +368,7 @@ export class PMAEvalHarness {
|
|
|
368
368
|
let loadedTraits: Record<string, number> = {}
|
|
369
369
|
|
|
370
370
|
for( const entity of state.entities.values() ){
|
|
371
|
-
if( entity.type === 'will.identity'
|
|
371
|
+
if( entity.type === 'will.identity'){
|
|
372
372
|
loadedTraits = ( entity.metadata?.['traits'] as Record<string, number> ) ?? {}
|
|
373
373
|
break
|
|
374
374
|
}
|
package/src/pma/index.ts
CHANGED
|
@@ -345,7 +345,7 @@ export class PMADistiller {
|
|
|
345
345
|
*/
|
|
346
346
|
private _extractPersona( state: SimulationState ): PMASnapshot['persona'] {
|
|
347
347
|
const priorMeta = state.entities.get( PERSONA_PRIOR_ID )?.metadata as { priors?: Record<string, Record<string, number>> } | undefined
|
|
348
|
-
const calibMeta = state.entities.get(
|
|
348
|
+
const calibMeta = state.entities.get('calibration-state')?.metadata as { domainBias?: Record<string, number> } | undefined
|
|
349
349
|
|
|
350
350
|
const configPriors = priorMeta?.priors ?? {}
|
|
351
351
|
const calibrationBias = calibMeta?.domainBias ?? {}
|
|
@@ -358,7 +358,7 @@ export class PMADistiller {
|
|
|
358
358
|
|
|
359
359
|
private _extractIdentity( state: SimulationState ): PMAIdentity {
|
|
360
360
|
for( const entity of state.entities.values() ){
|
|
361
|
-
if( entity.type === 'will.identity'
|
|
361
|
+
if( entity.type === 'will.identity'){
|
|
362
362
|
const m = entity.metadata ?? {}
|
|
363
363
|
return {
|
|
364
364
|
prompt: ( m['prompt'] as string ) ?? '',
|
|
@@ -390,9 +390,9 @@ export class PMADistiller {
|
|
|
390
390
|
// If socialOrientation not explicitly set, infer from top actions
|
|
391
391
|
if( !enhanced.socialOrientation && behavioral.fingerprint.topActions.length > 0 ){
|
|
392
392
|
const topAction = behavioral.fingerprint.topActions[0] ?? ''
|
|
393
|
-
if( topAction.includes(
|
|
393
|
+
if( topAction.includes('social') || topAction.includes('talk') || topAction.includes('text') ){
|
|
394
394
|
enhanced.socialOrientation = 'gregarious'
|
|
395
|
-
} else if( topAction.includes(
|
|
395
|
+
} else if( topAction.includes('reflect') || topAction.includes('meditate') ){
|
|
396
396
|
enhanced.socialOrientation = 'reserved'
|
|
397
397
|
} else {
|
|
398
398
|
enhanced.socialOrientation = 'ambivert'
|
|
@@ -418,7 +418,7 @@ export class PMADistiller {
|
|
|
418
418
|
const raw: PMABelief[] = []
|
|
419
419
|
|
|
420
420
|
for( const entity of state.entities.values() ){
|
|
421
|
-
if( entity.type !== 'belief'
|
|
421
|
+
if( entity.type !== 'belief') continue
|
|
422
422
|
|
|
423
423
|
const m = entity.metadata ?? {}
|
|
424
424
|
raw.push({
|
|
@@ -446,11 +446,11 @@ export class PMADistiller {
|
|
|
446
446
|
const goals: PMAGoal[] = []
|
|
447
447
|
|
|
448
448
|
for( const entity of state.entities.values() ){
|
|
449
|
-
if( entity.type !== 'goal'
|
|
449
|
+
if( entity.type !== 'goal') continue
|
|
450
450
|
|
|
451
451
|
const m = entity.metadata ?? {}
|
|
452
452
|
const status = ( m['status'] as string ) ?? 'active'
|
|
453
|
-
if( status !== 'active' && status !== 'in_progress'
|
|
453
|
+
if( status !== 'active' && status !== 'in_progress') continue
|
|
454
454
|
|
|
455
455
|
goals.push({
|
|
456
456
|
id: entity.id,
|
|
@@ -459,7 +459,7 @@ export class PMADistiller {
|
|
|
459
459
|
progress: ( m['progress'] as number ) ?? 0,
|
|
460
460
|
status,
|
|
461
461
|
tags: ( m['tags'] as string[] ) ?? [],
|
|
462
|
-
completionType: ( m['completionType'] as 'metric' | 'action' | 'epistemic'
|
|
462
|
+
completionType: ( m['completionType'] as 'metric' | 'action' | 'epistemic') ?? 'epistemic',
|
|
463
463
|
completionCondition: ( m['completionCondition'] as string ) ?? undefined,
|
|
464
464
|
})
|
|
465
465
|
}
|
|
@@ -475,7 +475,7 @@ export class PMADistiller {
|
|
|
475
475
|
const digestTick = new Map<string, number>()
|
|
476
476
|
|
|
477
477
|
for( const entity of state.entities.values() ){
|
|
478
|
-
if( entity.type === 'attachment.bond'
|
|
478
|
+
if( entity.type === 'attachment.bond'){
|
|
479
479
|
const m = entity.metadata ?? {}
|
|
480
480
|
const keid = m['keid'] as string | undefined
|
|
481
481
|
if( !keid ) continue
|
|
@@ -492,7 +492,7 @@ export class PMADistiller {
|
|
|
492
492
|
stubs.set( keid, stub )
|
|
493
493
|
}
|
|
494
494
|
|
|
495
|
-
else if( entity.type === 'reputation'
|
|
495
|
+
else if( entity.type === 'reputation'){
|
|
496
496
|
const m = entity.metadata ?? {}
|
|
497
497
|
const keid = m['keid'] as string | undefined
|
|
498
498
|
if( !keid ) continue
|
|
@@ -512,7 +512,7 @@ export class PMADistiller {
|
|
|
512
512
|
stubs.set( keid, stub )
|
|
513
513
|
}
|
|
514
514
|
|
|
515
|
-
else if( entity.type === 'theory_of_mind'
|
|
515
|
+
else if( entity.type === 'theory_of_mind'){
|
|
516
516
|
const m = entity.metadata ?? {}
|
|
517
517
|
const keid = m['keid'] as string | undefined
|
|
518
518
|
if( !keid ) continue
|
|
@@ -526,15 +526,15 @@ export class PMADistiller {
|
|
|
526
526
|
stubs.set( keid, stub )
|
|
527
527
|
}
|
|
528
528
|
|
|
529
|
-
else if( entity.type === 'known-entity'
|
|
529
|
+
else if( entity.type === 'known-entity'){
|
|
530
530
|
const m = entity.metadata ?? {}
|
|
531
531
|
const keid = m['keid'] as string | undefined
|
|
532
532
|
if( !keid ) continue
|
|
533
533
|
|
|
534
534
|
const stub = stubs.get( keid ) ?? { keid }
|
|
535
|
-
if( !stub.agentName && typeof m['name'] === 'string'
|
|
535
|
+
if( !stub.agentName && typeof m['name'] === 'string') stub.agentName = m['name'] as string
|
|
536
536
|
stub.dossier = {
|
|
537
|
-
kind: ( m['kind'] as 'sentient' | 'thing'
|
|
537
|
+
kind: ( m['kind'] as 'sentient' | 'thing') ?? 'sentient',
|
|
538
538
|
name: ( m['name'] as string | undefined ),
|
|
539
539
|
familiarity: ( m['familiarity'] as number ) ?? 0,
|
|
540
540
|
valence: ( m['valence'] as number ) ?? 0,
|
|
@@ -550,7 +550,7 @@ export class PMADistiller {
|
|
|
550
550
|
// AuditionEngine memory sink + ProactiveCommunicator). The most recent
|
|
551
551
|
// exchange summary wins.
|
|
552
552
|
else if( entity.type === 'episodic_memory'
|
|
553
|
-
&& entity.metadata?.['sourceType'] === 'conversation.exchange'
|
|
553
|
+
&& entity.metadata?.['sourceType'] === 'conversation.exchange'){
|
|
554
554
|
const content = ( entity.metadata['content'] as Record<string, unknown> | undefined ) ?? {}
|
|
555
555
|
const keid = content['entityId'] as string | undefined
|
|
556
556
|
if( !keid ) continue
|
|
@@ -599,7 +599,7 @@ export class PMADistiller {
|
|
|
599
599
|
reactivity: 0.5,
|
|
600
600
|
}
|
|
601
601
|
|
|
602
|
-
const filePath = join( dataDir, 'wills', willId, 'profiles', 'emotional_biography.jsonl'
|
|
602
|
+
const filePath = join( dataDir, 'wills', willId, 'profiles', 'emotional_biography.jsonl')
|
|
603
603
|
if( !existsSync( filePath ) ) return { baseline: defaultBaseline, sessionsRead: 0 }
|
|
604
604
|
|
|
605
605
|
const summaries = _readLastNSummaries( filePath, 'session_summary', 5 )
|
|
@@ -673,7 +673,7 @@ export class PMADistiller {
|
|
|
673
673
|
impulsivity: 0.3,
|
|
674
674
|
}
|
|
675
675
|
|
|
676
|
-
const filePath = join( dataDir, 'wills', willId, 'profiles', 'behavioral.jsonl'
|
|
676
|
+
const filePath = join( dataDir, 'wills', willId, 'profiles', 'behavioral.jsonl')
|
|
677
677
|
if( !existsSync( filePath ) ) return { fingerprint: defaultFingerprint, sessionsRead: 0 }
|
|
678
678
|
|
|
679
679
|
const summaries = _readLastNSummaries( filePath, 'session_summary', 5 )
|
|
@@ -860,7 +860,7 @@ export class PMALoader {
|
|
|
860
860
|
|
|
861
861
|
// ── 3. Goals ──────────────────────────────────────────────
|
|
862
862
|
for( const g of pma.goals ){
|
|
863
|
-
if( g.status !== 'active' && g.status !== 'in_progress'
|
|
863
|
+
if( g.status !== 'active' && g.status !== 'in_progress') continue
|
|
864
864
|
|
|
865
865
|
cognition.goalManager.addGoal(
|
|
866
866
|
g.description,
|
|
@@ -882,8 +882,8 @@ export class PMALoader {
|
|
|
882
882
|
pma.emotionalBaseline.arousalProfile === 'calm' ? 0.30 :
|
|
883
883
|
0.45
|
|
884
884
|
|
|
885
|
-
sm.setMetric(
|
|
886
|
-
sm.setMetric(
|
|
885
|
+
sm.setMetric('affect.valence', valence )
|
|
886
|
+
sm.setMetric('affect.arousal', arousal )
|
|
887
887
|
|
|
888
888
|
// ── 5. Temperament (influences emotional set-point) ───────
|
|
889
889
|
const temperamentValence = pma.emotionalBaseline.temperamentValence
|
|
@@ -1068,7 +1068,7 @@ function _readLastNSummaries(
|
|
|
1068
1068
|
n: number
|
|
1069
1069
|
): Array<Record<string, unknown>> {
|
|
1070
1070
|
try {
|
|
1071
|
-
return readFileSync( filePath, 'utf8'
|
|
1071
|
+
return readFileSync( filePath, 'utf8')
|
|
1072
1072
|
.split('\n')
|
|
1073
1073
|
.filter( l => l.trim().length > 0 )
|
|
1074
1074
|
.map( l => { try { return JSON.parse(l) as Record<string, unknown> } catch { return null } })
|
|
@@ -111,8 +111,8 @@ async function main(): Promise<void> {
|
|
|
111
111
|
lastBlocked = g('agency.communicate.blocked')
|
|
112
112
|
|
|
113
113
|
if( tick % 10 === 0 ){
|
|
114
|
-
const goals = [ ...snap.entities.values() ].filter( e => e.type === 'goal' && e.metadata?.status === 'active'
|
|
115
|
-
const sent = [ ...snap.entities.values() ].filter( e => e.type === 'conversation.sent'
|
|
114
|
+
const goals = [ ...snap.entities.values() ].filter( e => e.type === 'goal' && e.metadata?.status === 'active').length
|
|
115
|
+
const sent = [ ...snap.entities.values() ].filter( e => e.type === 'conversation.sent').length
|
|
116
116
|
console.log(
|
|
117
117
|
`[t${tick}] v=${g('affect.valence').toFixed(2)} arousal=${g('affect.arousal').toFixed(2)} ` +
|
|
118
118
|
`frust=${g('emotion.frustration').toFixed(2)} energy=${g('energy.level').toFixed(0)} ` +
|
|
@@ -130,7 +130,7 @@ async function main(): Promise<void> {
|
|
|
130
130
|
const startedAt = Date.now()
|
|
131
131
|
while( true ){
|
|
132
132
|
const s = m.listWills().find( w => w.id === WILL_ID )
|
|
133
|
-
if( !s || s.status === 'archived'
|
|
133
|
+
if( !s || s.status === 'archived') break
|
|
134
134
|
if( s.tickCount >= END_TICK ) break
|
|
135
135
|
if( sawReactive && sawProactive ){ console.log('\n[scenario] both paths observed — wrapping up'); break }
|
|
136
136
|
if( Date.now() - startedAt > SAFETY_MS ){ console.log('\n[scenario] safety cap hit'); break }
|
|
@@ -134,7 +134,7 @@ async function main(): Promise<void> {
|
|
|
134
134
|
|
|
135
135
|
// Beliefs the Will formed ABOUT Dr. Chen (social cognition evidence)
|
|
136
136
|
const chenBeliefs = ( ( pma as { beliefs?: Array<{ statement?: string; content?: string }> } ).beliefs ?? [] )
|
|
137
|
-
.map( b => b.statement ?? b.content ?? ''
|
|
137
|
+
.map( b => b.statement ?? b.content ?? '')
|
|
138
138
|
.filter( s => /chen|she|her|researcher|observ/i.test( s ) )
|
|
139
139
|
.slice( 0, 6 )
|
|
140
140
|
if( chenBeliefs.length ){
|
|
@@ -26,7 +26,7 @@ const TICK_MS = parseInt( process.env.WILL_TICK_MS ?? '1000')
|
|
|
26
26
|
const MAX_TICKS = parseInt( process.env.WILL_MAX_TICKS ?? '0' )
|
|
27
27
|
const LOG_INTERVAL = parseInt( process.env.WILL_LOG_INTERVAL ?? '10' )
|
|
28
28
|
const RANDOM_SEED = parseInt( process.env.WILL_SEED ?? String( Date.now() ) )
|
|
29
|
-
const ANATOMY = ( process.env.WILL_ANATOMY ?? 'mind'
|
|
29
|
+
const ANATOMY = ( process.env.WILL_ANATOMY ?? 'mind') as WillConfig['anatomy']
|
|
30
30
|
const EXECUTIVE_INT = process.env.WILL_EXECUTIVE_INTERVAL
|
|
31
31
|
? parseInt( process.env.WILL_EXECUTIVE_INTERVAL )
|
|
32
32
|
: undefined
|