@mindot/will 0.5.0 → 0.7.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/dist/channels/discord.d.ts +1 -1
- package/dist/channels/discord.js.map +1 -1
- package/dist/channels/whatsapp.d.ts +1 -1
- package/dist/channels/whatsapp.js.map +1 -1
- package/dist/cli.js +998 -59
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +998 -59
- 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/{will-BDq-TMQr.d.ts → will-DAW0l-lY.d.ts} +90 -10
- package/package.json +1 -1
- 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 +25 -25
- package/src/cli.ts +20 -20
- package/src/cognition/acp.ts +28 -0
- package/src/cognition/agency/consequence.ts +174 -0
- package/src/cognition/agency/engines/action.selector.ts +333 -48
- package/src/cognition/agency/engines/affordance.synthesizer.ts +35 -16
- package/src/cognition/agency/engines/deliberation.engine.ts +28 -14
- package/src/cognition/agency/engines/motor.schema.executor.ts +90 -14
- package/src/cognition/agency/engines/reafference.engine.ts +152 -23
- 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 +10 -1
- package/src/cognition/agency/revocation.ts +79 -0
- package/src/cognition/agency/schemas/repertoire.ts +109 -9
- package/src/cognition/agency/selection.scoring.ts +32 -10
- package/src/cognition/agency/types.ts +9 -0
- 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 +25 -25
- 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 +5 -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 +30 -30
- package/src/host/utterances.ts +1 -1
- package/src/llm/index.ts +9 -9
- 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 +5 -5
- package/src/serve/server.ts +12 -12
- package/src/stem/assembly.audit.ts +3 -3
- package/src/stem/guards/identity.coherence.ts +10 -10
- package/src/stem/guards/identity.guard.ts +22 -22
- package/src/stem/index.ts +26 -11
- package/src/stem/mind.ts +12 -12
- package/src/stem/policy/arbiter.ts +136 -0
- package/src/stem/policy/rule.table.ts +172 -0
- package/src/stem/policy/verdict.recorder.ts +0 -0
- package/src/stem/tracts/biography.writer.ts +3 -3
- package/src/stem/tracts/effector.controller.ts +383 -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/index.js
CHANGED
|
@@ -3607,6 +3607,9 @@ var SleepPressureRegulator = class {
|
|
|
3607
3607
|
}
|
|
3608
3608
|
};
|
|
3609
3609
|
|
|
3610
|
+
// src/cognition/acp.ts
|
|
3611
|
+
var ACP_SELF_PRECISION = 0.35;
|
|
3612
|
+
|
|
3610
3613
|
// src/cognition/persona.prior.ts
|
|
3611
3614
|
var PERSONA_PRIOR_ID = "persona-prior";
|
|
3612
3615
|
var PERSONA_PRIOR_TYPE = "persona.prior";
|
|
@@ -3715,6 +3718,8 @@ function consolidatePrior(current, adjustments, tick, opts = {}) {
|
|
|
3715
3718
|
}
|
|
3716
3719
|
|
|
3717
3720
|
// src/cognition/faculties/attention.allocator.ts
|
|
3721
|
+
var ACP_USAGE_UPLIFT = 0.15;
|
|
3722
|
+
var ACP_CONFIDENCE = 0.4;
|
|
3718
3723
|
var EFFORT_BASELINE2 = 0.7;
|
|
3719
3724
|
var EFFORT_MIN = 0.4;
|
|
3720
3725
|
var EFFORT_MAX = 1;
|
|
@@ -3736,6 +3741,8 @@ var AttentionAllocator = class {
|
|
|
3736
3741
|
_effort = EFFORT_BASELINE2;
|
|
3737
3742
|
/** A one-shot focus/rest request from the executive, applied next react(). */
|
|
3738
3743
|
_effortRequest = null;
|
|
3744
|
+
/** ACP-P2: a self-caused precision attenuation is armed; react() restores after one observe. */
|
|
3745
|
+
_acpOneShot = false;
|
|
3739
3746
|
_bus = null;
|
|
3740
3747
|
_model = new GenerativeModel();
|
|
3741
3748
|
constructor(config = {}) {
|
|
@@ -3756,8 +3763,12 @@ var AttentionAllocator = class {
|
|
|
3756
3763
|
"executive.prediction.formed",
|
|
3757
3764
|
"attention.regulate",
|
|
3758
3765
|
// voluntary focus/rest from the executive (Option C)
|
|
3759
|
-
"senses.*"
|
|
3766
|
+
"senses.*",
|
|
3760
3767
|
// all sense percepts — salience feeds attention allocation
|
|
3768
|
+
// ACP-P2: our own enactions — anticipate the attention swing they cause
|
|
3769
|
+
"agency.enacted",
|
|
3770
|
+
"agency.communicate",
|
|
3771
|
+
"agency.invocation"
|
|
3761
3772
|
];
|
|
3762
3773
|
}
|
|
3763
3774
|
publishes() {
|
|
@@ -3784,6 +3795,18 @@ var AttentionAllocator = class {
|
|
|
3784
3795
|
this._model.setPrecision("attention.usage", 1 + p.confidence * 0.5);
|
|
3785
3796
|
break;
|
|
3786
3797
|
}
|
|
3798
|
+
case "agency.enacted":
|
|
3799
|
+
case "agency.communicate":
|
|
3800
|
+
case "agency.invocation": {
|
|
3801
|
+
const usage = this._model.predict("attention.usage");
|
|
3802
|
+
const free = this._model.predict("attention.free_fraction");
|
|
3803
|
+
this._model.anticipate("attention.usage", Math.min(1, usage + ACP_USAGE_UPLIFT), ACP_CONFIDENCE);
|
|
3804
|
+
this._model.anticipate("attention.free_fraction", Math.max(0, free - ACP_USAGE_UPLIFT), ACP_CONFIDENCE);
|
|
3805
|
+
this._model.setPrecision("attention.usage", ACP_SELF_PRECISION);
|
|
3806
|
+
this._model.setPrecision("attention.free_fraction", ACP_SELF_PRECISION);
|
|
3807
|
+
this._acpOneShot = true;
|
|
3808
|
+
break;
|
|
3809
|
+
}
|
|
3787
3810
|
default:
|
|
3788
3811
|
if (e.type.startsWith("senses.")) {
|
|
3789
3812
|
const percept = e.payload;
|
|
@@ -3867,6 +3890,11 @@ var AttentionAllocator = class {
|
|
|
3867
3890
|
if (_bus) {
|
|
3868
3891
|
const usageErr = this._model.observe("attention.usage", attentionUsage);
|
|
3869
3892
|
const freeErr = this._model.observe("attention.free_fraction", freeFraction);
|
|
3893
|
+
if (this._acpOneShot) {
|
|
3894
|
+
this._model.setPrecision("attention.usage", 1);
|
|
3895
|
+
this._model.setPrecision("attention.free_fraction", 1);
|
|
3896
|
+
this._acpOneShot = false;
|
|
3897
|
+
}
|
|
3870
3898
|
if (!usageErr.gated || !freeErr.gated)
|
|
3871
3899
|
_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 } });
|
|
3872
3900
|
}
|
|
@@ -3986,7 +4014,18 @@ var StressRegulator = class {
|
|
|
3986
4014
|
}
|
|
3987
4015
|
// ── Engine interface ─────────────────────────────────────
|
|
3988
4016
|
subscribes() {
|
|
3989
|
-
return [
|
|
4017
|
+
return [
|
|
4018
|
+
"energy.state.changed",
|
|
4019
|
+
"sleep.state.changed",
|
|
4020
|
+
"novelty.state.changed",
|
|
4021
|
+
"goal.state.changed",
|
|
4022
|
+
"metacognition.state.changed",
|
|
4023
|
+
"executive.prediction.formed",
|
|
4024
|
+
// ACP-P2: our own enactions — the stress swing they cause is expected
|
|
4025
|
+
"agency.enacted",
|
|
4026
|
+
"agency.communicate",
|
|
4027
|
+
"agency.invocation"
|
|
4028
|
+
];
|
|
3990
4029
|
}
|
|
3991
4030
|
publishes() {
|
|
3992
4031
|
return [];
|
|
@@ -4015,8 +4054,17 @@ var StressRegulator = class {
|
|
|
4015
4054
|
this._model.setPrecision("stress.load", 1 + p.confidence * 0.5);
|
|
4016
4055
|
break;
|
|
4017
4056
|
}
|
|
4057
|
+
case "agency.enacted":
|
|
4058
|
+
case "agency.communicate":
|
|
4059
|
+
case "agency.invocation": {
|
|
4060
|
+
this._model.setPrecision("stress.load", ACP_SELF_PRECISION);
|
|
4061
|
+
this._acpOneShot = true;
|
|
4062
|
+
break;
|
|
4063
|
+
}
|
|
4018
4064
|
}
|
|
4019
4065
|
}
|
|
4066
|
+
/** ACP-P2: self-caused stress attenuation armed; react() restores after one observe. */
|
|
4067
|
+
_acpOneShot = false;
|
|
4020
4068
|
snapshot() {
|
|
4021
4069
|
return {
|
|
4022
4070
|
energyLevel: this._energyLevel,
|
|
@@ -4109,6 +4157,10 @@ var StressRegulator = class {
|
|
|
4109
4157
|
if (_bus) {
|
|
4110
4158
|
const zoneCode = zone === "low" ? 0 : zone === "optimal" ? 1 : zone === "distress" ? 2 : 3;
|
|
4111
4159
|
const predErr = this._model.observe("stress.load", newLoad);
|
|
4160
|
+
if (this._acpOneShot) {
|
|
4161
|
+
this._model.setPrecision("stress.load", 1);
|
|
4162
|
+
this._acpOneShot = false;
|
|
4163
|
+
}
|
|
4112
4164
|
if (!predErr.gated || zone !== previousZone) {
|
|
4113
4165
|
_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 } });
|
|
4114
4166
|
}
|
|
@@ -4331,6 +4383,116 @@ var CircadianOscillator = class {
|
|
|
4331
4383
|
}
|
|
4332
4384
|
};
|
|
4333
4385
|
|
|
4386
|
+
// src/cognition/agency/consequence.ts
|
|
4387
|
+
var CONSEQUENCE_TYPE = "agency.consequence";
|
|
4388
|
+
var ATTENUATION = 0.25;
|
|
4389
|
+
var MIN_TEXT_MATCH_LEN = 12;
|
|
4390
|
+
var CONSEQUENCE_TTL_TICKS = 30;
|
|
4391
|
+
function fnv1a(text) {
|
|
4392
|
+
let h = 2166136261;
|
|
4393
|
+
for (let i = 0; i < text.length; i++) {
|
|
4394
|
+
h ^= text.charCodeAt(i);
|
|
4395
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
4396
|
+
}
|
|
4397
|
+
return h >>> 0;
|
|
4398
|
+
}
|
|
4399
|
+
function paramsKey(value) {
|
|
4400
|
+
if (value === null || typeof value !== "object")
|
|
4401
|
+
return typeof value === "string" ? JSON.stringify(value) : String(value);
|
|
4402
|
+
if (Array.isArray(value))
|
|
4403
|
+
return `[${value.map(paramsKey).join(",")}]`;
|
|
4404
|
+
const obj = value;
|
|
4405
|
+
const keys = Object.keys(obj).sort();
|
|
4406
|
+
return `{${keys.map((k) => `${k}:${paramsKey(obj[k])}`).join(",")}}`;
|
|
4407
|
+
}
|
|
4408
|
+
function consequenceEntity(d) {
|
|
4409
|
+
return {
|
|
4410
|
+
id: `agency-consequence-${d.intentId}`,
|
|
4411
|
+
type: CONSEQUENCE_TYPE,
|
|
4412
|
+
metadata: { ...d }
|
|
4413
|
+
};
|
|
4414
|
+
}
|
|
4415
|
+
function readConsequence(m) {
|
|
4416
|
+
const meta = m ?? {};
|
|
4417
|
+
const intentId = typeof meta["intentId"] === "string" ? meta["intentId"] : void 0;
|
|
4418
|
+
const schema = typeof meta["schema"] === "string" ? meta["schema"] : void 0;
|
|
4419
|
+
const mode = meta["mode"] === "communicate" || meta["mode"] === "external" ? meta["mode"] : void 0;
|
|
4420
|
+
if (!intentId || !schema || !mode) return null;
|
|
4421
|
+
return {
|
|
4422
|
+
intentId,
|
|
4423
|
+
schema,
|
|
4424
|
+
mode,
|
|
4425
|
+
effector: typeof meta["effector"] === "string" ? meta["effector"] : void 0,
|
|
4426
|
+
targetEntityId: typeof meta["targetEntityId"] === "string" ? meta["targetEntityId"] : void 0,
|
|
4427
|
+
textHash: typeof meta["textHash"] === "number" ? meta["textHash"] : void 0,
|
|
4428
|
+
text: typeof meta["text"] === "string" ? meta["text"] : void 0,
|
|
4429
|
+
paramsHash: typeof meta["paramsHash"] === "number" ? meta["paramsHash"] : void 0,
|
|
4430
|
+
expiresAt: typeof meta["expiresAt"] === "number" ? meta["expiresAt"] : 0,
|
|
4431
|
+
tick: typeof meta["tick"] === "number" ? meta["tick"] : 0
|
|
4432
|
+
};
|
|
4433
|
+
}
|
|
4434
|
+
function liveConsequences(entities, tick) {
|
|
4435
|
+
const out = [];
|
|
4436
|
+
for (const [, e] of entities) {
|
|
4437
|
+
if (e.type !== CONSEQUENCE_TYPE) continue;
|
|
4438
|
+
const d = readConsequence(e.metadata);
|
|
4439
|
+
if (d && tick < d.expiresAt) out.push(d);
|
|
4440
|
+
}
|
|
4441
|
+
return out.sort((a, b) => a.intentId < b.intentId ? -1 : a.intentId > b.intentId ? 1 : 0);
|
|
4442
|
+
}
|
|
4443
|
+
function matchConsequenceText(descriptors, candidate) {
|
|
4444
|
+
if (candidate.length === 0) return null;
|
|
4445
|
+
const candidateHash = fnv1a(candidate);
|
|
4446
|
+
for (const d of descriptors) {
|
|
4447
|
+
if (d.textHash !== void 0 && d.textHash === candidateHash) return d;
|
|
4448
|
+
if (d.text !== void 0 && d.text.length >= MIN_TEXT_MATCH_LEN && candidate.includes(d.text)) return d;
|
|
4449
|
+
}
|
|
4450
|
+
return null;
|
|
4451
|
+
}
|
|
4452
|
+
var CORRESPONDENCE_ATTENUATION = 0.5;
|
|
4453
|
+
function matchConsequenceEntity(descriptors, entityId, changeType) {
|
|
4454
|
+
if (changeType !== "modified" || entityId.length === 0) return null;
|
|
4455
|
+
for (const d of descriptors)
|
|
4456
|
+
if (d.mode === "external" && d.targetEntityId === entityId) return d;
|
|
4457
|
+
return null;
|
|
4458
|
+
}
|
|
4459
|
+
|
|
4460
|
+
// src/cognition/agency/revocation.ts
|
|
4461
|
+
var REVOCATION_TYPE = "agency.revocation";
|
|
4462
|
+
var RUPTURE_REVOKE_GATE = 0.7;
|
|
4463
|
+
var REVOCATION_TTL_TICKS = 5;
|
|
4464
|
+
function revocationId(intentId) {
|
|
4465
|
+
return `agency-revocation-${intentId}`;
|
|
4466
|
+
}
|
|
4467
|
+
function revocationEntity(intentId, schema, rupture, tick) {
|
|
4468
|
+
return {
|
|
4469
|
+
id: revocationId(intentId),
|
|
4470
|
+
type: REVOCATION_TYPE,
|
|
4471
|
+
metadata: { intentId, schema, rupture, tick, expiresAt: tick + REVOCATION_TTL_TICKS }
|
|
4472
|
+
};
|
|
4473
|
+
}
|
|
4474
|
+
function revokedIntentIds(entities, tick) {
|
|
4475
|
+
const out = /* @__PURE__ */ new Set();
|
|
4476
|
+
for (const [, e] of entities) {
|
|
4477
|
+
if (e.type !== REVOCATION_TYPE) continue;
|
|
4478
|
+
const m = e.metadata ?? {};
|
|
4479
|
+
const intentId = typeof m["intentId"] === "string" ? m["intentId"] : void 0;
|
|
4480
|
+
const expiresAt = typeof m["expiresAt"] === "number" ? m["expiresAt"] : 0;
|
|
4481
|
+
if (intentId && tick < expiresAt) out.add(intentId);
|
|
4482
|
+
}
|
|
4483
|
+
return out;
|
|
4484
|
+
}
|
|
4485
|
+
function staleRevocationIds(entities, tick) {
|
|
4486
|
+
const stale = [];
|
|
4487
|
+
for (const [id, e] of entities) {
|
|
4488
|
+
if (e.type !== REVOCATION_TYPE) continue;
|
|
4489
|
+
const m = e.metadata ?? {};
|
|
4490
|
+
const expiresAt = typeof m["expiresAt"] === "number" ? m["expiresAt"] : 0;
|
|
4491
|
+
if (tick >= expiresAt) stale.push(id);
|
|
4492
|
+
}
|
|
4493
|
+
return stale;
|
|
4494
|
+
}
|
|
4495
|
+
|
|
4334
4496
|
// src/cognition/faculties/exteroception.ts
|
|
4335
4497
|
var internalTypes = /* @__PURE__ */ new Set([
|
|
4336
4498
|
"percept",
|
|
@@ -4356,7 +4518,12 @@ var internalTypes = /* @__PURE__ */ new Set([
|
|
|
4356
4518
|
"episodic_memory",
|
|
4357
4519
|
// Internal state entities written by our own engines — not external events
|
|
4358
4520
|
"affect.blends",
|
|
4359
|
-
"executive.summary"
|
|
4521
|
+
"executive.summary",
|
|
4522
|
+
// The agency's own forward-model records (EXAFFERENCE P1/P2): perceiving our
|
|
4523
|
+
// expected-consequence descriptors would be a self-noise loop.
|
|
4524
|
+
CONSEQUENCE_TYPE,
|
|
4525
|
+
// The agency's own revocation tombstones (EXAFFERENCE P4) — internal bookkeeping.
|
|
4526
|
+
REVOCATION_TYPE
|
|
4360
4527
|
]);
|
|
4361
4528
|
var Exteroception = class {
|
|
4362
4529
|
name = "exteroception";
|
|
@@ -4406,17 +4573,26 @@ var Exteroception = class {
|
|
|
4406
4573
|
const events = [], commands = { set: [], delete: [], metrics: [] };
|
|
4407
4574
|
const rawPercepts = this._scanWorld(state);
|
|
4408
4575
|
const capped = rawPercepts.slice(0, this._maxPerceptsPerTick);
|
|
4576
|
+
const consequences = liveConsequences(state.entities, tick);
|
|
4409
4577
|
for (let i = 0; i < capped.length; i++) {
|
|
4410
4578
|
const rp = capped[i];
|
|
4579
|
+
const textHit = consequences.length > 0 && rp.matchText ? matchConsequenceText(consequences, rp.matchText) : null;
|
|
4580
|
+
const entityHit = !textHit && consequences.length > 0 ? matchConsequenceEntity(consequences, rp.entityId, rp.changeType) : null;
|
|
4581
|
+
const hit = textHit ?? entityHit;
|
|
4582
|
+
const salience = textHit ? rp.salience * ATTENUATION : entityHit ? rp.salience * CORRESPONDENCE_ATTENUATION : rp.salience;
|
|
4411
4583
|
const perceptEntity = {
|
|
4412
4584
|
id: `percept-${tick}-${i}`,
|
|
4413
4585
|
type: "percept",
|
|
4414
4586
|
metadata: {
|
|
4415
4587
|
entityId: rp.entityId,
|
|
4416
4588
|
changeType: rp.changeType,
|
|
4417
|
-
salience
|
|
4589
|
+
salience,
|
|
4418
4590
|
category: rp.category,
|
|
4419
4591
|
summary: rp.summary,
|
|
4592
|
+
provenance: hit ? "reafferent" : "exafferent",
|
|
4593
|
+
...hit ? { sourceIntentId: hit.intentId } : {},
|
|
4594
|
+
// affect→percept seam (registry #5): what this percept FEELS like
|
|
4595
|
+
...rp.valence !== void 0 ? { valence: rp.valence, valenceSource: rp.valenceSource } : {},
|
|
4420
4596
|
tick
|
|
4421
4597
|
}
|
|
4422
4598
|
};
|
|
@@ -4427,7 +4603,7 @@ var Exteroception = class {
|
|
|
4427
4603
|
source: this.name,
|
|
4428
4604
|
payload: {
|
|
4429
4605
|
entityId: rp.entityId,
|
|
4430
|
-
salience
|
|
4606
|
+
salience,
|
|
4431
4607
|
category: rp.category,
|
|
4432
4608
|
summary: rp.summary
|
|
4433
4609
|
}
|
|
@@ -4475,7 +4651,9 @@ var Exteroception = class {
|
|
|
4475
4651
|
changeType: "appeared",
|
|
4476
4652
|
salience: this._computeSalience(entity, "appeared", state.time),
|
|
4477
4653
|
category: entity.type,
|
|
4478
|
-
summary: this._summarizeEntity(entity, "appeared")
|
|
4654
|
+
summary: this._summarizeEntity(entity, "appeared"),
|
|
4655
|
+
matchText: this._matchText(entity),
|
|
4656
|
+
...this._valenceOf(id, state)
|
|
4479
4657
|
});
|
|
4480
4658
|
} else if (entity.updatedAt > previousVersion) {
|
|
4481
4659
|
percepts.push({
|
|
@@ -4483,7 +4661,9 @@ var Exteroception = class {
|
|
|
4483
4661
|
changeType: "modified",
|
|
4484
4662
|
salience: this._computeSalience(entity, "modified", state.time),
|
|
4485
4663
|
category: entity.type,
|
|
4486
|
-
summary: this._summarizeEntity(entity, "modified")
|
|
4664
|
+
summary: this._summarizeEntity(entity, "modified"),
|
|
4665
|
+
matchText: this._matchText(entity),
|
|
4666
|
+
...this._valenceOf(id, state)
|
|
4487
4667
|
});
|
|
4488
4668
|
}
|
|
4489
4669
|
this._previousEntityVersions.set(id, entity.updatedAt);
|
|
@@ -4509,6 +4689,46 @@ var Exteroception = class {
|
|
|
4509
4689
|
* Generate a meaningful summary for an entity.
|
|
4510
4690
|
* Instead of "New percept: percept-54-0", produce something useful.
|
|
4511
4691
|
*/
|
|
4692
|
+
/**
|
|
4693
|
+
* The text the corollary-discharge matcher inspects for this entity — its
|
|
4694
|
+
* content (a message body) over its description over its summary. Where our
|
|
4695
|
+
* own delivered words would surface if the world echoes them back.
|
|
4696
|
+
*/
|
|
4697
|
+
/**
|
|
4698
|
+
* The affect→percept valence seam (registry #5). A percept carries how the
|
|
4699
|
+
* mind *feels* about what it is a percept OF, resolved most-specific-first:
|
|
4700
|
+
*
|
|
4701
|
+
* 1. the KnownEntityTracker's dossier for this entity (`ke-<id>.valence`) —
|
|
4702
|
+
* a real per-entity felt valence, the honest signal;
|
|
4703
|
+
* 2. otherwise the ambient `affect.valence` — the felt tone at perception
|
|
4704
|
+
* time. Weaker evidence, so it is tagged `'ambient'` and consumers
|
|
4705
|
+
* weight it down (mood is context, not appraisal of this thing).
|
|
4706
|
+
*
|
|
4707
|
+
* Absent both, no valence is stamped and every consumer keeps its
|
|
4708
|
+
* pre-seam behaviour.
|
|
4709
|
+
*/
|
|
4710
|
+
/** Spread-friendly form of `_valenceFor` for percept construction. */
|
|
4711
|
+
_valenceOf(entityId, state) {
|
|
4712
|
+
const v = this._valenceFor(entityId, state);
|
|
4713
|
+
return v ? { valence: v.valence, valenceSource: v.source } : {};
|
|
4714
|
+
}
|
|
4715
|
+
_valenceFor(entityId, state) {
|
|
4716
|
+
const dossier = state.entities.get(`ke-${entityId}`);
|
|
4717
|
+
const felt = dossier?.metadata?.["valence"];
|
|
4718
|
+
if (typeof felt === "number" && Number.isFinite(felt))
|
|
4719
|
+
return { valence: felt, source: "entity" };
|
|
4720
|
+
const ambient = state.metrics.get("affect.valence");
|
|
4721
|
+
if (typeof ambient === "number" && Number.isFinite(ambient))
|
|
4722
|
+
return { valence: ambient, source: "ambient" };
|
|
4723
|
+
return void 0;
|
|
4724
|
+
}
|
|
4725
|
+
_matchText(entity) {
|
|
4726
|
+
const m = entity.metadata;
|
|
4727
|
+
const content = typeof m?.["content"] === "string" ? m["content"] : void 0;
|
|
4728
|
+
const description = typeof m?.["description"] === "string" ? m["description"] : void 0;
|
|
4729
|
+
const summary = typeof m?.["summary"] === "string" ? m["summary"] : void 0;
|
|
4730
|
+
return content ?? description ?? summary;
|
|
4731
|
+
}
|
|
4512
4732
|
_summarizeEntity(entity, changeType) {
|
|
4513
4733
|
const name = entity.metadata?.name;
|
|
4514
4734
|
const description = entity.metadata?.description;
|
|
@@ -6493,6 +6713,8 @@ var MoralEvaluator = class {
|
|
|
6493
6713
|
};
|
|
6494
6714
|
|
|
6495
6715
|
// src/cognition/faculties/affective.blender.ts
|
|
6716
|
+
var ACP_AROUSAL_UPLIFT = 0.1;
|
|
6717
|
+
var ACP_CONFIDENCE2 = 0.4;
|
|
6496
6718
|
var DOMINANT_EMOTION_CODES = {
|
|
6497
6719
|
"neutral": 0,
|
|
6498
6720
|
"fear": 1,
|
|
@@ -6593,6 +6815,8 @@ var AffectiveBlender = class {
|
|
|
6593
6815
|
_previousPAD = { valence: 0, arousal: 0.3, dominance: 0.5 };
|
|
6594
6816
|
_emotionHistory = /* @__PURE__ */ new Map();
|
|
6595
6817
|
_moodBaseline = 0.5;
|
|
6818
|
+
/** ACP-P2: self-caused arousal attenuation armed; react() restores after one observe. */
|
|
6819
|
+
_acpOneShot = false;
|
|
6596
6820
|
_energyLevel = 100;
|
|
6597
6821
|
_comfort = 0.5;
|
|
6598
6822
|
_sleepPressure = 0;
|
|
@@ -6626,8 +6850,12 @@ var AffectiveBlender = class {
|
|
|
6626
6850
|
"sleep.state.changed",
|
|
6627
6851
|
"stress.state.changed",
|
|
6628
6852
|
"executive.prediction.formed",
|
|
6629
|
-
"interaction.occurred"
|
|
6853
|
+
"interaction.occurred",
|
|
6630
6854
|
// 2.1: social stimuli drive immediate arousal/valence shifts
|
|
6855
|
+
// ACP-P2: our own enactions — the arousal they cause is expected, not surprising
|
|
6856
|
+
"agency.enacted",
|
|
6857
|
+
"agency.communicate",
|
|
6858
|
+
"agency.invocation"
|
|
6631
6859
|
];
|
|
6632
6860
|
}
|
|
6633
6861
|
publishes() {
|
|
@@ -6636,6 +6864,15 @@ var AffectiveBlender = class {
|
|
|
6636
6864
|
onCognitiveEvent(e) {
|
|
6637
6865
|
this._model.observe(e.type, e.salience);
|
|
6638
6866
|
switch (e.type) {
|
|
6867
|
+
case "agency.enacted":
|
|
6868
|
+
case "agency.communicate":
|
|
6869
|
+
case "agency.invocation": {
|
|
6870
|
+
const arousal = this._model.predict("affect.arousal");
|
|
6871
|
+
this._model.anticipate("affect.arousal", Math.min(1, arousal + ACP_AROUSAL_UPLIFT), ACP_CONFIDENCE2);
|
|
6872
|
+
this._model.setPrecision("affect.arousal", ACP_SELF_PRECISION);
|
|
6873
|
+
this._acpOneShot = true;
|
|
6874
|
+
break;
|
|
6875
|
+
}
|
|
6639
6876
|
case "circadian.state.changed":
|
|
6640
6877
|
this._moodBaseline = e.payload["moodBaseline"] ?? this._moodBaseline;
|
|
6641
6878
|
break;
|
|
@@ -6739,8 +6976,14 @@ var AffectiveBlender = class {
|
|
|
6739
6976
|
const _bus = this._bus;
|
|
6740
6977
|
if (_bus)
|
|
6741
6978
|
_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 } });
|
|
6742
|
-
if (_bus)
|
|
6743
|
-
|
|
6979
|
+
if (_bus) {
|
|
6980
|
+
const arousalErr = this._model.observe("affect.arousal", modulatedPAD.arousal);
|
|
6981
|
+
if (this._acpOneShot) {
|
|
6982
|
+
this._model.setPrecision("affect.arousal", 1);
|
|
6983
|
+
this._acpOneShot = false;
|
|
6984
|
+
}
|
|
6985
|
+
_bus.publish({ type: "affect.state.changed", version: 1, sourceEngine: this.name, salience: arousalErr.salience, payload: { valence: modulatedPAD.valence, arousal: modulatedPAD.arousal, dominance: modulatedPAD.dominance } });
|
|
6986
|
+
}
|
|
6744
6987
|
return { events: events.length > 0 ? events : void 0, commands };
|
|
6745
6988
|
}
|
|
6746
6989
|
// ── PAD computation ──────────────────────────────────────
|
|
@@ -14752,7 +14995,8 @@ var TaskSwitcher = class {
|
|
|
14752
14995
|
const currentGoal = activeGoals.find((g) => g.id === this._currentFocus.goalId);
|
|
14753
14996
|
const currentPriority = currentGoal?.priority ?? 0;
|
|
14754
14997
|
const switchAdvantage = topGoal.priority - currentPriority;
|
|
14755
|
-
const
|
|
14998
|
+
const stability = state.metrics.get("situation.stability") ?? 1;
|
|
14999
|
+
const switchCost = this._baseSwitchCost * (1 + this._currentFocus.focusTicks * 0.01 * stability);
|
|
14756
15000
|
const netBenefit = switchAdvantage - switchCost;
|
|
14757
15001
|
if (netBenefit > this._switchThreshold && this._currentFocus.focusTicks >= this._minFocusTicks) {
|
|
14758
15002
|
this._currentFocus = {
|
|
@@ -18480,7 +18724,9 @@ function risk(a, bias) {
|
|
|
18480
18724
|
return clamp015(Math.max(0, -a.expectedValence) * 0.5 + bias.threat * 0.5);
|
|
18481
18725
|
}
|
|
18482
18726
|
function scoreAffordance(a, bias, w = DEFAULT_WEIGHTS) {
|
|
18483
|
-
|
|
18727
|
+
const raw = w.goal * goalRelevance(a, bias) + w.reward * a.expectedReward + w.novelty * novelty(a) + w.drive * driveUrgency(a, bias) + w.habit * a.habitStrength + w.plan * (a.planBias ?? 0) - w.cost * a.cost - w.inhib * bias.inhibition - w.risk * risk(a, bias);
|
|
18728
|
+
const availability = a.availability ?? 1;
|
|
18729
|
+
return raw > 0 ? raw * availability : raw;
|
|
18484
18730
|
}
|
|
18485
18731
|
function stakes(winner, bias) {
|
|
18486
18732
|
return clamp015(Math.max(
|
|
@@ -18559,6 +18805,7 @@ var AffordanceSynthesizer = class {
|
|
|
18559
18805
|
// ── react ─────────────────────────────────────────────────────
|
|
18560
18806
|
async react(_delta, tick, state, _context) {
|
|
18561
18807
|
this._repertoire?.restoreComposites(state.entities);
|
|
18808
|
+
this._repertoire?.restoreAvailability(state.entities);
|
|
18562
18809
|
const schemas = this._repertoire?.schemas() ?? this._schemas;
|
|
18563
18810
|
const skills = this._skills?.() ?? this._repertoire?.skills() ?? null;
|
|
18564
18811
|
const valence = metric(state, "affect.valence", 0);
|
|
@@ -18569,9 +18816,7 @@ var AffordanceSynthesizer = class {
|
|
|
18569
18816
|
if (e.type === "affordance") del.push(id);
|
|
18570
18817
|
const floor = schemas.filter((s) => s.binds === "none");
|
|
18571
18818
|
for (const schema of floor)
|
|
18572
|
-
set.push(this._toEntity(
|
|
18573
|
-
this._build(schema, tick, state, valence, energyLow, skills, {})
|
|
18574
|
-
));
|
|
18819
|
+
set.push(this._toEntity(this._build(schema, tick, state, valence, energyLow, skills, {})));
|
|
18575
18820
|
const candidates = [];
|
|
18576
18821
|
const goalTargets = collectGoalTargets(state);
|
|
18577
18822
|
const perceptSchema = schemas.find((s) => s.binds === "percept");
|
|
@@ -18686,6 +18931,7 @@ var AffordanceSynthesizer = class {
|
|
|
18686
18931
|
/** Compose an Affordance from a schema + the evoking context, folding in learned priors. */
|
|
18687
18932
|
_build(schema, tick, state, valence, energyLow, skills, ctx) {
|
|
18688
18933
|
const skill = skills?.get(schema.id);
|
|
18934
|
+
const availability = this._repertoire?.availabilityOf(schema.id) ?? 1;
|
|
18689
18935
|
const expectedReward = skill?.valueEstimate ?? clamp016(((schema.baseValence ?? 0) + 1) / 2);
|
|
18690
18936
|
const expectedValence = schema.baseValence ?? valence;
|
|
18691
18937
|
const habitStrength = skill?.habitStrength ?? 0;
|
|
@@ -18707,6 +18953,7 @@ var AffordanceSynthesizer = class {
|
|
|
18707
18953
|
available: this._available(schema.preconditions, (k) => metric(state, k, 0)),
|
|
18708
18954
|
tags: schema.tags ?? [],
|
|
18709
18955
|
...schema.description ? { description: schema.description } : {},
|
|
18956
|
+
...availability < 1 ? { availability } : {},
|
|
18710
18957
|
planBias: ctx.planBias,
|
|
18711
18958
|
planId: ctx.planId,
|
|
18712
18959
|
stepId: ctx.stepId,
|
|
@@ -18730,6 +18977,7 @@ var AffordanceSynthesizer = class {
|
|
|
18730
18977
|
available: a.available,
|
|
18731
18978
|
tags: a.tags,
|
|
18732
18979
|
description: a.description,
|
|
18980
|
+
...a.availability !== void 0 ? { availability: a.availability } : {},
|
|
18733
18981
|
planBias: a.planBias,
|
|
18734
18982
|
planId: a.planId,
|
|
18735
18983
|
stepId: a.stepId,
|
|
@@ -18785,11 +19033,24 @@ var BASE_SWITCH_COST = 0.15;
|
|
|
18785
19033
|
var FOCUS_GAIN = 0.01;
|
|
18786
19034
|
var AWAIT_STALE_TICKS = 15;
|
|
18787
19035
|
var STALE_DECAY = 0.5;
|
|
19036
|
+
var RUPTURE_SALIENCE_GATE = 0.4;
|
|
19037
|
+
var RUPTURE_WINDOW_TICKS = 2;
|
|
19038
|
+
var STABILITY_RECOVERY = 0.05;
|
|
19039
|
+
var STABILITY_EPSILON = 1e-4;
|
|
19040
|
+
var REVOKE_HINT_WINDOW = 8;
|
|
18788
19041
|
var ActionSelector = class {
|
|
18789
19042
|
name = "action-selector";
|
|
18790
19043
|
_bus = null;
|
|
18791
19044
|
_lastEntropy = 0;
|
|
18792
19045
|
_lastDeliberate = false;
|
|
19046
|
+
// EXAFFERENCE P4 follow-up (Channel B): the schema we most recently revoked
|
|
19047
|
+
// under rupture, so the *next* deliberation formed in its wake can own the
|
|
19048
|
+
// interruption in-character ("something changed — I dropped what I was
|
|
19049
|
+
// weighing"). Telemetry-grade instance state, mirroring _lastEntropy.
|
|
19050
|
+
_lastRevoked = null;
|
|
19051
|
+
// ACP §2b: sense-channel percepts buffered off the bus for the next react's
|
|
19052
|
+
// rupture computation (they never become entities). Cross-tick ⇒ FN9.
|
|
19053
|
+
_senseBuffer = [];
|
|
18793
19054
|
attachBus(bus) {
|
|
18794
19055
|
this._bus = bus;
|
|
18795
19056
|
}
|
|
@@ -18797,16 +19058,60 @@ var ActionSelector = class {
|
|
|
18797
19058
|
return [
|
|
18798
19059
|
{ type: "agency.selection.made", version: 1, validate: () => null },
|
|
18799
19060
|
{ type: "agency.selection.ambiguous", version: 1, validate: () => null },
|
|
18800
|
-
{ type: "agency.action.preempted", version: 1, validate: () => null }
|
|
19061
|
+
{ type: "agency.action.preempted", version: 1, validate: () => null },
|
|
19062
|
+
{ type: "agency.situation.rupture", version: 1, validate: () => null },
|
|
19063
|
+
{ type: "agency.commitment.revoked", version: 1, validate: () => null }
|
|
18801
19064
|
];
|
|
18802
19065
|
}
|
|
18803
19066
|
subscribes() {
|
|
18804
|
-
return [
|
|
19067
|
+
return [
|
|
19068
|
+
"senses.*",
|
|
19069
|
+
// Registry #6 (ACP-P3): the model-error term — each carries its
|
|
19070
|
+
// engine's prediction-error salience, ALREADY precision-attenuated for
|
|
19071
|
+
// self-caused swings by the ACP-P2 consumers, so the echo guard
|
|
19072
|
+
// composes by construction: our own action's interoceptive wake
|
|
19073
|
+
// arrives below the rupture gate.
|
|
19074
|
+
"attention.state.changed",
|
|
19075
|
+
"affect.state.changed",
|
|
19076
|
+
"stress.state.changed"
|
|
19077
|
+
];
|
|
18805
19078
|
}
|
|
18806
|
-
|
|
19079
|
+
/**
|
|
19080
|
+
* Mostly pull-model — but two afferent classes never become entities and
|
|
19081
|
+
* would leave rupture blind: sense-channel percepts
|
|
19082
|
+
* (ACTION_CONDITIONED_PREDICTION §2b) and the model-error state-change
|
|
19083
|
+
* events (registry #6). Buffer both (cross-tick: bus flush at T, consumed
|
|
19084
|
+
* by react at T+1 — FN9-snapshotted); the echo guard is applied at read
|
|
19085
|
+
* time for texts, and at the SOURCE for model errors (ACP-P2 precision).
|
|
19086
|
+
*/
|
|
19087
|
+
onCognitiveEvent(e) {
|
|
19088
|
+
const isSense = e.type.startsWith("senses.") && e.type.endsWith(".percept");
|
|
19089
|
+
const isModelError = e.type === "attention.state.changed" || e.type === "affect.state.changed" || e.type === "stress.state.changed";
|
|
19090
|
+
if (!isSense && !isModelError) return;
|
|
19091
|
+
const p = e.payload;
|
|
19092
|
+
this._senseBuffer.push({
|
|
19093
|
+
salience: e.salience,
|
|
19094
|
+
...isSense && typeof p?.content === "string" ? { text: p.content } : {}
|
|
19095
|
+
});
|
|
18807
19096
|
}
|
|
18808
19097
|
snapshot() {
|
|
18809
|
-
return {
|
|
19098
|
+
return {
|
|
19099
|
+
lastEntropy: this._lastEntropy,
|
|
19100
|
+
lastDeliberate: this._lastDeliberate,
|
|
19101
|
+
lastRevoked: this._lastRevoked,
|
|
19102
|
+
senseBuffer: this._senseBuffer
|
|
19103
|
+
};
|
|
19104
|
+
}
|
|
19105
|
+
/** FN9: `_lastRevoked` has behavioral effect (the Channel-B `revokedBy` stamp),
|
|
19106
|
+
* so a restored mind must carry it — a rupture-driven letting-go survives a
|
|
19107
|
+
* snapshot boundary instead of silently losing its narrative thread. */
|
|
19108
|
+
restore(s) {
|
|
19109
|
+
if (typeof s["lastEntropy"] === "number") this._lastEntropy = s["lastEntropy"];
|
|
19110
|
+
if (typeof s["lastDeliberate"] === "boolean") this._lastDeliberate = s["lastDeliberate"];
|
|
19111
|
+
const lr = s["lastRevoked"];
|
|
19112
|
+
this._lastRevoked = lr && typeof lr === "object" && typeof lr.schema === "string" && typeof lr.tick === "number" ? { schema: lr.schema, tick: lr.tick } : null;
|
|
19113
|
+
const sb = s["senseBuffer"];
|
|
19114
|
+
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 } : {} })) : [];
|
|
18810
19115
|
}
|
|
18811
19116
|
async react(_delta, tick, state, _context) {
|
|
18812
19117
|
const eligible = [];
|
|
@@ -18835,54 +19140,125 @@ var ActionSelector = class {
|
|
|
18835
19140
|
let blocking = false;
|
|
18836
19141
|
let awaiting = null;
|
|
18837
19142
|
let composite = null;
|
|
19143
|
+
let deliberating = null;
|
|
18838
19144
|
for (const it of intents) {
|
|
18839
|
-
if (it.st === "deliberating")
|
|
18840
|
-
|
|
19145
|
+
if (it.st === "deliberating") {
|
|
19146
|
+
blocking = true;
|
|
19147
|
+
deliberating = { id: it.id, schema: it.schema };
|
|
19148
|
+
} else if (it.st === "expanding") composite = { id: it.id, activation: it.activation, schema: it.schema };
|
|
18841
19149
|
else if (it.st === "awaiting") awaiting = { id: it.id, activation: it.activation, schema: it.schema, target: it.target, dispatchedAt: it.dispatchedAt };
|
|
18842
19150
|
else if (it.st === "selected") {
|
|
18843
19151
|
const activeMacroSub = it.parentIntentId !== void 0 && expandingParents.has(it.parentIntentId);
|
|
18844
19152
|
if (!activeMacroSub) blocking = true;
|
|
18845
19153
|
}
|
|
18846
19154
|
}
|
|
18847
|
-
const
|
|
18848
|
-
|
|
18849
|
-
|
|
18850
|
-
|
|
19155
|
+
const senseEvents = this._senseBuffer;
|
|
19156
|
+
this._senseBuffer = [];
|
|
19157
|
+
const rupture = computeRupture(state, tick, senseEvents);
|
|
19158
|
+
const prevStab = metric2(state, "situation.stability", 1);
|
|
19159
|
+
const nextStabRaw = clamp017(prevStab + STABILITY_RECOVERY * (1 - prevStab) - rupture);
|
|
19160
|
+
const nextStab = 1 - nextStabRaw < STABILITY_EPSILON ? 1 : nextStabRaw;
|
|
19161
|
+
const stabMetrics = rupture > 0 || prevStab < 1 ? [["situation.stability", nextStab]] : [];
|
|
19162
|
+
if (rupture > 0 && this._bus) {
|
|
19163
|
+
try {
|
|
19164
|
+
this._bus.publish({
|
|
19165
|
+
type: "agency.situation.rupture",
|
|
19166
|
+
version: 1,
|
|
19167
|
+
sourceEngine: this.name,
|
|
19168
|
+
salience: rupture,
|
|
19169
|
+
payload: { rupture, stability: nextStab, tick }
|
|
19170
|
+
});
|
|
19171
|
+
} catch (err) {
|
|
19172
|
+
logger.warn(`[selector] rupture publish failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
19173
|
+
}
|
|
19174
|
+
}
|
|
19175
|
+
const busy = (n) => ({
|
|
19176
|
+
commands: {
|
|
19177
|
+
metrics: [
|
|
19178
|
+
["agency.field.eligible", n],
|
|
19179
|
+
["agency.selection.busy", 1],
|
|
19180
|
+
...stabMetrics
|
|
19181
|
+
]
|
|
19182
|
+
}
|
|
19183
|
+
});
|
|
19184
|
+
const policyRevoke = !!deliberating && refusedClassSchemas(state).has(deliberating.schema);
|
|
19185
|
+
if (deliberating && (rupture >= RUPTURE_REVOKE_GATE || policyRevoke)) {
|
|
19186
|
+
const reason = policyRevoke ? "policy-refusal" : "exafferent-rupture";
|
|
19187
|
+
const revRupture = policyRevoke ? Math.max(rupture, RUPTURE_REVOKE_GATE) : rupture;
|
|
19188
|
+
if (this._bus) {
|
|
19189
|
+
try {
|
|
19190
|
+
this._bus.publish({
|
|
19191
|
+
type: "agency.commitment.revoked",
|
|
19192
|
+
version: 1,
|
|
19193
|
+
sourceEngine: this.name,
|
|
19194
|
+
salience: 0.85,
|
|
19195
|
+
payload: { from: deliberating.schema, reason, rupture: revRupture, tick }
|
|
19196
|
+
});
|
|
19197
|
+
} catch (err) {
|
|
19198
|
+
logger.warn(`[selector] revoked publish failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
19199
|
+
}
|
|
19200
|
+
}
|
|
19201
|
+
this._lastRevoked = { schema: deliberating.schema, tick };
|
|
19202
|
+
return {
|
|
19203
|
+
commands: {
|
|
19204
|
+
set: [revocationEntity(deliberating.id, deliberating.schema, revRupture, tick)],
|
|
19205
|
+
metrics: [
|
|
19206
|
+
["agency.field.eligible", eligible.length],
|
|
19207
|
+
["agency.selection.busy", 1],
|
|
19208
|
+
["agency.commitment.revoked", 1],
|
|
19209
|
+
...policyRevoke ? [["agency.policy.revoked", 1]] : [],
|
|
19210
|
+
...stabMetrics
|
|
19211
|
+
]
|
|
19212
|
+
}
|
|
19213
|
+
};
|
|
19214
|
+
}
|
|
18851
19215
|
if (blocking) return busy(eligible.length);
|
|
18852
19216
|
if (eligible.length === 0)
|
|
18853
|
-
return {
|
|
19217
|
+
return {
|
|
19218
|
+
commands: {
|
|
19219
|
+
metrics: [
|
|
19220
|
+
["agency.field.eligible", 0],
|
|
19221
|
+
["agency.selection.busy", awaiting || composite ? 1 : 0],
|
|
19222
|
+
...stabMetrics
|
|
19223
|
+
]
|
|
19224
|
+
}
|
|
19225
|
+
};
|
|
18854
19226
|
const bias = buildBias(state);
|
|
18855
|
-
const effSwitchCost = effectiveSwitchCost(state);
|
|
19227
|
+
const effSwitchCost = effectiveSwitchCost(state) * (1 - rupture);
|
|
18856
19228
|
const weights = effectiveWeights(state);
|
|
18857
19229
|
const scored = eligible.map((a) => ({ affordance: a, activation: scoreAffordance(a, bias, weights) })).sort((x, y) => y.activation - x.activation);
|
|
18858
19230
|
const winner = scored[0];
|
|
18859
19231
|
if (!winner) return busy(eligible.length);
|
|
19232
|
+
let compositeTombstone;
|
|
19233
|
+
let compositeFrom;
|
|
18860
19234
|
if (composite) {
|
|
18861
19235
|
const different = winner.affordance.schema !== composite.schema;
|
|
18862
19236
|
const switchCost = effSwitchCost * (1 - stakes(winner.affordance, bias));
|
|
18863
|
-
if (different
|
|
18864
|
-
|
|
19237
|
+
if (!different || winner.activation <= composite.activation + switchCost)
|
|
19238
|
+
return busy(eligible.length);
|
|
19239
|
+
if (this._bus)
|
|
19240
|
+
try {
|
|
18865
19241
|
this._bus.publish({
|
|
18866
19242
|
type: "agency.action.preempted",
|
|
18867
19243
|
version: 1,
|
|
18868
19244
|
sourceEngine: this.name,
|
|
18869
19245
|
salience: 0.8,
|
|
18870
|
-
payload: {
|
|
19246
|
+
payload: {
|
|
19247
|
+
from: composite.schema,
|
|
19248
|
+
to: winner.affordance.schema,
|
|
19249
|
+
activation: winner.activation,
|
|
19250
|
+
tick
|
|
19251
|
+
}
|
|
18871
19252
|
});
|
|
18872
19253
|
} catch (err) {
|
|
18873
19254
|
logger.warn(`[selector] preempt publish failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
18874
19255
|
}
|
|
18875
|
-
|
|
18876
|
-
|
|
18877
|
-
["agency.selection.busy", 1],
|
|
18878
|
-
["agency.selection.preempted", 1]
|
|
18879
|
-
] } };
|
|
18880
|
-
}
|
|
18881
|
-
return busy(eligible.length);
|
|
19256
|
+
compositeTombstone = composite.id;
|
|
19257
|
+
compositeFrom = composite.schema;
|
|
18882
19258
|
}
|
|
18883
19259
|
let preemptDelete;
|
|
18884
|
-
let preemptedFrom;
|
|
18885
|
-
if (awaiting) {
|
|
19260
|
+
let preemptedFrom = compositeFrom;
|
|
19261
|
+
if (awaiting && !compositeTombstone) {
|
|
18886
19262
|
const sameAction = winner.affordance.schema === awaiting.schema && (winner.affordance.targetEntityId ?? "") === awaiting.target;
|
|
18887
19263
|
if (sameAction) return busy(eligible.length);
|
|
18888
19264
|
const staleness = Math.min(1, (tick - awaiting.dispatchedAt) / AWAIT_STALE_TICKS);
|
|
@@ -18905,6 +19281,13 @@ var ActionSelector = class {
|
|
|
18905
19281
|
const deliberate = margin < marginGate || stk > stakesGate;
|
|
18906
19282
|
this._lastEntropy = entropy;
|
|
18907
19283
|
this._lastDeliberate = deliberate;
|
|
19284
|
+
let revokedBy;
|
|
19285
|
+
if (this._lastRevoked) {
|
|
19286
|
+
if (deliberate && tick - this._lastRevoked.tick <= REVOKE_HINT_WINDOW)
|
|
19287
|
+
revokedBy = this._lastRevoked.schema;
|
|
19288
|
+
if (revokedBy || tick - this._lastRevoked.tick > REVOKE_HINT_WINDOW)
|
|
19289
|
+
this._lastRevoked = null;
|
|
19290
|
+
}
|
|
18908
19291
|
const intent = {
|
|
18909
19292
|
id: `agency-intent-${tick}`,
|
|
18910
19293
|
type: "agency.intent",
|
|
@@ -18947,6 +19330,9 @@ var ActionSelector = class {
|
|
|
18947
19330
|
// interrupted, so the deliberation facet can own the interruption in-character
|
|
18948
19331
|
// ("I was about to X, but this pulled me away"). Only meaningful while deliberating.
|
|
18949
19332
|
...preemptedFrom ? { preemptedFrom } : {},
|
|
19333
|
+
// Channel B: this deliberation forms in the wake of a rupture-driven
|
|
19334
|
+
// revocation — the facet can own "something changed, I let go of X".
|
|
19335
|
+
...revokedBy ? { revokedBy } : {},
|
|
18950
19336
|
tick
|
|
18951
19337
|
}
|
|
18952
19338
|
};
|
|
@@ -18985,7 +19371,9 @@ var ActionSelector = class {
|
|
|
18985
19371
|
}
|
|
18986
19372
|
}
|
|
18987
19373
|
const commands = {
|
|
18988
|
-
|
|
19374
|
+
// A composite preemption rides along as a tombstone (never a delete — the
|
|
19375
|
+
// executor's in-tick macro-advance would resurrect the parent).
|
|
19376
|
+
set: compositeTombstone ? [intent, revocationEntity(compositeTombstone, compositeFrom ?? "", rupture, tick)] : [intent],
|
|
18989
19377
|
...preemptDelete ? { delete: [preemptDelete] } : {},
|
|
18990
19378
|
metrics: [
|
|
18991
19379
|
["agency.field.eligible", eligible.length],
|
|
@@ -18994,7 +19382,8 @@ var ActionSelector = class {
|
|
|
18994
19382
|
["agency.selection.margin", margin],
|
|
18995
19383
|
["agency.selection.deliberate", deliberate ? 1 : 0],
|
|
18996
19384
|
["agency.selection.preempted", preemptedFrom ? 1 : 0],
|
|
18997
|
-
["agency.selection.activation", winner.activation]
|
|
19385
|
+
["agency.selection.activation", winner.activation],
|
|
19386
|
+
...stabMetrics
|
|
18998
19387
|
]
|
|
18999
19388
|
};
|
|
19000
19389
|
return { commands };
|
|
@@ -19004,7 +19393,40 @@ function effectiveSwitchCost(state) {
|
|
|
19004
19393
|
const params = readEffectiveParams(state, "engine-config-action-selector");
|
|
19005
19394
|
const base = num2(params["switchCost"], BASE_SWITCH_COST);
|
|
19006
19395
|
const focusTicks = metric2(state, "task_switch.current_focus_ticks", 0);
|
|
19007
|
-
|
|
19396
|
+
const stability = metric2(state, "situation.stability", 1);
|
|
19397
|
+
return base * (1 + focusTicks * FOCUS_GAIN * stability);
|
|
19398
|
+
}
|
|
19399
|
+
function computeRupture(state, tick, senseEvents = []) {
|
|
19400
|
+
let maxSalience = 0;
|
|
19401
|
+
for (const e of state.entities.values()) {
|
|
19402
|
+
if (e.type !== "percept") continue;
|
|
19403
|
+
const m = e.metadata;
|
|
19404
|
+
if (str2(m?.["provenance"]) !== "exafferent") continue;
|
|
19405
|
+
const pTick = num2(m?.["tick"], -1);
|
|
19406
|
+
if (pTick < 0 || tick - pTick > RUPTURE_WINDOW_TICKS) continue;
|
|
19407
|
+
const s = num2(m?.["salience"], 0);
|
|
19408
|
+
if (s > maxSalience) maxSalience = s;
|
|
19409
|
+
}
|
|
19410
|
+
if (senseEvents.length > 0) {
|
|
19411
|
+
const live = liveConsequences(state.entities, tick);
|
|
19412
|
+
for (const ev of senseEvents) {
|
|
19413
|
+
if (ev.text !== void 0 && live.length > 0 && matchConsequenceText(live, ev.text)) continue;
|
|
19414
|
+
if (ev.salience > maxSalience) maxSalience = ev.salience;
|
|
19415
|
+
}
|
|
19416
|
+
}
|
|
19417
|
+
if (maxSalience <= RUPTURE_SALIENCE_GATE) return 0;
|
|
19418
|
+
return clamp017((maxSalience - RUPTURE_SALIENCE_GATE) / (1 - RUPTURE_SALIENCE_GATE));
|
|
19419
|
+
}
|
|
19420
|
+
function refusedClassSchemas(state) {
|
|
19421
|
+
const out = /* @__PURE__ */ new Set();
|
|
19422
|
+
for (const e of state.entities.values()) {
|
|
19423
|
+
if (e.type !== "agency.outcome") continue;
|
|
19424
|
+
const m = e.metadata;
|
|
19425
|
+
if (m?.["refused"] !== true || str2(m?.["finality"]) !== "class") continue;
|
|
19426
|
+
const schema = str2(m?.["schema"]);
|
|
19427
|
+
if (schema) out.add(schema);
|
|
19428
|
+
}
|
|
19429
|
+
return out;
|
|
19008
19430
|
}
|
|
19009
19431
|
function effectiveWeights(state) {
|
|
19010
19432
|
const p = readEffectiveParams(state, "engine-config-action-selector");
|
|
@@ -19105,19 +19527,28 @@ var DeliberationEngine = class {
|
|
|
19105
19527
|
return { deliberations: this._deliberations };
|
|
19106
19528
|
}
|
|
19107
19529
|
async react(_delta, tick, state, _context) {
|
|
19530
|
+
const revoked = revokedIntentIds(state.entities, tick);
|
|
19531
|
+
const del = [];
|
|
19108
19532
|
let target = null;
|
|
19109
19533
|
for (const [id2, e] of state.entities) {
|
|
19110
19534
|
if (e.type !== "agency.intent") continue;
|
|
19111
19535
|
if (str3(e.metadata?.["status"]) !== "deliberating") continue;
|
|
19536
|
+
if (revoked.has(id2)) {
|
|
19537
|
+
del.push(id2, revocationId(id2));
|
|
19538
|
+
continue;
|
|
19539
|
+
}
|
|
19112
19540
|
const meta2 = e.metadata ?? {};
|
|
19113
19541
|
if (!target || id2 < target.id) target = { id: id2, meta: meta2 };
|
|
19114
19542
|
}
|
|
19115
|
-
if (!target) return { commands: {} };
|
|
19543
|
+
if (!target) return del.length > 0 ? { commands: { delete: del } } : { commands: {} };
|
|
19116
19544
|
const { id, meta } = target;
|
|
19117
19545
|
const provisional = str3(meta["schema"]) ?? "wait";
|
|
19118
19546
|
const candidates = Array.isArray(meta["candidates"]) ? meta["candidates"] : [];
|
|
19119
19547
|
if (!this._provider)
|
|
19120
|
-
return { commands: {
|
|
19548
|
+
return { commands: {
|
|
19549
|
+
set: [this._commit(id, meta, provisional, candidates, "no-executive")],
|
|
19550
|
+
...del.length > 0 ? { delete: del } : {}
|
|
19551
|
+
} };
|
|
19121
19552
|
const chosen = await this._deliberate(state, candidates, provisional, meta);
|
|
19122
19553
|
this._deliberations++;
|
|
19123
19554
|
if (this._bus) {
|
|
@@ -19135,6 +19566,7 @@ var DeliberationEngine = class {
|
|
|
19135
19566
|
return {
|
|
19136
19567
|
commands: {
|
|
19137
19568
|
set: [this._commit(id, meta, chosen, candidates, "facet")],
|
|
19569
|
+
...del.length > 0 ? { delete: del } : {},
|
|
19138
19570
|
metrics: [["agency.deliberation.count", 1]]
|
|
19139
19571
|
}
|
|
19140
19572
|
};
|
|
@@ -19192,7 +19624,10 @@ var DeliberationEngine = class {
|
|
|
19192
19624
|
_buildFocusContent(state, candidates, meta) {
|
|
19193
19625
|
const lines = [];
|
|
19194
19626
|
const preemptedFrom = str3(meta["preemptedFrom"]);
|
|
19195
|
-
|
|
19627
|
+
const revokedBy = str3(meta["revokedBy"]);
|
|
19628
|
+
if (revokedBy)
|
|
19629
|
+
lines.push(`Something in my situation just shifted and I let go of what I was weighing ("${revokedBy}"). Decide afresh what to do now:`);
|
|
19630
|
+
else if (preemptedFrom)
|
|
19196
19631
|
lines.push(`I just broke off a pending action ("${preemptedFrom}") because something more pressing pulled at me. Decide what to do now:`);
|
|
19197
19632
|
else
|
|
19198
19633
|
lines.push("My automatic action-selection was uncertain. Candidate actions:");
|
|
@@ -19365,8 +19800,22 @@ var MotorSchemaExecutor = class {
|
|
|
19365
19800
|
const metrics = [];
|
|
19366
19801
|
const energy = state.metrics.get("energy.level") ?? 100;
|
|
19367
19802
|
const stress = state.metrics.get("stress.load") ?? 0;
|
|
19803
|
+
for (const [id, e] of state.entities) {
|
|
19804
|
+
if (e.type !== CONSEQUENCE_TYPE) continue;
|
|
19805
|
+
if (tick >= num3(e.metadata?.["expiresAt"], 0)) del.push(id);
|
|
19806
|
+
}
|
|
19807
|
+
del.push(...staleRevocationIds(state.entities, tick));
|
|
19808
|
+
const revoked = revokedIntentIds(state.entities, tick);
|
|
19809
|
+
if (revoked.size > 0)
|
|
19810
|
+
for (const [id, e] of state.entities) {
|
|
19811
|
+
if (e.type !== "agency.intent") continue;
|
|
19812
|
+
const parentId = str5(e.metadata?.["parentIntentId"]);
|
|
19813
|
+
if (revoked.has(id)) del.push(id, revocationId(id));
|
|
19814
|
+
else if (parentId && revoked.has(parentId)) del.push(id);
|
|
19815
|
+
}
|
|
19368
19816
|
for (const [id, e] of state.entities) {
|
|
19369
19817
|
if (e.type !== "agency.intent" || str5(e.metadata?.["status"]) !== "awaiting") continue;
|
|
19818
|
+
if (e.metadata?.["escalated"] === true) continue;
|
|
19370
19819
|
const dispatchedAt = num3(e.metadata?.["dispatchedAt"], tick);
|
|
19371
19820
|
if (tick - dispatchedAt < AWAIT_TIMEOUT) continue;
|
|
19372
19821
|
const intent = readIntent(id, e.metadata);
|
|
@@ -19391,6 +19840,9 @@ var MotorSchemaExecutor = class {
|
|
|
19391
19840
|
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);
|
|
19392
19841
|
let enactedCount = 0;
|
|
19393
19842
|
for (const [id, e] of selected) {
|
|
19843
|
+
if (revoked.has(id)) continue;
|
|
19844
|
+
const parentOf = str5(e.metadata?.["parentIntentId"]);
|
|
19845
|
+
if (parentOf && revoked.has(parentOf)) continue;
|
|
19394
19846
|
const intent = readIntent(id, e.metadata);
|
|
19395
19847
|
const schema = this._resolve(intent.schema);
|
|
19396
19848
|
if (schema?.kind === "composite" && schema.composedOf && schema.composedOf.length > 0) {
|
|
@@ -19439,6 +19891,18 @@ var MotorSchemaExecutor = class {
|
|
|
19439
19891
|
predictedValence: predicted.expectedValence
|
|
19440
19892
|
}
|
|
19441
19893
|
});
|
|
19894
|
+
const awaitingText = enaction.mode === "communicate" ? str5(intent.parameters["content"]) ?? firstMessage(intent.parameters["messages"]) : void 0;
|
|
19895
|
+
set.push(consequenceEntity({
|
|
19896
|
+
intentId: id,
|
|
19897
|
+
schema: intent.schema,
|
|
19898
|
+
mode: enaction.mode === "communicate" ? "communicate" : "external",
|
|
19899
|
+
...enaction.mode === "communicate" ? { effector: COMM_SCHEMA_TO_EFFECTOR[intent.schema] ?? intent.schema } : {},
|
|
19900
|
+
...intent.targetEntityId ? { targetEntityId: intent.targetEntityId } : {},
|
|
19901
|
+
...awaitingText ? { text: awaitingText, textHash: fnv1a(awaitingText) } : {},
|
|
19902
|
+
paramsHash: fnv1a(paramsKey(intent.parameters)),
|
|
19903
|
+
expiresAt: tick + CONSEQUENCE_TTL_TICKS,
|
|
19904
|
+
tick
|
|
19905
|
+
}));
|
|
19442
19906
|
this._emitDispatch(intent, enaction.mode, tick);
|
|
19443
19907
|
metrics.push([enaction.mode === "communicate" ? "agency.communicate.dispatched" : "agency.invocation.dispatched", 1]);
|
|
19444
19908
|
}
|
|
@@ -19605,6 +20069,18 @@ var MotorSchemaExecutor = class {
|
|
|
19605
20069
|
};
|
|
19606
20070
|
set.push(outcomeEntity(tick, intent, out, predicted));
|
|
19607
20071
|
del.push(id);
|
|
20072
|
+
if (result.success)
|
|
20073
|
+
set.push(consequenceEntity({
|
|
20074
|
+
intentId: id,
|
|
20075
|
+
schema: intent.schema,
|
|
20076
|
+
mode: "communicate",
|
|
20077
|
+
effector,
|
|
20078
|
+
...intent.targetEntityId ? { targetEntityId: intent.targetEntityId } : {},
|
|
20079
|
+
textHash: fnv1a(bubbles.join("\n")),
|
|
20080
|
+
text: bubbles.join("\n"),
|
|
20081
|
+
expiresAt: tick + CONSEQUENCE_TTL_TICKS,
|
|
20082
|
+
tick
|
|
20083
|
+
}));
|
|
19608
20084
|
this._emitEnacted(intent, out, predicted, tick);
|
|
19609
20085
|
this._emitActionOutcome(
|
|
19610
20086
|
intent,
|
|
@@ -19751,11 +20227,19 @@ var PROC_THRESHOLD = 0.6;
|
|
|
19751
20227
|
var IDLE_TICKS = 200;
|
|
19752
20228
|
var DECAY_RATE = 0.02;
|
|
19753
20229
|
var DROP_HABIT = 0.05;
|
|
20230
|
+
var AVAIL_DROP_CLASS = 0.5;
|
|
20231
|
+
var AVAIL_DROP_INSTANCE = 0.12;
|
|
20232
|
+
var AVAIL_FLOOR = 0.05;
|
|
20233
|
+
var AVAIL_RECOVERY = 0.02;
|
|
20234
|
+
var AVAIL_RECOVERED = 0.999;
|
|
19754
20235
|
var SchemaRepertoire = class {
|
|
19755
20236
|
_templates = /* @__PURE__ */ new Map();
|
|
19756
20237
|
_skills = /* @__PURE__ */ new Map();
|
|
19757
20238
|
/** Tracks which templates were learned at runtime (vs innate) so decay can forget them. */
|
|
19758
20239
|
_learned = /* @__PURE__ */ new Set();
|
|
20240
|
+
/** Availability layer (P2): schema → { value 0..1, lastRefusedTick }. Empty until
|
|
20241
|
+
* a refusal lands — a never-refused Will writes nothing here (byte-identical). */
|
|
20242
|
+
_availability = /* @__PURE__ */ new Map();
|
|
19759
20243
|
constructor(seed = INNATE_SCHEMAS) {
|
|
19760
20244
|
for (const s of seed) this._templates.set(s.id, s);
|
|
19761
20245
|
}
|
|
@@ -19789,6 +20273,31 @@ var SchemaRepertoire = class {
|
|
|
19789
20273
|
getSkill(id) {
|
|
19790
20274
|
return this._skills.get(id);
|
|
19791
20275
|
}
|
|
20276
|
+
// ── availability (P2) ─────────────────────────────────────────
|
|
20277
|
+
availability() {
|
|
20278
|
+
return this._availability;
|
|
20279
|
+
}
|
|
20280
|
+
/**
|
|
20281
|
+
* How available a schema is right now, 0..1. Absent from the ledger ⇒ 1
|
|
20282
|
+
* (fully available — the common case). This is the ONLY value the
|
|
20283
|
+
* AffordanceSynthesizer reads; it never touches competence.
|
|
20284
|
+
*/
|
|
20285
|
+
availabilityOf(schema) {
|
|
20286
|
+
return this._availability.get(schema)?.value ?? 1;
|
|
20287
|
+
}
|
|
20288
|
+
/**
|
|
20289
|
+
* Fold a policy refusal into the availability layer (NOT competence). A
|
|
20290
|
+
* `class` refusal cuts availability hard; an `instance` refusal dents it
|
|
20291
|
+
* lightly. Multiplicative so repeated refusals compound toward — but never
|
|
20292
|
+
* reach — zero, keeping re-probe alive.
|
|
20293
|
+
*/
|
|
20294
|
+
recordRefusal(schema, finality, tick) {
|
|
20295
|
+
const prev = this._availability.get(schema)?.value ?? 1;
|
|
20296
|
+
const drop = finality === "class" ? AVAIL_DROP_CLASS : AVAIL_DROP_INSTANCE;
|
|
20297
|
+
const value = Math.max(AVAIL_FLOOR, prev * (1 - drop));
|
|
20298
|
+
this._availability.set(schema, { value, lastRefusedTick: tick });
|
|
20299
|
+
return value;
|
|
20300
|
+
}
|
|
19792
20301
|
/**
|
|
19793
20302
|
* Fold one outcome into the schema's learned skill. Returns the updated skill
|
|
19794
20303
|
* and whether it just crossed the proceduralization threshold this update.
|
|
@@ -19815,12 +20324,14 @@ var SchemaRepertoire = class {
|
|
|
19815
20324
|
return { skill, proceduralized: !wasProceduralized && habitStrength >= PROC_THRESHOLD };
|
|
19816
20325
|
}
|
|
19817
20326
|
/**
|
|
19818
|
-
* Forgetting curve over the competence layer
|
|
19819
|
-
* lose habit; learned composites
|
|
19820
|
-
* entirely (template + skill).
|
|
20327
|
+
* Forgetting curve over the competence layer, plus availability recovery.
|
|
20328
|
+
* Skills unused for IDLE_TICKS lose habit; learned composites below DROP_HABIT
|
|
20329
|
+
* are dropped entirely (template + skill). Availability entries climb back
|
|
20330
|
+
* toward 1 and are dropped once fully recovered. Returns the ids that were
|
|
20331
|
+
* removed from each layer so their mirrored state entities can be deleted.
|
|
19821
20332
|
*/
|
|
19822
20333
|
decay(tick) {
|
|
19823
|
-
const
|
|
20334
|
+
const skills = [];
|
|
19824
20335
|
for (const [id, skill] of this._skills) {
|
|
19825
20336
|
if (tick - skill.lastEnactedTick <= IDLE_TICKS) continue;
|
|
19826
20337
|
const habitStrength = clamp0110(skill.habitStrength - DECAY_RATE);
|
|
@@ -19828,12 +20339,20 @@ var SchemaRepertoire = class {
|
|
|
19828
20339
|
this._skills.delete(id);
|
|
19829
20340
|
this._templates.delete(id);
|
|
19830
20341
|
this._learned.delete(id);
|
|
19831
|
-
|
|
20342
|
+
skills.push(id);
|
|
19832
20343
|
continue;
|
|
19833
20344
|
}
|
|
19834
20345
|
this._skills.set(id, { ...skill, habitStrength });
|
|
19835
20346
|
}
|
|
19836
|
-
|
|
20347
|
+
const availability = [];
|
|
20348
|
+
for (const [id, avail] of this._availability) {
|
|
20349
|
+
const value = avail.value + AVAIL_RECOVERY * (1 - avail.value);
|
|
20350
|
+
if (value >= AVAIL_RECOVERED) {
|
|
20351
|
+
this._availability.delete(id);
|
|
20352
|
+
availability.push(id);
|
|
20353
|
+
} else this._availability.set(id, { ...avail, value });
|
|
20354
|
+
}
|
|
20355
|
+
return { skills, availability };
|
|
19837
20356
|
}
|
|
19838
20357
|
// ── PMA portability (Phase 6 reads these) ─────────────────────
|
|
19839
20358
|
/** Learned composite templates + all skills above a confidence floor. */
|
|
@@ -19882,6 +20401,28 @@ var SchemaRepertoire = class {
|
|
|
19882
20401
|
this._learned.add(s.id);
|
|
19883
20402
|
}
|
|
19884
20403
|
}
|
|
20404
|
+
/** Availability ledger encoded as `agency.availability` state entities (P2).
|
|
20405
|
+
* Empty until a refusal lands, so the quiet path writes nothing. */
|
|
20406
|
+
availabilityEntities() {
|
|
20407
|
+
const out = [];
|
|
20408
|
+
for (const [schema, a] of this._availability)
|
|
20409
|
+
out.push(availabilityEntity(schema, a.value, a.lastRefusedTick));
|
|
20410
|
+
return out;
|
|
20411
|
+
}
|
|
20412
|
+
/** Rehydrate the availability ledger from state after a restore. Idempotent;
|
|
20413
|
+
* keeps whichever value is more restrictive so a concurrent refusal isn't lost. */
|
|
20414
|
+
restoreAvailability(entities) {
|
|
20415
|
+
for (const e of entities.values()) {
|
|
20416
|
+
if (e.type !== AVAILABILITY_ENTITY_TYPE) continue;
|
|
20417
|
+
const m = e.metadata ?? {};
|
|
20418
|
+
const schema = typeof m["schema"] === "string" ? m["schema"] : "";
|
|
20419
|
+
if (!schema) continue;
|
|
20420
|
+
const value = typeof m["value"] === "number" ? m["value"] : 1;
|
|
20421
|
+
const tick = typeof m["lastRefusedTick"] === "number" ? m["lastRefusedTick"] : 0;
|
|
20422
|
+
const prev = this._availability.get(schema);
|
|
20423
|
+
if (!prev || value < prev.value) this._availability.set(schema, { value, lastRefusedTick: tick });
|
|
20424
|
+
}
|
|
20425
|
+
}
|
|
19885
20426
|
};
|
|
19886
20427
|
function freshSkill(schema, value, tick) {
|
|
19887
20428
|
return {
|
|
@@ -19898,6 +20439,17 @@ function freshSkill(schema, value, tick) {
|
|
|
19898
20439
|
function clamp0110(n) {
|
|
19899
20440
|
return n < 0 ? 0 : n > 1 ? 1 : n;
|
|
19900
20441
|
}
|
|
20442
|
+
var AVAILABILITY_ENTITY_TYPE = "agency.availability";
|
|
20443
|
+
function availabilityEntityId(schema) {
|
|
20444
|
+
return `agency-availability-${schema}`;
|
|
20445
|
+
}
|
|
20446
|
+
function availabilityEntity(schema, value, lastRefusedTick) {
|
|
20447
|
+
return {
|
|
20448
|
+
id: availabilityEntityId(schema),
|
|
20449
|
+
type: AVAILABILITY_ENTITY_TYPE,
|
|
20450
|
+
metadata: { schema, value, lastRefusedTick }
|
|
20451
|
+
};
|
|
20452
|
+
}
|
|
19901
20453
|
var SCHEMA_ENTITY_TYPE = "agency.schema";
|
|
19902
20454
|
function schemaEntityId(schemaId) {
|
|
19903
20455
|
return `agency-schema-${schemaId}`;
|
|
@@ -19941,6 +20493,10 @@ function readSchema(m) {
|
|
|
19941
20493
|
|
|
19942
20494
|
// src/cognition/agency/engines/reafference.engine.ts
|
|
19943
20495
|
var PROC_THRESHOLD2 = 0.6;
|
|
20496
|
+
var SENSORY_SOFT_QUALITY = 0.6;
|
|
20497
|
+
var SENSORY_VALENCE_SPAN_ENTITY = 0.25;
|
|
20498
|
+
var SENSORY_VALENCE_SPAN_AMBIENT = 0.1;
|
|
20499
|
+
var SENSORY_SUCCESS_FLOOR = 0.5;
|
|
19944
20500
|
var ReafferenceEngine = class {
|
|
19945
20501
|
name = "reafference";
|
|
19946
20502
|
_repertoire;
|
|
@@ -19990,14 +20546,76 @@ var ReafferenceEngine = class {
|
|
|
19990
20546
|
const set = [];
|
|
19991
20547
|
const del = [];
|
|
19992
20548
|
const metrics = [];
|
|
19993
|
-
|
|
19994
|
-
|
|
20549
|
+
const outcomes = [];
|
|
20550
|
+
const gradedIntentIds = /* @__PURE__ */ new Set();
|
|
19995
20551
|
for (const [id, e] of state.entities) {
|
|
19996
20552
|
if (e.type !== "agency.outcome") continue;
|
|
19997
20553
|
const m = e.metadata ?? {};
|
|
20554
|
+
outcomes.push({ id, meta: m, fromState: true });
|
|
20555
|
+
const iid = str6(m["intentId"]);
|
|
20556
|
+
if (iid) gradedIntentIds.add(iid);
|
|
20557
|
+
}
|
|
20558
|
+
const awaiting = /* @__PURE__ */ new Map();
|
|
20559
|
+
for (const [id, e] of state.entities) {
|
|
20560
|
+
if (e.type !== "agency.intent" || str6(e.metadata?.["status"]) !== "awaiting") continue;
|
|
20561
|
+
const m = e.metadata ?? {};
|
|
20562
|
+
if (tick - num4(m["dispatchedAt"], tick) >= AWAIT_TIMEOUT) continue;
|
|
20563
|
+
awaiting.set(id, {
|
|
20564
|
+
schema: str6(m["schema"]) ?? "",
|
|
20565
|
+
predictedReward: num4(m["predictedReward"], 0.5),
|
|
20566
|
+
predictedValence: num4(m["predictedValence"], 0)
|
|
20567
|
+
});
|
|
20568
|
+
}
|
|
20569
|
+
let sensory = 0;
|
|
20570
|
+
const sensedIntentIds = /* @__PURE__ */ new Set();
|
|
20571
|
+
for (const [, e] of state.entities) {
|
|
20572
|
+
if (e.type !== "percept") continue;
|
|
20573
|
+
const m = e.metadata ?? {};
|
|
20574
|
+
if (str6(m["provenance"]) !== "reafferent") continue;
|
|
20575
|
+
const iid = str6(m["sourceIntentId"]);
|
|
20576
|
+
if (!iid || gradedIntentIds.has(iid) || sensedIntentIds.has(iid)) continue;
|
|
20577
|
+
const aw = awaiting.get(iid);
|
|
20578
|
+
if (!aw || !aw.schema) continue;
|
|
20579
|
+
sensedIntentIds.add(iid);
|
|
20580
|
+
sensory++;
|
|
20581
|
+
const feltRaw = m["valence"];
|
|
20582
|
+
const felt = typeof feltRaw === "number" && Number.isFinite(feltRaw) ? feltRaw : void 0;
|
|
20583
|
+
const span = str6(m["valenceSource"]) === "entity" ? SENSORY_VALENCE_SPAN_ENTITY : SENSORY_VALENCE_SPAN_AMBIENT;
|
|
20584
|
+
const quality = felt === void 0 ? SENSORY_SOFT_QUALITY : clamp0111(SENSORY_SOFT_QUALITY + Math.max(-1, Math.min(1, felt)) * span);
|
|
20585
|
+
outcomes.push({ id: `agency-outcome-${tick}-${iid}-sensory`, fromState: false, meta: {
|
|
20586
|
+
schema: aw.schema,
|
|
20587
|
+
intentId: iid,
|
|
20588
|
+
success: quality >= SENSORY_SUCCESS_FLOOR,
|
|
20589
|
+
outcomeQuality: quality,
|
|
20590
|
+
valence: felt ?? aw.predictedValence,
|
|
20591
|
+
predictedReward: aw.predictedReward,
|
|
20592
|
+
predictedValence: aw.predictedValence,
|
|
20593
|
+
surprise: clamp0111(Math.abs(aw.predictedReward - quality)),
|
|
20594
|
+
mode: "external",
|
|
20595
|
+
reconciled: true,
|
|
20596
|
+
sensory: true,
|
|
20597
|
+
...felt !== void 0 ? { sensoryValence: felt, valenceSource: str6(m["valenceSource"]) } : {},
|
|
20598
|
+
tick
|
|
20599
|
+
} });
|
|
20600
|
+
}
|
|
20601
|
+
let updates = 0;
|
|
20602
|
+
let discovered = 0;
|
|
20603
|
+
let refused = 0;
|
|
20604
|
+
for (const { id, meta: m, fromState } of outcomes) {
|
|
19998
20605
|
const schema = str6(m["schema"]);
|
|
19999
20606
|
if (!schema) {
|
|
20000
|
-
del.push(id);
|
|
20607
|
+
if (fromState) del.push(id);
|
|
20608
|
+
continue;
|
|
20609
|
+
}
|
|
20610
|
+
if (m["refused"] === true) {
|
|
20611
|
+
const finality = str6(m["finality"]) === "class" ? "class" : "instance";
|
|
20612
|
+
this._repertoire.recordRefusal(schema, finality, tick);
|
|
20613
|
+
if (fromState) del.push(id);
|
|
20614
|
+
const refusedIntent = str6(m["intentId"]);
|
|
20615
|
+
if (refusedIntent) del.push(refusedIntent);
|
|
20616
|
+
const refusedPlan = str6(m["planId"]);
|
|
20617
|
+
if (refusedPlan) this._emitPlanOutcome(refusedPlan, str6(m["stepId"]), schema, false, 0, 0, tick);
|
|
20618
|
+
refused++;
|
|
20001
20619
|
continue;
|
|
20002
20620
|
}
|
|
20003
20621
|
const { skill, proceduralized } = this._repertoire.recordOutcome({
|
|
@@ -20009,7 +20627,7 @@ var ReafferenceEngine = class {
|
|
|
20009
20627
|
tick
|
|
20010
20628
|
});
|
|
20011
20629
|
set.push(skillEntity(skill));
|
|
20012
|
-
del.push(id);
|
|
20630
|
+
if (fromState) del.push(id);
|
|
20013
20631
|
const intentId = str6(m["intentId"]);
|
|
20014
20632
|
if (intentId) del.push(intentId);
|
|
20015
20633
|
updates++;
|
|
@@ -20026,19 +20644,24 @@ var ReafferenceEngine = class {
|
|
|
20026
20644
|
}
|
|
20027
20645
|
}
|
|
20028
20646
|
const dropped = this._repertoire.decay(tick);
|
|
20029
|
-
for (const id of dropped) {
|
|
20647
|
+
for (const id of dropped.skills) {
|
|
20030
20648
|
del.push(`agency-skill-${id}`);
|
|
20031
20649
|
del.push(schemaEntityId(id));
|
|
20032
20650
|
}
|
|
20651
|
+
for (const id of dropped.availability)
|
|
20652
|
+
del.push(availabilityEntityId(id));
|
|
20033
20653
|
for (const e of this._repertoire.compositeEntities()) set.push(e);
|
|
20654
|
+
for (const e of this._repertoire.availabilityEntities()) set.push(e);
|
|
20034
20655
|
const skills = this._repertoire.skills();
|
|
20035
20656
|
const habitual = [...skills.values()].filter((s) => s.habitStrength >= PROC_THRESHOLD2).length;
|
|
20036
20657
|
metrics.push(
|
|
20037
20658
|
["agency.learning.updates", updates],
|
|
20038
20659
|
["agency.discovered.count", discovered],
|
|
20039
20660
|
["agency.skill.count", skills.size],
|
|
20040
|
-
["agency.habitual.count", habitual]
|
|
20661
|
+
["agency.habitual.count", habitual],
|
|
20662
|
+
["agency.sensory.confirmed", sensory]
|
|
20041
20663
|
);
|
|
20664
|
+
if (refused > 0) metrics.push(["agency.refused.count", refused]);
|
|
20042
20665
|
return { commands: { set, delete: del, metrics } };
|
|
20043
20666
|
}
|
|
20044
20667
|
_emitProceduralized(skill, tick) {
|
|
@@ -20121,6 +20744,9 @@ function str6(v) {
|
|
|
20121
20744
|
function num4(v, fallback) {
|
|
20122
20745
|
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
20123
20746
|
}
|
|
20747
|
+
function clamp0111(n) {
|
|
20748
|
+
return n < 0 ? 0 : n > 1 ? 1 : n;
|
|
20749
|
+
}
|
|
20124
20750
|
|
|
20125
20751
|
// src/stem/assembly.audit.ts
|
|
20126
20752
|
function fieldForAttach(method) {
|
|
@@ -24504,6 +25130,10 @@ var OutboxController = class {
|
|
|
24504
25130
|
summary: delivered ? `My message was delivered successfully.` : `My message failed to reach the recipient.`,
|
|
24505
25131
|
salience: delivered ? 0.35 : 0.6,
|
|
24506
25132
|
changeType: delivered ? "delivered" : "failed",
|
|
25133
|
+
// Reafference by construction — this percept describes our own action's
|
|
25134
|
+
// outcome ("ear hears the word"). Tagged, not attenuated: it is the ack
|
|
25135
|
+
// surface, not a content echo (EXAFFERENCE P2).
|
|
25136
|
+
provenance: "reafferent",
|
|
24507
25137
|
messageId
|
|
24508
25138
|
}
|
|
24509
25139
|
});
|
|
@@ -24905,7 +25535,7 @@ var InboundQueue = class {
|
|
|
24905
25535
|
function reconcileInvocation(intentId, schema, result, tick, predicted = { reward: 0.5, valence: 0 }, provenance = {}) {
|
|
24906
25536
|
const outcomeQuality = result.outcomeQuality ?? (result.success ? 0.8 : 0.1);
|
|
24907
25537
|
const valence = result.valence ?? (result.success ? 0.2 : -0.2);
|
|
24908
|
-
const surprise =
|
|
25538
|
+
const surprise = clamp0112(Math.abs(predicted.reward - outcomeQuality));
|
|
24909
25539
|
return {
|
|
24910
25540
|
id: `agency-outcome-${tick}-${intentId}`,
|
|
24911
25541
|
type: "agency.outcome",
|
|
@@ -24922,17 +25552,66 @@ function reconcileInvocation(intentId, schema, result, tick, predicted = { rewar
|
|
|
24922
25552
|
mode: "external",
|
|
24923
25553
|
tick,
|
|
24924
25554
|
reconciled: true,
|
|
25555
|
+
...result.refused ? { refused: true, finality: result.finality ?? "instance" } : {},
|
|
24925
25556
|
...provenance.planId ? { planId: provenance.planId } : {},
|
|
24926
25557
|
...provenance.stepId ? { stepId: provenance.stepId } : {}
|
|
24927
25558
|
}
|
|
24928
25559
|
};
|
|
24929
25560
|
}
|
|
24930
|
-
function
|
|
25561
|
+
function clamp0112(n) {
|
|
24931
25562
|
return n < 0 ? 0 : n > 1 ? 1 : n;
|
|
24932
25563
|
}
|
|
24933
25564
|
|
|
25565
|
+
// src/stem/policy/arbiter.ts
|
|
25566
|
+
var ALLOW = Object.freeze({ decision: "allow" });
|
|
25567
|
+
var NULL_ARBITER = {
|
|
25568
|
+
name: "null",
|
|
25569
|
+
evaluate() {
|
|
25570
|
+
return ALLOW;
|
|
25571
|
+
}
|
|
25572
|
+
};
|
|
25573
|
+
function isNullArbiter(arbiter) {
|
|
25574
|
+
return !arbiter || arbiter === NULL_ARBITER;
|
|
25575
|
+
}
|
|
25576
|
+
|
|
25577
|
+
// src/stem/policy/verdict.recorder.ts
|
|
25578
|
+
var _sinks3 = /* @__PURE__ */ new Map();
|
|
25579
|
+
function getVerdictRecorder(willId) {
|
|
25580
|
+
return _sinks3.get(willId);
|
|
25581
|
+
}
|
|
25582
|
+
var _sources3 = /* @__PURE__ */ new Map();
|
|
25583
|
+
function getVerdictSource(willId) {
|
|
25584
|
+
return _sources3.get(willId);
|
|
25585
|
+
}
|
|
25586
|
+
|
|
24934
25587
|
// src/stem/tracts/effector.controller.ts
|
|
25588
|
+
var ESCALATION_TTL_TICKS = 30;
|
|
24935
25589
|
var effectorController = class {
|
|
25590
|
+
/** The Policy Decision Point consulted before an invocation reaches the world.
|
|
25591
|
+
* Defaults to the no-op arbiter, so an unconfigured Will is byte-identical. */
|
|
25592
|
+
_arbiter = NULL_ARBITER;
|
|
25593
|
+
/**
|
|
25594
|
+
* Denials queued during a step's flush, drained at the NEXT tick boundary
|
|
25595
|
+
* (POLICY_REAFFERENCE P1). Keyed by willId — harness state, exactly like
|
|
25596
|
+
* `pendingEffectorInvocations`; never simulation state, so it does not touch
|
|
25597
|
+
* `simulation.step` determinism and is regenerated on any re-execution.
|
|
25598
|
+
*/
|
|
25599
|
+
_pendingRefusals = /* @__PURE__ */ new Map();
|
|
25600
|
+
/** Escalations awaiting their first application (mark intent + voice the ask). */
|
|
25601
|
+
_newEscalations = /* @__PURE__ */ new Map();
|
|
25602
|
+
/** Escalations currently held, keyed by intent id — the resolvable set. */
|
|
25603
|
+
_activeEscalations = /* @__PURE__ */ new Map();
|
|
25604
|
+
/** Host answers awaiting application at the next tick boundary. */
|
|
25605
|
+
_pendingResolutions = /* @__PURE__ */ new Map();
|
|
25606
|
+
/**
|
|
25607
|
+
* Install a Policy Decision Point (POLICY_REAFFERENCE P0). Passing null
|
|
25608
|
+
* restores the no-op default. The arbiter sees only the proposed act — never
|
|
25609
|
+
* simulation state — and its verdict decides whether the invocation is
|
|
25610
|
+
* handed to the host at all.
|
|
25611
|
+
*/
|
|
25612
|
+
setArbiter(arbiter) {
|
|
25613
|
+
this._arbiter = arbiter ?? NULL_ARBITER;
|
|
25614
|
+
}
|
|
24936
25615
|
/**
|
|
24937
25616
|
* Update the set of allowed communication effectors at runtime via AccessGrants
|
|
24938
25617
|
* (the permission / sense gate the senses + reply path read).
|
|
@@ -24948,6 +25627,224 @@ var effectorController = class {
|
|
|
24948
25627
|
* echoes it on its result-ack, and `confirmExecution` uses it to find the intent.
|
|
24949
25628
|
*/
|
|
24950
25629
|
bufferInvocation(instance, payload) {
|
|
25630
|
+
const willId = instance.config.id;
|
|
25631
|
+
const source = getVerdictSource(willId);
|
|
25632
|
+
if (source) {
|
|
25633
|
+
const invocation2 = toPolicyInvocation(instance, payload);
|
|
25634
|
+
const record = source.verdictFor(invocation2.tick, invocation2.intentId);
|
|
25635
|
+
if (record) this._applyVerdict(instance, payload, invocation2, recordToVerdict(record));
|
|
25636
|
+
else this._buffer(instance, payload);
|
|
25637
|
+
return;
|
|
25638
|
+
}
|
|
25639
|
+
if (isNullArbiter(this._arbiter)) {
|
|
25640
|
+
this._buffer(instance, payload);
|
|
25641
|
+
return;
|
|
25642
|
+
}
|
|
25643
|
+
const invocation = toPolicyInvocation(instance, payload);
|
|
25644
|
+
let verdict;
|
|
25645
|
+
try {
|
|
25646
|
+
verdict = this._arbiter.evaluate(invocation);
|
|
25647
|
+
} catch (err) {
|
|
25648
|
+
logger.error(`[policy] arbiter "${this._arbiter.name}" threw for "${invocation.schema}" \u2014 failing closed:`, err);
|
|
25649
|
+
return;
|
|
25650
|
+
}
|
|
25651
|
+
if (verdict instanceof Promise) {
|
|
25652
|
+
void verdict.then(
|
|
25653
|
+
(v) => this._recordAndApply(instance, payload, invocation, v),
|
|
25654
|
+
(err) => logger.error(`[policy] arbiter "${this._arbiter.name}" rejected for "${invocation.schema}" \u2014 failing closed:`, err)
|
|
25655
|
+
);
|
|
25656
|
+
return;
|
|
25657
|
+
}
|
|
25658
|
+
this._recordAndApply(instance, payload, invocation, verdict);
|
|
25659
|
+
}
|
|
25660
|
+
/** Capture the verdict on the tape (if a recorder is attached), then enforce it. */
|
|
25661
|
+
_recordAndApply(instance, payload, invocation, verdict) {
|
|
25662
|
+
const sink = getVerdictRecorder(instance.config.id);
|
|
25663
|
+
sink?.recordVerdict({
|
|
25664
|
+
tick: invocation.tick,
|
|
25665
|
+
willId: instance.config.id,
|
|
25666
|
+
intentId: invocation.intentId,
|
|
25667
|
+
schema: invocation.schema,
|
|
25668
|
+
arbiter: this._arbiter.name,
|
|
25669
|
+
decision: verdict.decision,
|
|
25670
|
+
...verdict.reasonCode ? { reasonCode: verdict.reasonCode } : {},
|
|
25671
|
+
...verdict.finality ? { finality: verdict.finality } : {},
|
|
25672
|
+
...verdict.counterfactual ? { counterfactual: verdict.counterfactual } : {},
|
|
25673
|
+
timestamp: Date.now()
|
|
25674
|
+
});
|
|
25675
|
+
this._applyVerdict(instance, payload, invocation, verdict);
|
|
25676
|
+
}
|
|
25677
|
+
/**
|
|
25678
|
+
* Enforce a verdict (POLICY_REAFFERENCE P1).
|
|
25679
|
+
*
|
|
25680
|
+
* • allow → hand the invocation to the world.
|
|
25681
|
+
* • deny → queue a refusal ack, applied at the next tick boundary via
|
|
25682
|
+
* `confirmExecution` — the same lifecycle as a host rejection,
|
|
25683
|
+
* so the mind meets *world resistance*, not a permission dialog.
|
|
25684
|
+
* • escalate → raise a held escalation (POLICY_REAFFERENCE P4): the intent is
|
|
25685
|
+
* held (the executor stops timing it out), the Will voices a
|
|
25686
|
+
* first-person ask once, and a host resolution later approves
|
|
25687
|
+
* (dispatch) or denies (refuse). Unresolved, it degrades to a
|
|
25688
|
+
* refusal at ESCALATION_TTL_TICKS.
|
|
25689
|
+
*
|
|
25690
|
+
* P1's refusal reconciles as a plain FAILURE — safe, but the wrong learning
|
|
25691
|
+
* signal (forbidden ≠ unskilled). P2 routes it to affordance AVAILABILITY
|
|
25692
|
+
* instead of competence.
|
|
25693
|
+
*/
|
|
25694
|
+
_applyVerdict(instance, payload, invocation, verdict) {
|
|
25695
|
+
if (verdict.decision === "allow") {
|
|
25696
|
+
this._buffer(instance, payload);
|
|
25697
|
+
return;
|
|
25698
|
+
}
|
|
25699
|
+
const cf = verdict.counterfactual;
|
|
25700
|
+
logger.info(
|
|
25701
|
+
`[policy] ${verdict.decision.toUpperCase()} "${invocation.schema}" intent "${invocation.intentId}" \u2014 ${verdict.reasonCode ?? "no reason code"}` + (verdict.finality ? ` (${verdict.finality})` : "") + (cf ? ` [${cf.field}: requested ${JSON.stringify(cf.requested)}, allowed ${JSON.stringify(cf.allowed)}]` : "")
|
|
25702
|
+
);
|
|
25703
|
+
if (verdict.decision === "deny") {
|
|
25704
|
+
const queue = this._pendingRefusals.get(instance.config.id) ?? [];
|
|
25705
|
+
queue.push({
|
|
25706
|
+
intentId: invocation.intentId,
|
|
25707
|
+
schema: invocation.schema,
|
|
25708
|
+
reasonCode: verdict.reasonCode ?? "POLICY_DENIED",
|
|
25709
|
+
finality: verdict.finality ?? "instance"
|
|
25710
|
+
});
|
|
25711
|
+
this._pendingRefusals.set(instance.config.id, queue);
|
|
25712
|
+
return;
|
|
25713
|
+
}
|
|
25714
|
+
const escalations = this._newEscalations.get(instance.config.id) ?? [];
|
|
25715
|
+
escalations.push({
|
|
25716
|
+
intentId: invocation.intentId,
|
|
25717
|
+
schema: invocation.schema,
|
|
25718
|
+
reasonCode: verdict.reasonCode ?? "APPROVAL_REQUIRED",
|
|
25719
|
+
payload,
|
|
25720
|
+
expiresAt: 0
|
|
25721
|
+
// stamped when applied (we don't have the current tick here)
|
|
25722
|
+
});
|
|
25723
|
+
this._newEscalations.set(instance.config.id, escalations);
|
|
25724
|
+
}
|
|
25725
|
+
/**
|
|
25726
|
+
* Record a host's answer to an escalation (POLICY_REAFFERENCE P4). Applied at
|
|
25727
|
+
* the next tick boundary so every simulation-state write stays on the boundary:
|
|
25728
|
+
* approve dispatches the held invocation to the world; deny refuses it. A
|
|
25729
|
+
* no-op if the intent id is not (or no longer) an active escalation.
|
|
25730
|
+
*/
|
|
25731
|
+
resolveEscalation(instance, intentId, approved) {
|
|
25732
|
+
const queue = this._pendingResolutions.get(instance.config.id) ?? [];
|
|
25733
|
+
queue.push({ intentId, approved });
|
|
25734
|
+
this._pendingResolutions.set(instance.config.id, queue);
|
|
25735
|
+
}
|
|
25736
|
+
/**
|
|
25737
|
+
* Apply queued policy refusals as failure acks (POLICY_REAFFERENCE P1).
|
|
25738
|
+
* Called by the tick loop at the same boundary as inbound acks — BEFORE the
|
|
25739
|
+
* step, stamped to this tick — so a denial reconciled here is the exact
|
|
25740
|
+
* lifecycle of a host rejection that arrived between ticks.
|
|
25741
|
+
*/
|
|
25742
|
+
applyPolicyOutcomes(instance) {
|
|
25743
|
+
const tick = instance.tickCount;
|
|
25744
|
+
this._applyResolutions(instance);
|
|
25745
|
+
this._expireEscalations(instance, tick);
|
|
25746
|
+
this._applyNewEscalations(instance, tick);
|
|
25747
|
+
this._applyRefusals(instance);
|
|
25748
|
+
}
|
|
25749
|
+
/** Drain queued refusals into failure acks (POLICY_REAFFERENCE P1). */
|
|
25750
|
+
_applyRefusals(instance) {
|
|
25751
|
+
const queue = this._pendingRefusals.get(instance.config.id);
|
|
25752
|
+
if (!queue || queue.length === 0) return;
|
|
25753
|
+
this._pendingRefusals.set(instance.config.id, []);
|
|
25754
|
+
for (const refusal of queue)
|
|
25755
|
+
this.confirmExecution(instance, refusal.intentId, {
|
|
25756
|
+
success: false,
|
|
25757
|
+
refused: true,
|
|
25758
|
+
finality: refusal.finality === "class" ? "class" : "instance",
|
|
25759
|
+
description: `refused by policy: ${refusal.reasonCode} (${refusal.finality})`
|
|
25760
|
+
});
|
|
25761
|
+
}
|
|
25762
|
+
/** Raise each newly-escalated intent (POLICY_REAFFERENCE P4): mark it held in
|
|
25763
|
+
* simulation state, voice the ask ONCE, and move it to the resolvable set. */
|
|
25764
|
+
_applyNewEscalations(instance, tick) {
|
|
25765
|
+
const pending = this._newEscalations.get(instance.config.id);
|
|
25766
|
+
if (!pending || pending.length === 0) return;
|
|
25767
|
+
this._newEscalations.set(instance.config.id, []);
|
|
25768
|
+
const active = this._activeEscalations.get(instance.config.id) ?? /* @__PURE__ */ new Map();
|
|
25769
|
+
for (const esc of pending) {
|
|
25770
|
+
esc.expiresAt = tick + ESCALATION_TTL_TICKS;
|
|
25771
|
+
this._markEscalated(instance, esc.intentId, esc.expiresAt);
|
|
25772
|
+
this._voiceEscalation(instance, esc);
|
|
25773
|
+
active.set(esc.intentId, esc);
|
|
25774
|
+
}
|
|
25775
|
+
this._activeEscalations.set(instance.config.id, active);
|
|
25776
|
+
}
|
|
25777
|
+
/** Apply host answers to active escalations (POLICY_REAFFERENCE P4). */
|
|
25778
|
+
_applyResolutions(instance) {
|
|
25779
|
+
const queue = this._pendingResolutions.get(instance.config.id);
|
|
25780
|
+
if (!queue || queue.length === 0) return;
|
|
25781
|
+
this._pendingResolutions.set(instance.config.id, []);
|
|
25782
|
+
const active = this._activeEscalations.get(instance.config.id);
|
|
25783
|
+
for (const { intentId, approved } of queue) {
|
|
25784
|
+
const esc = active?.get(intentId);
|
|
25785
|
+
if (!esc) continue;
|
|
25786
|
+
active.delete(intentId);
|
|
25787
|
+
this._clearEscalated(instance, intentId);
|
|
25788
|
+
if (approved) {
|
|
25789
|
+
this._buffer(instance, esc.payload);
|
|
25790
|
+
logger.info(`[policy] escalation APPROVED \u2192 dispatching "${esc.schema}" intent "${intentId}"`);
|
|
25791
|
+
} else {
|
|
25792
|
+
this._queueRefusal(instance, esc.intentId, esc.schema, esc.reasonCode, "class");
|
|
25793
|
+
logger.info(`[policy] escalation DENIED \u2192 refusing "${esc.schema}" intent "${intentId}"`);
|
|
25794
|
+
}
|
|
25795
|
+
}
|
|
25796
|
+
}
|
|
25797
|
+
/** Degrade escalations no one answered in time into instance-refusals (P4). */
|
|
25798
|
+
_expireEscalations(instance, tick) {
|
|
25799
|
+
const active = this._activeEscalations.get(instance.config.id);
|
|
25800
|
+
if (!active || active.size === 0) return;
|
|
25801
|
+
for (const [intentId, esc] of active) {
|
|
25802
|
+
if (tick < esc.expiresAt) continue;
|
|
25803
|
+
active.delete(intentId);
|
|
25804
|
+
this._clearEscalated(instance, intentId);
|
|
25805
|
+
this._queueRefusal(instance, esc.intentId, esc.schema, "ESCALATION_EXPIRED", "instance");
|
|
25806
|
+
logger.info(`[policy] escalation EXPIRED \u2192 refusing "${esc.schema}" intent "${intentId}"`);
|
|
25807
|
+
}
|
|
25808
|
+
}
|
|
25809
|
+
/** Push a refusal onto the queue drained by _applyRefusals this same tick. */
|
|
25810
|
+
_queueRefusal(instance, intentId, schema, reasonCode, finality) {
|
|
25811
|
+
const queue = this._pendingRefusals.get(instance.config.id) ?? [];
|
|
25812
|
+
queue.push({ intentId, schema, reasonCode, finality });
|
|
25813
|
+
this._pendingRefusals.set(instance.config.id, queue);
|
|
25814
|
+
}
|
|
25815
|
+
/** Mark the awaiting intent held: the executor stops timing it out (P4). */
|
|
25816
|
+
_markEscalated(instance, intentId, expiresAt) {
|
|
25817
|
+
const intent = instance.simulation.stateManager.snapshot().entities.get(intentId);
|
|
25818
|
+
if (!intent || intent.type !== "agency.intent") return;
|
|
25819
|
+
instance.simulation.stateManager.setEntity({
|
|
25820
|
+
id: intent.id,
|
|
25821
|
+
type: intent.type,
|
|
25822
|
+
metadata: { ...intent.metadata ?? {}, escalated: true, escalationExpiresAt: expiresAt }
|
|
25823
|
+
});
|
|
25824
|
+
}
|
|
25825
|
+
/** Release the hold so the executor resumes normal timeout for this intent. */
|
|
25826
|
+
_clearEscalated(instance, intentId) {
|
|
25827
|
+
const intent = instance.simulation.stateManager.snapshot().entities.get(intentId);
|
|
25828
|
+
if (!intent || intent.type !== "agency.intent") return;
|
|
25829
|
+
const meta = { ...intent.metadata ?? {} };
|
|
25830
|
+
delete meta["escalated"];
|
|
25831
|
+
delete meta["escalationExpiresAt"];
|
|
25832
|
+
instance.simulation.stateManager.setEntity({ id: intent.id, type: intent.type, metadata: meta });
|
|
25833
|
+
}
|
|
25834
|
+
/** Voice the escalation as a first-person broadcast ask — once, at raise time. */
|
|
25835
|
+
_voiceEscalation(instance, esc) {
|
|
25836
|
+
try {
|
|
25837
|
+
instance.cognition.outboxWriter.enqueue({
|
|
25838
|
+
targetEntityId: "*",
|
|
25839
|
+
content: escalationAsk(esc.schema, esc.reasonCode),
|
|
25840
|
+
effectorName: "broadcast"
|
|
25841
|
+
});
|
|
25842
|
+
} catch (err) {
|
|
25843
|
+
logger.warn(`[policy] escalation voice failed for "${esc.schema}": ${errMsg2(err)}`);
|
|
25844
|
+
}
|
|
25845
|
+
}
|
|
25846
|
+
/** Queue an approved invocation for the delivery layer. */
|
|
25847
|
+
_buffer(instance, payload) {
|
|
24951
25848
|
const intentId = payload.intentId ?? "";
|
|
24952
25849
|
instance.pendingEffectorInvocations.push({
|
|
24953
25850
|
id: intentId,
|
|
@@ -25022,6 +25919,38 @@ var effectorController = class {
|
|
|
25022
25919
|
function num5(v, fallback) {
|
|
25023
25920
|
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
25024
25921
|
}
|
|
25922
|
+
function escalationAsk(schema, reasonCode) {
|
|
25923
|
+
const meaning = ESCALATION_MEANINGS[reasonCode] ?? "I need your approval before I can do this";
|
|
25924
|
+
return `I want to ${schema}, but ${meaning}. May I go ahead?`;
|
|
25925
|
+
}
|
|
25926
|
+
var ESCALATION_MEANINGS = {
|
|
25927
|
+
APPROVAL_REQUIRED: "I need your approval before I can on my own",
|
|
25928
|
+
WRITE_REQUIRES_APPROVAL: "it writes to the world and I shouldn't on my own",
|
|
25929
|
+
PAYMENT_REQUIRES_APPROVAL: "it moves money and I must not do that unattended",
|
|
25930
|
+
DEPLOY_REQUIRES_APPROVAL: "it ships something and needs a human to sign off"
|
|
25931
|
+
};
|
|
25932
|
+
function errMsg2(err) {
|
|
25933
|
+
return err instanceof Error ? err.message : String(err);
|
|
25934
|
+
}
|
|
25935
|
+
function recordToVerdict(record) {
|
|
25936
|
+
return {
|
|
25937
|
+
decision: record.decision,
|
|
25938
|
+
...record.reasonCode ? { reasonCode: record.reasonCode } : {},
|
|
25939
|
+
...record.finality ? { finality: record.finality } : {},
|
|
25940
|
+
...record.counterfactual ? { counterfactual: record.counterfactual } : {}
|
|
25941
|
+
};
|
|
25942
|
+
}
|
|
25943
|
+
function toPolicyInvocation(instance, payload) {
|
|
25944
|
+
return {
|
|
25945
|
+
willId: instance.config.id,
|
|
25946
|
+
intentId: payload.intentId ?? "",
|
|
25947
|
+
schema: payload.schema ?? "",
|
|
25948
|
+
parameters: payload.parameters ?? {},
|
|
25949
|
+
...typeof payload.targetEntityId === "string" ? { targetEntityId: payload.targetEntityId } : {},
|
|
25950
|
+
...typeof payload.description === "string" ? { description: payload.description } : {},
|
|
25951
|
+
tick: payload.tick ?? 0
|
|
25952
|
+
};
|
|
25953
|
+
}
|
|
25025
25954
|
|
|
25026
25955
|
// src/stem/tracts/sensory.controller.ts
|
|
25027
25956
|
var SensoryController = class {
|
|
@@ -25824,6 +26753,15 @@ var WillStem = class {
|
|
|
25824
26753
|
confirmEffectorExecution(id, invocationId, result) {
|
|
25825
26754
|
this._effector.confirmExecution(this._get(id), invocationId, result);
|
|
25826
26755
|
}
|
|
26756
|
+
/**
|
|
26757
|
+
* Resolve a policy escalation the Will raised (POLICY_REAFFERENCE P4).
|
|
26758
|
+
* `approved` dispatches the held invocation to the world; otherwise it is
|
|
26759
|
+
* refused. Applied at the next tick boundary. `invocationId` is the awaiting
|
|
26760
|
+
* `agency.intent` id the escalation ask referenced.
|
|
26761
|
+
*/
|
|
26762
|
+
resolveEscalation(id, invocationId, approved) {
|
|
26763
|
+
this._effector.resolveEscalation(this._get(id), invocationId, approved);
|
|
26764
|
+
}
|
|
25827
26765
|
// ── Messaging / outbox (11.1) ────────────────────────────────────────────
|
|
25828
26766
|
// Delegates to OutboxController (R5-c). `_get(id)` validates the Will exists
|
|
25829
26767
|
// and supplies the WillInstance; the outbox ops touch only instance fields.
|
|
@@ -25954,6 +26892,7 @@ var WillStem = class {
|
|
|
25954
26892
|
outbox: this._outbox,
|
|
25955
26893
|
sensory: this._sensory
|
|
25956
26894
|
});
|
|
26895
|
+
this._effector.applyPolicyOutcomes(instance);
|
|
25957
26896
|
await instance.simulation.step(1);
|
|
25958
26897
|
instance.tickCount++;
|
|
25959
26898
|
instance.lastTickAt = /* @__PURE__ */ new Date();
|