@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/cli.js
CHANGED
|
@@ -3625,11 +3625,19 @@ var PROC_THRESHOLD = 0.6;
|
|
|
3625
3625
|
var IDLE_TICKS = 200;
|
|
3626
3626
|
var DECAY_RATE = 0.02;
|
|
3627
3627
|
var DROP_HABIT = 0.05;
|
|
3628
|
+
var AVAIL_DROP_CLASS = 0.5;
|
|
3629
|
+
var AVAIL_DROP_INSTANCE = 0.12;
|
|
3630
|
+
var AVAIL_FLOOR = 0.05;
|
|
3631
|
+
var AVAIL_RECOVERY = 0.02;
|
|
3632
|
+
var AVAIL_RECOVERED = 0.999;
|
|
3628
3633
|
var SchemaRepertoire = class {
|
|
3629
3634
|
_templates = /* @__PURE__ */ new Map();
|
|
3630
3635
|
_skills = /* @__PURE__ */ new Map();
|
|
3631
3636
|
/** Tracks which templates were learned at runtime (vs innate) so decay can forget them. */
|
|
3632
3637
|
_learned = /* @__PURE__ */ new Set();
|
|
3638
|
+
/** Availability layer (P2): schema → { value 0..1, lastRefusedTick }. Empty until
|
|
3639
|
+
* a refusal lands — a never-refused Will writes nothing here (byte-identical). */
|
|
3640
|
+
_availability = /* @__PURE__ */ new Map();
|
|
3633
3641
|
constructor(seed = INNATE_SCHEMAS) {
|
|
3634
3642
|
for (const s of seed) this._templates.set(s.id, s);
|
|
3635
3643
|
}
|
|
@@ -3663,6 +3671,31 @@ var SchemaRepertoire = class {
|
|
|
3663
3671
|
getSkill(id) {
|
|
3664
3672
|
return this._skills.get(id);
|
|
3665
3673
|
}
|
|
3674
|
+
// ── availability (P2) ─────────────────────────────────────────
|
|
3675
|
+
availability() {
|
|
3676
|
+
return this._availability;
|
|
3677
|
+
}
|
|
3678
|
+
/**
|
|
3679
|
+
* How available a schema is right now, 0..1. Absent from the ledger ⇒ 1
|
|
3680
|
+
* (fully available — the common case). This is the ONLY value the
|
|
3681
|
+
* AffordanceSynthesizer reads; it never touches competence.
|
|
3682
|
+
*/
|
|
3683
|
+
availabilityOf(schema) {
|
|
3684
|
+
return this._availability.get(schema)?.value ?? 1;
|
|
3685
|
+
}
|
|
3686
|
+
/**
|
|
3687
|
+
* Fold a policy refusal into the availability layer (NOT competence). A
|
|
3688
|
+
* `class` refusal cuts availability hard; an `instance` refusal dents it
|
|
3689
|
+
* lightly. Multiplicative so repeated refusals compound toward — but never
|
|
3690
|
+
* reach — zero, keeping re-probe alive.
|
|
3691
|
+
*/
|
|
3692
|
+
recordRefusal(schema, finality, tick) {
|
|
3693
|
+
const prev = this._availability.get(schema)?.value ?? 1;
|
|
3694
|
+
const drop = finality === "class" ? AVAIL_DROP_CLASS : AVAIL_DROP_INSTANCE;
|
|
3695
|
+
const value = Math.max(AVAIL_FLOOR, prev * (1 - drop));
|
|
3696
|
+
this._availability.set(schema, { value, lastRefusedTick: tick });
|
|
3697
|
+
return value;
|
|
3698
|
+
}
|
|
3666
3699
|
/**
|
|
3667
3700
|
* Fold one outcome into the schema's learned skill. Returns the updated skill
|
|
3668
3701
|
* and whether it just crossed the proceduralization threshold this update.
|
|
@@ -3689,12 +3722,14 @@ var SchemaRepertoire = class {
|
|
|
3689
3722
|
return { skill, proceduralized: !wasProceduralized && habitStrength >= PROC_THRESHOLD };
|
|
3690
3723
|
}
|
|
3691
3724
|
/**
|
|
3692
|
-
* Forgetting curve over the competence layer
|
|
3693
|
-
* lose habit; learned composites
|
|
3694
|
-
* entirely (template + skill).
|
|
3725
|
+
* Forgetting curve over the competence layer, plus availability recovery.
|
|
3726
|
+
* Skills unused for IDLE_TICKS lose habit; learned composites below DROP_HABIT
|
|
3727
|
+
* are dropped entirely (template + skill). Availability entries climb back
|
|
3728
|
+
* toward 1 and are dropped once fully recovered. Returns the ids that were
|
|
3729
|
+
* removed from each layer so their mirrored state entities can be deleted.
|
|
3695
3730
|
*/
|
|
3696
3731
|
decay(tick) {
|
|
3697
|
-
const
|
|
3732
|
+
const skills = [];
|
|
3698
3733
|
for (const [id, skill] of this._skills) {
|
|
3699
3734
|
if (tick - skill.lastEnactedTick <= IDLE_TICKS) continue;
|
|
3700
3735
|
const habitStrength = clamp01(skill.habitStrength - DECAY_RATE);
|
|
@@ -3702,12 +3737,20 @@ var SchemaRepertoire = class {
|
|
|
3702
3737
|
this._skills.delete(id);
|
|
3703
3738
|
this._templates.delete(id);
|
|
3704
3739
|
this._learned.delete(id);
|
|
3705
|
-
|
|
3740
|
+
skills.push(id);
|
|
3706
3741
|
continue;
|
|
3707
3742
|
}
|
|
3708
3743
|
this._skills.set(id, { ...skill, habitStrength });
|
|
3709
3744
|
}
|
|
3710
|
-
|
|
3745
|
+
const availability = [];
|
|
3746
|
+
for (const [id, avail] of this._availability) {
|
|
3747
|
+
const value = avail.value + AVAIL_RECOVERY * (1 - avail.value);
|
|
3748
|
+
if (value >= AVAIL_RECOVERED) {
|
|
3749
|
+
this._availability.delete(id);
|
|
3750
|
+
availability.push(id);
|
|
3751
|
+
} else this._availability.set(id, { ...avail, value });
|
|
3752
|
+
}
|
|
3753
|
+
return { skills, availability };
|
|
3711
3754
|
}
|
|
3712
3755
|
// ── PMA portability (Phase 6 reads these) ─────────────────────
|
|
3713
3756
|
/** Learned composite templates + all skills above a confidence floor. */
|
|
@@ -3756,6 +3799,28 @@ var SchemaRepertoire = class {
|
|
|
3756
3799
|
this._learned.add(s.id);
|
|
3757
3800
|
}
|
|
3758
3801
|
}
|
|
3802
|
+
/** Availability ledger encoded as `agency.availability` state entities (P2).
|
|
3803
|
+
* Empty until a refusal lands, so the quiet path writes nothing. */
|
|
3804
|
+
availabilityEntities() {
|
|
3805
|
+
const out = [];
|
|
3806
|
+
for (const [schema, a] of this._availability)
|
|
3807
|
+
out.push(availabilityEntity(schema, a.value, a.lastRefusedTick));
|
|
3808
|
+
return out;
|
|
3809
|
+
}
|
|
3810
|
+
/** Rehydrate the availability ledger from state after a restore. Idempotent;
|
|
3811
|
+
* keeps whichever value is more restrictive so a concurrent refusal isn't lost. */
|
|
3812
|
+
restoreAvailability(entities) {
|
|
3813
|
+
for (const e of entities.values()) {
|
|
3814
|
+
if (e.type !== AVAILABILITY_ENTITY_TYPE) continue;
|
|
3815
|
+
const m = e.metadata ?? {};
|
|
3816
|
+
const schema = typeof m["schema"] === "string" ? m["schema"] : "";
|
|
3817
|
+
if (!schema) continue;
|
|
3818
|
+
const value = typeof m["value"] === "number" ? m["value"] : 1;
|
|
3819
|
+
const tick = typeof m["lastRefusedTick"] === "number" ? m["lastRefusedTick"] : 0;
|
|
3820
|
+
const prev = this._availability.get(schema);
|
|
3821
|
+
if (!prev || value < prev.value) this._availability.set(schema, { value, lastRefusedTick: tick });
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3759
3824
|
};
|
|
3760
3825
|
function freshSkill(schema, value, tick) {
|
|
3761
3826
|
return {
|
|
@@ -3772,6 +3837,17 @@ function freshSkill(schema, value, tick) {
|
|
|
3772
3837
|
function clamp01(n) {
|
|
3773
3838
|
return n < 0 ? 0 : n > 1 ? 1 : n;
|
|
3774
3839
|
}
|
|
3840
|
+
var AVAILABILITY_ENTITY_TYPE = "agency.availability";
|
|
3841
|
+
function availabilityEntityId(schema) {
|
|
3842
|
+
return `agency-availability-${schema}`;
|
|
3843
|
+
}
|
|
3844
|
+
function availabilityEntity(schema, value, lastRefusedTick) {
|
|
3845
|
+
return {
|
|
3846
|
+
id: availabilityEntityId(schema),
|
|
3847
|
+
type: AVAILABILITY_ENTITY_TYPE,
|
|
3848
|
+
metadata: { schema, value, lastRefusedTick }
|
|
3849
|
+
};
|
|
3850
|
+
}
|
|
3775
3851
|
var SCHEMA_ENTITY_TYPE = "agency.schema";
|
|
3776
3852
|
function schemaEntityId(schemaId) {
|
|
3777
3853
|
return `agency-schema-${schemaId}`;
|
|
@@ -4655,6 +4731,9 @@ var SleepPressureRegulator = class {
|
|
|
4655
4731
|
}
|
|
4656
4732
|
};
|
|
4657
4733
|
|
|
4734
|
+
// src/cognition/acp.ts
|
|
4735
|
+
var ACP_SELF_PRECISION = 0.35;
|
|
4736
|
+
|
|
4658
4737
|
// src/cognition/persona.prior.ts
|
|
4659
4738
|
var PERSONA_PRIOR_ID = "persona-prior";
|
|
4660
4739
|
var PERSONA_PRIOR_TYPE = "persona.prior";
|
|
@@ -4763,6 +4842,8 @@ function consolidatePrior(current, adjustments, tick, opts = {}) {
|
|
|
4763
4842
|
}
|
|
4764
4843
|
|
|
4765
4844
|
// src/cognition/faculties/attention.allocator.ts
|
|
4845
|
+
var ACP_USAGE_UPLIFT = 0.15;
|
|
4846
|
+
var ACP_CONFIDENCE = 0.4;
|
|
4766
4847
|
var EFFORT_BASELINE2 = 0.7;
|
|
4767
4848
|
var EFFORT_MIN = 0.4;
|
|
4768
4849
|
var EFFORT_MAX = 1;
|
|
@@ -4784,6 +4865,8 @@ var AttentionAllocator = class {
|
|
|
4784
4865
|
_effort = EFFORT_BASELINE2;
|
|
4785
4866
|
/** A one-shot focus/rest request from the executive, applied next react(). */
|
|
4786
4867
|
_effortRequest = null;
|
|
4868
|
+
/** ACP-P2: a self-caused precision attenuation is armed; react() restores after one observe. */
|
|
4869
|
+
_acpOneShot = false;
|
|
4787
4870
|
_bus = null;
|
|
4788
4871
|
_model = new GenerativeModel();
|
|
4789
4872
|
constructor(config = {}) {
|
|
@@ -4804,8 +4887,12 @@ var AttentionAllocator = class {
|
|
|
4804
4887
|
"executive.prediction.formed",
|
|
4805
4888
|
"attention.regulate",
|
|
4806
4889
|
// voluntary focus/rest from the executive (Option C)
|
|
4807
|
-
"senses.*"
|
|
4890
|
+
"senses.*",
|
|
4808
4891
|
// all sense percepts — salience feeds attention allocation
|
|
4892
|
+
// ACP-P2: our own enactions — anticipate the attention swing they cause
|
|
4893
|
+
"agency.enacted",
|
|
4894
|
+
"agency.communicate",
|
|
4895
|
+
"agency.invocation"
|
|
4809
4896
|
];
|
|
4810
4897
|
}
|
|
4811
4898
|
publishes() {
|
|
@@ -4832,6 +4919,18 @@ var AttentionAllocator = class {
|
|
|
4832
4919
|
this._model.setPrecision("attention.usage", 1 + p.confidence * 0.5);
|
|
4833
4920
|
break;
|
|
4834
4921
|
}
|
|
4922
|
+
case "agency.enacted":
|
|
4923
|
+
case "agency.communicate":
|
|
4924
|
+
case "agency.invocation": {
|
|
4925
|
+
const usage = this._model.predict("attention.usage");
|
|
4926
|
+
const free = this._model.predict("attention.free_fraction");
|
|
4927
|
+
this._model.anticipate("attention.usage", Math.min(1, usage + ACP_USAGE_UPLIFT), ACP_CONFIDENCE);
|
|
4928
|
+
this._model.anticipate("attention.free_fraction", Math.max(0, free - ACP_USAGE_UPLIFT), ACP_CONFIDENCE);
|
|
4929
|
+
this._model.setPrecision("attention.usage", ACP_SELF_PRECISION);
|
|
4930
|
+
this._model.setPrecision("attention.free_fraction", ACP_SELF_PRECISION);
|
|
4931
|
+
this._acpOneShot = true;
|
|
4932
|
+
break;
|
|
4933
|
+
}
|
|
4835
4934
|
default:
|
|
4836
4935
|
if (e.type.startsWith("senses.")) {
|
|
4837
4936
|
const percept = e.payload;
|
|
@@ -4915,6 +5014,11 @@ var AttentionAllocator = class {
|
|
|
4915
5014
|
if (_bus) {
|
|
4916
5015
|
const usageErr = this._model.observe("attention.usage", attentionUsage);
|
|
4917
5016
|
const freeErr = this._model.observe("attention.free_fraction", freeFraction);
|
|
5017
|
+
if (this._acpOneShot) {
|
|
5018
|
+
this._model.setPrecision("attention.usage", 1);
|
|
5019
|
+
this._model.setPrecision("attention.free_fraction", 1);
|
|
5020
|
+
this._acpOneShot = false;
|
|
5021
|
+
}
|
|
4918
5022
|
if (!usageErr.gated || !freeErr.gated)
|
|
4919
5023
|
_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 } });
|
|
4920
5024
|
}
|
|
@@ -5034,7 +5138,18 @@ var StressRegulator = class {
|
|
|
5034
5138
|
}
|
|
5035
5139
|
// ── Engine interface ─────────────────────────────────────
|
|
5036
5140
|
subscribes() {
|
|
5037
|
-
return [
|
|
5141
|
+
return [
|
|
5142
|
+
"energy.state.changed",
|
|
5143
|
+
"sleep.state.changed",
|
|
5144
|
+
"novelty.state.changed",
|
|
5145
|
+
"goal.state.changed",
|
|
5146
|
+
"metacognition.state.changed",
|
|
5147
|
+
"executive.prediction.formed",
|
|
5148
|
+
// ACP-P2: our own enactions — the stress swing they cause is expected
|
|
5149
|
+
"agency.enacted",
|
|
5150
|
+
"agency.communicate",
|
|
5151
|
+
"agency.invocation"
|
|
5152
|
+
];
|
|
5038
5153
|
}
|
|
5039
5154
|
publishes() {
|
|
5040
5155
|
return [];
|
|
@@ -5063,8 +5178,17 @@ var StressRegulator = class {
|
|
|
5063
5178
|
this._model.setPrecision("stress.load", 1 + p.confidence * 0.5);
|
|
5064
5179
|
break;
|
|
5065
5180
|
}
|
|
5181
|
+
case "agency.enacted":
|
|
5182
|
+
case "agency.communicate":
|
|
5183
|
+
case "agency.invocation": {
|
|
5184
|
+
this._model.setPrecision("stress.load", ACP_SELF_PRECISION);
|
|
5185
|
+
this._acpOneShot = true;
|
|
5186
|
+
break;
|
|
5187
|
+
}
|
|
5066
5188
|
}
|
|
5067
5189
|
}
|
|
5190
|
+
/** ACP-P2: self-caused stress attenuation armed; react() restores after one observe. */
|
|
5191
|
+
_acpOneShot = false;
|
|
5068
5192
|
snapshot() {
|
|
5069
5193
|
return {
|
|
5070
5194
|
energyLevel: this._energyLevel,
|
|
@@ -5157,6 +5281,10 @@ var StressRegulator = class {
|
|
|
5157
5281
|
if (_bus) {
|
|
5158
5282
|
const zoneCode = zone === "low" ? 0 : zone === "optimal" ? 1 : zone === "distress" ? 2 : 3;
|
|
5159
5283
|
const predErr = this._model.observe("stress.load", newLoad);
|
|
5284
|
+
if (this._acpOneShot) {
|
|
5285
|
+
this._model.setPrecision("stress.load", 1);
|
|
5286
|
+
this._acpOneShot = false;
|
|
5287
|
+
}
|
|
5160
5288
|
if (!predErr.gated || zone !== previousZone) {
|
|
5161
5289
|
_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 } });
|
|
5162
5290
|
}
|
|
@@ -5379,6 +5507,116 @@ var CircadianOscillator = class {
|
|
|
5379
5507
|
}
|
|
5380
5508
|
};
|
|
5381
5509
|
|
|
5510
|
+
// src/cognition/agency/consequence.ts
|
|
5511
|
+
var CONSEQUENCE_TYPE = "agency.consequence";
|
|
5512
|
+
var ATTENUATION = 0.25;
|
|
5513
|
+
var MIN_TEXT_MATCH_LEN = 12;
|
|
5514
|
+
var CONSEQUENCE_TTL_TICKS = 30;
|
|
5515
|
+
function fnv1a(text) {
|
|
5516
|
+
let h = 2166136261;
|
|
5517
|
+
for (let i = 0; i < text.length; i++) {
|
|
5518
|
+
h ^= text.charCodeAt(i);
|
|
5519
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
5520
|
+
}
|
|
5521
|
+
return h >>> 0;
|
|
5522
|
+
}
|
|
5523
|
+
function paramsKey(value) {
|
|
5524
|
+
if (value === null || typeof value !== "object")
|
|
5525
|
+
return typeof value === "string" ? JSON.stringify(value) : String(value);
|
|
5526
|
+
if (Array.isArray(value))
|
|
5527
|
+
return `[${value.map(paramsKey).join(",")}]`;
|
|
5528
|
+
const obj = value;
|
|
5529
|
+
const keys = Object.keys(obj).sort();
|
|
5530
|
+
return `{${keys.map((k) => `${k}:${paramsKey(obj[k])}`).join(",")}}`;
|
|
5531
|
+
}
|
|
5532
|
+
function consequenceEntity(d) {
|
|
5533
|
+
return {
|
|
5534
|
+
id: `agency-consequence-${d.intentId}`,
|
|
5535
|
+
type: CONSEQUENCE_TYPE,
|
|
5536
|
+
metadata: { ...d }
|
|
5537
|
+
};
|
|
5538
|
+
}
|
|
5539
|
+
function readConsequence(m) {
|
|
5540
|
+
const meta = m ?? {};
|
|
5541
|
+
const intentId = typeof meta["intentId"] === "string" ? meta["intentId"] : void 0;
|
|
5542
|
+
const schema = typeof meta["schema"] === "string" ? meta["schema"] : void 0;
|
|
5543
|
+
const mode = meta["mode"] === "communicate" || meta["mode"] === "external" ? meta["mode"] : void 0;
|
|
5544
|
+
if (!intentId || !schema || !mode) return null;
|
|
5545
|
+
return {
|
|
5546
|
+
intentId,
|
|
5547
|
+
schema,
|
|
5548
|
+
mode,
|
|
5549
|
+
effector: typeof meta["effector"] === "string" ? meta["effector"] : void 0,
|
|
5550
|
+
targetEntityId: typeof meta["targetEntityId"] === "string" ? meta["targetEntityId"] : void 0,
|
|
5551
|
+
textHash: typeof meta["textHash"] === "number" ? meta["textHash"] : void 0,
|
|
5552
|
+
text: typeof meta["text"] === "string" ? meta["text"] : void 0,
|
|
5553
|
+
paramsHash: typeof meta["paramsHash"] === "number" ? meta["paramsHash"] : void 0,
|
|
5554
|
+
expiresAt: typeof meta["expiresAt"] === "number" ? meta["expiresAt"] : 0,
|
|
5555
|
+
tick: typeof meta["tick"] === "number" ? meta["tick"] : 0
|
|
5556
|
+
};
|
|
5557
|
+
}
|
|
5558
|
+
function liveConsequences(entities, tick) {
|
|
5559
|
+
const out = [];
|
|
5560
|
+
for (const [, e] of entities) {
|
|
5561
|
+
if (e.type !== CONSEQUENCE_TYPE) continue;
|
|
5562
|
+
const d = readConsequence(e.metadata);
|
|
5563
|
+
if (d && tick < d.expiresAt) out.push(d);
|
|
5564
|
+
}
|
|
5565
|
+
return out.sort((a, b) => a.intentId < b.intentId ? -1 : a.intentId > b.intentId ? 1 : 0);
|
|
5566
|
+
}
|
|
5567
|
+
function matchConsequenceText(descriptors, candidate) {
|
|
5568
|
+
if (candidate.length === 0) return null;
|
|
5569
|
+
const candidateHash = fnv1a(candidate);
|
|
5570
|
+
for (const d of descriptors) {
|
|
5571
|
+
if (d.textHash !== void 0 && d.textHash === candidateHash) return d;
|
|
5572
|
+
if (d.text !== void 0 && d.text.length >= MIN_TEXT_MATCH_LEN && candidate.includes(d.text)) return d;
|
|
5573
|
+
}
|
|
5574
|
+
return null;
|
|
5575
|
+
}
|
|
5576
|
+
var CORRESPONDENCE_ATTENUATION = 0.5;
|
|
5577
|
+
function matchConsequenceEntity(descriptors, entityId, changeType) {
|
|
5578
|
+
if (changeType !== "modified" || entityId.length === 0) return null;
|
|
5579
|
+
for (const d of descriptors)
|
|
5580
|
+
if (d.mode === "external" && d.targetEntityId === entityId) return d;
|
|
5581
|
+
return null;
|
|
5582
|
+
}
|
|
5583
|
+
|
|
5584
|
+
// src/cognition/agency/revocation.ts
|
|
5585
|
+
var REVOCATION_TYPE = "agency.revocation";
|
|
5586
|
+
var RUPTURE_REVOKE_GATE = 0.7;
|
|
5587
|
+
var REVOCATION_TTL_TICKS = 5;
|
|
5588
|
+
function revocationId(intentId) {
|
|
5589
|
+
return `agency-revocation-${intentId}`;
|
|
5590
|
+
}
|
|
5591
|
+
function revocationEntity(intentId, schema, rupture, tick) {
|
|
5592
|
+
return {
|
|
5593
|
+
id: revocationId(intentId),
|
|
5594
|
+
type: REVOCATION_TYPE,
|
|
5595
|
+
metadata: { intentId, schema, rupture, tick, expiresAt: tick + REVOCATION_TTL_TICKS }
|
|
5596
|
+
};
|
|
5597
|
+
}
|
|
5598
|
+
function revokedIntentIds(entities, tick) {
|
|
5599
|
+
const out = /* @__PURE__ */ new Set();
|
|
5600
|
+
for (const [, e] of entities) {
|
|
5601
|
+
if (e.type !== REVOCATION_TYPE) continue;
|
|
5602
|
+
const m = e.metadata ?? {};
|
|
5603
|
+
const intentId = typeof m["intentId"] === "string" ? m["intentId"] : void 0;
|
|
5604
|
+
const expiresAt = typeof m["expiresAt"] === "number" ? m["expiresAt"] : 0;
|
|
5605
|
+
if (intentId && tick < expiresAt) out.add(intentId);
|
|
5606
|
+
}
|
|
5607
|
+
return out;
|
|
5608
|
+
}
|
|
5609
|
+
function staleRevocationIds(entities, tick) {
|
|
5610
|
+
const stale = [];
|
|
5611
|
+
for (const [id, e] of entities) {
|
|
5612
|
+
if (e.type !== REVOCATION_TYPE) continue;
|
|
5613
|
+
const m = e.metadata ?? {};
|
|
5614
|
+
const expiresAt = typeof m["expiresAt"] === "number" ? m["expiresAt"] : 0;
|
|
5615
|
+
if (tick >= expiresAt) stale.push(id);
|
|
5616
|
+
}
|
|
5617
|
+
return stale;
|
|
5618
|
+
}
|
|
5619
|
+
|
|
5382
5620
|
// src/cognition/faculties/exteroception.ts
|
|
5383
5621
|
var internalTypes = /* @__PURE__ */ new Set([
|
|
5384
5622
|
"percept",
|
|
@@ -5404,7 +5642,12 @@ var internalTypes = /* @__PURE__ */ new Set([
|
|
|
5404
5642
|
"episodic_memory",
|
|
5405
5643
|
// Internal state entities written by our own engines — not external events
|
|
5406
5644
|
"affect.blends",
|
|
5407
|
-
"executive.summary"
|
|
5645
|
+
"executive.summary",
|
|
5646
|
+
// The agency's own forward-model records (EXAFFERENCE P1/P2): perceiving our
|
|
5647
|
+
// expected-consequence descriptors would be a self-noise loop.
|
|
5648
|
+
CONSEQUENCE_TYPE,
|
|
5649
|
+
// The agency's own revocation tombstones (EXAFFERENCE P4) — internal bookkeeping.
|
|
5650
|
+
REVOCATION_TYPE
|
|
5408
5651
|
]);
|
|
5409
5652
|
var Exteroception = class {
|
|
5410
5653
|
name = "exteroception";
|
|
@@ -5454,17 +5697,26 @@ var Exteroception = class {
|
|
|
5454
5697
|
const events = [], commands = { set: [], delete: [], metrics: [] };
|
|
5455
5698
|
const rawPercepts = this._scanWorld(state);
|
|
5456
5699
|
const capped = rawPercepts.slice(0, this._maxPerceptsPerTick);
|
|
5700
|
+
const consequences = liveConsequences(state.entities, tick);
|
|
5457
5701
|
for (let i = 0; i < capped.length; i++) {
|
|
5458
5702
|
const rp = capped[i];
|
|
5703
|
+
const textHit = consequences.length > 0 && rp.matchText ? matchConsequenceText(consequences, rp.matchText) : null;
|
|
5704
|
+
const entityHit = !textHit && consequences.length > 0 ? matchConsequenceEntity(consequences, rp.entityId, rp.changeType) : null;
|
|
5705
|
+
const hit = textHit ?? entityHit;
|
|
5706
|
+
const salience = textHit ? rp.salience * ATTENUATION : entityHit ? rp.salience * CORRESPONDENCE_ATTENUATION : rp.salience;
|
|
5459
5707
|
const perceptEntity = {
|
|
5460
5708
|
id: `percept-${tick}-${i}`,
|
|
5461
5709
|
type: "percept",
|
|
5462
5710
|
metadata: {
|
|
5463
5711
|
entityId: rp.entityId,
|
|
5464
5712
|
changeType: rp.changeType,
|
|
5465
|
-
salience
|
|
5713
|
+
salience,
|
|
5466
5714
|
category: rp.category,
|
|
5467
5715
|
summary: rp.summary,
|
|
5716
|
+
provenance: hit ? "reafferent" : "exafferent",
|
|
5717
|
+
...hit ? { sourceIntentId: hit.intentId } : {},
|
|
5718
|
+
// affect→percept seam (registry #5): what this percept FEELS like
|
|
5719
|
+
...rp.valence !== void 0 ? { valence: rp.valence, valenceSource: rp.valenceSource } : {},
|
|
5468
5720
|
tick
|
|
5469
5721
|
}
|
|
5470
5722
|
};
|
|
@@ -5475,7 +5727,7 @@ var Exteroception = class {
|
|
|
5475
5727
|
source: this.name,
|
|
5476
5728
|
payload: {
|
|
5477
5729
|
entityId: rp.entityId,
|
|
5478
|
-
salience
|
|
5730
|
+
salience,
|
|
5479
5731
|
category: rp.category,
|
|
5480
5732
|
summary: rp.summary
|
|
5481
5733
|
}
|
|
@@ -5523,7 +5775,9 @@ var Exteroception = class {
|
|
|
5523
5775
|
changeType: "appeared",
|
|
5524
5776
|
salience: this._computeSalience(entity, "appeared", state.time),
|
|
5525
5777
|
category: entity.type,
|
|
5526
|
-
summary: this._summarizeEntity(entity, "appeared")
|
|
5778
|
+
summary: this._summarizeEntity(entity, "appeared"),
|
|
5779
|
+
matchText: this._matchText(entity),
|
|
5780
|
+
...this._valenceOf(id, state)
|
|
5527
5781
|
});
|
|
5528
5782
|
} else if (entity.updatedAt > previousVersion) {
|
|
5529
5783
|
percepts.push({
|
|
@@ -5531,7 +5785,9 @@ var Exteroception = class {
|
|
|
5531
5785
|
changeType: "modified",
|
|
5532
5786
|
salience: this._computeSalience(entity, "modified", state.time),
|
|
5533
5787
|
category: entity.type,
|
|
5534
|
-
summary: this._summarizeEntity(entity, "modified")
|
|
5788
|
+
summary: this._summarizeEntity(entity, "modified"),
|
|
5789
|
+
matchText: this._matchText(entity),
|
|
5790
|
+
...this._valenceOf(id, state)
|
|
5535
5791
|
});
|
|
5536
5792
|
}
|
|
5537
5793
|
this._previousEntityVersions.set(id, entity.updatedAt);
|
|
@@ -5557,6 +5813,46 @@ var Exteroception = class {
|
|
|
5557
5813
|
* Generate a meaningful summary for an entity.
|
|
5558
5814
|
* Instead of "New percept: percept-54-0", produce something useful.
|
|
5559
5815
|
*/
|
|
5816
|
+
/**
|
|
5817
|
+
* The text the corollary-discharge matcher inspects for this entity — its
|
|
5818
|
+
* content (a message body) over its description over its summary. Where our
|
|
5819
|
+
* own delivered words would surface if the world echoes them back.
|
|
5820
|
+
*/
|
|
5821
|
+
/**
|
|
5822
|
+
* The affect→percept valence seam (registry #5). A percept carries how the
|
|
5823
|
+
* mind *feels* about what it is a percept OF, resolved most-specific-first:
|
|
5824
|
+
*
|
|
5825
|
+
* 1. the KnownEntityTracker's dossier for this entity (`ke-<id>.valence`) —
|
|
5826
|
+
* a real per-entity felt valence, the honest signal;
|
|
5827
|
+
* 2. otherwise the ambient `affect.valence` — the felt tone at perception
|
|
5828
|
+
* time. Weaker evidence, so it is tagged `'ambient'` and consumers
|
|
5829
|
+
* weight it down (mood is context, not appraisal of this thing).
|
|
5830
|
+
*
|
|
5831
|
+
* Absent both, no valence is stamped and every consumer keeps its
|
|
5832
|
+
* pre-seam behaviour.
|
|
5833
|
+
*/
|
|
5834
|
+
/** Spread-friendly form of `_valenceFor` for percept construction. */
|
|
5835
|
+
_valenceOf(entityId, state) {
|
|
5836
|
+
const v = this._valenceFor(entityId, state);
|
|
5837
|
+
return v ? { valence: v.valence, valenceSource: v.source } : {};
|
|
5838
|
+
}
|
|
5839
|
+
_valenceFor(entityId, state) {
|
|
5840
|
+
const dossier = state.entities.get(`ke-${entityId}`);
|
|
5841
|
+
const felt = dossier?.metadata?.["valence"];
|
|
5842
|
+
if (typeof felt === "number" && Number.isFinite(felt))
|
|
5843
|
+
return { valence: felt, source: "entity" };
|
|
5844
|
+
const ambient = state.metrics.get("affect.valence");
|
|
5845
|
+
if (typeof ambient === "number" && Number.isFinite(ambient))
|
|
5846
|
+
return { valence: ambient, source: "ambient" };
|
|
5847
|
+
return void 0;
|
|
5848
|
+
}
|
|
5849
|
+
_matchText(entity) {
|
|
5850
|
+
const m = entity.metadata;
|
|
5851
|
+
const content = typeof m?.["content"] === "string" ? m["content"] : void 0;
|
|
5852
|
+
const description = typeof m?.["description"] === "string" ? m["description"] : void 0;
|
|
5853
|
+
const summary = typeof m?.["summary"] === "string" ? m["summary"] : void 0;
|
|
5854
|
+
return content ?? description ?? summary;
|
|
5855
|
+
}
|
|
5560
5856
|
_summarizeEntity(entity, changeType) {
|
|
5561
5857
|
const name = entity.metadata?.name;
|
|
5562
5858
|
const description = entity.metadata?.description;
|
|
@@ -7541,6 +7837,8 @@ var MoralEvaluator = class {
|
|
|
7541
7837
|
};
|
|
7542
7838
|
|
|
7543
7839
|
// src/cognition/faculties/affective.blender.ts
|
|
7840
|
+
var ACP_AROUSAL_UPLIFT = 0.1;
|
|
7841
|
+
var ACP_CONFIDENCE2 = 0.4;
|
|
7544
7842
|
var DOMINANT_EMOTION_CODES = {
|
|
7545
7843
|
"neutral": 0,
|
|
7546
7844
|
"fear": 1,
|
|
@@ -7641,6 +7939,8 @@ var AffectiveBlender = class {
|
|
|
7641
7939
|
_previousPAD = { valence: 0, arousal: 0.3, dominance: 0.5 };
|
|
7642
7940
|
_emotionHistory = /* @__PURE__ */ new Map();
|
|
7643
7941
|
_moodBaseline = 0.5;
|
|
7942
|
+
/** ACP-P2: self-caused arousal attenuation armed; react() restores after one observe. */
|
|
7943
|
+
_acpOneShot = false;
|
|
7644
7944
|
_energyLevel = 100;
|
|
7645
7945
|
_comfort = 0.5;
|
|
7646
7946
|
_sleepPressure = 0;
|
|
@@ -7674,8 +7974,12 @@ var AffectiveBlender = class {
|
|
|
7674
7974
|
"sleep.state.changed",
|
|
7675
7975
|
"stress.state.changed",
|
|
7676
7976
|
"executive.prediction.formed",
|
|
7677
|
-
"interaction.occurred"
|
|
7977
|
+
"interaction.occurred",
|
|
7678
7978
|
// 2.1: social stimuli drive immediate arousal/valence shifts
|
|
7979
|
+
// ACP-P2: our own enactions — the arousal they cause is expected, not surprising
|
|
7980
|
+
"agency.enacted",
|
|
7981
|
+
"agency.communicate",
|
|
7982
|
+
"agency.invocation"
|
|
7679
7983
|
];
|
|
7680
7984
|
}
|
|
7681
7985
|
publishes() {
|
|
@@ -7684,6 +7988,15 @@ var AffectiveBlender = class {
|
|
|
7684
7988
|
onCognitiveEvent(e) {
|
|
7685
7989
|
this._model.observe(e.type, e.salience);
|
|
7686
7990
|
switch (e.type) {
|
|
7991
|
+
case "agency.enacted":
|
|
7992
|
+
case "agency.communicate":
|
|
7993
|
+
case "agency.invocation": {
|
|
7994
|
+
const arousal = this._model.predict("affect.arousal");
|
|
7995
|
+
this._model.anticipate("affect.arousal", Math.min(1, arousal + ACP_AROUSAL_UPLIFT), ACP_CONFIDENCE2);
|
|
7996
|
+
this._model.setPrecision("affect.arousal", ACP_SELF_PRECISION);
|
|
7997
|
+
this._acpOneShot = true;
|
|
7998
|
+
break;
|
|
7999
|
+
}
|
|
7687
8000
|
case "circadian.state.changed":
|
|
7688
8001
|
this._moodBaseline = e.payload["moodBaseline"] ?? this._moodBaseline;
|
|
7689
8002
|
break;
|
|
@@ -7787,8 +8100,14 @@ var AffectiveBlender = class {
|
|
|
7787
8100
|
const _bus = this._bus;
|
|
7788
8101
|
if (_bus)
|
|
7789
8102
|
_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 } });
|
|
7790
|
-
if (_bus)
|
|
7791
|
-
|
|
8103
|
+
if (_bus) {
|
|
8104
|
+
const arousalErr = this._model.observe("affect.arousal", modulatedPAD.arousal);
|
|
8105
|
+
if (this._acpOneShot) {
|
|
8106
|
+
this._model.setPrecision("affect.arousal", 1);
|
|
8107
|
+
this._acpOneShot = false;
|
|
8108
|
+
}
|
|
8109
|
+
_bus.publish({ type: "affect.state.changed", version: 1, sourceEngine: this.name, salience: arousalErr.salience, payload: { valence: modulatedPAD.valence, arousal: modulatedPAD.arousal, dominance: modulatedPAD.dominance } });
|
|
8110
|
+
}
|
|
7792
8111
|
return { events: events.length > 0 ? events : void 0, commands };
|
|
7793
8112
|
}
|
|
7794
8113
|
// ── PAD computation ──────────────────────────────────────
|
|
@@ -16206,7 +16525,8 @@ var TaskSwitcher = class {
|
|
|
16206
16525
|
const currentGoal = activeGoals.find((g) => g.id === this._currentFocus.goalId);
|
|
16207
16526
|
const currentPriority = currentGoal?.priority ?? 0;
|
|
16208
16527
|
const switchAdvantage = topGoal.priority - currentPriority;
|
|
16209
|
-
const
|
|
16528
|
+
const stability = state.metrics.get("situation.stability") ?? 1;
|
|
16529
|
+
const switchCost = this._baseSwitchCost * (1 + this._currentFocus.focusTicks * 0.01 * stability);
|
|
16210
16530
|
const netBenefit = switchAdvantage - switchCost;
|
|
16211
16531
|
if (netBenefit > this._switchThreshold && this._currentFocus.focusTicks >= this._minFocusTicks) {
|
|
16212
16532
|
this._currentFocus = {
|
|
@@ -19807,7 +20127,9 @@ function risk(a, bias) {
|
|
|
19807
20127
|
return clamp016(Math.max(0, -a.expectedValence) * 0.5 + bias.threat * 0.5);
|
|
19808
20128
|
}
|
|
19809
20129
|
function scoreAffordance(a, bias, w = DEFAULT_WEIGHTS) {
|
|
19810
|
-
|
|
20130
|
+
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);
|
|
20131
|
+
const availability = a.availability ?? 1;
|
|
20132
|
+
return raw > 0 ? raw * availability : raw;
|
|
19811
20133
|
}
|
|
19812
20134
|
function stakes(winner, bias) {
|
|
19813
20135
|
return clamp016(Math.max(
|
|
@@ -19886,6 +20208,7 @@ var AffordanceSynthesizer = class {
|
|
|
19886
20208
|
// ── react ─────────────────────────────────────────────────────
|
|
19887
20209
|
async react(_delta, tick, state, _context) {
|
|
19888
20210
|
this._repertoire?.restoreComposites(state.entities);
|
|
20211
|
+
this._repertoire?.restoreAvailability(state.entities);
|
|
19889
20212
|
const schemas = this._repertoire?.schemas() ?? this._schemas;
|
|
19890
20213
|
const skills = this._skills?.() ?? this._repertoire?.skills() ?? null;
|
|
19891
20214
|
const valence = metric(state, "affect.valence", 0);
|
|
@@ -19896,9 +20219,7 @@ var AffordanceSynthesizer = class {
|
|
|
19896
20219
|
if (e.type === "affordance") del.push(id);
|
|
19897
20220
|
const floor = schemas.filter((s) => s.binds === "none");
|
|
19898
20221
|
for (const schema of floor)
|
|
19899
|
-
set.push(this._toEntity(
|
|
19900
|
-
this._build(schema, tick, state, valence, energyLow, skills, {})
|
|
19901
|
-
));
|
|
20222
|
+
set.push(this._toEntity(this._build(schema, tick, state, valence, energyLow, skills, {})));
|
|
19902
20223
|
const candidates = [];
|
|
19903
20224
|
const goalTargets = collectGoalTargets(state);
|
|
19904
20225
|
const perceptSchema = schemas.find((s) => s.binds === "percept");
|
|
@@ -20013,6 +20334,7 @@ var AffordanceSynthesizer = class {
|
|
|
20013
20334
|
/** Compose an Affordance from a schema + the evoking context, folding in learned priors. */
|
|
20014
20335
|
_build(schema, tick, state, valence, energyLow, skills, ctx) {
|
|
20015
20336
|
const skill = skills?.get(schema.id);
|
|
20337
|
+
const availability = this._repertoire?.availabilityOf(schema.id) ?? 1;
|
|
20016
20338
|
const expectedReward = skill?.valueEstimate ?? clamp017(((schema.baseValence ?? 0) + 1) / 2);
|
|
20017
20339
|
const expectedValence = schema.baseValence ?? valence;
|
|
20018
20340
|
const habitStrength = skill?.habitStrength ?? 0;
|
|
@@ -20034,6 +20356,7 @@ var AffordanceSynthesizer = class {
|
|
|
20034
20356
|
available: this._available(schema.preconditions, (k) => metric(state, k, 0)),
|
|
20035
20357
|
tags: schema.tags ?? [],
|
|
20036
20358
|
...schema.description ? { description: schema.description } : {},
|
|
20359
|
+
...availability < 1 ? { availability } : {},
|
|
20037
20360
|
planBias: ctx.planBias,
|
|
20038
20361
|
planId: ctx.planId,
|
|
20039
20362
|
stepId: ctx.stepId,
|
|
@@ -20057,6 +20380,7 @@ var AffordanceSynthesizer = class {
|
|
|
20057
20380
|
available: a.available,
|
|
20058
20381
|
tags: a.tags,
|
|
20059
20382
|
description: a.description,
|
|
20383
|
+
...a.availability !== void 0 ? { availability: a.availability } : {},
|
|
20060
20384
|
planBias: a.planBias,
|
|
20061
20385
|
planId: a.planId,
|
|
20062
20386
|
stepId: a.stepId,
|
|
@@ -20112,11 +20436,24 @@ var BASE_SWITCH_COST = 0.15;
|
|
|
20112
20436
|
var FOCUS_GAIN = 0.01;
|
|
20113
20437
|
var AWAIT_STALE_TICKS = 15;
|
|
20114
20438
|
var STALE_DECAY = 0.5;
|
|
20439
|
+
var RUPTURE_SALIENCE_GATE = 0.4;
|
|
20440
|
+
var RUPTURE_WINDOW_TICKS = 2;
|
|
20441
|
+
var STABILITY_RECOVERY = 0.05;
|
|
20442
|
+
var STABILITY_EPSILON = 1e-4;
|
|
20443
|
+
var REVOKE_HINT_WINDOW = 8;
|
|
20115
20444
|
var ActionSelector = class {
|
|
20116
20445
|
name = "action-selector";
|
|
20117
20446
|
_bus = null;
|
|
20118
20447
|
_lastEntropy = 0;
|
|
20119
20448
|
_lastDeliberate = false;
|
|
20449
|
+
// EXAFFERENCE P4 follow-up (Channel B): the schema we most recently revoked
|
|
20450
|
+
// under rupture, so the *next* deliberation formed in its wake can own the
|
|
20451
|
+
// interruption in-character ("something changed — I dropped what I was
|
|
20452
|
+
// weighing"). Telemetry-grade instance state, mirroring _lastEntropy.
|
|
20453
|
+
_lastRevoked = null;
|
|
20454
|
+
// ACP §2b: sense-channel percepts buffered off the bus for the next react's
|
|
20455
|
+
// rupture computation (they never become entities). Cross-tick ⇒ FN9.
|
|
20456
|
+
_senseBuffer = [];
|
|
20120
20457
|
attachBus(bus) {
|
|
20121
20458
|
this._bus = bus;
|
|
20122
20459
|
}
|
|
@@ -20124,16 +20461,60 @@ var ActionSelector = class {
|
|
|
20124
20461
|
return [
|
|
20125
20462
|
{ type: "agency.selection.made", version: 1, validate: () => null },
|
|
20126
20463
|
{ type: "agency.selection.ambiguous", version: 1, validate: () => null },
|
|
20127
|
-
{ type: "agency.action.preempted", version: 1, validate: () => null }
|
|
20464
|
+
{ type: "agency.action.preempted", version: 1, validate: () => null },
|
|
20465
|
+
{ type: "agency.situation.rupture", version: 1, validate: () => null },
|
|
20466
|
+
{ type: "agency.commitment.revoked", version: 1, validate: () => null }
|
|
20128
20467
|
];
|
|
20129
20468
|
}
|
|
20130
20469
|
subscribes() {
|
|
20131
|
-
return [
|
|
20470
|
+
return [
|
|
20471
|
+
"senses.*",
|
|
20472
|
+
// Registry #6 (ACP-P3): the model-error term — each carries its
|
|
20473
|
+
// engine's prediction-error salience, ALREADY precision-attenuated for
|
|
20474
|
+
// self-caused swings by the ACP-P2 consumers, so the echo guard
|
|
20475
|
+
// composes by construction: our own action's interoceptive wake
|
|
20476
|
+
// arrives below the rupture gate.
|
|
20477
|
+
"attention.state.changed",
|
|
20478
|
+
"affect.state.changed",
|
|
20479
|
+
"stress.state.changed"
|
|
20480
|
+
];
|
|
20132
20481
|
}
|
|
20133
|
-
|
|
20482
|
+
/**
|
|
20483
|
+
* Mostly pull-model — but two afferent classes never become entities and
|
|
20484
|
+
* would leave rupture blind: sense-channel percepts
|
|
20485
|
+
* (ACTION_CONDITIONED_PREDICTION §2b) and the model-error state-change
|
|
20486
|
+
* events (registry #6). Buffer both (cross-tick: bus flush at T, consumed
|
|
20487
|
+
* by react at T+1 — FN9-snapshotted); the echo guard is applied at read
|
|
20488
|
+
* time for texts, and at the SOURCE for model errors (ACP-P2 precision).
|
|
20489
|
+
*/
|
|
20490
|
+
onCognitiveEvent(e) {
|
|
20491
|
+
const isSense = e.type.startsWith("senses.") && e.type.endsWith(".percept");
|
|
20492
|
+
const isModelError = e.type === "attention.state.changed" || e.type === "affect.state.changed" || e.type === "stress.state.changed";
|
|
20493
|
+
if (!isSense && !isModelError) return;
|
|
20494
|
+
const p = e.payload;
|
|
20495
|
+
this._senseBuffer.push({
|
|
20496
|
+
salience: e.salience,
|
|
20497
|
+
...isSense && typeof p?.content === "string" ? { text: p.content } : {}
|
|
20498
|
+
});
|
|
20134
20499
|
}
|
|
20135
20500
|
snapshot() {
|
|
20136
|
-
return {
|
|
20501
|
+
return {
|
|
20502
|
+
lastEntropy: this._lastEntropy,
|
|
20503
|
+
lastDeliberate: this._lastDeliberate,
|
|
20504
|
+
lastRevoked: this._lastRevoked,
|
|
20505
|
+
senseBuffer: this._senseBuffer
|
|
20506
|
+
};
|
|
20507
|
+
}
|
|
20508
|
+
/** FN9: `_lastRevoked` has behavioral effect (the Channel-B `revokedBy` stamp),
|
|
20509
|
+
* so a restored mind must carry it — a rupture-driven letting-go survives a
|
|
20510
|
+
* snapshot boundary instead of silently losing its narrative thread. */
|
|
20511
|
+
restore(s) {
|
|
20512
|
+
if (typeof s["lastEntropy"] === "number") this._lastEntropy = s["lastEntropy"];
|
|
20513
|
+
if (typeof s["lastDeliberate"] === "boolean") this._lastDeliberate = s["lastDeliberate"];
|
|
20514
|
+
const lr = s["lastRevoked"];
|
|
20515
|
+
this._lastRevoked = lr && typeof lr === "object" && typeof lr.schema === "string" && typeof lr.tick === "number" ? { schema: lr.schema, tick: lr.tick } : null;
|
|
20516
|
+
const sb = s["senseBuffer"];
|
|
20517
|
+
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 } : {} })) : [];
|
|
20137
20518
|
}
|
|
20138
20519
|
async react(_delta, tick, state, _context) {
|
|
20139
20520
|
const eligible = [];
|
|
@@ -20162,54 +20543,125 @@ var ActionSelector = class {
|
|
|
20162
20543
|
let blocking = false;
|
|
20163
20544
|
let awaiting = null;
|
|
20164
20545
|
let composite = null;
|
|
20546
|
+
let deliberating = null;
|
|
20165
20547
|
for (const it of intents) {
|
|
20166
|
-
if (it.st === "deliberating")
|
|
20167
|
-
|
|
20548
|
+
if (it.st === "deliberating") {
|
|
20549
|
+
blocking = true;
|
|
20550
|
+
deliberating = { id: it.id, schema: it.schema };
|
|
20551
|
+
} else if (it.st === "expanding") composite = { id: it.id, activation: it.activation, schema: it.schema };
|
|
20168
20552
|
else if (it.st === "awaiting") awaiting = { id: it.id, activation: it.activation, schema: it.schema, target: it.target, dispatchedAt: it.dispatchedAt };
|
|
20169
20553
|
else if (it.st === "selected") {
|
|
20170
20554
|
const activeMacroSub = it.parentIntentId !== void 0 && expandingParents.has(it.parentIntentId);
|
|
20171
20555
|
if (!activeMacroSub) blocking = true;
|
|
20172
20556
|
}
|
|
20173
20557
|
}
|
|
20174
|
-
const
|
|
20175
|
-
|
|
20176
|
-
|
|
20177
|
-
|
|
20558
|
+
const senseEvents = this._senseBuffer;
|
|
20559
|
+
this._senseBuffer = [];
|
|
20560
|
+
const rupture = computeRupture(state, tick, senseEvents);
|
|
20561
|
+
const prevStab = metric2(state, "situation.stability", 1);
|
|
20562
|
+
const nextStabRaw = clamp018(prevStab + STABILITY_RECOVERY * (1 - prevStab) - rupture);
|
|
20563
|
+
const nextStab = 1 - nextStabRaw < STABILITY_EPSILON ? 1 : nextStabRaw;
|
|
20564
|
+
const stabMetrics = rupture > 0 || prevStab < 1 ? [["situation.stability", nextStab]] : [];
|
|
20565
|
+
if (rupture > 0 && this._bus) {
|
|
20566
|
+
try {
|
|
20567
|
+
this._bus.publish({
|
|
20568
|
+
type: "agency.situation.rupture",
|
|
20569
|
+
version: 1,
|
|
20570
|
+
sourceEngine: this.name,
|
|
20571
|
+
salience: rupture,
|
|
20572
|
+
payload: { rupture, stability: nextStab, tick }
|
|
20573
|
+
});
|
|
20574
|
+
} catch (err) {
|
|
20575
|
+
logger.warn(`[selector] rupture publish failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
20576
|
+
}
|
|
20577
|
+
}
|
|
20578
|
+
const busy = (n) => ({
|
|
20579
|
+
commands: {
|
|
20580
|
+
metrics: [
|
|
20581
|
+
["agency.field.eligible", n],
|
|
20582
|
+
["agency.selection.busy", 1],
|
|
20583
|
+
...stabMetrics
|
|
20584
|
+
]
|
|
20585
|
+
}
|
|
20586
|
+
});
|
|
20587
|
+
const policyRevoke = !!deliberating && refusedClassSchemas(state).has(deliberating.schema);
|
|
20588
|
+
if (deliberating && (rupture >= RUPTURE_REVOKE_GATE || policyRevoke)) {
|
|
20589
|
+
const reason = policyRevoke ? "policy-refusal" : "exafferent-rupture";
|
|
20590
|
+
const revRupture = policyRevoke ? Math.max(rupture, RUPTURE_REVOKE_GATE) : rupture;
|
|
20591
|
+
if (this._bus) {
|
|
20592
|
+
try {
|
|
20593
|
+
this._bus.publish({
|
|
20594
|
+
type: "agency.commitment.revoked",
|
|
20595
|
+
version: 1,
|
|
20596
|
+
sourceEngine: this.name,
|
|
20597
|
+
salience: 0.85,
|
|
20598
|
+
payload: { from: deliberating.schema, reason, rupture: revRupture, tick }
|
|
20599
|
+
});
|
|
20600
|
+
} catch (err) {
|
|
20601
|
+
logger.warn(`[selector] revoked publish failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
20602
|
+
}
|
|
20603
|
+
}
|
|
20604
|
+
this._lastRevoked = { schema: deliberating.schema, tick };
|
|
20605
|
+
return {
|
|
20606
|
+
commands: {
|
|
20607
|
+
set: [revocationEntity(deliberating.id, deliberating.schema, revRupture, tick)],
|
|
20608
|
+
metrics: [
|
|
20609
|
+
["agency.field.eligible", eligible.length],
|
|
20610
|
+
["agency.selection.busy", 1],
|
|
20611
|
+
["agency.commitment.revoked", 1],
|
|
20612
|
+
...policyRevoke ? [["agency.policy.revoked", 1]] : [],
|
|
20613
|
+
...stabMetrics
|
|
20614
|
+
]
|
|
20615
|
+
}
|
|
20616
|
+
};
|
|
20617
|
+
}
|
|
20178
20618
|
if (blocking) return busy(eligible.length);
|
|
20179
20619
|
if (eligible.length === 0)
|
|
20180
|
-
return {
|
|
20620
|
+
return {
|
|
20621
|
+
commands: {
|
|
20622
|
+
metrics: [
|
|
20623
|
+
["agency.field.eligible", 0],
|
|
20624
|
+
["agency.selection.busy", awaiting || composite ? 1 : 0],
|
|
20625
|
+
...stabMetrics
|
|
20626
|
+
]
|
|
20627
|
+
}
|
|
20628
|
+
};
|
|
20181
20629
|
const bias = buildBias(state);
|
|
20182
|
-
const effSwitchCost = effectiveSwitchCost(state);
|
|
20630
|
+
const effSwitchCost = effectiveSwitchCost(state) * (1 - rupture);
|
|
20183
20631
|
const weights = effectiveWeights(state);
|
|
20184
20632
|
const scored = eligible.map((a) => ({ affordance: a, activation: scoreAffordance(a, bias, weights) })).sort((x, y) => y.activation - x.activation);
|
|
20185
20633
|
const winner = scored[0];
|
|
20186
20634
|
if (!winner) return busy(eligible.length);
|
|
20635
|
+
let compositeTombstone;
|
|
20636
|
+
let compositeFrom;
|
|
20187
20637
|
if (composite) {
|
|
20188
20638
|
const different = winner.affordance.schema !== composite.schema;
|
|
20189
20639
|
const switchCost = effSwitchCost * (1 - stakes(winner.affordance, bias));
|
|
20190
|
-
if (different
|
|
20191
|
-
|
|
20640
|
+
if (!different || winner.activation <= composite.activation + switchCost)
|
|
20641
|
+
return busy(eligible.length);
|
|
20642
|
+
if (this._bus)
|
|
20643
|
+
try {
|
|
20192
20644
|
this._bus.publish({
|
|
20193
20645
|
type: "agency.action.preempted",
|
|
20194
20646
|
version: 1,
|
|
20195
20647
|
sourceEngine: this.name,
|
|
20196
20648
|
salience: 0.8,
|
|
20197
|
-
payload: {
|
|
20649
|
+
payload: {
|
|
20650
|
+
from: composite.schema,
|
|
20651
|
+
to: winner.affordance.schema,
|
|
20652
|
+
activation: winner.activation,
|
|
20653
|
+
tick
|
|
20654
|
+
}
|
|
20198
20655
|
});
|
|
20199
20656
|
} catch (err) {
|
|
20200
20657
|
logger.warn(`[selector] preempt publish failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
20201
20658
|
}
|
|
20202
|
-
|
|
20203
|
-
|
|
20204
|
-
["agency.selection.busy", 1],
|
|
20205
|
-
["agency.selection.preempted", 1]
|
|
20206
|
-
] } };
|
|
20207
|
-
}
|
|
20208
|
-
return busy(eligible.length);
|
|
20659
|
+
compositeTombstone = composite.id;
|
|
20660
|
+
compositeFrom = composite.schema;
|
|
20209
20661
|
}
|
|
20210
20662
|
let preemptDelete;
|
|
20211
|
-
let preemptedFrom;
|
|
20212
|
-
if (awaiting) {
|
|
20663
|
+
let preemptedFrom = compositeFrom;
|
|
20664
|
+
if (awaiting && !compositeTombstone) {
|
|
20213
20665
|
const sameAction = winner.affordance.schema === awaiting.schema && (winner.affordance.targetEntityId ?? "") === awaiting.target;
|
|
20214
20666
|
if (sameAction) return busy(eligible.length);
|
|
20215
20667
|
const staleness = Math.min(1, (tick - awaiting.dispatchedAt) / AWAIT_STALE_TICKS);
|
|
@@ -20232,6 +20684,13 @@ var ActionSelector = class {
|
|
|
20232
20684
|
const deliberate = margin < marginGate || stk > stakesGate;
|
|
20233
20685
|
this._lastEntropy = entropy;
|
|
20234
20686
|
this._lastDeliberate = deliberate;
|
|
20687
|
+
let revokedBy;
|
|
20688
|
+
if (this._lastRevoked) {
|
|
20689
|
+
if (deliberate && tick - this._lastRevoked.tick <= REVOKE_HINT_WINDOW)
|
|
20690
|
+
revokedBy = this._lastRevoked.schema;
|
|
20691
|
+
if (revokedBy || tick - this._lastRevoked.tick > REVOKE_HINT_WINDOW)
|
|
20692
|
+
this._lastRevoked = null;
|
|
20693
|
+
}
|
|
20235
20694
|
const intent = {
|
|
20236
20695
|
id: `agency-intent-${tick}`,
|
|
20237
20696
|
type: "agency.intent",
|
|
@@ -20274,6 +20733,9 @@ var ActionSelector = class {
|
|
|
20274
20733
|
// interrupted, so the deliberation facet can own the interruption in-character
|
|
20275
20734
|
// ("I was about to X, but this pulled me away"). Only meaningful while deliberating.
|
|
20276
20735
|
...preemptedFrom ? { preemptedFrom } : {},
|
|
20736
|
+
// Channel B: this deliberation forms in the wake of a rupture-driven
|
|
20737
|
+
// revocation — the facet can own "something changed, I let go of X".
|
|
20738
|
+
...revokedBy ? { revokedBy } : {},
|
|
20277
20739
|
tick
|
|
20278
20740
|
}
|
|
20279
20741
|
};
|
|
@@ -20312,7 +20774,9 @@ var ActionSelector = class {
|
|
|
20312
20774
|
}
|
|
20313
20775
|
}
|
|
20314
20776
|
const commands = {
|
|
20315
|
-
|
|
20777
|
+
// A composite preemption rides along as a tombstone (never a delete — the
|
|
20778
|
+
// executor's in-tick macro-advance would resurrect the parent).
|
|
20779
|
+
set: compositeTombstone ? [intent, revocationEntity(compositeTombstone, compositeFrom ?? "", rupture, tick)] : [intent],
|
|
20316
20780
|
...preemptDelete ? { delete: [preemptDelete] } : {},
|
|
20317
20781
|
metrics: [
|
|
20318
20782
|
["agency.field.eligible", eligible.length],
|
|
@@ -20321,7 +20785,8 @@ var ActionSelector = class {
|
|
|
20321
20785
|
["agency.selection.margin", margin],
|
|
20322
20786
|
["agency.selection.deliberate", deliberate ? 1 : 0],
|
|
20323
20787
|
["agency.selection.preempted", preemptedFrom ? 1 : 0],
|
|
20324
|
-
["agency.selection.activation", winner.activation]
|
|
20788
|
+
["agency.selection.activation", winner.activation],
|
|
20789
|
+
...stabMetrics
|
|
20325
20790
|
]
|
|
20326
20791
|
};
|
|
20327
20792
|
return { commands };
|
|
@@ -20331,7 +20796,40 @@ function effectiveSwitchCost(state) {
|
|
|
20331
20796
|
const params = readEffectiveParams(state, "engine-config-action-selector");
|
|
20332
20797
|
const base = num2(params["switchCost"], BASE_SWITCH_COST);
|
|
20333
20798
|
const focusTicks = metric2(state, "task_switch.current_focus_ticks", 0);
|
|
20334
|
-
|
|
20799
|
+
const stability = metric2(state, "situation.stability", 1);
|
|
20800
|
+
return base * (1 + focusTicks * FOCUS_GAIN * stability);
|
|
20801
|
+
}
|
|
20802
|
+
function computeRupture(state, tick, senseEvents = []) {
|
|
20803
|
+
let maxSalience = 0;
|
|
20804
|
+
for (const e of state.entities.values()) {
|
|
20805
|
+
if (e.type !== "percept") continue;
|
|
20806
|
+
const m = e.metadata;
|
|
20807
|
+
if (str2(m?.["provenance"]) !== "exafferent") continue;
|
|
20808
|
+
const pTick = num2(m?.["tick"], -1);
|
|
20809
|
+
if (pTick < 0 || tick - pTick > RUPTURE_WINDOW_TICKS) continue;
|
|
20810
|
+
const s = num2(m?.["salience"], 0);
|
|
20811
|
+
if (s > maxSalience) maxSalience = s;
|
|
20812
|
+
}
|
|
20813
|
+
if (senseEvents.length > 0) {
|
|
20814
|
+
const live = liveConsequences(state.entities, tick);
|
|
20815
|
+
for (const ev of senseEvents) {
|
|
20816
|
+
if (ev.text !== void 0 && live.length > 0 && matchConsequenceText(live, ev.text)) continue;
|
|
20817
|
+
if (ev.salience > maxSalience) maxSalience = ev.salience;
|
|
20818
|
+
}
|
|
20819
|
+
}
|
|
20820
|
+
if (maxSalience <= RUPTURE_SALIENCE_GATE) return 0;
|
|
20821
|
+
return clamp018((maxSalience - RUPTURE_SALIENCE_GATE) / (1 - RUPTURE_SALIENCE_GATE));
|
|
20822
|
+
}
|
|
20823
|
+
function refusedClassSchemas(state) {
|
|
20824
|
+
const out = /* @__PURE__ */ new Set();
|
|
20825
|
+
for (const e of state.entities.values()) {
|
|
20826
|
+
if (e.type !== "agency.outcome") continue;
|
|
20827
|
+
const m = e.metadata;
|
|
20828
|
+
if (m?.["refused"] !== true || str2(m?.["finality"]) !== "class") continue;
|
|
20829
|
+
const schema = str2(m?.["schema"]);
|
|
20830
|
+
if (schema) out.add(schema);
|
|
20831
|
+
}
|
|
20832
|
+
return out;
|
|
20335
20833
|
}
|
|
20336
20834
|
function effectiveWeights(state) {
|
|
20337
20835
|
const p = readEffectiveParams(state, "engine-config-action-selector");
|
|
@@ -20432,19 +20930,28 @@ var DeliberationEngine = class {
|
|
|
20432
20930
|
return { deliberations: this._deliberations };
|
|
20433
20931
|
}
|
|
20434
20932
|
async react(_delta, tick, state, _context) {
|
|
20933
|
+
const revoked = revokedIntentIds(state.entities, tick);
|
|
20934
|
+
const del = [];
|
|
20435
20935
|
let target = null;
|
|
20436
20936
|
for (const [id2, e] of state.entities) {
|
|
20437
20937
|
if (e.type !== "agency.intent") continue;
|
|
20438
20938
|
if (str3(e.metadata?.["status"]) !== "deliberating") continue;
|
|
20939
|
+
if (revoked.has(id2)) {
|
|
20940
|
+
del.push(id2, revocationId(id2));
|
|
20941
|
+
continue;
|
|
20942
|
+
}
|
|
20439
20943
|
const meta2 = e.metadata ?? {};
|
|
20440
20944
|
if (!target || id2 < target.id) target = { id: id2, meta: meta2 };
|
|
20441
20945
|
}
|
|
20442
|
-
if (!target) return { commands: {} };
|
|
20946
|
+
if (!target) return del.length > 0 ? { commands: { delete: del } } : { commands: {} };
|
|
20443
20947
|
const { id, meta } = target;
|
|
20444
20948
|
const provisional = str3(meta["schema"]) ?? "wait";
|
|
20445
20949
|
const candidates = Array.isArray(meta["candidates"]) ? meta["candidates"] : [];
|
|
20446
20950
|
if (!this._provider)
|
|
20447
|
-
return { commands: {
|
|
20951
|
+
return { commands: {
|
|
20952
|
+
set: [this._commit(id, meta, provisional, candidates, "no-executive")],
|
|
20953
|
+
...del.length > 0 ? { delete: del } : {}
|
|
20954
|
+
} };
|
|
20448
20955
|
const chosen = await this._deliberate(state, candidates, provisional, meta);
|
|
20449
20956
|
this._deliberations++;
|
|
20450
20957
|
if (this._bus) {
|
|
@@ -20462,6 +20969,7 @@ var DeliberationEngine = class {
|
|
|
20462
20969
|
return {
|
|
20463
20970
|
commands: {
|
|
20464
20971
|
set: [this._commit(id, meta, chosen, candidates, "facet")],
|
|
20972
|
+
...del.length > 0 ? { delete: del } : {},
|
|
20465
20973
|
metrics: [["agency.deliberation.count", 1]]
|
|
20466
20974
|
}
|
|
20467
20975
|
};
|
|
@@ -20519,7 +21027,10 @@ var DeliberationEngine = class {
|
|
|
20519
21027
|
_buildFocusContent(state, candidates, meta) {
|
|
20520
21028
|
const lines = [];
|
|
20521
21029
|
const preemptedFrom = str3(meta["preemptedFrom"]);
|
|
20522
|
-
|
|
21030
|
+
const revokedBy = str3(meta["revokedBy"]);
|
|
21031
|
+
if (revokedBy)
|
|
21032
|
+
lines.push(`Something in my situation just shifted and I let go of what I was weighing ("${revokedBy}"). Decide afresh what to do now:`);
|
|
21033
|
+
else if (preemptedFrom)
|
|
20523
21034
|
lines.push(`I just broke off a pending action ("${preemptedFrom}") because something more pressing pulled at me. Decide what to do now:`);
|
|
20524
21035
|
else
|
|
20525
21036
|
lines.push("My automatic action-selection was uncertain. Candidate actions:");
|
|
@@ -20692,8 +21203,22 @@ var MotorSchemaExecutor = class {
|
|
|
20692
21203
|
const metrics = [];
|
|
20693
21204
|
const energy = state.metrics.get("energy.level") ?? 100;
|
|
20694
21205
|
const stress = state.metrics.get("stress.load") ?? 0;
|
|
21206
|
+
for (const [id, e] of state.entities) {
|
|
21207
|
+
if (e.type !== CONSEQUENCE_TYPE) continue;
|
|
21208
|
+
if (tick >= num3(e.metadata?.["expiresAt"], 0)) del.push(id);
|
|
21209
|
+
}
|
|
21210
|
+
del.push(...staleRevocationIds(state.entities, tick));
|
|
21211
|
+
const revoked = revokedIntentIds(state.entities, tick);
|
|
21212
|
+
if (revoked.size > 0)
|
|
21213
|
+
for (const [id, e] of state.entities) {
|
|
21214
|
+
if (e.type !== "agency.intent") continue;
|
|
21215
|
+
const parentId = str5(e.metadata?.["parentIntentId"]);
|
|
21216
|
+
if (revoked.has(id)) del.push(id, revocationId(id));
|
|
21217
|
+
else if (parentId && revoked.has(parentId)) del.push(id);
|
|
21218
|
+
}
|
|
20695
21219
|
for (const [id, e] of state.entities) {
|
|
20696
21220
|
if (e.type !== "agency.intent" || str5(e.metadata?.["status"]) !== "awaiting") continue;
|
|
21221
|
+
if (e.metadata?.["escalated"] === true) continue;
|
|
20697
21222
|
const dispatchedAt = num3(e.metadata?.["dispatchedAt"], tick);
|
|
20698
21223
|
if (tick - dispatchedAt < AWAIT_TIMEOUT) continue;
|
|
20699
21224
|
const intent = readIntent(id, e.metadata);
|
|
@@ -20718,6 +21243,9 @@ var MotorSchemaExecutor = class {
|
|
|
20718
21243
|
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);
|
|
20719
21244
|
let enactedCount = 0;
|
|
20720
21245
|
for (const [id, e] of selected) {
|
|
21246
|
+
if (revoked.has(id)) continue;
|
|
21247
|
+
const parentOf = str5(e.metadata?.["parentIntentId"]);
|
|
21248
|
+
if (parentOf && revoked.has(parentOf)) continue;
|
|
20721
21249
|
const intent = readIntent(id, e.metadata);
|
|
20722
21250
|
const schema = this._resolve(intent.schema);
|
|
20723
21251
|
if (schema?.kind === "composite" && schema.composedOf && schema.composedOf.length > 0) {
|
|
@@ -20766,6 +21294,18 @@ var MotorSchemaExecutor = class {
|
|
|
20766
21294
|
predictedValence: predicted.expectedValence
|
|
20767
21295
|
}
|
|
20768
21296
|
});
|
|
21297
|
+
const awaitingText = enaction.mode === "communicate" ? str5(intent.parameters["content"]) ?? firstMessage(intent.parameters["messages"]) : void 0;
|
|
21298
|
+
set.push(consequenceEntity({
|
|
21299
|
+
intentId: id,
|
|
21300
|
+
schema: intent.schema,
|
|
21301
|
+
mode: enaction.mode === "communicate" ? "communicate" : "external",
|
|
21302
|
+
...enaction.mode === "communicate" ? { effector: COMM_SCHEMA_TO_EFFECTOR[intent.schema] ?? intent.schema } : {},
|
|
21303
|
+
...intent.targetEntityId ? { targetEntityId: intent.targetEntityId } : {},
|
|
21304
|
+
...awaitingText ? { text: awaitingText, textHash: fnv1a(awaitingText) } : {},
|
|
21305
|
+
paramsHash: fnv1a(paramsKey(intent.parameters)),
|
|
21306
|
+
expiresAt: tick + CONSEQUENCE_TTL_TICKS,
|
|
21307
|
+
tick
|
|
21308
|
+
}));
|
|
20769
21309
|
this._emitDispatch(intent, enaction.mode, tick);
|
|
20770
21310
|
metrics.push([enaction.mode === "communicate" ? "agency.communicate.dispatched" : "agency.invocation.dispatched", 1]);
|
|
20771
21311
|
}
|
|
@@ -20932,6 +21472,18 @@ var MotorSchemaExecutor = class {
|
|
|
20932
21472
|
};
|
|
20933
21473
|
set.push(outcomeEntity(tick, intent, out, predicted));
|
|
20934
21474
|
del.push(id);
|
|
21475
|
+
if (result.success)
|
|
21476
|
+
set.push(consequenceEntity({
|
|
21477
|
+
intentId: id,
|
|
21478
|
+
schema: intent.schema,
|
|
21479
|
+
mode: "communicate",
|
|
21480
|
+
effector,
|
|
21481
|
+
...intent.targetEntityId ? { targetEntityId: intent.targetEntityId } : {},
|
|
21482
|
+
textHash: fnv1a(bubbles.join("\n")),
|
|
21483
|
+
text: bubbles.join("\n"),
|
|
21484
|
+
expiresAt: tick + CONSEQUENCE_TTL_TICKS,
|
|
21485
|
+
tick
|
|
21486
|
+
}));
|
|
20935
21487
|
this._emitEnacted(intent, out, predicted, tick);
|
|
20936
21488
|
this._emitActionOutcome(
|
|
20937
21489
|
intent,
|
|
@@ -21070,6 +21622,10 @@ function errMsg(err) {
|
|
|
21070
21622
|
|
|
21071
21623
|
// src/cognition/agency/engines/reafference.engine.ts
|
|
21072
21624
|
var PROC_THRESHOLD2 = 0.6;
|
|
21625
|
+
var SENSORY_SOFT_QUALITY = 0.6;
|
|
21626
|
+
var SENSORY_VALENCE_SPAN_ENTITY = 0.25;
|
|
21627
|
+
var SENSORY_VALENCE_SPAN_AMBIENT = 0.1;
|
|
21628
|
+
var SENSORY_SUCCESS_FLOOR = 0.5;
|
|
21073
21629
|
var ReafferenceEngine = class {
|
|
21074
21630
|
name = "reafference";
|
|
21075
21631
|
_repertoire;
|
|
@@ -21119,14 +21675,76 @@ var ReafferenceEngine = class {
|
|
|
21119
21675
|
const set = [];
|
|
21120
21676
|
const del = [];
|
|
21121
21677
|
const metrics = [];
|
|
21122
|
-
|
|
21123
|
-
|
|
21678
|
+
const outcomes = [];
|
|
21679
|
+
const gradedIntentIds = /* @__PURE__ */ new Set();
|
|
21124
21680
|
for (const [id, e] of state.entities) {
|
|
21125
21681
|
if (e.type !== "agency.outcome") continue;
|
|
21126
21682
|
const m = e.metadata ?? {};
|
|
21683
|
+
outcomes.push({ id, meta: m, fromState: true });
|
|
21684
|
+
const iid = str6(m["intentId"]);
|
|
21685
|
+
if (iid) gradedIntentIds.add(iid);
|
|
21686
|
+
}
|
|
21687
|
+
const awaiting = /* @__PURE__ */ new Map();
|
|
21688
|
+
for (const [id, e] of state.entities) {
|
|
21689
|
+
if (e.type !== "agency.intent" || str6(e.metadata?.["status"]) !== "awaiting") continue;
|
|
21690
|
+
const m = e.metadata ?? {};
|
|
21691
|
+
if (tick - num4(m["dispatchedAt"], tick) >= AWAIT_TIMEOUT) continue;
|
|
21692
|
+
awaiting.set(id, {
|
|
21693
|
+
schema: str6(m["schema"]) ?? "",
|
|
21694
|
+
predictedReward: num4(m["predictedReward"], 0.5),
|
|
21695
|
+
predictedValence: num4(m["predictedValence"], 0)
|
|
21696
|
+
});
|
|
21697
|
+
}
|
|
21698
|
+
let sensory = 0;
|
|
21699
|
+
const sensedIntentIds = /* @__PURE__ */ new Set();
|
|
21700
|
+
for (const [, e] of state.entities) {
|
|
21701
|
+
if (e.type !== "percept") continue;
|
|
21702
|
+
const m = e.metadata ?? {};
|
|
21703
|
+
if (str6(m["provenance"]) !== "reafferent") continue;
|
|
21704
|
+
const iid = str6(m["sourceIntentId"]);
|
|
21705
|
+
if (!iid || gradedIntentIds.has(iid) || sensedIntentIds.has(iid)) continue;
|
|
21706
|
+
const aw = awaiting.get(iid);
|
|
21707
|
+
if (!aw || !aw.schema) continue;
|
|
21708
|
+
sensedIntentIds.add(iid);
|
|
21709
|
+
sensory++;
|
|
21710
|
+
const feltRaw = m["valence"];
|
|
21711
|
+
const felt = typeof feltRaw === "number" && Number.isFinite(feltRaw) ? feltRaw : void 0;
|
|
21712
|
+
const span = str6(m["valenceSource"]) === "entity" ? SENSORY_VALENCE_SPAN_ENTITY : SENSORY_VALENCE_SPAN_AMBIENT;
|
|
21713
|
+
const quality = felt === void 0 ? SENSORY_SOFT_QUALITY : clamp0111(SENSORY_SOFT_QUALITY + Math.max(-1, Math.min(1, felt)) * span);
|
|
21714
|
+
outcomes.push({ id: `agency-outcome-${tick}-${iid}-sensory`, fromState: false, meta: {
|
|
21715
|
+
schema: aw.schema,
|
|
21716
|
+
intentId: iid,
|
|
21717
|
+
success: quality >= SENSORY_SUCCESS_FLOOR,
|
|
21718
|
+
outcomeQuality: quality,
|
|
21719
|
+
valence: felt ?? aw.predictedValence,
|
|
21720
|
+
predictedReward: aw.predictedReward,
|
|
21721
|
+
predictedValence: aw.predictedValence,
|
|
21722
|
+
surprise: clamp0111(Math.abs(aw.predictedReward - quality)),
|
|
21723
|
+
mode: "external",
|
|
21724
|
+
reconciled: true,
|
|
21725
|
+
sensory: true,
|
|
21726
|
+
...felt !== void 0 ? { sensoryValence: felt, valenceSource: str6(m["valenceSource"]) } : {},
|
|
21727
|
+
tick
|
|
21728
|
+
} });
|
|
21729
|
+
}
|
|
21730
|
+
let updates = 0;
|
|
21731
|
+
let discovered = 0;
|
|
21732
|
+
let refused = 0;
|
|
21733
|
+
for (const { id, meta: m, fromState } of outcomes) {
|
|
21127
21734
|
const schema = str6(m["schema"]);
|
|
21128
21735
|
if (!schema) {
|
|
21129
|
-
del.push(id);
|
|
21736
|
+
if (fromState) del.push(id);
|
|
21737
|
+
continue;
|
|
21738
|
+
}
|
|
21739
|
+
if (m["refused"] === true) {
|
|
21740
|
+
const finality = str6(m["finality"]) === "class" ? "class" : "instance";
|
|
21741
|
+
this._repertoire.recordRefusal(schema, finality, tick);
|
|
21742
|
+
if (fromState) del.push(id);
|
|
21743
|
+
const refusedIntent = str6(m["intentId"]);
|
|
21744
|
+
if (refusedIntent) del.push(refusedIntent);
|
|
21745
|
+
const refusedPlan = str6(m["planId"]);
|
|
21746
|
+
if (refusedPlan) this._emitPlanOutcome(refusedPlan, str6(m["stepId"]), schema, false, 0, 0, tick);
|
|
21747
|
+
refused++;
|
|
21130
21748
|
continue;
|
|
21131
21749
|
}
|
|
21132
21750
|
const { skill, proceduralized } = this._repertoire.recordOutcome({
|
|
@@ -21138,7 +21756,7 @@ var ReafferenceEngine = class {
|
|
|
21138
21756
|
tick
|
|
21139
21757
|
});
|
|
21140
21758
|
set.push(skillEntity(skill));
|
|
21141
|
-
del.push(id);
|
|
21759
|
+
if (fromState) del.push(id);
|
|
21142
21760
|
const intentId = str6(m["intentId"]);
|
|
21143
21761
|
if (intentId) del.push(intentId);
|
|
21144
21762
|
updates++;
|
|
@@ -21155,19 +21773,24 @@ var ReafferenceEngine = class {
|
|
|
21155
21773
|
}
|
|
21156
21774
|
}
|
|
21157
21775
|
const dropped = this._repertoire.decay(tick);
|
|
21158
|
-
for (const id of dropped) {
|
|
21776
|
+
for (const id of dropped.skills) {
|
|
21159
21777
|
del.push(`agency-skill-${id}`);
|
|
21160
21778
|
del.push(schemaEntityId(id));
|
|
21161
21779
|
}
|
|
21780
|
+
for (const id of dropped.availability)
|
|
21781
|
+
del.push(availabilityEntityId(id));
|
|
21162
21782
|
for (const e of this._repertoire.compositeEntities()) set.push(e);
|
|
21783
|
+
for (const e of this._repertoire.availabilityEntities()) set.push(e);
|
|
21163
21784
|
const skills = this._repertoire.skills();
|
|
21164
21785
|
const habitual = [...skills.values()].filter((s) => s.habitStrength >= PROC_THRESHOLD2).length;
|
|
21165
21786
|
metrics.push(
|
|
21166
21787
|
["agency.learning.updates", updates],
|
|
21167
21788
|
["agency.discovered.count", discovered],
|
|
21168
21789
|
["agency.skill.count", skills.size],
|
|
21169
|
-
["agency.habitual.count", habitual]
|
|
21790
|
+
["agency.habitual.count", habitual],
|
|
21791
|
+
["agency.sensory.confirmed", sensory]
|
|
21170
21792
|
);
|
|
21793
|
+
if (refused > 0) metrics.push(["agency.refused.count", refused]);
|
|
21171
21794
|
return { commands: { set, delete: del, metrics } };
|
|
21172
21795
|
}
|
|
21173
21796
|
_emitProceduralized(skill, tick) {
|
|
@@ -21250,6 +21873,9 @@ function str6(v) {
|
|
|
21250
21873
|
function num4(v, fallback) {
|
|
21251
21874
|
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
21252
21875
|
}
|
|
21876
|
+
function clamp0111(n) {
|
|
21877
|
+
return n < 0 ? 0 : n > 1 ? 1 : n;
|
|
21878
|
+
}
|
|
21253
21879
|
|
|
21254
21880
|
// src/cognition/config.mirror.entities.ts
|
|
21255
21881
|
function buildEngineConfigEntities(config, executiveInterval) {
|
|
@@ -23981,6 +24607,10 @@ var OutboxController = class {
|
|
|
23981
24607
|
summary: delivered ? `My message was delivered successfully.` : `My message failed to reach the recipient.`,
|
|
23982
24608
|
salience: delivered ? 0.35 : 0.6,
|
|
23983
24609
|
changeType: delivered ? "delivered" : "failed",
|
|
24610
|
+
// Reafference by construction — this percept describes our own action's
|
|
24611
|
+
// outcome ("ear hears the word"). Tagged, not attenuated: it is the ack
|
|
24612
|
+
// surface, not a content echo (EXAFFERENCE P2).
|
|
24613
|
+
provenance: "reafferent",
|
|
23984
24614
|
messageId
|
|
23985
24615
|
}
|
|
23986
24616
|
});
|
|
@@ -24382,7 +25012,7 @@ var InboundQueue = class {
|
|
|
24382
25012
|
function reconcileInvocation(intentId, schema, result, tick, predicted = { reward: 0.5, valence: 0 }, provenance = {}) {
|
|
24383
25013
|
const outcomeQuality = result.outcomeQuality ?? (result.success ? 0.8 : 0.1);
|
|
24384
25014
|
const valence = result.valence ?? (result.success ? 0.2 : -0.2);
|
|
24385
|
-
const surprise =
|
|
25015
|
+
const surprise = clamp0112(Math.abs(predicted.reward - outcomeQuality));
|
|
24386
25016
|
return {
|
|
24387
25017
|
id: `agency-outcome-${tick}-${intentId}`,
|
|
24388
25018
|
type: "agency.outcome",
|
|
@@ -24399,17 +25029,66 @@ function reconcileInvocation(intentId, schema, result, tick, predicted = { rewar
|
|
|
24399
25029
|
mode: "external",
|
|
24400
25030
|
tick,
|
|
24401
25031
|
reconciled: true,
|
|
25032
|
+
...result.refused ? { refused: true, finality: result.finality ?? "instance" } : {},
|
|
24402
25033
|
...provenance.planId ? { planId: provenance.planId } : {},
|
|
24403
25034
|
...provenance.stepId ? { stepId: provenance.stepId } : {}
|
|
24404
25035
|
}
|
|
24405
25036
|
};
|
|
24406
25037
|
}
|
|
24407
|
-
function
|
|
25038
|
+
function clamp0112(n) {
|
|
24408
25039
|
return n < 0 ? 0 : n > 1 ? 1 : n;
|
|
24409
25040
|
}
|
|
24410
25041
|
|
|
25042
|
+
// src/stem/policy/arbiter.ts
|
|
25043
|
+
var ALLOW = Object.freeze({ decision: "allow" });
|
|
25044
|
+
var NULL_ARBITER = {
|
|
25045
|
+
name: "null",
|
|
25046
|
+
evaluate() {
|
|
25047
|
+
return ALLOW;
|
|
25048
|
+
}
|
|
25049
|
+
};
|
|
25050
|
+
function isNullArbiter(arbiter) {
|
|
25051
|
+
return !arbiter || arbiter === NULL_ARBITER;
|
|
25052
|
+
}
|
|
25053
|
+
|
|
25054
|
+
// src/stem/policy/verdict.recorder.ts
|
|
25055
|
+
var _sinks3 = /* @__PURE__ */ new Map();
|
|
25056
|
+
function getVerdictRecorder(willId) {
|
|
25057
|
+
return _sinks3.get(willId);
|
|
25058
|
+
}
|
|
25059
|
+
var _sources3 = /* @__PURE__ */ new Map();
|
|
25060
|
+
function getVerdictSource(willId) {
|
|
25061
|
+
return _sources3.get(willId);
|
|
25062
|
+
}
|
|
25063
|
+
|
|
24411
25064
|
// src/stem/tracts/effector.controller.ts
|
|
25065
|
+
var ESCALATION_TTL_TICKS = 30;
|
|
24412
25066
|
var effectorController = class {
|
|
25067
|
+
/** The Policy Decision Point consulted before an invocation reaches the world.
|
|
25068
|
+
* Defaults to the no-op arbiter, so an unconfigured Will is byte-identical. */
|
|
25069
|
+
_arbiter = NULL_ARBITER;
|
|
25070
|
+
/**
|
|
25071
|
+
* Denials queued during a step's flush, drained at the NEXT tick boundary
|
|
25072
|
+
* (POLICY_REAFFERENCE P1). Keyed by willId — harness state, exactly like
|
|
25073
|
+
* `pendingEffectorInvocations`; never simulation state, so it does not touch
|
|
25074
|
+
* `simulation.step` determinism and is regenerated on any re-execution.
|
|
25075
|
+
*/
|
|
25076
|
+
_pendingRefusals = /* @__PURE__ */ new Map();
|
|
25077
|
+
/** Escalations awaiting their first application (mark intent + voice the ask). */
|
|
25078
|
+
_newEscalations = /* @__PURE__ */ new Map();
|
|
25079
|
+
/** Escalations currently held, keyed by intent id — the resolvable set. */
|
|
25080
|
+
_activeEscalations = /* @__PURE__ */ new Map();
|
|
25081
|
+
/** Host answers awaiting application at the next tick boundary. */
|
|
25082
|
+
_pendingResolutions = /* @__PURE__ */ new Map();
|
|
25083
|
+
/**
|
|
25084
|
+
* Install a Policy Decision Point (POLICY_REAFFERENCE P0). Passing null
|
|
25085
|
+
* restores the no-op default. The arbiter sees only the proposed act — never
|
|
25086
|
+
* simulation state — and its verdict decides whether the invocation is
|
|
25087
|
+
* handed to the host at all.
|
|
25088
|
+
*/
|
|
25089
|
+
setArbiter(arbiter) {
|
|
25090
|
+
this._arbiter = arbiter ?? NULL_ARBITER;
|
|
25091
|
+
}
|
|
24413
25092
|
/**
|
|
24414
25093
|
* Update the set of allowed communication effectors at runtime via AccessGrants
|
|
24415
25094
|
* (the permission / sense gate the senses + reply path read).
|
|
@@ -24425,6 +25104,224 @@ var effectorController = class {
|
|
|
24425
25104
|
* echoes it on its result-ack, and `confirmExecution` uses it to find the intent.
|
|
24426
25105
|
*/
|
|
24427
25106
|
bufferInvocation(instance, payload) {
|
|
25107
|
+
const willId = instance.config.id;
|
|
25108
|
+
const source = getVerdictSource(willId);
|
|
25109
|
+
if (source) {
|
|
25110
|
+
const invocation2 = toPolicyInvocation(instance, payload);
|
|
25111
|
+
const record = source.verdictFor(invocation2.tick, invocation2.intentId);
|
|
25112
|
+
if (record) this._applyVerdict(instance, payload, invocation2, recordToVerdict(record));
|
|
25113
|
+
else this._buffer(instance, payload);
|
|
25114
|
+
return;
|
|
25115
|
+
}
|
|
25116
|
+
if (isNullArbiter(this._arbiter)) {
|
|
25117
|
+
this._buffer(instance, payload);
|
|
25118
|
+
return;
|
|
25119
|
+
}
|
|
25120
|
+
const invocation = toPolicyInvocation(instance, payload);
|
|
25121
|
+
let verdict;
|
|
25122
|
+
try {
|
|
25123
|
+
verdict = this._arbiter.evaluate(invocation);
|
|
25124
|
+
} catch (err) {
|
|
25125
|
+
logger.error(`[policy] arbiter "${this._arbiter.name}" threw for "${invocation.schema}" \u2014 failing closed:`, err);
|
|
25126
|
+
return;
|
|
25127
|
+
}
|
|
25128
|
+
if (verdict instanceof Promise) {
|
|
25129
|
+
void verdict.then(
|
|
25130
|
+
(v) => this._recordAndApply(instance, payload, invocation, v),
|
|
25131
|
+
(err) => logger.error(`[policy] arbiter "${this._arbiter.name}" rejected for "${invocation.schema}" \u2014 failing closed:`, err)
|
|
25132
|
+
);
|
|
25133
|
+
return;
|
|
25134
|
+
}
|
|
25135
|
+
this._recordAndApply(instance, payload, invocation, verdict);
|
|
25136
|
+
}
|
|
25137
|
+
/** Capture the verdict on the tape (if a recorder is attached), then enforce it. */
|
|
25138
|
+
_recordAndApply(instance, payload, invocation, verdict) {
|
|
25139
|
+
const sink = getVerdictRecorder(instance.config.id);
|
|
25140
|
+
sink?.recordVerdict({
|
|
25141
|
+
tick: invocation.tick,
|
|
25142
|
+
willId: instance.config.id,
|
|
25143
|
+
intentId: invocation.intentId,
|
|
25144
|
+
schema: invocation.schema,
|
|
25145
|
+
arbiter: this._arbiter.name,
|
|
25146
|
+
decision: verdict.decision,
|
|
25147
|
+
...verdict.reasonCode ? { reasonCode: verdict.reasonCode } : {},
|
|
25148
|
+
...verdict.finality ? { finality: verdict.finality } : {},
|
|
25149
|
+
...verdict.counterfactual ? { counterfactual: verdict.counterfactual } : {},
|
|
25150
|
+
timestamp: Date.now()
|
|
25151
|
+
});
|
|
25152
|
+
this._applyVerdict(instance, payload, invocation, verdict);
|
|
25153
|
+
}
|
|
25154
|
+
/**
|
|
25155
|
+
* Enforce a verdict (POLICY_REAFFERENCE P1).
|
|
25156
|
+
*
|
|
25157
|
+
* • allow → hand the invocation to the world.
|
|
25158
|
+
* • deny → queue a refusal ack, applied at the next tick boundary via
|
|
25159
|
+
* `confirmExecution` — the same lifecycle as a host rejection,
|
|
25160
|
+
* so the mind meets *world resistance*, not a permission dialog.
|
|
25161
|
+
* • escalate → raise a held escalation (POLICY_REAFFERENCE P4): the intent is
|
|
25162
|
+
* held (the executor stops timing it out), the Will voices a
|
|
25163
|
+
* first-person ask once, and a host resolution later approves
|
|
25164
|
+
* (dispatch) or denies (refuse). Unresolved, it degrades to a
|
|
25165
|
+
* refusal at ESCALATION_TTL_TICKS.
|
|
25166
|
+
*
|
|
25167
|
+
* P1's refusal reconciles as a plain FAILURE — safe, but the wrong learning
|
|
25168
|
+
* signal (forbidden ≠ unskilled). P2 routes it to affordance AVAILABILITY
|
|
25169
|
+
* instead of competence.
|
|
25170
|
+
*/
|
|
25171
|
+
_applyVerdict(instance, payload, invocation, verdict) {
|
|
25172
|
+
if (verdict.decision === "allow") {
|
|
25173
|
+
this._buffer(instance, payload);
|
|
25174
|
+
return;
|
|
25175
|
+
}
|
|
25176
|
+
const cf = verdict.counterfactual;
|
|
25177
|
+
logger.info(
|
|
25178
|
+
`[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)}]` : "")
|
|
25179
|
+
);
|
|
25180
|
+
if (verdict.decision === "deny") {
|
|
25181
|
+
const queue = this._pendingRefusals.get(instance.config.id) ?? [];
|
|
25182
|
+
queue.push({
|
|
25183
|
+
intentId: invocation.intentId,
|
|
25184
|
+
schema: invocation.schema,
|
|
25185
|
+
reasonCode: verdict.reasonCode ?? "POLICY_DENIED",
|
|
25186
|
+
finality: verdict.finality ?? "instance"
|
|
25187
|
+
});
|
|
25188
|
+
this._pendingRefusals.set(instance.config.id, queue);
|
|
25189
|
+
return;
|
|
25190
|
+
}
|
|
25191
|
+
const escalations = this._newEscalations.get(instance.config.id) ?? [];
|
|
25192
|
+
escalations.push({
|
|
25193
|
+
intentId: invocation.intentId,
|
|
25194
|
+
schema: invocation.schema,
|
|
25195
|
+
reasonCode: verdict.reasonCode ?? "APPROVAL_REQUIRED",
|
|
25196
|
+
payload,
|
|
25197
|
+
expiresAt: 0
|
|
25198
|
+
// stamped when applied (we don't have the current tick here)
|
|
25199
|
+
});
|
|
25200
|
+
this._newEscalations.set(instance.config.id, escalations);
|
|
25201
|
+
}
|
|
25202
|
+
/**
|
|
25203
|
+
* Record a host's answer to an escalation (POLICY_REAFFERENCE P4). Applied at
|
|
25204
|
+
* the next tick boundary so every simulation-state write stays on the boundary:
|
|
25205
|
+
* approve dispatches the held invocation to the world; deny refuses it. A
|
|
25206
|
+
* no-op if the intent id is not (or no longer) an active escalation.
|
|
25207
|
+
*/
|
|
25208
|
+
resolveEscalation(instance, intentId, approved) {
|
|
25209
|
+
const queue = this._pendingResolutions.get(instance.config.id) ?? [];
|
|
25210
|
+
queue.push({ intentId, approved });
|
|
25211
|
+
this._pendingResolutions.set(instance.config.id, queue);
|
|
25212
|
+
}
|
|
25213
|
+
/**
|
|
25214
|
+
* Apply queued policy refusals as failure acks (POLICY_REAFFERENCE P1).
|
|
25215
|
+
* Called by the tick loop at the same boundary as inbound acks — BEFORE the
|
|
25216
|
+
* step, stamped to this tick — so a denial reconciled here is the exact
|
|
25217
|
+
* lifecycle of a host rejection that arrived between ticks.
|
|
25218
|
+
*/
|
|
25219
|
+
applyPolicyOutcomes(instance) {
|
|
25220
|
+
const tick = instance.tickCount;
|
|
25221
|
+
this._applyResolutions(instance);
|
|
25222
|
+
this._expireEscalations(instance, tick);
|
|
25223
|
+
this._applyNewEscalations(instance, tick);
|
|
25224
|
+
this._applyRefusals(instance);
|
|
25225
|
+
}
|
|
25226
|
+
/** Drain queued refusals into failure acks (POLICY_REAFFERENCE P1). */
|
|
25227
|
+
_applyRefusals(instance) {
|
|
25228
|
+
const queue = this._pendingRefusals.get(instance.config.id);
|
|
25229
|
+
if (!queue || queue.length === 0) return;
|
|
25230
|
+
this._pendingRefusals.set(instance.config.id, []);
|
|
25231
|
+
for (const refusal of queue)
|
|
25232
|
+
this.confirmExecution(instance, refusal.intentId, {
|
|
25233
|
+
success: false,
|
|
25234
|
+
refused: true,
|
|
25235
|
+
finality: refusal.finality === "class" ? "class" : "instance",
|
|
25236
|
+
description: `refused by policy: ${refusal.reasonCode} (${refusal.finality})`
|
|
25237
|
+
});
|
|
25238
|
+
}
|
|
25239
|
+
/** Raise each newly-escalated intent (POLICY_REAFFERENCE P4): mark it held in
|
|
25240
|
+
* simulation state, voice the ask ONCE, and move it to the resolvable set. */
|
|
25241
|
+
_applyNewEscalations(instance, tick) {
|
|
25242
|
+
const pending = this._newEscalations.get(instance.config.id);
|
|
25243
|
+
if (!pending || pending.length === 0) return;
|
|
25244
|
+
this._newEscalations.set(instance.config.id, []);
|
|
25245
|
+
const active = this._activeEscalations.get(instance.config.id) ?? /* @__PURE__ */ new Map();
|
|
25246
|
+
for (const esc of pending) {
|
|
25247
|
+
esc.expiresAt = tick + ESCALATION_TTL_TICKS;
|
|
25248
|
+
this._markEscalated(instance, esc.intentId, esc.expiresAt);
|
|
25249
|
+
this._voiceEscalation(instance, esc);
|
|
25250
|
+
active.set(esc.intentId, esc);
|
|
25251
|
+
}
|
|
25252
|
+
this._activeEscalations.set(instance.config.id, active);
|
|
25253
|
+
}
|
|
25254
|
+
/** Apply host answers to active escalations (POLICY_REAFFERENCE P4). */
|
|
25255
|
+
_applyResolutions(instance) {
|
|
25256
|
+
const queue = this._pendingResolutions.get(instance.config.id);
|
|
25257
|
+
if (!queue || queue.length === 0) return;
|
|
25258
|
+
this._pendingResolutions.set(instance.config.id, []);
|
|
25259
|
+
const active = this._activeEscalations.get(instance.config.id);
|
|
25260
|
+
for (const { intentId, approved } of queue) {
|
|
25261
|
+
const esc = active?.get(intentId);
|
|
25262
|
+
if (!esc) continue;
|
|
25263
|
+
active.delete(intentId);
|
|
25264
|
+
this._clearEscalated(instance, intentId);
|
|
25265
|
+
if (approved) {
|
|
25266
|
+
this._buffer(instance, esc.payload);
|
|
25267
|
+
logger.info(`[policy] escalation APPROVED \u2192 dispatching "${esc.schema}" intent "${intentId}"`);
|
|
25268
|
+
} else {
|
|
25269
|
+
this._queueRefusal(instance, esc.intentId, esc.schema, esc.reasonCode, "class");
|
|
25270
|
+
logger.info(`[policy] escalation DENIED \u2192 refusing "${esc.schema}" intent "${intentId}"`);
|
|
25271
|
+
}
|
|
25272
|
+
}
|
|
25273
|
+
}
|
|
25274
|
+
/** Degrade escalations no one answered in time into instance-refusals (P4). */
|
|
25275
|
+
_expireEscalations(instance, tick) {
|
|
25276
|
+
const active = this._activeEscalations.get(instance.config.id);
|
|
25277
|
+
if (!active || active.size === 0) return;
|
|
25278
|
+
for (const [intentId, esc] of active) {
|
|
25279
|
+
if (tick < esc.expiresAt) continue;
|
|
25280
|
+
active.delete(intentId);
|
|
25281
|
+
this._clearEscalated(instance, intentId);
|
|
25282
|
+
this._queueRefusal(instance, esc.intentId, esc.schema, "ESCALATION_EXPIRED", "instance");
|
|
25283
|
+
logger.info(`[policy] escalation EXPIRED \u2192 refusing "${esc.schema}" intent "${intentId}"`);
|
|
25284
|
+
}
|
|
25285
|
+
}
|
|
25286
|
+
/** Push a refusal onto the queue drained by _applyRefusals this same tick. */
|
|
25287
|
+
_queueRefusal(instance, intentId, schema, reasonCode, finality) {
|
|
25288
|
+
const queue = this._pendingRefusals.get(instance.config.id) ?? [];
|
|
25289
|
+
queue.push({ intentId, schema, reasonCode, finality });
|
|
25290
|
+
this._pendingRefusals.set(instance.config.id, queue);
|
|
25291
|
+
}
|
|
25292
|
+
/** Mark the awaiting intent held: the executor stops timing it out (P4). */
|
|
25293
|
+
_markEscalated(instance, intentId, expiresAt) {
|
|
25294
|
+
const intent = instance.simulation.stateManager.snapshot().entities.get(intentId);
|
|
25295
|
+
if (!intent || intent.type !== "agency.intent") return;
|
|
25296
|
+
instance.simulation.stateManager.setEntity({
|
|
25297
|
+
id: intent.id,
|
|
25298
|
+
type: intent.type,
|
|
25299
|
+
metadata: { ...intent.metadata ?? {}, escalated: true, escalationExpiresAt: expiresAt }
|
|
25300
|
+
});
|
|
25301
|
+
}
|
|
25302
|
+
/** Release the hold so the executor resumes normal timeout for this intent. */
|
|
25303
|
+
_clearEscalated(instance, intentId) {
|
|
25304
|
+
const intent = instance.simulation.stateManager.snapshot().entities.get(intentId);
|
|
25305
|
+
if (!intent || intent.type !== "agency.intent") return;
|
|
25306
|
+
const meta = { ...intent.metadata ?? {} };
|
|
25307
|
+
delete meta["escalated"];
|
|
25308
|
+
delete meta["escalationExpiresAt"];
|
|
25309
|
+
instance.simulation.stateManager.setEntity({ id: intent.id, type: intent.type, metadata: meta });
|
|
25310
|
+
}
|
|
25311
|
+
/** Voice the escalation as a first-person broadcast ask — once, at raise time. */
|
|
25312
|
+
_voiceEscalation(instance, esc) {
|
|
25313
|
+
try {
|
|
25314
|
+
instance.cognition.outboxWriter.enqueue({
|
|
25315
|
+
targetEntityId: "*",
|
|
25316
|
+
content: escalationAsk(esc.schema, esc.reasonCode),
|
|
25317
|
+
effectorName: "broadcast"
|
|
25318
|
+
});
|
|
25319
|
+
} catch (err) {
|
|
25320
|
+
logger.warn(`[policy] escalation voice failed for "${esc.schema}": ${errMsg2(err)}`);
|
|
25321
|
+
}
|
|
25322
|
+
}
|
|
25323
|
+
/** Queue an approved invocation for the delivery layer. */
|
|
25324
|
+
_buffer(instance, payload) {
|
|
24428
25325
|
const intentId = payload.intentId ?? "";
|
|
24429
25326
|
instance.pendingEffectorInvocations.push({
|
|
24430
25327
|
id: intentId,
|
|
@@ -24499,6 +25396,38 @@ var effectorController = class {
|
|
|
24499
25396
|
function num5(v, fallback) {
|
|
24500
25397
|
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
24501
25398
|
}
|
|
25399
|
+
function escalationAsk(schema, reasonCode) {
|
|
25400
|
+
const meaning = ESCALATION_MEANINGS[reasonCode] ?? "I need your approval before I can do this";
|
|
25401
|
+
return `I want to ${schema}, but ${meaning}. May I go ahead?`;
|
|
25402
|
+
}
|
|
25403
|
+
var ESCALATION_MEANINGS = {
|
|
25404
|
+
APPROVAL_REQUIRED: "I need your approval before I can on my own",
|
|
25405
|
+
WRITE_REQUIRES_APPROVAL: "it writes to the world and I shouldn't on my own",
|
|
25406
|
+
PAYMENT_REQUIRES_APPROVAL: "it moves money and I must not do that unattended",
|
|
25407
|
+
DEPLOY_REQUIRES_APPROVAL: "it ships something and needs a human to sign off"
|
|
25408
|
+
};
|
|
25409
|
+
function errMsg2(err) {
|
|
25410
|
+
return err instanceof Error ? err.message : String(err);
|
|
25411
|
+
}
|
|
25412
|
+
function recordToVerdict(record) {
|
|
25413
|
+
return {
|
|
25414
|
+
decision: record.decision,
|
|
25415
|
+
...record.reasonCode ? { reasonCode: record.reasonCode } : {},
|
|
25416
|
+
...record.finality ? { finality: record.finality } : {},
|
|
25417
|
+
...record.counterfactual ? { counterfactual: record.counterfactual } : {}
|
|
25418
|
+
};
|
|
25419
|
+
}
|
|
25420
|
+
function toPolicyInvocation(instance, payload) {
|
|
25421
|
+
return {
|
|
25422
|
+
willId: instance.config.id,
|
|
25423
|
+
intentId: payload.intentId ?? "",
|
|
25424
|
+
schema: payload.schema ?? "",
|
|
25425
|
+
parameters: payload.parameters ?? {},
|
|
25426
|
+
...typeof payload.targetEntityId === "string" ? { targetEntityId: payload.targetEntityId } : {},
|
|
25427
|
+
...typeof payload.description === "string" ? { description: payload.description } : {},
|
|
25428
|
+
tick: payload.tick ?? 0
|
|
25429
|
+
};
|
|
25430
|
+
}
|
|
24502
25431
|
|
|
24503
25432
|
// src/stem/tracts/sensory.controller.ts
|
|
24504
25433
|
var SensoryController = class {
|
|
@@ -25301,6 +26230,15 @@ var WillStem = class {
|
|
|
25301
26230
|
confirmEffectorExecution(id, invocationId, result) {
|
|
25302
26231
|
this._effector.confirmExecution(this._get(id), invocationId, result);
|
|
25303
26232
|
}
|
|
26233
|
+
/**
|
|
26234
|
+
* Resolve a policy escalation the Will raised (POLICY_REAFFERENCE P4).
|
|
26235
|
+
* `approved` dispatches the held invocation to the world; otherwise it is
|
|
26236
|
+
* refused. Applied at the next tick boundary. `invocationId` is the awaiting
|
|
26237
|
+
* `agency.intent` id the escalation ask referenced.
|
|
26238
|
+
*/
|
|
26239
|
+
resolveEscalation(id, invocationId, approved) {
|
|
26240
|
+
this._effector.resolveEscalation(this._get(id), invocationId, approved);
|
|
26241
|
+
}
|
|
25304
26242
|
// ── Messaging / outbox (11.1) ────────────────────────────────────────────
|
|
25305
26243
|
// Delegates to OutboxController (R5-c). `_get(id)` validates the Will exists
|
|
25306
26244
|
// and supplies the WillInstance; the outbox ops touch only instance fields.
|
|
@@ -25431,6 +26369,7 @@ var WillStem = class {
|
|
|
25431
26369
|
outbox: this._outbox,
|
|
25432
26370
|
sensory: this._sensory
|
|
25433
26371
|
});
|
|
26372
|
+
this._effector.applyPolicyOutcomes(instance);
|
|
25434
26373
|
await instance.simulation.step(1);
|
|
25435
26374
|
instance.tickCount++;
|
|
25436
26375
|
instance.lastTickAt = /* @__PURE__ */ new Date();
|