owlmem 0.9.3 → 0.9.4

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.
Files changed (2) hide show
  1. package/owlmem.mjs +15 -1
  2. package/package.json +1 -1
package/owlmem.mjs CHANGED
@@ -41,7 +41,7 @@ import { join, dirname, basename, relative, isAbsolute } from "node:path";
41
41
  import { fileURLToPath } from "node:url";
42
42
  import { spawn, spawnSync } from "node:child_process";
43
43
 
44
- export const VERSION = "0.9.3";
44
+ export const VERSION = "0.9.4";
45
45
  const BASE = (process.env.OWLMEM_URL || "https://owlmem.com").replace(/\/$/, "");
46
46
  const DIR = process.env.OWLMEM_HOME || join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "owlmem");
47
47
  const enc = new TextEncoder(), dec = new TextDecoder();
@@ -1253,6 +1253,19 @@ export class Scheduler {
1253
1253
  get size() { return this.running.size + this.queue.length; }
1254
1254
  }
1255
1255
 
1256
+ // Check-ins for the AI (0.9.4, 站长 11-01「npm 方式、不消耗 token 上报」): while an AI this program started is still working
1257
+ // on a task, tell OwlMem every ALIVE_EVERY that its process is running. That counts as the task's heartbeat, so the AI
1258
+ // doesn't spend tokens reporting in itself. Only tasks whose process is running (the scheduler's running set); replies
1259
+ // (type note) have no heartbeat. When the process ends this stops by itself and report() says how it ended.
1260
+ export const ALIVE_EVERY = 60 * 1000;
1261
+ export async function aliveTick(sched, api, log = () => {}) {
1262
+ const ids = [...sched.running].filter((j) => j.task?.type !== "note" && j.id != null).map((j) => j.id);
1263
+ if (!ids.length) return [];
1264
+ const r = await api("alive", { ids });
1265
+ if (r.status !== 200 && r.status !== 404) log("check-in: OwlMem answered " + (r.data?.detail || "HTTP " + r.status));
1266
+ return ids;
1267
+ }
1268
+
1256
1269
  // The long-poll loop. api(sub, body) → {status, data}. Returns "revoked" after cleaning up on a 401.
1257
1270
  export async function wakeLoop(o) {
1258
1271
  const { cfg, api, sched, log = () => {}, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), once = false, cleanup } = o;
@@ -1586,6 +1599,7 @@ async function wakeRun() {
1586
1599
  log("OwlMem auto-wake " + VERSION + " running on " + (cfg.machine || hostname()) + ".");
1587
1600
  const usage = () => usageTick(cfg, api, log).catch((e) => log("usage: " + e.message));
1588
1601
  setTimeout(usage, 30000).unref(); setInterval(usage, USAGE_EVERY).unref();
1602
+ setInterval(() => aliveTick(sched, api, log).catch((e) => log("check-in: " + e.message)), ALIVE_EVERY).unref();
1589
1603
  const out = await wakeLoop({ cfg, api, sched, log, update: (v) => wakeUpdate(v, { log }),
1590
1604
  cleanup: () => { try { wakeUninstall(autostartOpts(), wakeRunCmd, true); } catch (e) { log("cleanup: " + e.message); } } });
1591
1605
  if (out === "revoked") process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "owlmem",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "description": "OwlMem command line: connect your AI apps to OwlMem in one command (npx -y owlmem install), an end-to-end encrypted vault for your AI agents, and a local MCP server.",
5
5
  "type": "module",
6
6
  "bin": { "owlmem": "owlmem.mjs" },