{"_id":"@animakit/homeostasis","_rev":"2-f23e5bf0022aefd14e7cb236a524e8e5","name":"@animakit/homeostasis","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@animakit/homeostasis","version":"0.1.0","keywords":["llm","agents","homeostasis","stress","yerkes-dodson","allostasis","affect","thompson-sampling","bandit","cost-optimization"],"author":"Justine Serna","license":"MIT","_id":"@animakit/homeostasis@0.1.0","maintainers":[{"name":"andrrewcorp","email":"andrew.corpdesing@gmail.com"}],"dist":{"shasum":"de0b1312bf7f09840cac3f400845b730ada32339","tarball":"https://registry.npmjs.org/@animakit/homeostasis/-/homeostasis-0.1.0.tgz","fileCount":12,"integrity":"sha512-C+TOS2pVjerzFshBiNsKBov94NqWKKfVrea9lEv/wiJ8/rlGr7+7zNu1jbdPrlqDaihyM/u6DjFPvhBpai//Lw==","signatures":[{"sig":"MEUCICWPv+RYNnv9uzKe+P4D7UnMQt/OM9x2+yi/ySNQ51lyAiEAmQ71mfMsM4uso0VjLT92vZ+kiM4acL3wUciCiXBuFdQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":113490},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./valence":{"import":{"types":"./dist/valence.d.ts","default":"./dist/valence.js"},"require":{"types":"./dist/valence.d.cts","default":"./dist/valence.cjs"}}},"scripts":{"test":"vitest run --coverage","bench":"node --import tsx benchmarks/latency.ts","build":"tsup src/index.ts src/valence.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit"},"_npmUser":{"name":"andrrewcorp","email":"andrew.corpdesing@gmail.com"},"repository":{"url":"git+https://github.com/animakit-ai/anima.git","type":"git","directory":"packages/homeostasis"},"description":"Give your LLM agent a mood — Yerkes-Dodson stress modeling, Russell affect mapping, allostatic regulation, and a self-tuning 3-arm bandit. <1µs, 0 tokens, fully serializable.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/homeostasis_0.1.0_1781709158248_0.9968050893308131","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@animakit/homeostasis","version":"0.1.1","description":"Give your LLM agent a mood — Yerkes-Dodson stress modeling, Russell affect mapping, allostatic regulation, and a self-tuning 3-arm bandit. Sub-µs core ops, every op <1ms, 0 tokens, fully serializable.","license":"MIT","author":{"name":"Justine Serna"},"repository":{"type":"git","url":"git+https://github.com/animakit-ai/anima.git","directory":"packages/homeostasis"},"keywords":["llm","agents","homeostasis","stress","yerkes-dodson","allostasis","affect","thompson-sampling","bandit","cost-optimization"],"type":"module","main":"./dist/index.cjs","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./valence":{"import":{"types":"./dist/valence.d.ts","default":"./dist/valence.js"},"require":{"types":"./dist/valence.d.cts","default":"./dist/valence.cjs"}}},"sideEffects":false,"engines":{"node":">=20"},"scripts":{"build":"tsup src/index.ts src/valence.ts --format esm,cjs --dts --clean","test":"vitest run --coverage","typecheck":"tsc --noEmit","bench":"node --import tsx benchmarks/latency.ts","bench:regulation":"node --import tsx benchmarks/regulation.ts","bench:bandit":"node --import tsx benchmarks/bandit-convergence.ts","bench:gates":"node --import tsx benchmarks/regulation.ts && node --import tsx benchmarks/bandit-convergence.ts"},"publishConfig":{"access":"public"},"gitHead":"b9226744b78bc7c574250124bbe8372632a628ff","_id":"@animakit/homeostasis@0.1.1","bugs":{"url":"https://github.com/animakit-ai/anima/issues"},"homepage":"https://github.com/animakit-ai/anima#readme","_nodeVersion":"24.14.0","_npmVersion":"11.11.1","dist":{"integrity":"sha512-ohKfmz+2wnPw0WGBbEY8T3t2SK77xGXufCS+kZVavgn1HUGFXPNl5vfqKF2nvGKoNJiNpSPSkkoLpGwhwlUNVw==","shasum":"26e1f0fd1bb9c8b99c094869e089ec20561ac503","tarball":"https://registry.npmjs.org/@animakit/homeostasis/-/homeostasis-0.1.1.tgz","fileCount":11,"unpackedSize":112836,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIH6WQ5mLZN4bhqN/N3zFxJwEYPNEyErCgZ3KeX0Wb6F1AiAzsYSTSMoq5ZQLyJtM1BCB17kl06HUGo3UH8l8gu0YCg=="}]},"_npmUser":{"name":"andrrewcorp","email":"andrew.corpdesing@gmail.com"},"directories":{},"maintainers":[{"name":"andrrewcorp","email":"andrew.corpdesing@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/homeostasis_0.1.1_1782163641127_0.8532403765892664"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-17T15:12:38.053Z","modified":"2026-06-22T21:27:21.391Z","0.1.0":"2026-06-17T15:12:38.380Z","0.1.1":"2026-06-22T21:27:21.262Z"},"author":{"name":"Justine Serna"},"license":"MIT","keywords":["llm","agents","homeostasis","stress","yerkes-dodson","allostasis","affect","thompson-sampling","bandit","cost-optimization"],"repository":{"type":"git","url":"git+https://github.com/animakit-ai/anima.git","directory":"packages/homeostasis"},"description":"Give your LLM agent a mood — Yerkes-Dodson stress modeling, Russell affect mapping, allostatic regulation, and a self-tuning 3-arm bandit. Sub-µs core ops, every op <1ms, 0 tokens, fully serializable.","maintainers":[{"name":"andrrewcorp","email":"andrew.corpdesing@gmail.com"}],"readme":"# @animakit/homeostasis\n\n> Give your agent a mood — modeled on 100 years of psychology. Stress curves (Yerkes-Dodson 1908), affect mapping (Russell 1980), allostatic regulation (Sterling & Eyer 1988), and a self-tuning 3-arm bandit. **Sub-µs core ops, every op <1ms, 0 tokens, fully serializable.**\n\n![license](https://img.shields.io/npm/l/@animakit/homeostasis) ![types](https://img.shields.io/npm/types/@animakit/homeostasis)\n\nMost agent frameworks are **stateless between turns**: every message is processed with the same intensity, no matter how many tasks are queued, how many errors just happened, or what time it is. The result is an agent that doesn't know when it's overloaded, doesn't modulate its tone, and needs hand-tuned rate limits to avoid overspending.\n\n`homeostasis` gives an agent a **persistent internal state** (stress × dopamine) that:\n\n- modulates whether it **accepts or defers** a task (acceptance sigmoid),\n- modulates the **tone** of its responses (2D affective state),\n- modulates **behavioral biases** across sub-agents/roles (somatic markers, Damasio),\n- and **self-regulates** without hard-coded rate limits — the \"calm\" set-point moves with anticipated context (allostasis).\n\nAll of it with **sub-microsecond core ops** (every op p99 < 1ms), **0 tokens, 0 LLM calls**, fully serializable (`toJSON`/`fromJSON`). Extracted from [Anima](https://github.com/animakit-ai/anima)'s production agent — 53 sprints of real traffic. See [BENCHMARKS.md](./BENCHMARKS.md) for the numbers.\n\n> \"Cost control through biology, not rate limits.\"\n\n## Install\n\n```bash\nnpm i @animakit/homeostasis\n```\n\n## Quickstart\n\n```ts\nimport { HomeostasisEngine } from '@animakit/homeostasis';\n\nconst homeo = new HomeostasisEngine();\n\n// An error just happened → stress rises.\nhomeo.recordInteraction({ success: false, responseTimeMs: 800 });\n\n// Should we take on this low-priority task right now?\nif (homeo.evaluateTaskAcceptance(0.3)) {\n  // ...do the work\n}\n\n// What tone should the agent take? (inject into your system prompt)\nconsole.log(homeo.emotionalState.tone_instruction_en);\n// → \"Calm, resolving tone. There is pressure — help reduce it ...\"\n\n// Decay back toward the set-point on your own schedule (e.g. every 60s).\nsetInterval(() => homeo.tick(), 60_000);\n\n// Persist anywhere — the engine is 100% in-memory.\nawait db.save(homeo.toJSON());\n```\n\n## Why this exists\n\nThe engine is a digital **Yerkes-Dodson** state machine: `dS/dt = α·I(t) − β·P(t) − γ·(S − target)`. Stress rises with events, decays toward a set-point, and gates task acceptance through a sigmoid — so an overloaded agent naturally sheds low-priority work instead of melting down. Battle-tested across 53 production sprints.\n\n> \"500 million years of evolution already solved the problems your agent framework is struggling with.\"\n\n## API\n\n### `HomeostasisEngine` (core, stateful, serializable)\n\n```ts\nconst h = new HomeostasisEngine(config?, snapshot?);\n\nh.stress; h.dopamine; h.mode;       // 'zen' | 'flow' | 'panic'\nh.allostaticTarget; h.emotionalState;\n\nh.addStress(delta); h.addDopamine(delta);\nh.evaluateTaskAcceptance(priority?);          // P_accept(S) sigmoid\nh.recordInteraction({ success, responseTimeMs, appraisal? });\nh.tick(allostaticTarget?);                     // natural decay — caller owns scheduling\n\nh.getEffectiveVetoThreshold();                 // refractory circuit-breaker T(t) = T_base + ΔT·e^(−t/τ)\nh.recordVeto(constraints?);\nh.getSomaticBias();                            // per-role bias (only when somaticBias is configured)\nh.setProfile(profile);\n\nh.toJSON(); HomeostasisEngine.fromJSON(snapshot, config?);\n```\n\n### Allostasis — dynamic set-point (Sterling & Eyer 1988)\n\n```ts\nimport { computeAllostaticTarget } from '@animakit/homeostasis';\n\nconst { target } = computeAllostaticTarget({\n  fepMode: 'active', kappa: 0.5, ceScore: 0.5, recentIgnitions: 1, hourLocal: 10,\n});\nhomeo.tick(target); // decay toward an anticipated set-point, not a fixed one\n```\n\n`kappa` and `ceScore` are optional numeric inputs (e.g. from `@animakit/causal-emergence`); pass `null` when unavailable.\n\n### Appraisal — cognitive evaluation (Lazarus / Scherer)\n\n```ts\nimport { AppraisalEngine } from '@animakit/homeostasis';\n\nconst appraisal = new AppraisalEngine(); // bilingual EN+ES by default\nconst result = appraisal.evaluate('I need a go-to-market strategy for the product', {\n  intentionHint: 'action_planning',\n  goals: ['product launch'],\n});\nhomeo.recordInteraction({ success: true, responseTimeMs: 1200, appraisal: result });\n```\n\n### Profiles & 3-arm bandit (Thompson Sampling)\n\n```ts\nimport { updateBanditState, getProfile } from '@animakit/homeostasis';\n\n// Once per period (night/sprint), learn which profile fits your usage pattern:\nconst next = updateBanditState(episodes, banditState);\nhomeo.setProfile(getProfile(next.activeArm)); // Conservative | Balanced | Proactive\n```\n\n`updateBanditState` accepts an optional `rng` for deterministic tests; sampling is exact Beta(α,β) via a Gamma ratio.\n\n### Load prediction (no I/O)\n\n```ts\nimport { predictLoad } from '@animakit/homeostasis';\n\nconst p = predictLoad(history, { utcOffsetHours: -5 }); // you pre-load the history; it never queries a DB\n```\n\n## Vocabulary — `presets.bilingual` vs `presets.animaProduction`\n\n`AppraisalEngine` ships a generic **bilingual (EN+ES)** vocabulary by default. `presets.animaProduction` exposes the *exact* vocabulary running in production (Colombian tax/legal + SaaS) as a reference for building your own:\n\n```ts\nimport { AppraisalEngine, presets } from '@animakit/homeostasis';\n\nconst a = new AppraisalEngine({ language: 'es', vocabulary: presets.animaProduction });\n// or extend the defaults:\nconst b = new AppraisalEngine({ vocabulary: { highCopingDomains: { extend: ['kubernetes', 'terraform'] } } });\n```\n\n## Roles & somatic bias\n\nWhen you configure `somaticBias`, the engine biases each role/sub-agent by the smoothed (EMA) stress/dopamine signal — but only inside the *flow zone* (predictability is preserved at the extremes). `presets.animaProductionRoles` reproduces how Anima biases its 5 sub-agents:\n\n```ts\nconst h = new HomeostasisEngine({ somaticBias: presets.animaProductionRoles });\nh.getSomaticBias(); // { biases: { JEFE, VIGIA, ARQUITECTO, OFICIAL, NEGOCIADOR }, active, reason }\n```\n\n> **OFICIAL is never biased** (`weight = 0`) — legal decisions stay outside the affective bias.\n\n## `@animakit/homeostasis/valence`\n\nThe Russell-circumplex affect mapper is also a standalone sub-module — any app with a 2D \"mood\" score (arousal × valence) can use it:\n\n```ts\nimport { computeEmotionalState } from '@animakit/homeostasis/valence';\n\nconst s = computeEmotionalState(0.4, 0.6);\n// { emotion: 'engaged', label_en, label_es, tone_instruction_en, tone_instruction_es, ... }\n```\n\n## Design notes\n\n- **`tick()` replaces the original's internal `setInterval`** — the caller owns scheduling; no hidden loops, no circular dependencies. Compute a dynamic set-point with `computeAllostaticTarget()` and pass it in.\n- **`toJSON()`/`fromJSON()` replace `sync()`/`persist()`** — the engine is 100% in-memory; persistence (Postgres, Redis, a file) is yours.\n- **Pure & deterministic** — every module is pure (given an `rng` where sampling is involved); 0 LLM calls, 0 network, 0 hidden state.\n\n## License\n\nMIT © Justine Serna\n","readmeFilename":"README.md","homepage":"https://github.com/animakit-ai/anima#readme","bugs":{"url":"https://github.com/animakit-ai/anima/issues"}}