@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/dist/cli.js
CHANGED
|
@@ -3862,6 +3862,11 @@ var MODEL_PRICING = {
|
|
|
3862
3862
|
// Legacy aliases kept for backward compat
|
|
3863
3863
|
"anthropic/claude-haiku-4": { input: 1, output: 5 },
|
|
3864
3864
|
"anthropic/claude-opus-4": { input: 5, output: 25 },
|
|
3865
|
+
// Z.ai (GLM-5 family). `glm-5.2[1m]` is the same model asking for its 1M
|
|
3866
|
+
// context window — same rate, so it gets its own row rather than relying on
|
|
3867
|
+
// the normalizer (a future long-context tier would price differently).
|
|
3868
|
+
"glm/glm-5.2": { input: 1.4, output: 4.4 },
|
|
3869
|
+
"glm/glm-5.2[1m]": { input: 1.4, output: 4.4 },
|
|
3865
3870
|
// Google
|
|
3866
3871
|
"google/gemini-2.0-flash": { input: 0.1, output: 0.4 },
|
|
3867
3872
|
"google/gemini-2.0-pro": { input: 1.25, output: 5 },
|
|
@@ -4650,6 +4655,9 @@ var SleepPressureRegulator = class {
|
|
|
4650
4655
|
}
|
|
4651
4656
|
};
|
|
4652
4657
|
|
|
4658
|
+
// src/cognition/acp.ts
|
|
4659
|
+
var ACP_SELF_PRECISION = 0.35;
|
|
4660
|
+
|
|
4653
4661
|
// src/cognition/persona.prior.ts
|
|
4654
4662
|
var PERSONA_PRIOR_ID = "persona-prior";
|
|
4655
4663
|
var PERSONA_PRIOR_TYPE = "persona.prior";
|
|
@@ -4758,6 +4766,8 @@ function consolidatePrior(current, adjustments, tick, opts = {}) {
|
|
|
4758
4766
|
}
|
|
4759
4767
|
|
|
4760
4768
|
// src/cognition/faculties/attention.allocator.ts
|
|
4769
|
+
var ACP_USAGE_UPLIFT = 0.15;
|
|
4770
|
+
var ACP_CONFIDENCE = 0.4;
|
|
4761
4771
|
var EFFORT_BASELINE2 = 0.7;
|
|
4762
4772
|
var EFFORT_MIN = 0.4;
|
|
4763
4773
|
var EFFORT_MAX = 1;
|
|
@@ -4779,6 +4789,8 @@ var AttentionAllocator = class {
|
|
|
4779
4789
|
_effort = EFFORT_BASELINE2;
|
|
4780
4790
|
/** A one-shot focus/rest request from the executive, applied next react(). */
|
|
4781
4791
|
_effortRequest = null;
|
|
4792
|
+
/** ACP-P2: a self-caused precision attenuation is armed; react() restores after one observe. */
|
|
4793
|
+
_acpOneShot = false;
|
|
4782
4794
|
_bus = null;
|
|
4783
4795
|
_model = new GenerativeModel();
|
|
4784
4796
|
constructor(config = {}) {
|
|
@@ -4799,8 +4811,12 @@ var AttentionAllocator = class {
|
|
|
4799
4811
|
"executive.prediction.formed",
|
|
4800
4812
|
"attention.regulate",
|
|
4801
4813
|
// voluntary focus/rest from the executive (Option C)
|
|
4802
|
-
"senses.*"
|
|
4814
|
+
"senses.*",
|
|
4803
4815
|
// all sense percepts — salience feeds attention allocation
|
|
4816
|
+
// ACP-P2: our own enactions — anticipate the attention swing they cause
|
|
4817
|
+
"agency.enacted",
|
|
4818
|
+
"agency.communicate",
|
|
4819
|
+
"agency.invocation"
|
|
4804
4820
|
];
|
|
4805
4821
|
}
|
|
4806
4822
|
publishes() {
|
|
@@ -4827,6 +4843,18 @@ var AttentionAllocator = class {
|
|
|
4827
4843
|
this._model.setPrecision("attention.usage", 1 + p.confidence * 0.5);
|
|
4828
4844
|
break;
|
|
4829
4845
|
}
|
|
4846
|
+
case "agency.enacted":
|
|
4847
|
+
case "agency.communicate":
|
|
4848
|
+
case "agency.invocation": {
|
|
4849
|
+
const usage = this._model.predict("attention.usage");
|
|
4850
|
+
const free = this._model.predict("attention.free_fraction");
|
|
4851
|
+
this._model.anticipate("attention.usage", Math.min(1, usage + ACP_USAGE_UPLIFT), ACP_CONFIDENCE);
|
|
4852
|
+
this._model.anticipate("attention.free_fraction", Math.max(0, free - ACP_USAGE_UPLIFT), ACP_CONFIDENCE);
|
|
4853
|
+
this._model.setPrecision("attention.usage", ACP_SELF_PRECISION);
|
|
4854
|
+
this._model.setPrecision("attention.free_fraction", ACP_SELF_PRECISION);
|
|
4855
|
+
this._acpOneShot = true;
|
|
4856
|
+
break;
|
|
4857
|
+
}
|
|
4830
4858
|
default:
|
|
4831
4859
|
if (e.type.startsWith("senses.")) {
|
|
4832
4860
|
const percept = e.payload;
|
|
@@ -4910,6 +4938,11 @@ var AttentionAllocator = class {
|
|
|
4910
4938
|
if (_bus) {
|
|
4911
4939
|
const usageErr = this._model.observe("attention.usage", attentionUsage);
|
|
4912
4940
|
const freeErr = this._model.observe("attention.free_fraction", freeFraction);
|
|
4941
|
+
if (this._acpOneShot) {
|
|
4942
|
+
this._model.setPrecision("attention.usage", 1);
|
|
4943
|
+
this._model.setPrecision("attention.free_fraction", 1);
|
|
4944
|
+
this._acpOneShot = false;
|
|
4945
|
+
}
|
|
4913
4946
|
if (!usageErr.gated || !freeErr.gated)
|
|
4914
4947
|
_bus.publish({ type: "attention.state.changed", version: 1, sourceEngine: this.name, salience: Math.max(usageErr.salience, freeErr.salience), payload: { usage: attentionUsage, focusCount, capacity: effectiveCapacity, freeFraction } });
|
|
4915
4948
|
}
|
|
@@ -5029,7 +5062,18 @@ var StressRegulator = class {
|
|
|
5029
5062
|
}
|
|
5030
5063
|
// ── Engine interface ─────────────────────────────────────
|
|
5031
5064
|
subscribes() {
|
|
5032
|
-
return [
|
|
5065
|
+
return [
|
|
5066
|
+
"energy.state.changed",
|
|
5067
|
+
"sleep.state.changed",
|
|
5068
|
+
"novelty.state.changed",
|
|
5069
|
+
"goal.state.changed",
|
|
5070
|
+
"metacognition.state.changed",
|
|
5071
|
+
"executive.prediction.formed",
|
|
5072
|
+
// ACP-P2: our own enactions — the stress swing they cause is expected
|
|
5073
|
+
"agency.enacted",
|
|
5074
|
+
"agency.communicate",
|
|
5075
|
+
"agency.invocation"
|
|
5076
|
+
];
|
|
5033
5077
|
}
|
|
5034
5078
|
publishes() {
|
|
5035
5079
|
return [];
|
|
@@ -5058,8 +5102,17 @@ var StressRegulator = class {
|
|
|
5058
5102
|
this._model.setPrecision("stress.load", 1 + p.confidence * 0.5);
|
|
5059
5103
|
break;
|
|
5060
5104
|
}
|
|
5105
|
+
case "agency.enacted":
|
|
5106
|
+
case "agency.communicate":
|
|
5107
|
+
case "agency.invocation": {
|
|
5108
|
+
this._model.setPrecision("stress.load", ACP_SELF_PRECISION);
|
|
5109
|
+
this._acpOneShot = true;
|
|
5110
|
+
break;
|
|
5111
|
+
}
|
|
5061
5112
|
}
|
|
5062
5113
|
}
|
|
5114
|
+
/** ACP-P2: self-caused stress attenuation armed; react() restores after one observe. */
|
|
5115
|
+
_acpOneShot = false;
|
|
5063
5116
|
snapshot() {
|
|
5064
5117
|
return {
|
|
5065
5118
|
energyLevel: this._energyLevel,
|
|
@@ -5152,6 +5205,10 @@ var StressRegulator = class {
|
|
|
5152
5205
|
if (_bus) {
|
|
5153
5206
|
const zoneCode = zone === "low" ? 0 : zone === "optimal" ? 1 : zone === "distress" ? 2 : 3;
|
|
5154
5207
|
const predErr = this._model.observe("stress.load", newLoad);
|
|
5208
|
+
if (this._acpOneShot) {
|
|
5209
|
+
this._model.setPrecision("stress.load", 1);
|
|
5210
|
+
this._acpOneShot = false;
|
|
5211
|
+
}
|
|
5155
5212
|
if (!predErr.gated || zone !== previousZone) {
|
|
5156
5213
|
_bus.publish({ type: "stress.state.changed", version: 1, sourceEngine: this.name, salience: predErr.salience, payload: { load: newLoad, zoneCode, deadlineUrgency: state.metrics.get("deadline.urgency") ?? 0, cognitiveLoad: state.metrics.get("cognitive.load") ?? state.metrics.get("attention.usage") ?? 0 } });
|
|
5157
5214
|
}
|
|
@@ -5374,6 +5431,116 @@ var CircadianOscillator = class {
|
|
|
5374
5431
|
}
|
|
5375
5432
|
};
|
|
5376
5433
|
|
|
5434
|
+
// src/cognition/agency/consequence.ts
|
|
5435
|
+
var CONSEQUENCE_TYPE = "agency.consequence";
|
|
5436
|
+
var ATTENUATION = 0.25;
|
|
5437
|
+
var MIN_TEXT_MATCH_LEN = 12;
|
|
5438
|
+
var CONSEQUENCE_TTL_TICKS = 30;
|
|
5439
|
+
function fnv1a(text) {
|
|
5440
|
+
let h = 2166136261;
|
|
5441
|
+
for (let i = 0; i < text.length; i++) {
|
|
5442
|
+
h ^= text.charCodeAt(i);
|
|
5443
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
5444
|
+
}
|
|
5445
|
+
return h >>> 0;
|
|
5446
|
+
}
|
|
5447
|
+
function paramsKey(value) {
|
|
5448
|
+
if (value === null || typeof value !== "object")
|
|
5449
|
+
return typeof value === "string" ? JSON.stringify(value) : String(value);
|
|
5450
|
+
if (Array.isArray(value))
|
|
5451
|
+
return `[${value.map(paramsKey).join(",")}]`;
|
|
5452
|
+
const obj = value;
|
|
5453
|
+
const keys = Object.keys(obj).sort();
|
|
5454
|
+
return `{${keys.map((k) => `${k}:${paramsKey(obj[k])}`).join(",")}}`;
|
|
5455
|
+
}
|
|
5456
|
+
function consequenceEntity(d) {
|
|
5457
|
+
return {
|
|
5458
|
+
id: `agency-consequence-${d.intentId}`,
|
|
5459
|
+
type: CONSEQUENCE_TYPE,
|
|
5460
|
+
metadata: { ...d }
|
|
5461
|
+
};
|
|
5462
|
+
}
|
|
5463
|
+
function readConsequence(m) {
|
|
5464
|
+
const meta = m ?? {};
|
|
5465
|
+
const intentId = typeof meta["intentId"] === "string" ? meta["intentId"] : void 0;
|
|
5466
|
+
const schema = typeof meta["schema"] === "string" ? meta["schema"] : void 0;
|
|
5467
|
+
const mode = meta["mode"] === "communicate" || meta["mode"] === "external" ? meta["mode"] : void 0;
|
|
5468
|
+
if (!intentId || !schema || !mode) return null;
|
|
5469
|
+
return {
|
|
5470
|
+
intentId,
|
|
5471
|
+
schema,
|
|
5472
|
+
mode,
|
|
5473
|
+
effector: typeof meta["effector"] === "string" ? meta["effector"] : void 0,
|
|
5474
|
+
targetEntityId: typeof meta["targetEntityId"] === "string" ? meta["targetEntityId"] : void 0,
|
|
5475
|
+
textHash: typeof meta["textHash"] === "number" ? meta["textHash"] : void 0,
|
|
5476
|
+
text: typeof meta["text"] === "string" ? meta["text"] : void 0,
|
|
5477
|
+
paramsHash: typeof meta["paramsHash"] === "number" ? meta["paramsHash"] : void 0,
|
|
5478
|
+
expiresAt: typeof meta["expiresAt"] === "number" ? meta["expiresAt"] : 0,
|
|
5479
|
+
tick: typeof meta["tick"] === "number" ? meta["tick"] : 0
|
|
5480
|
+
};
|
|
5481
|
+
}
|
|
5482
|
+
function liveConsequences(entities, tick) {
|
|
5483
|
+
const out = [];
|
|
5484
|
+
for (const [, e] of entities) {
|
|
5485
|
+
if (e.type !== CONSEQUENCE_TYPE) continue;
|
|
5486
|
+
const d = readConsequence(e.metadata);
|
|
5487
|
+
if (d && tick < d.expiresAt) out.push(d);
|
|
5488
|
+
}
|
|
5489
|
+
return out.sort((a, b) => a.intentId < b.intentId ? -1 : a.intentId > b.intentId ? 1 : 0);
|
|
5490
|
+
}
|
|
5491
|
+
function matchConsequenceText(descriptors, candidate) {
|
|
5492
|
+
if (candidate.length === 0) return null;
|
|
5493
|
+
const candidateHash = fnv1a(candidate);
|
|
5494
|
+
for (const d of descriptors) {
|
|
5495
|
+
if (d.textHash !== void 0 && d.textHash === candidateHash) return d;
|
|
5496
|
+
if (d.text !== void 0 && d.text.length >= MIN_TEXT_MATCH_LEN && candidate.includes(d.text)) return d;
|
|
5497
|
+
}
|
|
5498
|
+
return null;
|
|
5499
|
+
}
|
|
5500
|
+
var CORRESPONDENCE_ATTENUATION = 0.5;
|
|
5501
|
+
function matchConsequenceEntity(descriptors, entityId, changeType) {
|
|
5502
|
+
if (changeType !== "modified" || entityId.length === 0) return null;
|
|
5503
|
+
for (const d of descriptors)
|
|
5504
|
+
if (d.mode === "external" && d.targetEntityId === entityId) return d;
|
|
5505
|
+
return null;
|
|
5506
|
+
}
|
|
5507
|
+
|
|
5508
|
+
// src/cognition/agency/revocation.ts
|
|
5509
|
+
var REVOCATION_TYPE = "agency.revocation";
|
|
5510
|
+
var RUPTURE_REVOKE_GATE = 0.7;
|
|
5511
|
+
var REVOCATION_TTL_TICKS = 5;
|
|
5512
|
+
function revocationId(intentId) {
|
|
5513
|
+
return `agency-revocation-${intentId}`;
|
|
5514
|
+
}
|
|
5515
|
+
function revocationEntity(intentId, schema, rupture, tick) {
|
|
5516
|
+
return {
|
|
5517
|
+
id: revocationId(intentId),
|
|
5518
|
+
type: REVOCATION_TYPE,
|
|
5519
|
+
metadata: { intentId, schema, rupture, tick, expiresAt: tick + REVOCATION_TTL_TICKS }
|
|
5520
|
+
};
|
|
5521
|
+
}
|
|
5522
|
+
function revokedIntentIds(entities, tick) {
|
|
5523
|
+
const out = /* @__PURE__ */ new Set();
|
|
5524
|
+
for (const [, e] of entities) {
|
|
5525
|
+
if (e.type !== REVOCATION_TYPE) continue;
|
|
5526
|
+
const m = e.metadata ?? {};
|
|
5527
|
+
const intentId = typeof m["intentId"] === "string" ? m["intentId"] : void 0;
|
|
5528
|
+
const expiresAt = typeof m["expiresAt"] === "number" ? m["expiresAt"] : 0;
|
|
5529
|
+
if (intentId && tick < expiresAt) out.add(intentId);
|
|
5530
|
+
}
|
|
5531
|
+
return out;
|
|
5532
|
+
}
|
|
5533
|
+
function staleRevocationIds(entities, tick) {
|
|
5534
|
+
const stale = [];
|
|
5535
|
+
for (const [id, e] of entities) {
|
|
5536
|
+
if (e.type !== REVOCATION_TYPE) continue;
|
|
5537
|
+
const m = e.metadata ?? {};
|
|
5538
|
+
const expiresAt = typeof m["expiresAt"] === "number" ? m["expiresAt"] : 0;
|
|
5539
|
+
if (tick >= expiresAt) stale.push(id);
|
|
5540
|
+
}
|
|
5541
|
+
return stale;
|
|
5542
|
+
}
|
|
5543
|
+
|
|
5377
5544
|
// src/cognition/faculties/exteroception.ts
|
|
5378
5545
|
var internalTypes = /* @__PURE__ */ new Set([
|
|
5379
5546
|
"percept",
|
|
@@ -5399,7 +5566,12 @@ var internalTypes = /* @__PURE__ */ new Set([
|
|
|
5399
5566
|
"episodic_memory",
|
|
5400
5567
|
// Internal state entities written by our own engines — not external events
|
|
5401
5568
|
"affect.blends",
|
|
5402
|
-
"executive.summary"
|
|
5569
|
+
"executive.summary",
|
|
5570
|
+
// The agency's own forward-model records (EXAFFERENCE P1/P2): perceiving our
|
|
5571
|
+
// expected-consequence descriptors would be a self-noise loop.
|
|
5572
|
+
CONSEQUENCE_TYPE,
|
|
5573
|
+
// The agency's own revocation tombstones (EXAFFERENCE P4) — internal bookkeeping.
|
|
5574
|
+
REVOCATION_TYPE
|
|
5403
5575
|
]);
|
|
5404
5576
|
var Exteroception = class {
|
|
5405
5577
|
name = "exteroception";
|
|
@@ -5449,17 +5621,26 @@ var Exteroception = class {
|
|
|
5449
5621
|
const events = [], commands = { set: [], delete: [], metrics: [] };
|
|
5450
5622
|
const rawPercepts = this._scanWorld(state);
|
|
5451
5623
|
const capped = rawPercepts.slice(0, this._maxPerceptsPerTick);
|
|
5624
|
+
const consequences = liveConsequences(state.entities, tick);
|
|
5452
5625
|
for (let i = 0; i < capped.length; i++) {
|
|
5453
5626
|
const rp = capped[i];
|
|
5627
|
+
const textHit = consequences.length > 0 && rp.matchText ? matchConsequenceText(consequences, rp.matchText) : null;
|
|
5628
|
+
const entityHit = !textHit && consequences.length > 0 ? matchConsequenceEntity(consequences, rp.entityId, rp.changeType) : null;
|
|
5629
|
+
const hit = textHit ?? entityHit;
|
|
5630
|
+
const salience = textHit ? rp.salience * ATTENUATION : entityHit ? rp.salience * CORRESPONDENCE_ATTENUATION : rp.salience;
|
|
5454
5631
|
const perceptEntity = {
|
|
5455
5632
|
id: `percept-${tick}-${i}`,
|
|
5456
5633
|
type: "percept",
|
|
5457
5634
|
metadata: {
|
|
5458
5635
|
entityId: rp.entityId,
|
|
5459
5636
|
changeType: rp.changeType,
|
|
5460
|
-
salience
|
|
5637
|
+
salience,
|
|
5461
5638
|
category: rp.category,
|
|
5462
5639
|
summary: rp.summary,
|
|
5640
|
+
provenance: hit ? "reafferent" : "exafferent",
|
|
5641
|
+
...hit ? { sourceIntentId: hit.intentId } : {},
|
|
5642
|
+
// affect→percept seam (registry #5): what this percept FEELS like
|
|
5643
|
+
...rp.valence !== void 0 ? { valence: rp.valence, valenceSource: rp.valenceSource } : {},
|
|
5463
5644
|
tick
|
|
5464
5645
|
}
|
|
5465
5646
|
};
|
|
@@ -5470,7 +5651,7 @@ var Exteroception = class {
|
|
|
5470
5651
|
source: this.name,
|
|
5471
5652
|
payload: {
|
|
5472
5653
|
entityId: rp.entityId,
|
|
5473
|
-
salience
|
|
5654
|
+
salience,
|
|
5474
5655
|
category: rp.category,
|
|
5475
5656
|
summary: rp.summary
|
|
5476
5657
|
}
|
|
@@ -5518,7 +5699,9 @@ var Exteroception = class {
|
|
|
5518
5699
|
changeType: "appeared",
|
|
5519
5700
|
salience: this._computeSalience(entity, "appeared", state.time),
|
|
5520
5701
|
category: entity.type,
|
|
5521
|
-
summary: this._summarizeEntity(entity, "appeared")
|
|
5702
|
+
summary: this._summarizeEntity(entity, "appeared"),
|
|
5703
|
+
matchText: this._matchText(entity),
|
|
5704
|
+
...this._valenceOf(id, state)
|
|
5522
5705
|
});
|
|
5523
5706
|
} else if (entity.updatedAt > previousVersion) {
|
|
5524
5707
|
percepts.push({
|
|
@@ -5526,7 +5709,9 @@ var Exteroception = class {
|
|
|
5526
5709
|
changeType: "modified",
|
|
5527
5710
|
salience: this._computeSalience(entity, "modified", state.time),
|
|
5528
5711
|
category: entity.type,
|
|
5529
|
-
summary: this._summarizeEntity(entity, "modified")
|
|
5712
|
+
summary: this._summarizeEntity(entity, "modified"),
|
|
5713
|
+
matchText: this._matchText(entity),
|
|
5714
|
+
...this._valenceOf(id, state)
|
|
5530
5715
|
});
|
|
5531
5716
|
}
|
|
5532
5717
|
this._previousEntityVersions.set(id, entity.updatedAt);
|
|
@@ -5552,6 +5737,46 @@ var Exteroception = class {
|
|
|
5552
5737
|
* Generate a meaningful summary for an entity.
|
|
5553
5738
|
* Instead of "New percept: percept-54-0", produce something useful.
|
|
5554
5739
|
*/
|
|
5740
|
+
/**
|
|
5741
|
+
* The text the corollary-discharge matcher inspects for this entity — its
|
|
5742
|
+
* content (a message body) over its description over its summary. Where our
|
|
5743
|
+
* own delivered words would surface if the world echoes them back.
|
|
5744
|
+
*/
|
|
5745
|
+
/**
|
|
5746
|
+
* The affect→percept valence seam (registry #5). A percept carries how the
|
|
5747
|
+
* mind *feels* about what it is a percept OF, resolved most-specific-first:
|
|
5748
|
+
*
|
|
5749
|
+
* 1. the KnownEntityTracker's dossier for this entity (`ke-<id>.valence`) —
|
|
5750
|
+
* a real per-entity felt valence, the honest signal;
|
|
5751
|
+
* 2. otherwise the ambient `affect.valence` — the felt tone at perception
|
|
5752
|
+
* time. Weaker evidence, so it is tagged `'ambient'` and consumers
|
|
5753
|
+
* weight it down (mood is context, not appraisal of this thing).
|
|
5754
|
+
*
|
|
5755
|
+
* Absent both, no valence is stamped and every consumer keeps its
|
|
5756
|
+
* pre-seam behaviour.
|
|
5757
|
+
*/
|
|
5758
|
+
/** Spread-friendly form of `_valenceFor` for percept construction. */
|
|
5759
|
+
_valenceOf(entityId, state) {
|
|
5760
|
+
const v = this._valenceFor(entityId, state);
|
|
5761
|
+
return v ? { valence: v.valence, valenceSource: v.source } : {};
|
|
5762
|
+
}
|
|
5763
|
+
_valenceFor(entityId, state) {
|
|
5764
|
+
const dossier = state.entities.get(`ke-${entityId}`);
|
|
5765
|
+
const felt = dossier?.metadata?.["valence"];
|
|
5766
|
+
if (typeof felt === "number" && Number.isFinite(felt))
|
|
5767
|
+
return { valence: felt, source: "entity" };
|
|
5768
|
+
const ambient = state.metrics.get("affect.valence");
|
|
5769
|
+
if (typeof ambient === "number" && Number.isFinite(ambient))
|
|
5770
|
+
return { valence: ambient, source: "ambient" };
|
|
5771
|
+
return void 0;
|
|
5772
|
+
}
|
|
5773
|
+
_matchText(entity) {
|
|
5774
|
+
const m = entity.metadata;
|
|
5775
|
+
const content = typeof m?.["content"] === "string" ? m["content"] : void 0;
|
|
5776
|
+
const description = typeof m?.["description"] === "string" ? m["description"] : void 0;
|
|
5777
|
+
const summary = typeof m?.["summary"] === "string" ? m["summary"] : void 0;
|
|
5778
|
+
return content ?? description ?? summary;
|
|
5779
|
+
}
|
|
5555
5780
|
_summarizeEntity(entity, changeType) {
|
|
5556
5781
|
const name = entity.metadata?.name;
|
|
5557
5782
|
const description = entity.metadata?.description;
|
|
@@ -7536,6 +7761,8 @@ var MoralEvaluator = class {
|
|
|
7536
7761
|
};
|
|
7537
7762
|
|
|
7538
7763
|
// src/cognition/faculties/affective.blender.ts
|
|
7764
|
+
var ACP_AROUSAL_UPLIFT = 0.1;
|
|
7765
|
+
var ACP_CONFIDENCE2 = 0.4;
|
|
7539
7766
|
var DOMINANT_EMOTION_CODES = {
|
|
7540
7767
|
"neutral": 0,
|
|
7541
7768
|
"fear": 1,
|
|
@@ -7636,6 +7863,8 @@ var AffectiveBlender = class {
|
|
|
7636
7863
|
_previousPAD = { valence: 0, arousal: 0.3, dominance: 0.5 };
|
|
7637
7864
|
_emotionHistory = /* @__PURE__ */ new Map();
|
|
7638
7865
|
_moodBaseline = 0.5;
|
|
7866
|
+
/** ACP-P2: self-caused arousal attenuation armed; react() restores after one observe. */
|
|
7867
|
+
_acpOneShot = false;
|
|
7639
7868
|
_energyLevel = 100;
|
|
7640
7869
|
_comfort = 0.5;
|
|
7641
7870
|
_sleepPressure = 0;
|
|
@@ -7669,8 +7898,12 @@ var AffectiveBlender = class {
|
|
|
7669
7898
|
"sleep.state.changed",
|
|
7670
7899
|
"stress.state.changed",
|
|
7671
7900
|
"executive.prediction.formed",
|
|
7672
|
-
"interaction.occurred"
|
|
7901
|
+
"interaction.occurred",
|
|
7673
7902
|
// 2.1: social stimuli drive immediate arousal/valence shifts
|
|
7903
|
+
// ACP-P2: our own enactions — the arousal they cause is expected, not surprising
|
|
7904
|
+
"agency.enacted",
|
|
7905
|
+
"agency.communicate",
|
|
7906
|
+
"agency.invocation"
|
|
7674
7907
|
];
|
|
7675
7908
|
}
|
|
7676
7909
|
publishes() {
|
|
@@ -7679,6 +7912,15 @@ var AffectiveBlender = class {
|
|
|
7679
7912
|
onCognitiveEvent(e) {
|
|
7680
7913
|
this._model.observe(e.type, e.salience);
|
|
7681
7914
|
switch (e.type) {
|
|
7915
|
+
case "agency.enacted":
|
|
7916
|
+
case "agency.communicate":
|
|
7917
|
+
case "agency.invocation": {
|
|
7918
|
+
const arousal = this._model.predict("affect.arousal");
|
|
7919
|
+
this._model.anticipate("affect.arousal", Math.min(1, arousal + ACP_AROUSAL_UPLIFT), ACP_CONFIDENCE2);
|
|
7920
|
+
this._model.setPrecision("affect.arousal", ACP_SELF_PRECISION);
|
|
7921
|
+
this._acpOneShot = true;
|
|
7922
|
+
break;
|
|
7923
|
+
}
|
|
7682
7924
|
case "circadian.state.changed":
|
|
7683
7925
|
this._moodBaseline = e.payload["moodBaseline"] ?? this._moodBaseline;
|
|
7684
7926
|
break;
|
|
@@ -7782,8 +8024,14 @@ var AffectiveBlender = class {
|
|
|
7782
8024
|
const _bus = this._bus;
|
|
7783
8025
|
if (_bus)
|
|
7784
8026
|
_bus.publish({ type: "affect.state.shifted", version: 1, sourceEngine: this.name, salience: Math.min(1, Math.abs(modulatedPAD.valence) + modulatedPAD.arousal * 0.5), payload: { valence: modulatedPAD.valence, arousal: modulatedPAD.arousal, dominantEmotion: dominant } });
|
|
7785
|
-
if (_bus)
|
|
7786
|
-
|
|
8027
|
+
if (_bus) {
|
|
8028
|
+
const arousalErr = this._model.observe("affect.arousal", modulatedPAD.arousal);
|
|
8029
|
+
if (this._acpOneShot) {
|
|
8030
|
+
this._model.setPrecision("affect.arousal", 1);
|
|
8031
|
+
this._acpOneShot = false;
|
|
8032
|
+
}
|
|
8033
|
+
_bus.publish({ type: "affect.state.changed", version: 1, sourceEngine: this.name, salience: arousalErr.salience, payload: { valence: modulatedPAD.valence, arousal: modulatedPAD.arousal, dominance: modulatedPAD.dominance } });
|
|
8034
|
+
}
|
|
7787
8035
|
return { events: events.length > 0 ? events : void 0, commands };
|
|
7788
8036
|
}
|
|
7789
8037
|
// ── PAD computation ──────────────────────────────────────
|
|
@@ -13153,6 +13401,38 @@ async function withGate(fn, label, gate = llmGate) {
|
|
|
13153
13401
|
}
|
|
13154
13402
|
|
|
13155
13403
|
// src/llm/index.ts
|
|
13404
|
+
var ANTHROPIC_WIRE = /* @__PURE__ */ new Set(["anthropic", "glm"]);
|
|
13405
|
+
function speaksAnthropicWire(provider) {
|
|
13406
|
+
return ANTHROPIC_WIRE.has(provider);
|
|
13407
|
+
}
|
|
13408
|
+
function defaultBaseFor(provider) {
|
|
13409
|
+
switch (provider) {
|
|
13410
|
+
case "anthropic":
|
|
13411
|
+
return "https://api.anthropic.com/v1";
|
|
13412
|
+
// Z.ai documents the base as `…/api/anthropic` because the Anthropic SDK
|
|
13413
|
+
// appends `/v1/messages`; this client appends `/messages`, so the version
|
|
13414
|
+
// segment belongs here — verified against the live endpoint.
|
|
13415
|
+
case "glm":
|
|
13416
|
+
return "https://api.z.ai/api/anthropic/v1";
|
|
13417
|
+
case "openai":
|
|
13418
|
+
return "https://api.openai.com/v1";
|
|
13419
|
+
case "deepseek":
|
|
13420
|
+
return "https://api.deepseek.com/v1";
|
|
13421
|
+
case "google":
|
|
13422
|
+
return "https://generativelanguage.googleapis.com/v1beta";
|
|
13423
|
+
}
|
|
13424
|
+
}
|
|
13425
|
+
function defaultModelFor(provider) {
|
|
13426
|
+
return provider === "glm" ? "glm-5.2" : "claude-sonnet-4-5-20250929";
|
|
13427
|
+
}
|
|
13428
|
+
function anthropicWireHeaders(provider, apiKey) {
|
|
13429
|
+
return {
|
|
13430
|
+
"Content-Type": "application/json",
|
|
13431
|
+
"anthropic-version": "2023-06-01",
|
|
13432
|
+
"x-api-key": apiKey,
|
|
13433
|
+
...provider === "glm" ? { Authorization: `Bearer ${apiKey}` } : {}
|
|
13434
|
+
};
|
|
13435
|
+
}
|
|
13156
13436
|
var DEFAULT_CALL_META = { category: "executive", attribute: "master", function: "decision" };
|
|
13157
13437
|
var LLMDirector = class {
|
|
13158
13438
|
_willId;
|
|
@@ -13255,7 +13535,7 @@ var LLMDirector = class {
|
|
|
13255
13535
|
this._recordCompletion(systemPrompt, userMessage, tick, result2, Date.now() - start, true);
|
|
13256
13536
|
return result2;
|
|
13257
13537
|
}
|
|
13258
|
-
const result = this._provider
|
|
13538
|
+
const result = speaksAnthropicWire(this._provider) ? await this._callAnthropicStream(systemPrompt, userMessage, onChunk, temperature) : await (async () => {
|
|
13259
13539
|
const r = await this._callProvider(systemPrompt, userMessage, temperature);
|
|
13260
13540
|
onChunk(r.text);
|
|
13261
13541
|
return r;
|
|
@@ -13335,11 +13615,7 @@ var LLMDirector = class {
|
|
|
13335
13615
|
try {
|
|
13336
13616
|
res = await fetch(`${this._resolvedBase()}/messages`, {
|
|
13337
13617
|
method: "POST",
|
|
13338
|
-
headers:
|
|
13339
|
-
"Content-Type": "application/json",
|
|
13340
|
-
"anthropic-version": "2023-06-01",
|
|
13341
|
-
"x-api-key": this._apiKey
|
|
13342
|
-
},
|
|
13618
|
+
headers: anthropicWireHeaders(this._provider, this._apiKey),
|
|
13343
13619
|
body: JSON.stringify({
|
|
13344
13620
|
model: this._model,
|
|
13345
13621
|
max_tokens: this._maxOutputTokens,
|
|
@@ -13414,7 +13690,7 @@ var LLMDirector = class {
|
|
|
13414
13690
|
return result2;
|
|
13415
13691
|
}
|
|
13416
13692
|
const result = await withGate(
|
|
13417
|
-
() => this._provider
|
|
13693
|
+
() => speaksAnthropicWire(this._provider) ? this._callAnthropicStream(systemPrompt, userMessage, () => {
|
|
13418
13694
|
}, temperature) : this._callProvider(systemPrompt, userMessage, temperature),
|
|
13419
13695
|
"executive/direct"
|
|
13420
13696
|
);
|
|
@@ -13426,6 +13702,8 @@ var LLMDirector = class {
|
|
|
13426
13702
|
switch (this._provider) {
|
|
13427
13703
|
case "anthropic":
|
|
13428
13704
|
return this._callAnthropic(systemPrompt, userMessage, temperature);
|
|
13705
|
+
case "glm":
|
|
13706
|
+
return this._callAnthropic(systemPrompt, userMessage, temperature);
|
|
13429
13707
|
case "deepseek":
|
|
13430
13708
|
return this._callOpenAI(systemPrompt, userMessage, temperature);
|
|
13431
13709
|
case "openai":
|
|
@@ -13438,16 +13716,7 @@ var LLMDirector = class {
|
|
|
13438
13716
|
}
|
|
13439
13717
|
/** Default API base URL (including version segment) for a provider. */
|
|
13440
13718
|
_baseFor(provider) {
|
|
13441
|
-
|
|
13442
|
-
case "anthropic":
|
|
13443
|
-
return "https://api.anthropic.com/v1";
|
|
13444
|
-
case "openai":
|
|
13445
|
-
return "https://api.openai.com/v1";
|
|
13446
|
-
case "deepseek":
|
|
13447
|
-
return "https://api.deepseek.com/v1";
|
|
13448
|
-
case "google":
|
|
13449
|
-
return "https://generativelanguage.googleapis.com/v1beta";
|
|
13450
|
-
}
|
|
13719
|
+
return defaultBaseFor(provider);
|
|
13451
13720
|
}
|
|
13452
13721
|
/** Resolved API base: explicit override wins, else the provider default. */
|
|
13453
13722
|
_resolvedBase() {
|
|
@@ -13487,15 +13756,11 @@ var LLMDirector = class {
|
|
|
13487
13756
|
};
|
|
13488
13757
|
const res = await this._fetchWithTimeout(`${this._resolvedBase()}/messages`, {
|
|
13489
13758
|
method: "POST",
|
|
13490
|
-
headers:
|
|
13491
|
-
"Content-Type": "application/json",
|
|
13492
|
-
"anthropic-version": "2023-06-01",
|
|
13493
|
-
"x-api-key": this._apiKey
|
|
13494
|
-
},
|
|
13759
|
+
headers: anthropicWireHeaders(this._provider, this._apiKey),
|
|
13495
13760
|
body: JSON.stringify(body)
|
|
13496
13761
|
});
|
|
13497
13762
|
if (!res.ok)
|
|
13498
|
-
throw new Error(
|
|
13763
|
+
throw new Error(`${this._provider} API ${res.status}: ${(await res.text()).slice(0, 300)}`);
|
|
13499
13764
|
const data = await res.json(), text = data.content.find((b) => b.type === "text")?.text ?? "";
|
|
13500
13765
|
return {
|
|
13501
13766
|
text,
|
|
@@ -14275,7 +14540,7 @@ var ExecutiveEngine = class extends AsyncEngine {
|
|
|
14275
14540
|
this._gatingState.executiveInterval = rtConfig.executiveInterval;
|
|
14276
14541
|
this._gatingState.cooldownTicks = rtConfig.cooldownTicks;
|
|
14277
14542
|
if (!this._llmDirector && this._willId) {
|
|
14278
|
-
const execModel = this._models.executive ?? process.env.WILL_LLM_MODEL ?? "
|
|
14543
|
+
const execModel = this._models.executive ?? process.env.WILL_LLM_MODEL ?? defaultModelFor(this._llm?.provider ?? process.env.WILL_LLM_PROVIDER ?? "anthropic");
|
|
14279
14544
|
this._llmDirector = this._directorFor(execModel);
|
|
14280
14545
|
this._summarizer?.attachLLMDirector(this._directorFor(this._models.summarizer ?? execModel));
|
|
14281
14546
|
}
|
|
@@ -16184,7 +16449,8 @@ var TaskSwitcher = class {
|
|
|
16184
16449
|
const currentGoal = activeGoals.find((g) => g.id === this._currentFocus.goalId);
|
|
16185
16450
|
const currentPriority = currentGoal?.priority ?? 0;
|
|
16186
16451
|
const switchAdvantage = topGoal.priority - currentPriority;
|
|
16187
|
-
const
|
|
16452
|
+
const stability = state.metrics.get("situation.stability") ?? 1;
|
|
16453
|
+
const switchCost = this._baseSwitchCost * (1 + this._currentFocus.focusTicks * 0.01 * stability);
|
|
16188
16454
|
const netBenefit = switchAdvantage - switchCost;
|
|
16189
16455
|
if (netBenefit > this._switchThreshold && this._currentFocus.focusTicks >= this._minFocusTicks) {
|
|
16190
16456
|
this._currentFocus = {
|
|
@@ -19874,9 +20140,7 @@ var AffordanceSynthesizer = class {
|
|
|
19874
20140
|
if (e.type === "affordance") del.push(id);
|
|
19875
20141
|
const floor = schemas.filter((s) => s.binds === "none");
|
|
19876
20142
|
for (const schema of floor)
|
|
19877
|
-
set.push(this._toEntity(
|
|
19878
|
-
this._build(schema, tick, state, valence, energyLow, skills, {})
|
|
19879
|
-
));
|
|
20143
|
+
set.push(this._toEntity(this._build(schema, tick, state, valence, energyLow, skills, {})));
|
|
19880
20144
|
const candidates = [];
|
|
19881
20145
|
const goalTargets = collectGoalTargets(state);
|
|
19882
20146
|
const perceptSchema = schemas.find((s) => s.binds === "percept");
|
|
@@ -20090,11 +20354,24 @@ var BASE_SWITCH_COST = 0.15;
|
|
|
20090
20354
|
var FOCUS_GAIN = 0.01;
|
|
20091
20355
|
var AWAIT_STALE_TICKS = 15;
|
|
20092
20356
|
var STALE_DECAY = 0.5;
|
|
20357
|
+
var RUPTURE_SALIENCE_GATE = 0.4;
|
|
20358
|
+
var RUPTURE_WINDOW_TICKS = 2;
|
|
20359
|
+
var STABILITY_RECOVERY = 0.05;
|
|
20360
|
+
var STABILITY_EPSILON = 1e-4;
|
|
20361
|
+
var REVOKE_HINT_WINDOW = 8;
|
|
20093
20362
|
var ActionSelector = class {
|
|
20094
20363
|
name = "action-selector";
|
|
20095
20364
|
_bus = null;
|
|
20096
20365
|
_lastEntropy = 0;
|
|
20097
20366
|
_lastDeliberate = false;
|
|
20367
|
+
// EXAFFERENCE P4 follow-up (Channel B): the schema we most recently revoked
|
|
20368
|
+
// under rupture, so the *next* deliberation formed in its wake can own the
|
|
20369
|
+
// interruption in-character ("something changed — I dropped what I was
|
|
20370
|
+
// weighing"). Telemetry-grade instance state, mirroring _lastEntropy.
|
|
20371
|
+
_lastRevoked = null;
|
|
20372
|
+
// ACP §2b: sense-channel percepts buffered off the bus for the next react's
|
|
20373
|
+
// rupture computation (they never become entities). Cross-tick ⇒ FN9.
|
|
20374
|
+
_senseBuffer = [];
|
|
20098
20375
|
attachBus(bus) {
|
|
20099
20376
|
this._bus = bus;
|
|
20100
20377
|
}
|
|
@@ -20102,16 +20379,60 @@ var ActionSelector = class {
|
|
|
20102
20379
|
return [
|
|
20103
20380
|
{ type: "agency.selection.made", version: 1, validate: () => null },
|
|
20104
20381
|
{ type: "agency.selection.ambiguous", version: 1, validate: () => null },
|
|
20105
|
-
{ type: "agency.action.preempted", version: 1, validate: () => null }
|
|
20382
|
+
{ type: "agency.action.preempted", version: 1, validate: () => null },
|
|
20383
|
+
{ type: "agency.situation.rupture", version: 1, validate: () => null },
|
|
20384
|
+
{ type: "agency.commitment.revoked", version: 1, validate: () => null }
|
|
20106
20385
|
];
|
|
20107
20386
|
}
|
|
20108
20387
|
subscribes() {
|
|
20109
|
-
return [
|
|
20388
|
+
return [
|
|
20389
|
+
"senses.*",
|
|
20390
|
+
// Registry #6 (ACP-P3): the model-error term — each carries its
|
|
20391
|
+
// engine's prediction-error salience, ALREADY precision-attenuated for
|
|
20392
|
+
// self-caused swings by the ACP-P2 consumers, so the echo guard
|
|
20393
|
+
// composes by construction: our own action's interoceptive wake
|
|
20394
|
+
// arrives below the rupture gate.
|
|
20395
|
+
"attention.state.changed",
|
|
20396
|
+
"affect.state.changed",
|
|
20397
|
+
"stress.state.changed"
|
|
20398
|
+
];
|
|
20110
20399
|
}
|
|
20111
|
-
|
|
20400
|
+
/**
|
|
20401
|
+
* Mostly pull-model — but two afferent classes never become entities and
|
|
20402
|
+
* would leave rupture blind: sense-channel percepts
|
|
20403
|
+
* (ACTION_CONDITIONED_PREDICTION §2b) and the model-error state-change
|
|
20404
|
+
* events (registry #6). Buffer both (cross-tick: bus flush at T, consumed
|
|
20405
|
+
* by react at T+1 — FN9-snapshotted); the echo guard is applied at read
|
|
20406
|
+
* time for texts, and at the SOURCE for model errors (ACP-P2 precision).
|
|
20407
|
+
*/
|
|
20408
|
+
onCognitiveEvent(e) {
|
|
20409
|
+
const isSense = e.type.startsWith("senses.") && e.type.endsWith(".percept");
|
|
20410
|
+
const isModelError = e.type === "attention.state.changed" || e.type === "affect.state.changed" || e.type === "stress.state.changed";
|
|
20411
|
+
if (!isSense && !isModelError) return;
|
|
20412
|
+
const p = e.payload;
|
|
20413
|
+
this._senseBuffer.push({
|
|
20414
|
+
salience: e.salience,
|
|
20415
|
+
...isSense && typeof p?.content === "string" ? { text: p.content } : {}
|
|
20416
|
+
});
|
|
20112
20417
|
}
|
|
20113
20418
|
snapshot() {
|
|
20114
|
-
return {
|
|
20419
|
+
return {
|
|
20420
|
+
lastEntropy: this._lastEntropy,
|
|
20421
|
+
lastDeliberate: this._lastDeliberate,
|
|
20422
|
+
lastRevoked: this._lastRevoked,
|
|
20423
|
+
senseBuffer: this._senseBuffer
|
|
20424
|
+
};
|
|
20425
|
+
}
|
|
20426
|
+
/** FN9: `_lastRevoked` has behavioral effect (the Channel-B `revokedBy` stamp),
|
|
20427
|
+
* so a restored mind must carry it — a rupture-driven letting-go survives a
|
|
20428
|
+
* snapshot boundary instead of silently losing its narrative thread. */
|
|
20429
|
+
restore(s) {
|
|
20430
|
+
if (typeof s["lastEntropy"] === "number") this._lastEntropy = s["lastEntropy"];
|
|
20431
|
+
if (typeof s["lastDeliberate"] === "boolean") this._lastDeliberate = s["lastDeliberate"];
|
|
20432
|
+
const lr = s["lastRevoked"];
|
|
20433
|
+
this._lastRevoked = lr && typeof lr === "object" && typeof lr.schema === "string" && typeof lr.tick === "number" ? { schema: lr.schema, tick: lr.tick } : null;
|
|
20434
|
+
const sb = s["senseBuffer"];
|
|
20435
|
+
this._senseBuffer = Array.isArray(sb) ? sb.filter((it) => it && typeof it.salience === "number").map((it) => ({ salience: it.salience, ...typeof it.text === "string" ? { text: it.text } : {} })) : [];
|
|
20115
20436
|
}
|
|
20116
20437
|
async react(_delta, tick, state, _context) {
|
|
20117
20438
|
const eligible = [];
|
|
@@ -20140,54 +20461,121 @@ var ActionSelector = class {
|
|
|
20140
20461
|
let blocking = false;
|
|
20141
20462
|
let awaiting = null;
|
|
20142
20463
|
let composite = null;
|
|
20464
|
+
let deliberating = null;
|
|
20143
20465
|
for (const it of intents) {
|
|
20144
|
-
if (it.st === "deliberating")
|
|
20145
|
-
|
|
20466
|
+
if (it.st === "deliberating") {
|
|
20467
|
+
blocking = true;
|
|
20468
|
+
deliberating = { id: it.id, schema: it.schema };
|
|
20469
|
+
} else if (it.st === "expanding") composite = { id: it.id, activation: it.activation, schema: it.schema };
|
|
20146
20470
|
else if (it.st === "awaiting") awaiting = { id: it.id, activation: it.activation, schema: it.schema, target: it.target, dispatchedAt: it.dispatchedAt };
|
|
20147
20471
|
else if (it.st === "selected") {
|
|
20148
20472
|
const activeMacroSub = it.parentIntentId !== void 0 && expandingParents.has(it.parentIntentId);
|
|
20149
20473
|
if (!activeMacroSub) blocking = true;
|
|
20150
20474
|
}
|
|
20151
20475
|
}
|
|
20152
|
-
const
|
|
20153
|
-
|
|
20154
|
-
|
|
20155
|
-
|
|
20476
|
+
const senseEvents = this._senseBuffer;
|
|
20477
|
+
this._senseBuffer = [];
|
|
20478
|
+
const rupture = computeRupture(state, tick, senseEvents);
|
|
20479
|
+
const prevStab = metric2(state, "situation.stability", 1);
|
|
20480
|
+
const nextStabRaw = clamp018(prevStab + STABILITY_RECOVERY * (1 - prevStab) - rupture);
|
|
20481
|
+
const nextStab = 1 - nextStabRaw < STABILITY_EPSILON ? 1 : nextStabRaw;
|
|
20482
|
+
const stabMetrics = rupture > 0 || prevStab < 1 ? [["situation.stability", nextStab]] : [];
|
|
20483
|
+
if (rupture > 0 && this._bus) {
|
|
20484
|
+
try {
|
|
20485
|
+
this._bus.publish({
|
|
20486
|
+
type: "agency.situation.rupture",
|
|
20487
|
+
version: 1,
|
|
20488
|
+
sourceEngine: this.name,
|
|
20489
|
+
salience: rupture,
|
|
20490
|
+
payload: { rupture, stability: nextStab, tick }
|
|
20491
|
+
});
|
|
20492
|
+
} catch (err) {
|
|
20493
|
+
logger.warn(`[selector] rupture publish failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
20494
|
+
}
|
|
20495
|
+
}
|
|
20496
|
+
const busy = (n) => ({
|
|
20497
|
+
commands: {
|
|
20498
|
+
metrics: [
|
|
20499
|
+
["agency.field.eligible", n],
|
|
20500
|
+
["agency.selection.busy", 1],
|
|
20501
|
+
...stabMetrics
|
|
20502
|
+
]
|
|
20503
|
+
}
|
|
20504
|
+
});
|
|
20505
|
+
if (deliberating && rupture >= RUPTURE_REVOKE_GATE) {
|
|
20506
|
+
if (this._bus) {
|
|
20507
|
+
try {
|
|
20508
|
+
this._bus.publish({
|
|
20509
|
+
type: "agency.commitment.revoked",
|
|
20510
|
+
version: 1,
|
|
20511
|
+
sourceEngine: this.name,
|
|
20512
|
+
salience: 0.85,
|
|
20513
|
+
payload: { from: deliberating.schema, reason: "exafferent-rupture", rupture, tick }
|
|
20514
|
+
});
|
|
20515
|
+
} catch (err) {
|
|
20516
|
+
logger.warn(`[selector] revoked publish failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
20517
|
+
}
|
|
20518
|
+
}
|
|
20519
|
+
this._lastRevoked = { schema: deliberating.schema, tick };
|
|
20520
|
+
return {
|
|
20521
|
+
commands: {
|
|
20522
|
+
set: [revocationEntity(deliberating.id, deliberating.schema, rupture, tick)],
|
|
20523
|
+
metrics: [
|
|
20524
|
+
["agency.field.eligible", eligible.length],
|
|
20525
|
+
["agency.selection.busy", 1],
|
|
20526
|
+
["agency.commitment.revoked", 1],
|
|
20527
|
+
...stabMetrics
|
|
20528
|
+
]
|
|
20529
|
+
}
|
|
20530
|
+
};
|
|
20531
|
+
}
|
|
20156
20532
|
if (blocking) return busy(eligible.length);
|
|
20157
20533
|
if (eligible.length === 0)
|
|
20158
|
-
return {
|
|
20534
|
+
return {
|
|
20535
|
+
commands: {
|
|
20536
|
+
metrics: [
|
|
20537
|
+
["agency.field.eligible", 0],
|
|
20538
|
+
["agency.selection.busy", awaiting || composite ? 1 : 0],
|
|
20539
|
+
...stabMetrics
|
|
20540
|
+
]
|
|
20541
|
+
}
|
|
20542
|
+
};
|
|
20159
20543
|
const bias = buildBias(state);
|
|
20160
|
-
const effSwitchCost = effectiveSwitchCost(state);
|
|
20544
|
+
const effSwitchCost = effectiveSwitchCost(state) * (1 - rupture);
|
|
20161
20545
|
const weights = effectiveWeights(state);
|
|
20162
20546
|
const scored = eligible.map((a) => ({ affordance: a, activation: scoreAffordance(a, bias, weights) })).sort((x, y) => y.activation - x.activation);
|
|
20163
20547
|
const winner = scored[0];
|
|
20164
20548
|
if (!winner) return busy(eligible.length);
|
|
20549
|
+
let compositeTombstone;
|
|
20550
|
+
let compositeFrom;
|
|
20165
20551
|
if (composite) {
|
|
20166
20552
|
const different = winner.affordance.schema !== composite.schema;
|
|
20167
20553
|
const switchCost = effSwitchCost * (1 - stakes(winner.affordance, bias));
|
|
20168
|
-
if (different
|
|
20169
|
-
|
|
20554
|
+
if (!different || winner.activation <= composite.activation + switchCost)
|
|
20555
|
+
return busy(eligible.length);
|
|
20556
|
+
if (this._bus)
|
|
20557
|
+
try {
|
|
20170
20558
|
this._bus.publish({
|
|
20171
20559
|
type: "agency.action.preempted",
|
|
20172
20560
|
version: 1,
|
|
20173
20561
|
sourceEngine: this.name,
|
|
20174
20562
|
salience: 0.8,
|
|
20175
|
-
payload: {
|
|
20563
|
+
payload: {
|
|
20564
|
+
from: composite.schema,
|
|
20565
|
+
to: winner.affordance.schema,
|
|
20566
|
+
activation: winner.activation,
|
|
20567
|
+
tick
|
|
20568
|
+
}
|
|
20176
20569
|
});
|
|
20177
20570
|
} catch (err) {
|
|
20178
20571
|
logger.warn(`[selector] preempt publish failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
20179
20572
|
}
|
|
20180
|
-
|
|
20181
|
-
|
|
20182
|
-
["agency.selection.busy", 1],
|
|
20183
|
-
["agency.selection.preempted", 1]
|
|
20184
|
-
] } };
|
|
20185
|
-
}
|
|
20186
|
-
return busy(eligible.length);
|
|
20573
|
+
compositeTombstone = composite.id;
|
|
20574
|
+
compositeFrom = composite.schema;
|
|
20187
20575
|
}
|
|
20188
20576
|
let preemptDelete;
|
|
20189
|
-
let preemptedFrom;
|
|
20190
|
-
if (awaiting) {
|
|
20577
|
+
let preemptedFrom = compositeFrom;
|
|
20578
|
+
if (awaiting && !compositeTombstone) {
|
|
20191
20579
|
const sameAction = winner.affordance.schema === awaiting.schema && (winner.affordance.targetEntityId ?? "") === awaiting.target;
|
|
20192
20580
|
if (sameAction) return busy(eligible.length);
|
|
20193
20581
|
const staleness = Math.min(1, (tick - awaiting.dispatchedAt) / AWAIT_STALE_TICKS);
|
|
@@ -20210,6 +20598,13 @@ var ActionSelector = class {
|
|
|
20210
20598
|
const deliberate = margin < marginGate || stk > stakesGate;
|
|
20211
20599
|
this._lastEntropy = entropy;
|
|
20212
20600
|
this._lastDeliberate = deliberate;
|
|
20601
|
+
let revokedBy;
|
|
20602
|
+
if (this._lastRevoked) {
|
|
20603
|
+
if (deliberate && tick - this._lastRevoked.tick <= REVOKE_HINT_WINDOW)
|
|
20604
|
+
revokedBy = this._lastRevoked.schema;
|
|
20605
|
+
if (revokedBy || tick - this._lastRevoked.tick > REVOKE_HINT_WINDOW)
|
|
20606
|
+
this._lastRevoked = null;
|
|
20607
|
+
}
|
|
20213
20608
|
const intent = {
|
|
20214
20609
|
id: `agency-intent-${tick}`,
|
|
20215
20610
|
type: "agency.intent",
|
|
@@ -20252,6 +20647,9 @@ var ActionSelector = class {
|
|
|
20252
20647
|
// interrupted, so the deliberation facet can own the interruption in-character
|
|
20253
20648
|
// ("I was about to X, but this pulled me away"). Only meaningful while deliberating.
|
|
20254
20649
|
...preemptedFrom ? { preemptedFrom } : {},
|
|
20650
|
+
// Channel B: this deliberation forms in the wake of a rupture-driven
|
|
20651
|
+
// revocation — the facet can own "something changed, I let go of X".
|
|
20652
|
+
...revokedBy ? { revokedBy } : {},
|
|
20255
20653
|
tick
|
|
20256
20654
|
}
|
|
20257
20655
|
};
|
|
@@ -20290,7 +20688,9 @@ var ActionSelector = class {
|
|
|
20290
20688
|
}
|
|
20291
20689
|
}
|
|
20292
20690
|
const commands = {
|
|
20293
|
-
|
|
20691
|
+
// A composite preemption rides along as a tombstone (never a delete — the
|
|
20692
|
+
// executor's in-tick macro-advance would resurrect the parent).
|
|
20693
|
+
set: compositeTombstone ? [intent, revocationEntity(compositeTombstone, compositeFrom ?? "", rupture, tick)] : [intent],
|
|
20294
20694
|
...preemptDelete ? { delete: [preemptDelete] } : {},
|
|
20295
20695
|
metrics: [
|
|
20296
20696
|
["agency.field.eligible", eligible.length],
|
|
@@ -20299,7 +20699,8 @@ var ActionSelector = class {
|
|
|
20299
20699
|
["agency.selection.margin", margin],
|
|
20300
20700
|
["agency.selection.deliberate", deliberate ? 1 : 0],
|
|
20301
20701
|
["agency.selection.preempted", preemptedFrom ? 1 : 0],
|
|
20302
|
-
["agency.selection.activation", winner.activation]
|
|
20702
|
+
["agency.selection.activation", winner.activation],
|
|
20703
|
+
...stabMetrics
|
|
20303
20704
|
]
|
|
20304
20705
|
};
|
|
20305
20706
|
return { commands };
|
|
@@ -20309,7 +20710,29 @@ function effectiveSwitchCost(state) {
|
|
|
20309
20710
|
const params = readEffectiveParams(state, "engine-config-action-selector");
|
|
20310
20711
|
const base = num2(params["switchCost"], BASE_SWITCH_COST);
|
|
20311
20712
|
const focusTicks = metric2(state, "task_switch.current_focus_ticks", 0);
|
|
20312
|
-
|
|
20713
|
+
const stability = metric2(state, "situation.stability", 1);
|
|
20714
|
+
return base * (1 + focusTicks * FOCUS_GAIN * stability);
|
|
20715
|
+
}
|
|
20716
|
+
function computeRupture(state, tick, senseEvents = []) {
|
|
20717
|
+
let maxSalience = 0;
|
|
20718
|
+
for (const e of state.entities.values()) {
|
|
20719
|
+
if (e.type !== "percept") continue;
|
|
20720
|
+
const m = e.metadata;
|
|
20721
|
+
if (str2(m?.["provenance"]) !== "exafferent") continue;
|
|
20722
|
+
const pTick = num2(m?.["tick"], -1);
|
|
20723
|
+
if (pTick < 0 || tick - pTick > RUPTURE_WINDOW_TICKS) continue;
|
|
20724
|
+
const s = num2(m?.["salience"], 0);
|
|
20725
|
+
if (s > maxSalience) maxSalience = s;
|
|
20726
|
+
}
|
|
20727
|
+
if (senseEvents.length > 0) {
|
|
20728
|
+
const live = liveConsequences(state.entities, tick);
|
|
20729
|
+
for (const ev of senseEvents) {
|
|
20730
|
+
if (ev.text !== void 0 && live.length > 0 && matchConsequenceText(live, ev.text)) continue;
|
|
20731
|
+
if (ev.salience > maxSalience) maxSalience = ev.salience;
|
|
20732
|
+
}
|
|
20733
|
+
}
|
|
20734
|
+
if (maxSalience <= RUPTURE_SALIENCE_GATE) return 0;
|
|
20735
|
+
return clamp018((maxSalience - RUPTURE_SALIENCE_GATE) / (1 - RUPTURE_SALIENCE_GATE));
|
|
20313
20736
|
}
|
|
20314
20737
|
function effectiveWeights(state) {
|
|
20315
20738
|
const p = readEffectiveParams(state, "engine-config-action-selector");
|
|
@@ -20410,19 +20833,28 @@ var DeliberationEngine = class {
|
|
|
20410
20833
|
return { deliberations: this._deliberations };
|
|
20411
20834
|
}
|
|
20412
20835
|
async react(_delta, tick, state, _context) {
|
|
20836
|
+
const revoked = revokedIntentIds(state.entities, tick);
|
|
20837
|
+
const del = [];
|
|
20413
20838
|
let target = null;
|
|
20414
20839
|
for (const [id2, e] of state.entities) {
|
|
20415
20840
|
if (e.type !== "agency.intent") continue;
|
|
20416
20841
|
if (str3(e.metadata?.["status"]) !== "deliberating") continue;
|
|
20842
|
+
if (revoked.has(id2)) {
|
|
20843
|
+
del.push(id2, revocationId(id2));
|
|
20844
|
+
continue;
|
|
20845
|
+
}
|
|
20417
20846
|
const meta2 = e.metadata ?? {};
|
|
20418
20847
|
if (!target || id2 < target.id) target = { id: id2, meta: meta2 };
|
|
20419
20848
|
}
|
|
20420
|
-
if (!target) return { commands: {} };
|
|
20849
|
+
if (!target) return del.length > 0 ? { commands: { delete: del } } : { commands: {} };
|
|
20421
20850
|
const { id, meta } = target;
|
|
20422
20851
|
const provisional = str3(meta["schema"]) ?? "wait";
|
|
20423
20852
|
const candidates = Array.isArray(meta["candidates"]) ? meta["candidates"] : [];
|
|
20424
20853
|
if (!this._provider)
|
|
20425
|
-
return { commands: {
|
|
20854
|
+
return { commands: {
|
|
20855
|
+
set: [this._commit(id, meta, provisional, candidates, "no-executive")],
|
|
20856
|
+
...del.length > 0 ? { delete: del } : {}
|
|
20857
|
+
} };
|
|
20426
20858
|
const chosen = await this._deliberate(state, candidates, provisional, meta);
|
|
20427
20859
|
this._deliberations++;
|
|
20428
20860
|
if (this._bus) {
|
|
@@ -20440,6 +20872,7 @@ var DeliberationEngine = class {
|
|
|
20440
20872
|
return {
|
|
20441
20873
|
commands: {
|
|
20442
20874
|
set: [this._commit(id, meta, chosen, candidates, "facet")],
|
|
20875
|
+
...del.length > 0 ? { delete: del } : {},
|
|
20443
20876
|
metrics: [["agency.deliberation.count", 1]]
|
|
20444
20877
|
}
|
|
20445
20878
|
};
|
|
@@ -20497,7 +20930,10 @@ var DeliberationEngine = class {
|
|
|
20497
20930
|
_buildFocusContent(state, candidates, meta) {
|
|
20498
20931
|
const lines = [];
|
|
20499
20932
|
const preemptedFrom = str3(meta["preemptedFrom"]);
|
|
20500
|
-
|
|
20933
|
+
const revokedBy = str3(meta["revokedBy"]);
|
|
20934
|
+
if (revokedBy)
|
|
20935
|
+
lines.push(`Something in my situation just shifted and I let go of what I was weighing ("${revokedBy}"). Decide afresh what to do now:`);
|
|
20936
|
+
else if (preemptedFrom)
|
|
20501
20937
|
lines.push(`I just broke off a pending action ("${preemptedFrom}") because something more pressing pulled at me. Decide what to do now:`);
|
|
20502
20938
|
else
|
|
20503
20939
|
lines.push("My automatic action-selection was uncertain. Candidate actions:");
|
|
@@ -20670,6 +21106,19 @@ var MotorSchemaExecutor = class {
|
|
|
20670
21106
|
const metrics = [];
|
|
20671
21107
|
const energy = state.metrics.get("energy.level") ?? 100;
|
|
20672
21108
|
const stress = state.metrics.get("stress.load") ?? 0;
|
|
21109
|
+
for (const [id, e] of state.entities) {
|
|
21110
|
+
if (e.type !== CONSEQUENCE_TYPE) continue;
|
|
21111
|
+
if (tick >= num3(e.metadata?.["expiresAt"], 0)) del.push(id);
|
|
21112
|
+
}
|
|
21113
|
+
del.push(...staleRevocationIds(state.entities, tick));
|
|
21114
|
+
const revoked = revokedIntentIds(state.entities, tick);
|
|
21115
|
+
if (revoked.size > 0)
|
|
21116
|
+
for (const [id, e] of state.entities) {
|
|
21117
|
+
if (e.type !== "agency.intent") continue;
|
|
21118
|
+
const parentId = str5(e.metadata?.["parentIntentId"]);
|
|
21119
|
+
if (revoked.has(id)) del.push(id, revocationId(id));
|
|
21120
|
+
else if (parentId && revoked.has(parentId)) del.push(id);
|
|
21121
|
+
}
|
|
20673
21122
|
for (const [id, e] of state.entities) {
|
|
20674
21123
|
if (e.type !== "agency.intent" || str5(e.metadata?.["status"]) !== "awaiting") continue;
|
|
20675
21124
|
const dispatchedAt = num3(e.metadata?.["dispatchedAt"], tick);
|
|
@@ -20696,6 +21145,9 @@ var MotorSchemaExecutor = class {
|
|
|
20696
21145
|
const selected = [...state.entities.entries()].filter(([, e]) => e.type === "agency.intent" && str5(e.metadata?.["status"]) === "selected").sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
|
|
20697
21146
|
let enactedCount = 0;
|
|
20698
21147
|
for (const [id, e] of selected) {
|
|
21148
|
+
if (revoked.has(id)) continue;
|
|
21149
|
+
const parentOf = str5(e.metadata?.["parentIntentId"]);
|
|
21150
|
+
if (parentOf && revoked.has(parentOf)) continue;
|
|
20699
21151
|
const intent = readIntent(id, e.metadata);
|
|
20700
21152
|
const schema = this._resolve(intent.schema);
|
|
20701
21153
|
if (schema?.kind === "composite" && schema.composedOf && schema.composedOf.length > 0) {
|
|
@@ -20744,6 +21196,18 @@ var MotorSchemaExecutor = class {
|
|
|
20744
21196
|
predictedValence: predicted.expectedValence
|
|
20745
21197
|
}
|
|
20746
21198
|
});
|
|
21199
|
+
const awaitingText = enaction.mode === "communicate" ? str5(intent.parameters["content"]) ?? firstMessage(intent.parameters["messages"]) : void 0;
|
|
21200
|
+
set.push(consequenceEntity({
|
|
21201
|
+
intentId: id,
|
|
21202
|
+
schema: intent.schema,
|
|
21203
|
+
mode: enaction.mode === "communicate" ? "communicate" : "external",
|
|
21204
|
+
...enaction.mode === "communicate" ? { effector: COMM_SCHEMA_TO_EFFECTOR[intent.schema] ?? intent.schema } : {},
|
|
21205
|
+
...intent.targetEntityId ? { targetEntityId: intent.targetEntityId } : {},
|
|
21206
|
+
...awaitingText ? { text: awaitingText, textHash: fnv1a(awaitingText) } : {},
|
|
21207
|
+
paramsHash: fnv1a(paramsKey(intent.parameters)),
|
|
21208
|
+
expiresAt: tick + CONSEQUENCE_TTL_TICKS,
|
|
21209
|
+
tick
|
|
21210
|
+
}));
|
|
20747
21211
|
this._emitDispatch(intent, enaction.mode, tick);
|
|
20748
21212
|
metrics.push([enaction.mode === "communicate" ? "agency.communicate.dispatched" : "agency.invocation.dispatched", 1]);
|
|
20749
21213
|
}
|
|
@@ -20910,6 +21374,18 @@ var MotorSchemaExecutor = class {
|
|
|
20910
21374
|
};
|
|
20911
21375
|
set.push(outcomeEntity(tick, intent, out, predicted));
|
|
20912
21376
|
del.push(id);
|
|
21377
|
+
if (result.success)
|
|
21378
|
+
set.push(consequenceEntity({
|
|
21379
|
+
intentId: id,
|
|
21380
|
+
schema: intent.schema,
|
|
21381
|
+
mode: "communicate",
|
|
21382
|
+
effector,
|
|
21383
|
+
...intent.targetEntityId ? { targetEntityId: intent.targetEntityId } : {},
|
|
21384
|
+
textHash: fnv1a(bubbles.join("\n")),
|
|
21385
|
+
text: bubbles.join("\n"),
|
|
21386
|
+
expiresAt: tick + CONSEQUENCE_TTL_TICKS,
|
|
21387
|
+
tick
|
|
21388
|
+
}));
|
|
20913
21389
|
this._emitEnacted(intent, out, predicted, tick);
|
|
20914
21390
|
this._emitActionOutcome(
|
|
20915
21391
|
intent,
|
|
@@ -21048,6 +21524,10 @@ function errMsg(err) {
|
|
|
21048
21524
|
|
|
21049
21525
|
// src/cognition/agency/engines/reafference.engine.ts
|
|
21050
21526
|
var PROC_THRESHOLD2 = 0.6;
|
|
21527
|
+
var SENSORY_SOFT_QUALITY = 0.6;
|
|
21528
|
+
var SENSORY_VALENCE_SPAN_ENTITY = 0.25;
|
|
21529
|
+
var SENSORY_VALENCE_SPAN_AMBIENT = 0.1;
|
|
21530
|
+
var SENSORY_SUCCESS_FLOOR = 0.5;
|
|
21051
21531
|
var ReafferenceEngine = class {
|
|
21052
21532
|
name = "reafference";
|
|
21053
21533
|
_repertoire;
|
|
@@ -21097,14 +21577,64 @@ var ReafferenceEngine = class {
|
|
|
21097
21577
|
const set = [];
|
|
21098
21578
|
const del = [];
|
|
21099
21579
|
const metrics = [];
|
|
21100
|
-
|
|
21101
|
-
|
|
21580
|
+
const outcomes = [];
|
|
21581
|
+
const gradedIntentIds = /* @__PURE__ */ new Set();
|
|
21102
21582
|
for (const [id, e] of state.entities) {
|
|
21103
21583
|
if (e.type !== "agency.outcome") continue;
|
|
21104
21584
|
const m = e.metadata ?? {};
|
|
21585
|
+
outcomes.push({ id, meta: m, fromState: true });
|
|
21586
|
+
const iid = str6(m["intentId"]);
|
|
21587
|
+
if (iid) gradedIntentIds.add(iid);
|
|
21588
|
+
}
|
|
21589
|
+
const awaiting = /* @__PURE__ */ new Map();
|
|
21590
|
+
for (const [id, e] of state.entities) {
|
|
21591
|
+
if (e.type !== "agency.intent" || str6(e.metadata?.["status"]) !== "awaiting") continue;
|
|
21592
|
+
const m = e.metadata ?? {};
|
|
21593
|
+
if (tick - num4(m["dispatchedAt"], tick) >= AWAIT_TIMEOUT) continue;
|
|
21594
|
+
awaiting.set(id, {
|
|
21595
|
+
schema: str6(m["schema"]) ?? "",
|
|
21596
|
+
predictedReward: num4(m["predictedReward"], 0.5),
|
|
21597
|
+
predictedValence: num4(m["predictedValence"], 0)
|
|
21598
|
+
});
|
|
21599
|
+
}
|
|
21600
|
+
let sensory = 0;
|
|
21601
|
+
const sensedIntentIds = /* @__PURE__ */ new Set();
|
|
21602
|
+
for (const [, e] of state.entities) {
|
|
21603
|
+
if (e.type !== "percept") continue;
|
|
21604
|
+
const m = e.metadata ?? {};
|
|
21605
|
+
if (str6(m["provenance"]) !== "reafferent") continue;
|
|
21606
|
+
const iid = str6(m["sourceIntentId"]);
|
|
21607
|
+
if (!iid || gradedIntentIds.has(iid) || sensedIntentIds.has(iid)) continue;
|
|
21608
|
+
const aw = awaiting.get(iid);
|
|
21609
|
+
if (!aw || !aw.schema) continue;
|
|
21610
|
+
sensedIntentIds.add(iid);
|
|
21611
|
+
sensory++;
|
|
21612
|
+
const feltRaw = m["valence"];
|
|
21613
|
+
const felt = typeof feltRaw === "number" && Number.isFinite(feltRaw) ? feltRaw : void 0;
|
|
21614
|
+
const span = str6(m["valenceSource"]) === "entity" ? SENSORY_VALENCE_SPAN_ENTITY : SENSORY_VALENCE_SPAN_AMBIENT;
|
|
21615
|
+
const quality = felt === void 0 ? SENSORY_SOFT_QUALITY : clamp0111(SENSORY_SOFT_QUALITY + Math.max(-1, Math.min(1, felt)) * span);
|
|
21616
|
+
outcomes.push({ id: `agency-outcome-${tick}-${iid}-sensory`, fromState: false, meta: {
|
|
21617
|
+
schema: aw.schema,
|
|
21618
|
+
intentId: iid,
|
|
21619
|
+
success: quality >= SENSORY_SUCCESS_FLOOR,
|
|
21620
|
+
outcomeQuality: quality,
|
|
21621
|
+
valence: felt ?? aw.predictedValence,
|
|
21622
|
+
predictedReward: aw.predictedReward,
|
|
21623
|
+
predictedValence: aw.predictedValence,
|
|
21624
|
+
surprise: clamp0111(Math.abs(aw.predictedReward - quality)),
|
|
21625
|
+
mode: "external",
|
|
21626
|
+
reconciled: true,
|
|
21627
|
+
sensory: true,
|
|
21628
|
+
...felt !== void 0 ? { sensoryValence: felt, valenceSource: str6(m["valenceSource"]) } : {},
|
|
21629
|
+
tick
|
|
21630
|
+
} });
|
|
21631
|
+
}
|
|
21632
|
+
let updates = 0;
|
|
21633
|
+
let discovered = 0;
|
|
21634
|
+
for (const { id, meta: m, fromState } of outcomes) {
|
|
21105
21635
|
const schema = str6(m["schema"]);
|
|
21106
21636
|
if (!schema) {
|
|
21107
|
-
del.push(id);
|
|
21637
|
+
if (fromState) del.push(id);
|
|
21108
21638
|
continue;
|
|
21109
21639
|
}
|
|
21110
21640
|
const { skill, proceduralized } = this._repertoire.recordOutcome({
|
|
@@ -21116,7 +21646,7 @@ var ReafferenceEngine = class {
|
|
|
21116
21646
|
tick
|
|
21117
21647
|
});
|
|
21118
21648
|
set.push(skillEntity(skill));
|
|
21119
|
-
del.push(id);
|
|
21649
|
+
if (fromState) del.push(id);
|
|
21120
21650
|
const intentId = str6(m["intentId"]);
|
|
21121
21651
|
if (intentId) del.push(intentId);
|
|
21122
21652
|
updates++;
|
|
@@ -21144,7 +21674,8 @@ var ReafferenceEngine = class {
|
|
|
21144
21674
|
["agency.learning.updates", updates],
|
|
21145
21675
|
["agency.discovered.count", discovered],
|
|
21146
21676
|
["agency.skill.count", skills.size],
|
|
21147
|
-
["agency.habitual.count", habitual]
|
|
21677
|
+
["agency.habitual.count", habitual],
|
|
21678
|
+
["agency.sensory.confirmed", sensory]
|
|
21148
21679
|
);
|
|
21149
21680
|
return { commands: { set, delete: del, metrics } };
|
|
21150
21681
|
}
|
|
@@ -21228,6 +21759,9 @@ function str6(v) {
|
|
|
21228
21759
|
function num4(v, fallback) {
|
|
21229
21760
|
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
21230
21761
|
}
|
|
21762
|
+
function clamp0111(n) {
|
|
21763
|
+
return n < 0 ? 0 : n > 1 ? 1 : n;
|
|
21764
|
+
}
|
|
21231
21765
|
|
|
21232
21766
|
// src/cognition/config.mirror.entities.ts
|
|
21233
21767
|
function buildEngineConfigEntities(config, executiveInterval) {
|
|
@@ -22198,12 +22732,13 @@ async function checkIdentityCoherence(input, reviewer) {
|
|
|
22198
22732
|
return { ok: !issues.some((i) => i.severity === "error"), ran: true, issues, raw: text };
|
|
22199
22733
|
}
|
|
22200
22734
|
async function reviewIdentityCoherence(input, opts = {}) {
|
|
22735
|
+
const provider = process.env.WILL_LLM_PROVIDER ?? "anthropic";
|
|
22201
22736
|
const director = new LLMDirector({
|
|
22202
22737
|
willId: opts.willId ?? "identity-coherence",
|
|
22203
|
-
model: process.env.WILL_LLM_MODEL ??
|
|
22738
|
+
model: process.env.WILL_LLM_MODEL ?? defaultModelFor(provider),
|
|
22204
22739
|
maxOutputTokens: 512,
|
|
22205
22740
|
apiKey: process.env.WILL_LLM_API_KEY ?? process.env.ANTHROPIC_API_KEY ?? "",
|
|
22206
|
-
provider
|
|
22741
|
+
provider,
|
|
22207
22742
|
sessionLogger: null,
|
|
22208
22743
|
baseUrl: process.env.WILL_LLM_BASE_URL ?? process.env.OPENAI_BASE_URL,
|
|
22209
22744
|
// When a per-Will tracker is supplied, the creation-time review records under
|
|
@@ -23958,6 +24493,10 @@ var OutboxController = class {
|
|
|
23958
24493
|
summary: delivered ? `My message was delivered successfully.` : `My message failed to reach the recipient.`,
|
|
23959
24494
|
salience: delivered ? 0.35 : 0.6,
|
|
23960
24495
|
changeType: delivered ? "delivered" : "failed",
|
|
24496
|
+
// Reafference by construction — this percept describes our own action's
|
|
24497
|
+
// outcome ("ear hears the word"). Tagged, not attenuated: it is the ack
|
|
24498
|
+
// surface, not a content echo (EXAFFERENCE P2).
|
|
24499
|
+
provenance: "reafferent",
|
|
23961
24500
|
messageId
|
|
23962
24501
|
}
|
|
23963
24502
|
});
|
|
@@ -24359,7 +24898,7 @@ var InboundQueue = class {
|
|
|
24359
24898
|
function reconcileInvocation(intentId, schema, result, tick, predicted = { reward: 0.5, valence: 0 }, provenance = {}) {
|
|
24360
24899
|
const outcomeQuality = result.outcomeQuality ?? (result.success ? 0.8 : 0.1);
|
|
24361
24900
|
const valence = result.valence ?? (result.success ? 0.2 : -0.2);
|
|
24362
|
-
const surprise =
|
|
24901
|
+
const surprise = clamp0112(Math.abs(predicted.reward - outcomeQuality));
|
|
24363
24902
|
return {
|
|
24364
24903
|
id: `agency-outcome-${tick}-${intentId}`,
|
|
24365
24904
|
type: "agency.outcome",
|
|
@@ -24381,7 +24920,7 @@ function reconcileInvocation(intentId, schema, result, tick, predicted = { rewar
|
|
|
24381
24920
|
}
|
|
24382
24921
|
};
|
|
24383
24922
|
}
|
|
24384
|
-
function
|
|
24923
|
+
function clamp0112(n) {
|
|
24385
24924
|
return n < 0 ? 0 : n > 1 ? 1 : n;
|
|
24386
24925
|
}
|
|
24387
24926
|
|
|
@@ -25760,7 +26299,9 @@ var Will = class _Will {
|
|
|
25760
26299
|
}
|
|
25761
26300
|
// ── Internals ──────────────────────────────────────────────
|
|
25762
26301
|
_buildConfig(id, opts) {
|
|
25763
|
-
const
|
|
26302
|
+
const mode = opts.llm ?? (process.env.ANTHROPIC_API_KEY ? "anthropic" : process.env.ZAI_API_KEY ? "glm" : "mock");
|
|
26303
|
+
const useMock = mode === "mock";
|
|
26304
|
+
const llmConfig = mode === "glm" ? { provider: "glm", ...opts.llmConfig } : opts.llmConfig;
|
|
25764
26305
|
return {
|
|
25765
26306
|
id,
|
|
25766
26307
|
name: opts.name,
|
|
@@ -25772,7 +26313,7 @@ var Will = class _Will {
|
|
|
25772
26313
|
},
|
|
25773
26314
|
anatomy: opts.anatomy ?? "mind",
|
|
25774
26315
|
model: opts.model,
|
|
25775
|
-
llm:
|
|
26316
|
+
llm: llmConfig,
|
|
25776
26317
|
testMode: useMock,
|
|
25777
26318
|
persistentMemory: opts.persist ?? false,
|
|
25778
26319
|
snapshotInterval: 100,
|
|
@@ -25955,21 +26496,32 @@ function routeLogsToStderr() {
|
|
|
25955
26496
|
function slug2(s) {
|
|
25956
26497
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "will";
|
|
25957
26498
|
}
|
|
26499
|
+
function resolveLlmMode() {
|
|
26500
|
+
const explicit = process.env.WILL_LLM;
|
|
26501
|
+
if (explicit) return explicit;
|
|
26502
|
+
if (process.env.ANTHROPIC_API_KEY) return "anthropic";
|
|
26503
|
+
if (process.env.ZAI_API_KEY) return "glm";
|
|
26504
|
+
return "mock";
|
|
26505
|
+
}
|
|
26506
|
+
function resolveLlmKey(mode) {
|
|
26507
|
+
return process.env.WILL_LLM_API_KEY ?? (mode === "glm" ? process.env.ZAI_API_KEY : process.env.ANTHROPIC_API_KEY);
|
|
26508
|
+
}
|
|
25958
26509
|
async function preflightLLM(anatomy) {
|
|
25959
|
-
const mode =
|
|
26510
|
+
const mode = resolveLlmMode();
|
|
25960
26511
|
if (mode === "mock" || anatomy === "reflex") return;
|
|
25961
|
-
const key =
|
|
26512
|
+
const key = resolveLlmKey(mode);
|
|
25962
26513
|
if (!key) {
|
|
25963
|
-
|
|
26514
|
+
const expected = mode === "glm" ? "ZAI_API_KEY" : "ANTHROPIC_API_KEY";
|
|
26515
|
+
console.error(`[will] WILL_LLM=${mode} but no ${expected} / WILL_LLM_API_KEY is set.`);
|
|
25964
26516
|
console.error("[will] The Will would boot, perceive, and never speak. Set a key, or run keyless with WILL_LLM=mock.");
|
|
25965
26517
|
process.exit(2);
|
|
25966
26518
|
}
|
|
25967
|
-
const base = process.env.WILL_LLM_BASE_URL ??
|
|
25968
|
-
const model = process.env.WILL_LLM_MODEL ?? "claude-haiku-4-5-20251001";
|
|
26519
|
+
const base = process.env.WILL_LLM_BASE_URL ?? defaultBaseFor(mode);
|
|
26520
|
+
const model = process.env.WILL_LLM_MODEL ?? (mode === "glm" ? defaultModelFor("glm") : "claude-haiku-4-5-20251001");
|
|
25969
26521
|
try {
|
|
25970
26522
|
const res = await fetch(`${base}/messages`, {
|
|
25971
26523
|
method: "POST",
|
|
25972
|
-
headers:
|
|
26524
|
+
headers: anthropicWireHeaders(mode, key),
|
|
25973
26525
|
body: JSON.stringify({ model, max_tokens: 1, messages: [{ role: "user", content: "ping" }] }),
|
|
25974
26526
|
signal: AbortSignal.timeout(2e4)
|
|
25975
26527
|
});
|
|
@@ -26474,21 +27026,200 @@ async function createDiscordClient() {
|
|
|
26474
27026
|
});
|
|
26475
27027
|
}
|
|
26476
27028
|
|
|
27029
|
+
// src/channels/whatsapp.ts
|
|
27030
|
+
var WHATSAPP_MESSAGE_LIMIT = 65536;
|
|
27031
|
+
var isGroupJid = (jid) => jid.endsWith("@g.us");
|
|
27032
|
+
var bareId = (jid) => jid.split("@")[0].split(":")[0];
|
|
27033
|
+
var dmJidFor = (userId) => `${userId}@s.whatsapp.net`;
|
|
27034
|
+
function textOf(m) {
|
|
27035
|
+
const msg = m.message;
|
|
27036
|
+
return msg?.conversation ?? msg?.extendedTextMessage?.text ?? msg?.imageMessage?.caption ?? msg?.videoMessage?.caption ?? "";
|
|
27037
|
+
}
|
|
27038
|
+
async function connectWhatsApp(will, opts = {}) {
|
|
27039
|
+
const log = opts.log ?? ((m) => console.error(`[will:whatsapp] ${m}`));
|
|
27040
|
+
const roster = new ChannelRoster(opts.rosterPath ?? `.will/${will.id}.whatsapp.json`);
|
|
27041
|
+
const allowed = opts.chats?.length ? new Set(opts.chats) : null;
|
|
27042
|
+
let closed = false;
|
|
27043
|
+
const socket = opts.socket ?? await createWhatsAppSocket({
|
|
27044
|
+
authPath: opts.authPath ?? `.will/${will.id}.wa-auth`,
|
|
27045
|
+
log,
|
|
27046
|
+
stillOpen: () => !closed
|
|
27047
|
+
});
|
|
27048
|
+
let lastActiveChatId = opts.homeChatId ?? null;
|
|
27049
|
+
socket.ev.on("messages.upsert", ({ messages, type }) => {
|
|
27050
|
+
if (type && type !== "notify") return;
|
|
27051
|
+
for (const m of messages) void onMessage(m);
|
|
27052
|
+
});
|
|
27053
|
+
async function onMessage(m) {
|
|
27054
|
+
const jid = m.key.remoteJid;
|
|
27055
|
+
if (!jid || m.key.fromMe || !m.message || m.messageStubType) return;
|
|
27056
|
+
if (jid.endsWith("@broadcast") || jid.endsWith("@newsletter")) return;
|
|
27057
|
+
if (allowed && !allowed.has(jid)) return;
|
|
27058
|
+
const isGroup = isGroupJid(jid);
|
|
27059
|
+
const senderJid = isGroup ? m.key.participant : jid;
|
|
27060
|
+
if (!senderJid) return;
|
|
27061
|
+
const selfId = socket.user ? bareId(socket.user.id) : null;
|
|
27062
|
+
const mentioned = m.message.extendedTextMessage?.contextInfo?.mentionedJid ?? [];
|
|
27063
|
+
const addressed = !isGroup || selfId != null && mentioned.some((j) => bareId(j) === selfId);
|
|
27064
|
+
if (opts.mentionOnly && !addressed) return;
|
|
27065
|
+
const userId = bareId(senderJid);
|
|
27066
|
+
const entityId = `whatsapp:${userId}`;
|
|
27067
|
+
const speaker = m.pushName ?? void 0;
|
|
27068
|
+
roster.record({
|
|
27069
|
+
entityId,
|
|
27070
|
+
userId,
|
|
27071
|
+
...speaker ? { displayName: speaker } : {},
|
|
27072
|
+
...isGroup ? { lastChannelId: jid } : { dmChannelId: jid }
|
|
27073
|
+
});
|
|
27074
|
+
if (isGroup) lastActiveChatId = jid;
|
|
27075
|
+
if (addressed) await socket.sendPresenceUpdate?.("composing", jid).catch(() => {
|
|
27076
|
+
});
|
|
27077
|
+
const text = textOf(m);
|
|
27078
|
+
if (!text.trim()) return;
|
|
27079
|
+
await will.perceive({
|
|
27080
|
+
text,
|
|
27081
|
+
from: entityId,
|
|
27082
|
+
thread: `whatsapp:${jid}`,
|
|
27083
|
+
...speaker ? { speaker } : {}
|
|
27084
|
+
});
|
|
27085
|
+
}
|
|
27086
|
+
will.on("message", (m) => {
|
|
27087
|
+
if (!closed) void deliver(m);
|
|
27088
|
+
});
|
|
27089
|
+
async function deliver(m) {
|
|
27090
|
+
const peer = m.to ? roster.resolve(m.to) : void 0;
|
|
27091
|
+
const chunks = chunkText(m.content, WHATSAPP_MESSAGE_LIMIT);
|
|
27092
|
+
const derivedDm = m.to?.startsWith("whatsapp:") ? dmJidFor(m.to.slice("whatsapp:".length)) : void 0;
|
|
27093
|
+
const targets = [peer?.lastChannelId, peer?.dmChannelId, derivedDm, opts.homeChatId ?? void 0, lastActiveChatId ?? void 0];
|
|
27094
|
+
for (const jid of targets) {
|
|
27095
|
+
if (!jid) continue;
|
|
27096
|
+
try {
|
|
27097
|
+
for (const chunk of chunks) await socket.sendMessage(jid, { text: chunk });
|
|
27098
|
+
return;
|
|
27099
|
+
} catch {
|
|
27100
|
+
}
|
|
27101
|
+
}
|
|
27102
|
+
log(`no route for utterance to '${m.to}' \u2014 dropped (${m.content.length} chars)`);
|
|
27103
|
+
}
|
|
27104
|
+
return {
|
|
27105
|
+
kind: "whatsapp",
|
|
27106
|
+
async start() {
|
|
27107
|
+
log(`${will.name} is present on WhatsApp${socket.user ? ` as ${bareId(socket.user.id)}` : ""}`);
|
|
27108
|
+
},
|
|
27109
|
+
async close() {
|
|
27110
|
+
if (closed) return;
|
|
27111
|
+
closed = true;
|
|
27112
|
+
roster.flush();
|
|
27113
|
+
try {
|
|
27114
|
+
socket.end?.();
|
|
27115
|
+
} catch {
|
|
27116
|
+
}
|
|
27117
|
+
}
|
|
27118
|
+
};
|
|
27119
|
+
}
|
|
27120
|
+
async function createWhatsAppSocket(o) {
|
|
27121
|
+
let baileys;
|
|
27122
|
+
try {
|
|
27123
|
+
baileys = await import('baileys');
|
|
27124
|
+
} catch {
|
|
27125
|
+
throw new Error("baileys is not installed (it is an optionalDependency) \u2014 run `bun add baileys` / `npm i baileys` and retry.");
|
|
27126
|
+
}
|
|
27127
|
+
const { default: makeWASocket, useMultiFileAuthState, DisconnectReason } = baileys;
|
|
27128
|
+
const noop = () => {
|
|
27129
|
+
};
|
|
27130
|
+
const logger2 = {
|
|
27131
|
+
level: "silent",
|
|
27132
|
+
child() {
|
|
27133
|
+
return logger2;
|
|
27134
|
+
},
|
|
27135
|
+
trace: noop,
|
|
27136
|
+
debug: noop,
|
|
27137
|
+
info: noop,
|
|
27138
|
+
warn: noop,
|
|
27139
|
+
error: noop,
|
|
27140
|
+
fatal: noop
|
|
27141
|
+
};
|
|
27142
|
+
const subscribers = [];
|
|
27143
|
+
let inner = null;
|
|
27144
|
+
const facade = {
|
|
27145
|
+
get user() {
|
|
27146
|
+
return inner?.user ? { id: inner.user.id, name: inner.user.name ?? void 0 } : null;
|
|
27147
|
+
},
|
|
27148
|
+
ev: { on: (_e, fn) => {
|
|
27149
|
+
subscribers.push(fn);
|
|
27150
|
+
} },
|
|
27151
|
+
sendMessage: (jid, content) => {
|
|
27152
|
+
if (!inner) return Promise.reject(new Error("whatsapp socket not connected"));
|
|
27153
|
+
return inner.sendMessage(jid, content);
|
|
27154
|
+
},
|
|
27155
|
+
sendPresenceUpdate: (state2, jid) => inner?.sendPresenceUpdate(state2, jid) ?? Promise.resolve(),
|
|
27156
|
+
end: () => inner?.end(void 0)
|
|
27157
|
+
};
|
|
27158
|
+
const { state, saveCreds } = await useMultiFileAuthState(o.authPath);
|
|
27159
|
+
await new Promise((resolveOpen, rejectOpen) => {
|
|
27160
|
+
let opened = false;
|
|
27161
|
+
function connect2() {
|
|
27162
|
+
const sock = makeWASocket({ auth: state, logger: logger2 });
|
|
27163
|
+
inner = sock;
|
|
27164
|
+
sock.ev.on("creds.update", saveCreds);
|
|
27165
|
+
sock.ev.on("messages.upsert", (u) => {
|
|
27166
|
+
for (const fn of subscribers) fn(u);
|
|
27167
|
+
});
|
|
27168
|
+
sock.ev.on("connection.update", (update) => {
|
|
27169
|
+
const { connection, lastDisconnect, qr } = update;
|
|
27170
|
+
if (qr) void printQr(qr, o.log);
|
|
27171
|
+
if (connection === "open" && !opened) {
|
|
27172
|
+
opened = true;
|
|
27173
|
+
resolveOpen();
|
|
27174
|
+
}
|
|
27175
|
+
if (connection === "close") {
|
|
27176
|
+
const code = lastDisconnect?.error?.output?.statusCode;
|
|
27177
|
+
if (code === DisconnectReason.loggedOut) {
|
|
27178
|
+
const err = new Error("WhatsApp unlinked this device (logged out) \u2014 delete the auth dir and pair again.");
|
|
27179
|
+
o.log(err.message);
|
|
27180
|
+
if (!opened) rejectOpen(err);
|
|
27181
|
+
return;
|
|
27182
|
+
}
|
|
27183
|
+
if (o.stillOpen()) {
|
|
27184
|
+
o.log(`connection closed (status ${code ?? "?"}) \u2014 reconnecting\u2026`);
|
|
27185
|
+
setTimeout(connect2, 3e3);
|
|
27186
|
+
}
|
|
27187
|
+
}
|
|
27188
|
+
});
|
|
27189
|
+
}
|
|
27190
|
+
connect2();
|
|
27191
|
+
});
|
|
27192
|
+
return facade;
|
|
27193
|
+
}
|
|
27194
|
+
async function printQr(qr, log) {
|
|
27195
|
+
log("pair this device: WhatsApp \u2192 Settings \u2192 Linked devices \u2192 Link a device");
|
|
27196
|
+
try {
|
|
27197
|
+
const qrt = await import('qrcode-terminal');
|
|
27198
|
+
(qrt.default ?? qrt).generate(qr, { small: true });
|
|
27199
|
+
} catch {
|
|
27200
|
+
log(`qrcode-terminal not installed \u2014 raw pairing code:
|
|
27201
|
+
${qr}`);
|
|
27202
|
+
}
|
|
27203
|
+
}
|
|
27204
|
+
|
|
26477
27205
|
// src/cli.ts
|
|
26478
27206
|
routeLogsToStderr();
|
|
26479
|
-
var USAGE = `usage: will <mcp | serve | discord>
|
|
27207
|
+
var USAGE = `usage: will <mcp | serve | discord | whatsapp>
|
|
26480
27208
|
|
|
26481
|
-
mcp
|
|
26482
|
-
serve
|
|
26483
|
-
discord
|
|
26484
|
-
|
|
27209
|
+
mcp host a persistent mind over MCP stdio (Claude Desktop / Claude Code)
|
|
27210
|
+
serve host a persistent mind over HTTP (any language; WILL_PORT, default 7777)
|
|
27211
|
+
discord put a persistent mind in a Discord server (DISCORD_BOT_TOKEN; optional
|
|
27212
|
+
WILL_DISCORD_CHANNELS, WILL_DISCORD_MENTION_ONLY, WILL_DISCORD_HOME_CHANNEL)
|
|
27213
|
+
whatsapp put a persistent mind on WhatsApp \u2014 QR-pairs as a linked device; no token.
|
|
27214
|
+
UNOFFICIAL protocol (ban risk; use a spare number \u2014 docs/channels/whatsapp.md).
|
|
27215
|
+
Optional WILL_WHATSAPP_CHATS, WILL_WHATSAPP_MENTION_ONLY, WILL_WHATSAPP_HOME_CHAT
|
|
26485
27216
|
|
|
26486
27217
|
Shared env: WILL_NAME, WILL_IDENTITY, WILL_TIER, WILL_LLM, WILL_TICK_MS,
|
|
26487
27218
|
WILL_SEED, WILL_PMA_PATH, WILL_MCP_SERVERS. The mind persists across runs via
|
|
26488
27219
|
its PMA artifact.`;
|
|
26489
27220
|
async function main() {
|
|
26490
27221
|
const sub = process.argv[2];
|
|
26491
|
-
if (sub !== "mcp" && sub !== "serve" && sub !== "discord") {
|
|
27222
|
+
if (sub !== "mcp" && sub !== "serve" && sub !== "discord" && sub !== "whatsapp") {
|
|
26492
27223
|
console.error(sub ? `unknown subcommand: ${sub}
|
|
26493
27224
|
|
|
26494
27225
|
${USAGE}` : USAGE);
|
|
@@ -26520,6 +27251,21 @@ ${USAGE}` : USAGE);
|
|
|
26520
27251
|
console.error(`[will] ${name} is present on Discord (tick ${tickMs}ms, anatomy ${anatomy}) \u2014 it speaks when it decides to.`);
|
|
26521
27252
|
return;
|
|
26522
27253
|
}
|
|
27254
|
+
if (sub === "whatsapp") {
|
|
27255
|
+
const csv = (v) => v?.split(",").map((s) => s.trim()).filter(Boolean);
|
|
27256
|
+
const stem = pmaPath.replace(/(\.pma)?\.json$/, "");
|
|
27257
|
+
const bridge = await connectWhatsApp(will, {
|
|
27258
|
+
chats: csv(process.env.WILL_WHATSAPP_CHATS),
|
|
27259
|
+
mentionOnly: /^(1|true|yes)$/i.test(process.env.WILL_WHATSAPP_MENTION_ONLY ?? ""),
|
|
27260
|
+
homeChatId: process.env.WILL_WHATSAPP_HOME_CHAT,
|
|
27261
|
+
authPath: stem + ".wa-auth",
|
|
27262
|
+
rosterPath: stem + ".whatsapp.json"
|
|
27263
|
+
});
|
|
27264
|
+
onCleanup(() => bridge.close());
|
|
27265
|
+
await bridge.start();
|
|
27266
|
+
console.error(`[will] ${name} is present on WhatsApp (tick ${tickMs}ms, anatomy ${anatomy}) \u2014 it speaks when it decides to.`);
|
|
27267
|
+
return;
|
|
27268
|
+
}
|
|
26523
27269
|
const port = parseInt(process.env.WILL_PORT ?? "7777");
|
|
26524
27270
|
const host = process.env.WILL_HOST ?? "127.0.0.1";
|
|
26525
27271
|
const server = buildWillHttpServer(will, { pmaPath });
|