@adam0white/human-framework 2.18.0 → 2.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/dist/agenda/agenda.d.ts +47 -0
- package/dist/agenda/agenda.js +4 -1
- package/dist/chronicle/story.js +3 -2
- package/dist/conversation/conversation.js +10 -4
- package/dist/family/family.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/longrun.js +1 -1
- package/dist/narrate/lexicon.d.ts +2 -1
- package/dist/narrate/lexicon.js +2 -1
- package/dist/narrate/narrate.d.ts +14 -1
- package/dist/narrate/narrate.js +81 -39
- package/dist/narrate/plain.d.ts +7 -0
- package/dist/narrate/plain.js +293 -0
- package/dist/partnering/partnering.js +1 -1
- package/dist/person.js +34 -7
- package/dist/presentation.d.ts +10 -0
- package/dist/presentation.js +88 -0
- package/dist/promptings/promptings.d.ts +1 -0
- package/dist/promptings/promptings.js +40 -4
- package/dist/prospection/forecast.d.ts +2 -0
- package/dist/prospection/forecast.js +15 -1
- package/dist/review/review.d.ts +32 -0
- package/dist/review/review.js +6 -2
- package/dist/scenarios/village.js +63 -26
- package/dist/sim/longrun.js +20 -3
- package/dist/sim/sim.d.ts +1 -1
- package/dist/sim/sim.js +93 -15
- package/dist/types.d.ts +2 -0
- package/dist/will/will.js +22 -4
- package/package.json +1 -1
package/dist/review/review.d.ts
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SCOPE (evening self-review, muhasaba, 2.7.0): once a day, from `at` (default 21:00), a person looks back over
|
|
3
|
+
* the commitments the chronicle recorded as kept or broken since their last review, and for each one they broke
|
|
4
|
+
* forms or renews a *resolve*: an if–then intention for that commitment's next occasion (Gollwitzer & Sheeran
|
|
5
|
+
* 2006, research/reconciliation.md E1). While a matching commitment is pending, the resolve adds one bounded term,
|
|
6
|
+
* `review:resolve` (each resolve counted once per option, the sum clamped to ±`resolveScale`; 2.9.0: the term's
|
|
7
|
+
* `ref` is the resolve's key when exactly one resolve weighed in), with the sign of the commitment's own term (toward a duty, away from an abstention's breaking
|
|
8
|
+
* act), scaled by its strength. Strength grows with diminishing gains at each further lapse, relaxes once the
|
|
9
|
+
* commitment is kept, and fades over `halfLifeDays` of disuse. Released and excused commitments (exemptions,
|
|
10
|
+
* sleep, necessity) form no resolve: what was beyond capacity is not held against the person (2:286). The review
|
|
11
|
+
* also runs when the day closes, if the evening passed without it or a lapse came after it.
|
|
12
|
+
*
|
|
13
|
+
* Held readings (`ReviewStyle`): `accounting` is self-accounting as the tradition describes it, naming the lapse
|
|
14
|
+
* with a view to tomorrow (Q 59:18, whose "tomorrow" most exegetes read as the hereafter, so a daily review is an
|
|
15
|
+
* inference; ʿUmar's saying reported by Tirmidhi after 2459, an athar, not a prophetic
|
|
16
|
+
* hadith) and turning back without despair (3:135, 39:53); it forms full resolves and adds no emotion. Reading accounting as
|
|
17
|
+
* non-punishing, like self-compassion after failure raising the motivation to repair (Breines & Chen 2012, E3),
|
|
18
|
+
* is an engineering mapping, not a finding about muhasaba. `ruminating` goes over
|
|
19
|
+
* the lapse abstractly: weaker resolves and a small distress emotion (Watkins 2008, E4: abstract, unconstructive
|
|
20
|
+
* repetitive thought). `none` never reviews. The review reads only chronicle notes and changes no other module's
|
|
21
|
+
* state except that one emotion.
|
|
22
|
+
*
|
|
23
|
+
* Every number is an engineering default, not fitted. Does not claim: divine reckoning or acceptance, a measure of
|
|
24
|
+
* piety, repentance as a ruling (tawba conditions are not modelled), effects on sleep onset (Harvey's model, E6, is
|
|
25
|
+
* not evidence enough), or that review improves outcomes beyond the borrowed if–then shape. It draws no randomness;
|
|
26
|
+
* without `enableReview` nothing here runs and existing runs replay byte for byte.
|
|
27
|
+
*
|
|
28
|
+
* Host notes (2.9.0, docs only). `reviewLine` sets commitment labels into "I didn't keep …" and "Today I kept …",
|
|
29
|
+
* so a label should be a noun phrase ("my call to Mum", "the evening prayer"), not a verb phrase ("calling Mum").
|
|
30
|
+
* A recurring commitment lapses on any day its window passes unlived: a host that skips a day (no service, a
|
|
31
|
+
* fast-forward) should still live, or release, that day's occasions, or the review counts each one as missed.
|
|
32
|
+
*/
|
|
1
33
|
import type { DayRecord, Minute, Person, ReviewRecord, ReviewSpec, ReviewState, ReviewStyle, Term } from '../types.ts';
|
|
2
34
|
export declare const REVIEW_DEFAULTS: {
|
|
3
35
|
/** Default evening review time, minute of day. */
|
package/dist/review/review.js
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
*/
|
|
33
33
|
import { clamp01, dexp, isObj, minuteOfDay, round } from '../core/index.js';
|
|
34
34
|
import { pickLine } from '../narrate/lexicon.js';
|
|
35
|
+
import { labelLine } from '../presentation.js';
|
|
35
36
|
export const REVIEW_DEFAULTS = {
|
|
36
37
|
/** Default evening review time, minute of day. */
|
|
37
38
|
at: 21 * 60,
|
|
@@ -198,7 +199,10 @@ export function reviewLine(p, options = {}) {
|
|
|
198
199
|
const r = st?.last;
|
|
199
200
|
if (!st || st.style === 'none' || !r)
|
|
200
201
|
return undefined;
|
|
201
|
-
const list = (
|
|
202
|
+
const list = (items) => {
|
|
203
|
+
const xs = items.map((item) => labelLine(item, p.lexicon));
|
|
204
|
+
return xs.length <= 1 ? (xs[0] ?? '') : `${xs.slice(0, -1).join(', ')} and ${xs.at(-1)}`;
|
|
205
|
+
};
|
|
202
206
|
if (r.missed.length === 0)
|
|
203
207
|
return r.kept.length > 0 ? `Today I kept ${list(r.kept)}.` : undefined;
|
|
204
208
|
if (options.cause) {
|
|
@@ -208,7 +212,7 @@ export function reviewLine(p, options = {}) {
|
|
|
208
212
|
: 'Next time I will make room to return to it.';
|
|
209
213
|
return pickLine('review.cause', `${p.id}:${r.day}`, { cause, missed: list(r.missed), next }, p.lexicon);
|
|
210
214
|
}
|
|
211
|
-
if (options.variety ?? p.lexicon?.variety) {
|
|
215
|
+
if (p.lexicon?.plainEnglish || (options.variety ?? p.lexicon?.variety)) {
|
|
212
216
|
return pickLine(`review.${st.style}`, `${p.id}:${r.day}`, { missed: list(r.missed) }, p.lexicon);
|
|
213
217
|
}
|
|
214
218
|
if (st.style === 'ruminating')
|
|
@@ -257,6 +257,7 @@ export function createVillage(people, opts) {
|
|
|
257
257
|
return out;
|
|
258
258
|
};
|
|
259
259
|
const resolve = (p, act, reason) => {
|
|
260
|
+
const say = (legacy, plain) => (p.lexicon?.plainEnglish ? plain : legacy);
|
|
260
261
|
const now = p.now;
|
|
261
262
|
state.now = Math.max(state.now, now);
|
|
262
263
|
const aff = act.affordance;
|
|
@@ -272,12 +273,16 @@ export function createVillage(people, opts) {
|
|
|
272
273
|
// Partial work counts: a field shift left early yields and pays pro rata for the time put in.
|
|
273
274
|
const span = Math.max(1, act.endsAt - act.startedAt);
|
|
274
275
|
const progress = clamp01((now - act.startedAt) / span);
|
|
275
|
-
const out = {
|
|
276
|
+
const out = {
|
|
277
|
+
...base,
|
|
278
|
+
status: 'interrupted',
|
|
279
|
+
summary: say(`${aff.label}: interrupted`, `I was interrupted during the task “${aff.label}”.`),
|
|
280
|
+
};
|
|
276
281
|
if (act.action === 'work-field' && progress > 0) {
|
|
277
282
|
state.food += V.fieldYield * progress;
|
|
278
283
|
out.material = V.wage * progress;
|
|
279
284
|
out.needs = { competence: 0.1 * progress };
|
|
280
|
-
out.summary = `${aff.label}: stopped ${Math.round(progress * 100)}% of the way through
|
|
285
|
+
out.summary = say(`${aff.label}: stopped ${Math.round(progress * 100)}% of the way through`, `I stopped the task “${aff.label}” after completing ${Math.round(progress * 100)}% of it.`);
|
|
281
286
|
}
|
|
282
287
|
return out;
|
|
283
288
|
}
|
|
@@ -291,17 +296,29 @@ export function createVillage(people, opts) {
|
|
|
291
296
|
case 'eat':
|
|
292
297
|
if (state.food >= 1) {
|
|
293
298
|
state.food -= 1;
|
|
294
|
-
return done({
|
|
299
|
+
return done({
|
|
300
|
+
...base,
|
|
301
|
+
needs: { food: 0.6 },
|
|
302
|
+
summary: say('ate at the kitchen', 'I ate at the kitchen.'),
|
|
303
|
+
});
|
|
295
304
|
}
|
|
296
|
-
return {
|
|
305
|
+
return {
|
|
306
|
+
...base,
|
|
307
|
+
status: 'failed',
|
|
308
|
+
summary: say('found the kitchen empty', 'I found the kitchen empty.'),
|
|
309
|
+
};
|
|
297
310
|
case 'drink':
|
|
298
|
-
return done({
|
|
311
|
+
return done({
|
|
312
|
+
...base,
|
|
313
|
+
needs: { water: 0.6 },
|
|
314
|
+
summary: say('drank at the well', 'I drank at the well.'),
|
|
315
|
+
});
|
|
299
316
|
case 'sleep':
|
|
300
|
-
return done({ ...base, summary: 'slept' });
|
|
317
|
+
return done({ ...base, summary: say('slept', 'I slept.') });
|
|
301
318
|
case 'rest':
|
|
302
|
-
return done({ ...base, needs: { leisure: 0.1 }, summary: 'rested' });
|
|
319
|
+
return done({ ...base, needs: { leisure: 0.1 }, summary: say('rested', 'I rested.') });
|
|
303
320
|
case 'wait':
|
|
304
|
-
return done({ ...base, summary: 'waited' });
|
|
321
|
+
return done({ ...base, summary: say('waited', 'I waited.') });
|
|
305
322
|
case 'work-field': {
|
|
306
323
|
const ok = chance(state.rng, successChance(p, 'farming', 0.3, capacity));
|
|
307
324
|
if (ok) {
|
|
@@ -310,7 +327,7 @@ export function createVillage(people, opts) {
|
|
|
310
327
|
...base,
|
|
311
328
|
needs: { competence: 0.1 },
|
|
312
329
|
material: V.wage,
|
|
313
|
-
summary: 'worked the field; a good shift',
|
|
330
|
+
summary: say('worked the field; a good shift', 'I worked in the field. The shift went well.'),
|
|
314
331
|
});
|
|
315
332
|
}
|
|
316
333
|
state.food += 1;
|
|
@@ -318,7 +335,7 @@ export function createVillage(people, opts) {
|
|
|
318
335
|
...base,
|
|
319
336
|
status: 'failed',
|
|
320
337
|
needs: { competence: 0.02 },
|
|
321
|
-
summary: 'worked the field; a poor shift',
|
|
338
|
+
summary: say('worked the field; a poor shift', 'I worked in the field. The shift went poorly.'),
|
|
322
339
|
};
|
|
323
340
|
}
|
|
324
341
|
case 'forage': {
|
|
@@ -329,23 +346,35 @@ export function createVillage(people, opts) {
|
|
|
329
346
|
status: 'failed',
|
|
330
347
|
injury: { part: 'leg', severity: risk.severity, healRatePerDay: 0.1 },
|
|
331
348
|
summary: isNightAt(act.startedAt)
|
|
332
|
-
? 'went to the forest at night and got hurt by an animal'
|
|
333
|
-
: 'got hurt by an animal in the forest',
|
|
349
|
+
? say('went to the forest at night and got hurt by an animal', 'I went to the forest at night. An animal hurt me.')
|
|
350
|
+
: say('got hurt by an animal in the forest', 'An animal hurt me in the forest.'),
|
|
334
351
|
};
|
|
335
352
|
}
|
|
336
353
|
state.food += V.forageYield;
|
|
337
|
-
return done({
|
|
354
|
+
return done({
|
|
355
|
+
...base,
|
|
356
|
+
needs: { food: 0.3 },
|
|
357
|
+
summary: say('foraged in the forest', 'I gathered food in the forest.'),
|
|
358
|
+
});
|
|
338
359
|
}
|
|
339
360
|
case 'cook': {
|
|
340
361
|
const ok = chance(state.rng, successChance(p, 'cooking', 0.3, capacity));
|
|
341
362
|
if (ok) {
|
|
342
363
|
state.food += V.cookYield;
|
|
343
|
-
return done({
|
|
364
|
+
return done({
|
|
365
|
+
...base,
|
|
366
|
+
needs: { competence: 0.08 },
|
|
367
|
+
summary: say('cooked a good meal', 'I cooked a good meal.'),
|
|
368
|
+
});
|
|
344
369
|
}
|
|
345
|
-
return { ...base, status: 'failed', summary: 'burnt the meal' };
|
|
370
|
+
return { ...base, status: 'failed', summary: say('burnt the meal', 'I burnt the meal.') };
|
|
346
371
|
}
|
|
347
372
|
case 'pray':
|
|
348
|
-
return done({
|
|
373
|
+
return done({
|
|
374
|
+
...base,
|
|
375
|
+
needs: { meaning: 0.1 },
|
|
376
|
+
summary: say('prayed at the mosque', 'I prayed at the mosque.'),
|
|
377
|
+
});
|
|
349
378
|
case 'apologize': {
|
|
350
379
|
const other = act.targetId;
|
|
351
380
|
if (other !== undefined) {
|
|
@@ -357,10 +386,13 @@ export function createVillage(people, opts) {
|
|
|
357
386
|
targetId: other,
|
|
358
387
|
valence: 0.3,
|
|
359
388
|
salience: 0.6,
|
|
360
|
-
summary: `${p.name} apologised`,
|
|
389
|
+
summary: say(`${p.name} apologised`, `${p.name} apologised.`),
|
|
361
390
|
});
|
|
362
391
|
}
|
|
363
|
-
return done({
|
|
392
|
+
return done({
|
|
393
|
+
...base,
|
|
394
|
+
summary: say(`apologised to ${other ?? 'a neighbour'}`, `I apologised to ${other ?? 'a neighbour'}.`),
|
|
395
|
+
});
|
|
364
396
|
}
|
|
365
397
|
case 'chat': {
|
|
366
398
|
const other = aff.with?.[0];
|
|
@@ -373,13 +405,13 @@ export function createVillage(people, opts) {
|
|
|
373
405
|
targetId: other,
|
|
374
406
|
valence: 0.3,
|
|
375
407
|
salience: 0.4,
|
|
376
|
-
summary: `${p.name} stopped to chat`,
|
|
408
|
+
summary: say(`${p.name} stopped to chat`, `${p.name} stopped to chat.`),
|
|
377
409
|
});
|
|
378
410
|
}
|
|
379
411
|
return done({
|
|
380
412
|
...base,
|
|
381
413
|
needs: { belonging: 0.3, leisure: 0.1 },
|
|
382
|
-
summary: `chatted with ${other ?? 'a neighbour'}`,
|
|
414
|
+
summary: say(`chatted with ${other ?? 'a neighbour'}`, `I chatted with ${other ?? 'a neighbour'}.`),
|
|
383
415
|
});
|
|
384
416
|
}
|
|
385
417
|
case 'help': {
|
|
@@ -394,13 +426,13 @@ export function createVillage(people, opts) {
|
|
|
394
426
|
valence: 0.5,
|
|
395
427
|
salience: 0.6,
|
|
396
428
|
norms: [{ normId: 'help-neighbor', relation: 'fulfills' }],
|
|
397
|
-
summary: `${p.name} helped with the work`,
|
|
429
|
+
summary: say(`${p.name} helped with the work`, `${p.name} helped with the work.`),
|
|
398
430
|
});
|
|
399
431
|
}
|
|
400
432
|
return done({
|
|
401
433
|
...base,
|
|
402
434
|
needs: { meaning: 0.2, esteem: 0.05 },
|
|
403
|
-
summary: `helped ${other ?? 'a neighbour'}`,
|
|
435
|
+
summary: say(`helped ${other ?? 'a neighbour'}`, `I helped ${other ?? 'a neighbour'}.`),
|
|
404
436
|
percepts: other
|
|
405
437
|
? [
|
|
406
438
|
{
|
|
@@ -411,7 +443,7 @@ export function createVillage(people, opts) {
|
|
|
411
443
|
targetId: p.id,
|
|
412
444
|
valence: 0.3,
|
|
413
445
|
salience: 0.5,
|
|
414
|
-
summary: `${other} said thank you`,
|
|
446
|
+
summary: say(`${other} said thank you`, `${other} said thank you.`),
|
|
415
447
|
},
|
|
416
448
|
]
|
|
417
449
|
: [],
|
|
@@ -429,13 +461,18 @@ export function createVillage(people, opts) {
|
|
|
429
461
|
valence: -0.5,
|
|
430
462
|
salience: 0.8,
|
|
431
463
|
norms: [{ normId: 'theft', relation: 'violates' }],
|
|
432
|
-
summary: `${p.name} took bread from the house`,
|
|
464
|
+
summary: say(`${p.name} took bread from the house`, `${p.name} took bread from the house.`),
|
|
433
465
|
});
|
|
434
466
|
}
|
|
435
|
-
return done({
|
|
467
|
+
return done({
|
|
468
|
+
...base,
|
|
469
|
+
needs: { food: 0.5 },
|
|
470
|
+
material: 1,
|
|
471
|
+
summary: say('took bread that was not mine', 'I took bread that was not mine.'),
|
|
472
|
+
});
|
|
436
473
|
}
|
|
437
474
|
default:
|
|
438
|
-
return done({ ...base, summary: `${aff.label}: done` });
|
|
475
|
+
return done({ ...base, summary: say(`${aff.label}: done`, `I completed the task “${aff.label}”.`) });
|
|
439
476
|
}
|
|
440
477
|
};
|
|
441
478
|
const perceptsFor = (p, since, until) => {
|
package/dist/sim/longrun.js
CHANGED
|
@@ -77,11 +77,28 @@ export function liveCommunity(c, until, opts) {
|
|
|
77
77
|
days[p.id] = list;
|
|
78
78
|
}
|
|
79
79
|
for (const kind of r.onsets)
|
|
80
|
-
events.push({
|
|
80
|
+
events.push({
|
|
81
|
+
at: r.at,
|
|
82
|
+
personId: p.id,
|
|
83
|
+
kind: 'onset',
|
|
84
|
+
detail: p.lexicon?.plainEnglish ? `${p.name} developed ${kind}.` : `${p.name}: ${kind}`,
|
|
85
|
+
});
|
|
81
86
|
if (r.stage)
|
|
82
|
-
events.push({
|
|
87
|
+
events.push({
|
|
88
|
+
at: r.at,
|
|
89
|
+
personId: p.id,
|
|
90
|
+
kind: 'stage',
|
|
91
|
+
detail: p.lexicon?.plainEnglish
|
|
92
|
+
? `${p.name} entered the ${r.stage} stage of life.`
|
|
93
|
+
: `${p.name} is now ${r.stage}`,
|
|
94
|
+
});
|
|
83
95
|
if (r.died) {
|
|
84
|
-
events.push({
|
|
96
|
+
events.push({
|
|
97
|
+
at: r.at,
|
|
98
|
+
personId: p.id,
|
|
99
|
+
kind: 'died',
|
|
100
|
+
detail: p.lexicon?.plainEnglish ? `${p.name} died.` : `${p.name} died`,
|
|
101
|
+
});
|
|
85
102
|
died.push(p);
|
|
86
103
|
}
|
|
87
104
|
}
|
package/dist/sim/sim.d.ts
CHANGED
|
@@ -280,7 +280,7 @@ export declare function declineJoint(c: Community, proposal: JointProposal, prop
|
|
|
280
280
|
* activities are resolved as interrupted first, then the proposer begins the offer and each partner their
|
|
281
281
|
* mirror. Returns the activities begun (empty while other partners have yet to answer).
|
|
282
282
|
*/
|
|
283
|
-
export declare function acceptJoint(c: Community, world: World, proposal: JointProposal, partner: Person, partnerRecord: DecisionRecord,
|
|
283
|
+
export declare function acceptJoint(c: Community, world: World, proposal: JointProposal, partner: Person, partnerRecord: DecisionRecord, writeLog?: (e: SimEvent) => void): Activity[];
|
|
284
284
|
/**
|
|
285
285
|
* Chance that `lead` succeeds at a skilled task with `partners` helping: `successChance` with
|
|
286
286
|
* support = Σ partner skill × partner capacity / max(difficulty, 0.1), clamped to 0..1.
|
package/dist/sim/sim.js
CHANGED
|
@@ -79,6 +79,54 @@ function finishOpts(world) {
|
|
|
79
79
|
o.transfer = world.skillTransfer;
|
|
80
80
|
return o;
|
|
81
81
|
}
|
|
82
|
+
/** Complete sentences for generated event details. Host outcome summaries bypass this reader. */
|
|
83
|
+
function plainEventDetail(p, event) {
|
|
84
|
+
const name = p.name;
|
|
85
|
+
const detail = event.detail;
|
|
86
|
+
switch (event.kind) {
|
|
87
|
+
case 'decide':
|
|
88
|
+
return detail;
|
|
89
|
+
case 'idle':
|
|
90
|
+
return `${name} did not choose a task.`;
|
|
91
|
+
case 'died':
|
|
92
|
+
return `${name} died.`;
|
|
93
|
+
case 'begin':
|
|
94
|
+
case 'continue':
|
|
95
|
+
case 'finish':
|
|
96
|
+
return detail;
|
|
97
|
+
case 'perceive': {
|
|
98
|
+
const counts = /^(\d+)\/(\d+) percepts$/.exec(detail);
|
|
99
|
+
return counts ? `${name} noticed ${counts[1]} of ${counts[2]} events.` : `${name} noticed “${detail}”.`;
|
|
100
|
+
}
|
|
101
|
+
case 'interrupt':
|
|
102
|
+
return `${name} was interrupted by the event “${detail.replace(/^percept:/, '')}”.`;
|
|
103
|
+
case 'propose':
|
|
104
|
+
return `${name} proposed the shared task “${detail}”.`;
|
|
105
|
+
case 'accept':
|
|
106
|
+
return `${name} joined the shared task “${detail.replace(/^joins /, '')}”.`;
|
|
107
|
+
case 'decline':
|
|
108
|
+
return `${name} declined the shared task “${detail.replace(/^declined /, '')}”.`;
|
|
109
|
+
case 'converse':
|
|
110
|
+
return `${name} spoke. The exchange included: “${detail}”.`;
|
|
111
|
+
case 'contagion':
|
|
112
|
+
return `${name} ${detail}.`;
|
|
113
|
+
case 'command':
|
|
114
|
+
return `${name} received the order “${detail}”.`;
|
|
115
|
+
case 'release':
|
|
116
|
+
return `${name} was released from the order.`;
|
|
117
|
+
case 'onset':
|
|
118
|
+
return `${name} developed the condition “${detail}”.`;
|
|
119
|
+
case 'stage':
|
|
120
|
+
return `${name} entered the life stage “${detail}”.`;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function taskEndLine(p, label, status) {
|
|
124
|
+
if (status === 'completed')
|
|
125
|
+
return `${p.name} completed the task “${label}”.`;
|
|
126
|
+
if (status === 'failed')
|
|
127
|
+
return `${p.name} failed to complete the task “${label}”.`;
|
|
128
|
+
return `${p.name} was interrupted during the task “${label}”.`;
|
|
129
|
+
}
|
|
82
130
|
/**
|
|
83
131
|
* Whether standing suggestion `s` is heard by `p` at a decision over `affordances` (standing-advice SCOPE): its target
|
|
84
132
|
* must be on offer or be the running activity, and if the action keeps commitments and was completed since the suggestion was given, doing it
|
|
@@ -208,7 +256,7 @@ export function tellDeath(c, dead, at, opts = {}) {
|
|
|
208
256
|
targetId: dead.id,
|
|
209
257
|
valence: -0.8,
|
|
210
258
|
salience: 0.9,
|
|
211
|
-
summary: `${dead.name} died`,
|
|
259
|
+
summary: q.lexicon?.plainEnglish ? `${dead.name} died.` : `${dead.name} died`,
|
|
212
260
|
},
|
|
213
261
|
]);
|
|
214
262
|
// A spouse is widowed even if the news went unattended.
|
|
@@ -355,7 +403,11 @@ export function declineJoint(c, proposal, proposer) {
|
|
|
355
403
|
* activities are resolved as interrupted first, then the proposer begins the offer and each partner their
|
|
356
404
|
* mirror. Returns the activities begun (empty while other partners have yet to answer).
|
|
357
405
|
*/
|
|
358
|
-
export function acceptJoint(c, world, proposal, partner, partnerRecord,
|
|
406
|
+
export function acceptJoint(c, world, proposal, partner, partnerRecord, writeLog = () => { }) {
|
|
407
|
+
const log = (e) => {
|
|
408
|
+
const person = personById(c, e.personId);
|
|
409
|
+
writeLog(person?.lexicon?.plainEnglish ? { ...e, detail: plainEventDetail(person, e) } : e);
|
|
410
|
+
};
|
|
359
411
|
if (proposal.status !== 'pending' || !proposal.partnerIds.includes(partner.id))
|
|
360
412
|
return [];
|
|
361
413
|
if (!proposal.accepted.includes(partner.id))
|
|
@@ -387,7 +439,9 @@ export function acceptJoint(c, world, proposal, partner, partnerRecord, log = ()
|
|
|
387
439
|
at,
|
|
388
440
|
personId: person.id,
|
|
389
441
|
kind: 'finish',
|
|
390
|
-
detail:
|
|
442
|
+
detail: person.lexicon?.plainEnglish
|
|
443
|
+
? taskEndLine(person, act.affordance.label, outcome.status)
|
|
444
|
+
: `${act.action} ${outcome.status}`,
|
|
391
445
|
decisionId: act.decisionId,
|
|
392
446
|
affordanceId: act.affordanceId,
|
|
393
447
|
action: act.action,
|
|
@@ -404,7 +458,9 @@ export function acceptJoint(c, world, proposal, partner, partnerRecord, log = ()
|
|
|
404
458
|
at,
|
|
405
459
|
personId: person.id,
|
|
406
460
|
kind: 'begin',
|
|
407
|
-
detail:
|
|
461
|
+
detail: person.lexicon?.plainEnglish
|
|
462
|
+
? `${person.name} began the shared task “${offer.label}”. ${record.intention}`
|
|
463
|
+
: `${offer.label} (joint ${proposal.id})`,
|
|
408
464
|
decisionId: record.id,
|
|
409
465
|
affordanceId: offer.id,
|
|
410
466
|
action: offer.action,
|
|
@@ -703,9 +759,12 @@ export function stepCommunity(c, world, until, opts = {}) {
|
|
|
703
759
|
// Communities created before joint support (plain JSON from an older host) get the new bookkeeping.
|
|
704
760
|
c.interrupts ??= {};
|
|
705
761
|
c.joint ??= { nextId: 0, proposals: [], excluded: {} };
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
762
|
+
// Presentation only: retain host-authored summaries and every event field other than generated detail.
|
|
763
|
+
const log = (e, authored = false) => {
|
|
764
|
+
const person = personById(c, e.personId);
|
|
765
|
+
if (events.length < maxEvents) {
|
|
766
|
+
events.push(person?.lexicon?.plainEnglish && !authored ? { ...e, detail: plainEventDetail(person, e) } : e);
|
|
767
|
+
}
|
|
709
768
|
};
|
|
710
769
|
const contagion = opts.contagion ?? true;
|
|
711
770
|
c.queued ??= {};
|
|
@@ -772,14 +831,17 @@ export function stepCommunity(c, world, until, opts = {}) {
|
|
|
772
831
|
at: t,
|
|
773
832
|
personId: p.id,
|
|
774
833
|
kind: 'finish',
|
|
775
|
-
detail: outcome.summary ??
|
|
834
|
+
detail: outcome.summary ??
|
|
835
|
+
(p.lexicon?.plainEnglish
|
|
836
|
+
? taskEndLine(p, act.affordance.label, outcome.status)
|
|
837
|
+
: `${act.action} ${outcome.status}`),
|
|
776
838
|
decisionId: act.decisionId,
|
|
777
839
|
affordanceId: act.affordanceId,
|
|
778
840
|
action: act.action,
|
|
779
841
|
};
|
|
780
842
|
if (report)
|
|
781
843
|
ev.status = report.status;
|
|
782
|
-
log(ev);
|
|
844
|
+
log(ev, outcome.summary !== undefined);
|
|
783
845
|
if (outcome.status === 'completed') {
|
|
784
846
|
noteStandingDone(c, p, act, t);
|
|
785
847
|
if (pairMinute !== t) {
|
|
@@ -837,14 +899,22 @@ export function stepCommunity(c, world, until, opts = {}) {
|
|
|
837
899
|
detail: `joins ${acceptedProposal.offer.label}`,
|
|
838
900
|
jointId: acceptedProposal.id,
|
|
839
901
|
});
|
|
840
|
-
acceptJoint(c, world, acceptedProposal, p, record, log);
|
|
902
|
+
acceptJoint(c, world, acceptedProposal, p, record, (event) => log(event, true));
|
|
841
903
|
continue;
|
|
842
904
|
}
|
|
843
905
|
const chosen = affordances.find((a) => a.id === record.chosenAffordanceId);
|
|
844
906
|
const continuing = act !== null && (record.chosenAffordanceId === null || record.chosenAffordanceId === act.affordanceId);
|
|
845
907
|
if (act && continuing) {
|
|
846
908
|
reviewed(p);
|
|
847
|
-
log({
|
|
909
|
+
log({
|
|
910
|
+
at: t,
|
|
911
|
+
personId: p.id,
|
|
912
|
+
kind: 'continue',
|
|
913
|
+
detail: p.lexicon?.plainEnglish
|
|
914
|
+
? `${p.name} continued the task “${act.affordance.label}”.`
|
|
915
|
+
: act.action,
|
|
916
|
+
affordanceId: act.affordanceId,
|
|
917
|
+
});
|
|
848
918
|
continue;
|
|
849
919
|
}
|
|
850
920
|
if (chosen && isJointOffer(c, p, chosen)) {
|
|
@@ -854,11 +924,15 @@ export function stepCommunity(c, world, until, opts = {}) {
|
|
|
854
924
|
at: t,
|
|
855
925
|
personId: p.id,
|
|
856
926
|
kind: proposal.status === 'declined' ? 'decline' : 'propose',
|
|
857
|
-
detail:
|
|
927
|
+
detail: p.lexicon?.plainEnglish
|
|
928
|
+
? proposal.status === 'declined'
|
|
929
|
+
? `The shared task “${chosen.label}” could not start because a partner was unavailable.`
|
|
930
|
+
: `${chosen.label} with ${proposal.partnerIds.map((id) => personById(c, id)?.name ?? id).join(', ')}`
|
|
931
|
+
: `${chosen.label} with ${proposal.partnerIds.join(', ')}`,
|
|
858
932
|
affordanceId: chosen.id,
|
|
859
933
|
action: chosen.action,
|
|
860
934
|
jointId: proposal.id,
|
|
861
|
-
});
|
|
935
|
+
}, Boolean(p.lexicon?.plainEnglish && proposal.status === 'declined'));
|
|
862
936
|
continue;
|
|
863
937
|
}
|
|
864
938
|
if (act) {
|
|
@@ -868,7 +942,9 @@ export function stepCommunity(c, world, until, opts = {}) {
|
|
|
868
942
|
at: t,
|
|
869
943
|
personId: p.id,
|
|
870
944
|
kind: 'finish',
|
|
871
|
-
detail:
|
|
945
|
+
detail: p.lexicon?.plainEnglish
|
|
946
|
+
? taskEndLine(p, act.affordance.label, 'interrupted')
|
|
947
|
+
: `${act.action} interrupted`,
|
|
872
948
|
decisionId: act.decisionId,
|
|
873
949
|
affordanceId: act.affordanceId,
|
|
874
950
|
action: act.action,
|
|
@@ -889,7 +965,9 @@ export function stepCommunity(c, world, until, opts = {}) {
|
|
|
889
965
|
at: t,
|
|
890
966
|
personId: p.id,
|
|
891
967
|
kind: 'begin',
|
|
892
|
-
detail:
|
|
968
|
+
detail: p.lexicon?.plainEnglish
|
|
969
|
+
? `${p.name} began the task “${chosen.label}”. ${record.intention}`
|
|
970
|
+
: `${chosen.label} (${record.intention})`,
|
|
893
971
|
decisionId: record.id,
|
|
894
972
|
affordanceId: chosen.id,
|
|
895
973
|
action: chosen.action,
|
package/dist/types.d.ts
CHANGED
|
@@ -1767,6 +1767,8 @@ export interface VoiceConflict {
|
|
|
1767
1767
|
* slots documented next to each key.
|
|
1768
1768
|
*/
|
|
1769
1769
|
export interface Lexicon {
|
|
1770
|
+
/** Use complete, plain English in built-in narration. Omitted keeps exact legacy wording. */
|
|
1771
|
+
plainEnglish?: boolean;
|
|
1770
1772
|
/** Include person identity and stable temperament in assent/deferral selection (no RNG draws). */
|
|
1771
1773
|
variety?: boolean;
|
|
1772
1774
|
/** What material gains mean here, e.g. 'food', 'household keep' or 'resources'; absent keeps legacy money lines. */
|
package/dist/will/will.js
CHANGED
|
@@ -37,6 +37,7 @@ import { commitmentPressure, isUnderWay, pressureReachedAt } from '../agenda/ind
|
|
|
37
37
|
import { downedAllows, readCapacities } from '../body/index.js';
|
|
38
38
|
import { CONSCIENCE_DEFAULTS, normVeto } from '../conscience/index.js';
|
|
39
39
|
import { clamp01, cmpStr, decay, dexp, dpow, hasNumbers, isObj, random, round } from '../core/index.js';
|
|
40
|
+
import { commitmentLabel } from '../presentation.js';
|
|
40
41
|
import { skillLevel } from '../skills/index.js';
|
|
41
42
|
import { MINUTES_PER_DAY, MINUTES_PER_HOUR } from '../types.js';
|
|
42
43
|
export const WILL_DEFAULTS = {
|
|
@@ -829,7 +830,10 @@ function judgeVoices(p, ctx, suggestions, prepared, selection) {
|
|
|
829
830
|
kind: 'notNow',
|
|
830
831
|
commitmentId: v.omission,
|
|
831
832
|
...(winnerAff ? { insteadAffordanceId: winnerAff.id } : {}),
|
|
832
|
-
counterOffer: {
|
|
833
|
+
counterOffer: {
|
|
834
|
+
affordanceId: suggested[0]?.affordanceId,
|
|
835
|
+
label: dutyLabel(duty, winnerAff, p),
|
|
836
|
+
},
|
|
833
837
|
}));
|
|
834
838
|
}
|
|
835
839
|
return out(resolution('refused', v.reason, { kind: 'willNot', commitmentId: v.omission }));
|
|
@@ -886,7 +890,12 @@ function judgeVoices(p, ctx, suggestions, prepared, selection) {
|
|
|
886
890
|
kind: 'notNow',
|
|
887
891
|
insteadAffordanceId: winnerAff?.id,
|
|
888
892
|
counterOffer: winnerAff
|
|
889
|
-
? {
|
|
893
|
+
? {
|
|
894
|
+
affordanceId: bestSuggested.affordanceId,
|
|
895
|
+
label: p.lexicon?.plainEnglish
|
|
896
|
+
? `after I finish this task (${winnerAff.label})`
|
|
897
|
+
: `after I ${winnerAff.label}`,
|
|
898
|
+
}
|
|
890
899
|
: { affordanceId: bestSuggested.affordanceId, label: 'later' },
|
|
891
900
|
}));
|
|
892
901
|
});
|
|
@@ -940,7 +949,11 @@ function arbitrateInsistence(p, judged, considered, affById, ev) {
|
|
|
940
949
|
insteadAffordanceId: forced,
|
|
941
950
|
counterOffer: {
|
|
942
951
|
...(firstTarget !== undefined ? { affordanceId: firstTarget } : {}),
|
|
943
|
-
label: forcedAff
|
|
952
|
+
label: forcedAff
|
|
953
|
+
? p.lexicon?.plainEnglish
|
|
954
|
+
? `after I finish this task (${forcedAff.label})`
|
|
955
|
+
: `after I ${forcedAff.label}`
|
|
956
|
+
: 'later',
|
|
944
957
|
},
|
|
945
958
|
};
|
|
946
959
|
if (j.res.likelihood !== undefined)
|
|
@@ -1134,7 +1147,12 @@ export function conflictBetweenVoices(considered, resolutions, chosenAffordanceI
|
|
|
1134
1147
|
};
|
|
1135
1148
|
}
|
|
1136
1149
|
/** Counter-offer for a request deferred behind a duty: "after I pray", "after I feed the children". */
|
|
1137
|
-
function dutyLabel(duty, winner) {
|
|
1150
|
+
function dutyLabel(duty, winner, p) {
|
|
1151
|
+
if (p.lexicon?.plainEnglish) {
|
|
1152
|
+
if (duty)
|
|
1153
|
+
return `after I finish this duty (${commitmentLabel(duty, p.lexicon)})`;
|
|
1154
|
+
return winner ? `after I finish this task (${winner.label})` : 'after my duty';
|
|
1155
|
+
}
|
|
1138
1156
|
if (duty?.kind === 'worship')
|
|
1139
1157
|
return duty.label ? `after I pray ${duty.label}` : 'after I pray';
|
|
1140
1158
|
if (duty?.label)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adam0white/human-framework",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.19.0",
|
|
4
4
|
"description": "Deterministic, explainable simulated people: body, needs, affect, memory, beliefs, skills, habits, relationships, values and a will that can refuse a suggestion",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"simulation",
|