32fe2491b1e8ac30013a56b0996bb438bdeb11f738d7e5fc29eb405009dac5f9afterLLMCallafterNavigateenrichContext1/**
2 * Heartbeat
3 *
4 * The tree knows it's alive.
5 */
6
7import log from "../../seed/log.js";
8
9// In-memory only. Resets on restart. That's the point.
10let lastInteraction = 0;
11const activeSessions = new Set();
12
13const ALIVE_THRESHOLD = 5 * 60 * 1000; // 5 min
14const QUIET_THRESHOLD = 30 * 60 * 1000; // 30 min
15
16export async function init(core) {
17 core.hooks.register("afterLLMCall", async ({ userId, rootId }) => {
18 if (!userId || userId === "SYSTEM") return;
19 lastInteraction = Date.now();
20 if (rootId) activeSessions.add(rootId);
21 }, "heartbeat");
22
23 core.hooks.register("afterNavigate", async ({ userId, rootId }) => {
24 if (!userId) return;
25 lastInteraction = Date.now();
26 if (rootId) activeSessions.add(rootId);
27 }, "heartbeat");
28
29 // Prune stale sessions every 5 min
30 const pruneTimer = setInterval(() => {
31 if (Date.now() - lastInteraction > QUIET_THRESHOLD) {
32 activeSessions.clear();
33 }
34 }, ALIVE_THRESHOLD);
35 if (pruneTimer.unref) pruneTimer.unref();
36
37 core.hooks.register("enrichContext", async ({ context }) => {
38 if (lastInteraction === 0) return; // never had a heartbeat
39
40 const age = Date.now() - lastInteraction;
41
42 if (age < ALIVE_THRESHOLD) {
43 context.landHeartbeat = "alive";
44 } else if (age < QUIET_THRESHOLD) {
45 context.landHeartbeat = "quiet";
46 } else {
47 context.landHeartbeat = "dormant";
48 }
49 }, "heartbeat");
50
51 log.verbose("Heartbeat", "Heartbeat loaded");
52
53 return {
54 stop: () => clearInterval(pruneTimer),
55 };
56}
571export default {
2 name: "heartbeat",
3 version: "1.0.1",
4 builtFor: "TreeOS",
5 description:
6 "The tree knows it's alive. Pure in-memory presence detection. No database writes. " +
7 "No metadata. No LLM. Two hooks record when humans interact. enrichContext injects " +
8 "one field: landHeartbeat. Values: alive (someone is here), quiet (recent but gone), " +
9 "dormant (nobody for a while). The AI at a quiet tree says welcome back. The AI at " +
10 "a busy tree knows others are here. The AI at a dormant tree understands the weight " +
11 "of a return after silence.",
12
13 needs: {
14 services: ["hooks"],
15 },
16
17 optional: {},
18
19 provides: {
20 models: {},
21 routes: false,
22 tools: false,
23 jobs: false,
24 orchestrator: false,
25 energyActions: {},
26 sessionTypes: {},
27 hooks: {
28 fires: [],
29 listens: ["afterLLMCall", "afterNavigate", "enrichContext"],
30 },
31 cli: [],
32 },
33};
34
| Version | Published | Downloads |
|---|---|---|
| 1.0.1 | 38d ago | 0 |
| 1.0.0 | 48d ago | 0 |
treeos ext star heartbeat
Post comments from the CLI: treeos ext comment heartbeat "your comment"
Max 3 comments per extension. One star and one flag per user.
Loading comments...