agentlife 1.5.2 → 1.5.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/dist/index.js +345 -25
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2,8 +2,8 @@ import { createRequire } from "node:module";
2
2
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
3
 
4
4
  // index.ts
5
- import { homedir as homedir11 } from "node:os";
6
- import * as path15 from "node:path";
5
+ import { homedir as homedir13 } from "node:os";
6
+ import * as path17 from "node:path";
7
7
  import { existsSync as existsSync6 } from "node:fs";
8
8
 
9
9
  // db.ts
@@ -1812,6 +1812,27 @@ async function provisionAgents(state, cfg, runtime, log) {
1812
1812
  rawCfgForVisibility.tools.sessions.visibility = "all";
1813
1813
  visibilityWritten = true;
1814
1814
  }
1815
+ const currentA2A = rawCfgForVisibility?.tools?.agentToAgent?.enabled;
1816
+ let a2aWritten = false;
1817
+ if (currentA2A !== true) {
1818
+ try {
1819
+ let backup = {};
1820
+ try {
1821
+ backup = JSON.parse(readFileSync(backupPath, "utf-8"));
1822
+ } catch {}
1823
+ if (backup.agentToAgentEnabled === undefined) {
1824
+ backup.agentToAgentEnabled = currentA2A ?? null;
1825
+ writeFileSync(backupPath, JSON.stringify(backup, null, 2) + `
1826
+ `, "utf-8");
1827
+ }
1828
+ } catch {}
1829
+ if (!rawCfgForVisibility.tools)
1830
+ rawCfgForVisibility.tools = {};
1831
+ if (!rawCfgForVisibility.tools.agentToAgent)
1832
+ rawCfgForVisibility.tools.agentToAgent = {};
1833
+ rawCfgForVisibility.tools.agentToAgent.enabled = true;
1834
+ a2aWritten = true;
1835
+ }
1815
1836
  const currentAllow = rawCfgForVisibility?.tools?.allow;
1816
1837
  let globalAllowWritten = false;
1817
1838
  if (Array.isArray(currentAllow) && currentAllow.length > 0 && !currentAllow.includes("*")) {
@@ -1832,12 +1853,14 @@ async function provisionAgents(state, cfg, runtime, log) {
1832
1853
  globalAllowWritten = true;
1833
1854
  }
1834
1855
  }
1835
- if (visibilityWritten || globalAllowWritten) {
1856
+ if (visibilityWritten || a2aWritten || globalAllowWritten) {
1836
1857
  writeFileSync(configPath, JSON.stringify(rawCfgForVisibility, null, 2) + `
1837
1858
  `, "utf-8");
1838
1859
  configChanged = true;
1839
1860
  if (visibilityWritten)
1840
1861
  log("[agentlife] set tools.sessions.visibility=all (cross-agent delegation)");
1862
+ if (a2aWritten)
1863
+ log("[agentlife] set tools.agentToAgent.enabled=true (cross-agent sends)");
1841
1864
  if (globalAllowWritten)
1842
1865
  log('[agentlife] added "*" to tools.allow (unblock exec/read/write for provisioned agents)');
1843
1866
  }
@@ -2215,6 +2238,10 @@ async function transition(state, runtime, log, trigger) {
2215
2238
  if (visionSurfaceCount(state) >= 1) {
2216
2239
  return enterPhase(state, runtime, log, "READY");
2217
2240
  }
2241
+ if (lastText.length === 0) {
2242
+ log(`[cold-start] agentlife-vision replied empty in SYNTHESIZING — model error or silent fail`);
2243
+ return enterFailed(state, log, "vision_agent_empty_reply");
2244
+ }
2218
2245
  return cur;
2219
2246
  }
2220
2247
  if (cur.phase === "AWAITING_BASELINE") {
@@ -2956,6 +2983,7 @@ function computeEnhancedMetrics(db, agentId, since) {
2956
2983
 
2957
2984
  // followup.ts
2958
2985
  var pollerInterval = null;
2986
+ var startupPollTimeout = null;
2959
2987
  var sweepCounter = 0;
2960
2988
  function initFollowupSystem(api, state) {
2961
2989
  if (!state.runCommand) {
@@ -2983,14 +3011,26 @@ function initFollowupSystem(api, state) {
2983
3011
  CREATE INDEX IF NOT EXISTS idx_followups_status ON followups(status);
2984
3012
  `);
2985
3013
  pollerInterval = setInterval(() => pollFollowups(state), 60000);
2986
- setTimeout(() => pollFollowups(state), 5000);
3014
+ startupPollTimeout = setTimeout(() => {
3015
+ startupPollTimeout = null;
3016
+ pollFollowups(state);
3017
+ }, 5000);
2987
3018
  console.log("[agentlife:followup] system initialized — polling every 60s");
2988
3019
  }
2989
- function stopFollowupSystem() {
3020
+ function stopFollowupSystem(state) {
2990
3021
  if (pollerInterval) {
2991
3022
  clearInterval(pollerInterval);
2992
3023
  pollerInterval = null;
2993
3024
  }
3025
+ if (startupPollTimeout) {
3026
+ clearTimeout(startupPollTimeout);
3027
+ startupPollTimeout = null;
3028
+ }
3029
+ if (state) {
3030
+ for (const handle of state.pendingFollowups.values())
3031
+ clearTimeout(handle);
3032
+ state.pendingFollowups.clear();
3033
+ }
2994
3034
  }
2995
3035
  function parseFollowup(raw) {
2996
3036
  const match = raw.match(/^(\+\d+(?:ms|s|m|h|d))\s+(.+)/);
@@ -3012,7 +3052,15 @@ function scheduleFollowup(state, surfaceId, followupRaw, agentId) {
3012
3052
  clearTimeout(existing);
3013
3053
  state.pendingFollowups.set(surfaceId, setTimeout(() => {
3014
3054
  state.pendingFollowups.delete(surfaceId);
3015
- executeSchedule(state, surfaceId, parsed, agentId);
3055
+ if (state.disabled)
3056
+ return;
3057
+ try {
3058
+ executeSchedule(state, surfaceId, parsed, agentId);
3059
+ } catch (err) {
3060
+ if (err?.code === "ERR_INVALID_STATE")
3061
+ return;
3062
+ console.warn("[agentlife:followup] executeSchedule threw: %s", err?.message ?? err);
3063
+ }
3016
3064
  }, 2000));
3017
3065
  }
3018
3066
  function removeFollowup(state, surfaceId) {
@@ -7622,14 +7670,13 @@ function registerAdminGateway(api, state2) {
7622
7670
  } catch {
7623
7671
  cleaned.push("maxPingPongTurns already at default (no backup found)");
7624
7672
  }
7625
- stopFollowupSystem();
7673
+ stopFollowupSystem(state2);
7626
7674
  if (state2.surfaceDb)
7627
7675
  state2.surfaceDb.clear();
7628
7676
  closeAllDbs(state2);
7629
7677
  state2.agentRegistry.clear();
7630
7678
  state2.usageAccumulator.clear();
7631
7679
  state2.sessionBootstrapSnapshots.clear();
7632
- state2.pendingFollowups.clear();
7633
7680
  state2.surfaceDb = null;
7634
7681
  state2.disabled = true;
7635
7682
  cleaned.push("stopped runtime (poller, DBs, in-memory state)");
@@ -7910,17 +7957,17 @@ function parseOffset2(offset) {
7910
7957
  }
7911
7958
 
7912
7959
  // gateway/providers.ts
7913
- import * as fs11 from "node:fs";
7914
- import * as os9 from "node:os";
7915
- import * as path14 from "node:path";
7916
7960
  import {
7917
7961
  upsertApiKeyProfile,
7962
+ upsertAuthProfile,
7963
+ buildApiKeyCredential,
7918
7964
  applyAuthProfileConfig
7919
7965
  } from "openclaw/plugin-sdk/provider-auth-api-key";
7920
- var catalogCache = null;
7921
- var catalogPromise = null;
7922
- var modelsCache = null;
7923
- var modelsPromise = null;
7966
+
7967
+ // gateway/config-utils.ts
7968
+ import * as fs11 from "node:fs";
7969
+ import * as os9 from "node:os";
7970
+ import * as path14 from "node:path";
7924
7971
  function configPath() {
7925
7972
  return path14.join(os9.homedir(), ".openclaw", "openclaw.json");
7926
7973
  }
@@ -7935,6 +7982,35 @@ function writeConfig(cfg) {
7935
7982
  fs11.writeFileSync(configPath(), JSON.stringify(cfg, null, 2) + `
7936
7983
  `, "utf-8");
7937
7984
  }
7985
+
7986
+ // gateway/providers.ts
7987
+ import * as fs12 from "node:fs";
7988
+ import * as os10 from "node:os";
7989
+ import * as path15 from "node:path";
7990
+ function siblingAgentDirs() {
7991
+ const root = path15.join(os10.homedir(), ".openclaw", "agents");
7992
+ let entries;
7993
+ try {
7994
+ entries = fs12.readdirSync(root, { withFileTypes: true });
7995
+ } catch {
7996
+ return [];
7997
+ }
7998
+ const out = [];
7999
+ for (const entry of entries) {
8000
+ if (!entry.isDirectory() && !entry.isSymbolicLink())
8001
+ continue;
8002
+ const dir = path15.join(root, entry.name, "agent");
8003
+ try {
8004
+ if (fs12.statSync(dir).isDirectory())
8005
+ out.push(dir);
8006
+ } catch {}
8007
+ }
8008
+ return out;
8009
+ }
8010
+ var catalogCache = null;
8011
+ var catalogPromise = null;
8012
+ var modelsCache = null;
8013
+ var modelsPromise = null;
7938
8014
  async function fetchCatalog(run) {
7939
8015
  const result = await run(["openclaw", "infer", "model", "providers", "--json"], { timeoutMs: 60000 });
7940
8016
  if ((result?.code ?? 0) !== 0)
@@ -7993,6 +8069,37 @@ async function ensureModels(run) {
7993
8069
  }
7994
8070
  return modelsPromise;
7995
8071
  }
8072
+ function readOAuthExpiries() {
8073
+ const result = new Map;
8074
+ const fs13 = __require("node:fs");
8075
+ const path16 = __require("node:path");
8076
+ const os11 = __require("node:os");
8077
+ const agentsDir = path16.join(os11.homedir(), ".openclaw", "agents");
8078
+ let entries;
8079
+ try {
8080
+ entries = fs13.readdirSync(agentsDir);
8081
+ } catch {
8082
+ return result;
8083
+ }
8084
+ for (const name of entries) {
8085
+ const filePath = path16.join(agentsDir, name, "agent", "auth-profiles.json");
8086
+ try {
8087
+ const raw = fs13.readFileSync(filePath, "utf-8");
8088
+ const data = JSON.parse(raw);
8089
+ const profiles = data?.profiles ?? {};
8090
+ for (const entry of Object.values(profiles)) {
8091
+ const p = entry;
8092
+ if (p?.type === "oauth" && typeof p.provider === "string" && typeof p.expires === "number") {
8093
+ const prev = result.get(p.provider);
8094
+ if (!prev || p.expires > prev.expiresAt) {
8095
+ result.set(p.provider, { expiresAt: p.expires });
8096
+ }
8097
+ }
8098
+ }
8099
+ } catch {}
8100
+ }
8101
+ return result;
8102
+ }
7996
8103
  function authenticatedProviders() {
7997
8104
  const cfg = readConfig();
7998
8105
  const profiles = cfg?.auth?.profiles ?? {};
@@ -8112,6 +8219,12 @@ function registerProvidersGateway(api, state2) {
8112
8219
  } catch {}
8113
8220
  try {
8114
8221
  const profileId = upsertApiKeyProfile({ provider, input: apiKey });
8222
+ const credential = buildApiKeyCredential(provider, apiKey);
8223
+ for (const agentDir of siblingAgentDirs()) {
8224
+ try {
8225
+ upsertAuthProfile({ profileId, credential, agentDir });
8226
+ } catch {}
8227
+ }
8115
8228
  const cfg = readConfig();
8116
8229
  const nextCfg = applyAuthProfileConfig(cfg, {
8117
8230
  profileId,
@@ -8142,6 +8255,29 @@ function registerProvidersGateway(api, state2) {
8142
8255
  delete cfg.auth.order[provider];
8143
8256
  }
8144
8257
  writeConfig(cfg);
8258
+ for (const agentDir of siblingAgentDirs()) {
8259
+ const file = path15.join(agentDir, "auth-profiles.json");
8260
+ try {
8261
+ const raw = fs12.readFileSync(file, "utf-8");
8262
+ const data = JSON.parse(raw);
8263
+ const agentProfiles = data?.profiles;
8264
+ if (!agentProfiles || typeof agentProfiles !== "object")
8265
+ continue;
8266
+ let changed = false;
8267
+ for (const [id, entry] of Object.entries(agentProfiles)) {
8268
+ if (entry?.provider === provider) {
8269
+ delete agentProfiles[id];
8270
+ changed = true;
8271
+ }
8272
+ }
8273
+ if (data?.order?.[provider]) {
8274
+ delete data.order[provider];
8275
+ changed = true;
8276
+ }
8277
+ if (changed)
8278
+ fs12.writeFileSync(file, JSON.stringify(data, null, 2), "utf-8");
8279
+ } catch {}
8280
+ }
8145
8281
  respond(true, { provider, configured: false });
8146
8282
  } catch (err) {
8147
8283
  respond(false, { error: err?.message ?? String(err) });
@@ -8180,6 +8316,36 @@ function registerProvidersGateway(api, state2) {
8180
8316
  respond(false, { error: err?.message ?? String(err) });
8181
8317
  }
8182
8318
  }, { scope: "operator.read" });
8319
+ api.registerGatewayMethod("agentlife.providers.health", ({ respond }) => {
8320
+ try {
8321
+ const cfg = readConfig();
8322
+ const profiles = cfg?.auth?.profiles ?? {};
8323
+ const oauthInfo = readOAuthExpiries();
8324
+ const probes = [];
8325
+ for (const entry of Object.values(profiles)) {
8326
+ const p = entry;
8327
+ if (typeof p?.provider !== "string")
8328
+ continue;
8329
+ const provider = p.provider;
8330
+ const probe2 = {
8331
+ provider,
8332
+ configured: true,
8333
+ supported: true
8334
+ };
8335
+ if (p.mode === "oauth") {
8336
+ const info = oauthInfo.get(provider);
8337
+ if (info?.expiresAt) {
8338
+ probe2.expiresAt = info.expiresAt;
8339
+ probe2.oauthExpired = info.expiresAt < Date.now();
8340
+ }
8341
+ }
8342
+ probes.push(probe2);
8343
+ }
8344
+ respond(true, { probes });
8345
+ } catch (err) {
8346
+ respond(false, { error: err?.message ?? String(err) });
8347
+ }
8348
+ }, { scope: "operator.read" });
8183
8349
  api.registerGatewayMethod("agentlife.providers.loginCodex", async ({ respond }) => {
8184
8350
  if (!run)
8185
8351
  return respond(false, { error: "runCommand unavailable" });
@@ -8198,6 +8364,159 @@ ${result?.stderr ?? ""}`;
8198
8364
  }, { scope: "operator.write" });
8199
8365
  }
8200
8366
 
8367
+ // gateway/models-config.ts
8368
+ import * as fs13 from "node:fs";
8369
+ import * as os11 from "node:os";
8370
+ import * as path16 from "node:path";
8371
+ function pluginConfigPath2() {
8372
+ return path16.join(os11.homedir(), ".openclaw", "agentlife", "plugin-config.json");
8373
+ }
8374
+ function readPluginConfig2() {
8375
+ try {
8376
+ return JSON.parse(fs13.readFileSync(pluginConfigPath2(), "utf-8"));
8377
+ } catch {
8378
+ return {};
8379
+ }
8380
+ }
8381
+ function writePluginConfig2(cfg) {
8382
+ fs13.mkdirSync(path16.dirname(pluginConfigPath2()), { recursive: true });
8383
+ fs13.writeFileSync(pluginConfigPath2(), JSON.stringify(cfg, null, 2) + `
8384
+ `, "utf-8");
8385
+ }
8386
+ function registerModelsConfigGateway(api) {
8387
+ api.registerGatewayMethod("agentlife.models.defaults.get", ({ respond }) => {
8388
+ try {
8389
+ const cfg = readConfig();
8390
+ const m = cfg?.agents?.defaults?.model ?? {};
8391
+ const pluginCfg = readPluginConfig2();
8392
+ respond(true, {
8393
+ primary: typeof m.primary === "string" ? m.primary : "",
8394
+ internal: typeof pluginCfg.internalModel === "string" ? pluginCfg.internalModel : "",
8395
+ fallbacks: Array.isArray(m.fallbacks) ? m.fallbacks.filter((x) => typeof x === "string") : []
8396
+ });
8397
+ } catch (err) {
8398
+ respond(false, { error: err?.message ?? String(err) });
8399
+ }
8400
+ }, { scope: "operator.read" });
8401
+ api.registerGatewayMethod("agentlife.models.defaults.setPrimary", ({ params, respond }) => {
8402
+ const model = typeof params?.model === "string" ? params.model.trim() : "";
8403
+ if (!model)
8404
+ return respond(false, { error: "model is required" });
8405
+ try {
8406
+ const cfg = readConfig();
8407
+ cfg.agents = cfg.agents ?? {};
8408
+ cfg.agents.defaults = cfg.agents.defaults ?? {};
8409
+ cfg.agents.defaults.model = cfg.agents.defaults.model ?? {};
8410
+ cfg.agents.defaults.model.primary = model;
8411
+ writeConfig(cfg);
8412
+ respond(true, { ok: true });
8413
+ } catch (err) {
8414
+ respond(false, { error: err?.message ?? String(err) });
8415
+ }
8416
+ }, { scope: "operator.write" });
8417
+ api.registerGatewayMethod("agentlife.models.defaults.setInternal", ({ params, respond }) => {
8418
+ const model = typeof params?.model === "string" ? params.model.trim() : "";
8419
+ if (!model)
8420
+ return respond(false, { error: "model is required" });
8421
+ try {
8422
+ const cfg = readPluginConfig2();
8423
+ cfg.internalModel = model;
8424
+ writePluginConfig2(cfg);
8425
+ respond(true, { ok: true });
8426
+ } catch (err) {
8427
+ respond(false, { error: err?.message ?? String(err) });
8428
+ }
8429
+ }, { scope: "operator.write" });
8430
+ api.registerGatewayMethod("agentlife.models.fallbacks.set", ({ params, respond }) => {
8431
+ const models = Array.isArray(params?.models) ? params.models.filter((x) => typeof x === "string") : null;
8432
+ if (!models)
8433
+ return respond(false, { error: "models must be an array of strings" });
8434
+ try {
8435
+ const cfg = readConfig();
8436
+ cfg.agents = cfg.agents ?? {};
8437
+ cfg.agents.defaults = cfg.agents.defaults ?? {};
8438
+ cfg.agents.defaults.model = cfg.agents.defaults.model ?? {};
8439
+ cfg.agents.defaults.model.fallbacks = models;
8440
+ writeConfig(cfg);
8441
+ respond(true, { ok: true });
8442
+ } catch (err) {
8443
+ respond(false, { error: err?.message ?? String(err) });
8444
+ }
8445
+ }, { scope: "operator.write" });
8446
+ api.registerGatewayMethod("agentlife.agents.list", ({ respond }) => {
8447
+ try {
8448
+ const cfg = readConfig();
8449
+ const list = Array.isArray(cfg?.agents?.list) ? cfg.agents.list : [];
8450
+ const agents = list.map((a) => ({
8451
+ id: typeof a?.id === "string" ? a.id : null,
8452
+ name: typeof a?.name === "string" ? a.name : null,
8453
+ modelOverride: typeof a?.model === "string" ? a.model : null
8454
+ })).filter((a) => a.id !== null && a.name !== null);
8455
+ respond(true, { agents });
8456
+ } catch (err) {
8457
+ respond(false, { error: err?.message ?? String(err) });
8458
+ }
8459
+ }, { scope: "operator.read" });
8460
+ api.registerGatewayMethod("agentlife.agents.setModel", ({ params, respond }) => {
8461
+ const agentId = typeof params?.agentId === "string" ? params.agentId.trim() : "";
8462
+ if (!agentId)
8463
+ return respond(false, { error: "agentId is required" });
8464
+ const model = params?.model;
8465
+ if (model !== null && typeof model !== "string") {
8466
+ return respond(false, { error: "model must be string or null" });
8467
+ }
8468
+ try {
8469
+ const cfg = readConfig();
8470
+ const list = Array.isArray(cfg?.agents?.list) ? cfg.agents.list : [];
8471
+ const idx = list.findIndex((a) => a?.id === agentId);
8472
+ if (idx < 0)
8473
+ return respond(false, { error: `agent not found: ${agentId}` });
8474
+ if (model === null) {
8475
+ delete list[idx].model;
8476
+ } else {
8477
+ list[idx].model = model.trim();
8478
+ }
8479
+ writeConfig(cfg);
8480
+ respond(true, { ok: true });
8481
+ } catch (err) {
8482
+ respond(false, { error: err?.message ?? String(err) });
8483
+ }
8484
+ }, { scope: "operator.write" });
8485
+ api.registerGatewayMethod("agentlife.agents.setModel.bulk", ({ params, respond }) => {
8486
+ const updates = Array.isArray(params?.updates) ? params.updates : null;
8487
+ if (!updates)
8488
+ return respond(false, { error: "updates must be an array" });
8489
+ for (const u of updates) {
8490
+ if (!u || typeof u.agentId !== "string" || !u.agentId.trim()) {
8491
+ return respond(false, { error: "each update needs agentId (string)" });
8492
+ }
8493
+ if (u.model !== null && typeof u.model !== "string") {
8494
+ return respond(false, { error: "each update model must be string or null" });
8495
+ }
8496
+ }
8497
+ try {
8498
+ const cfg = readConfig();
8499
+ const list = Array.isArray(cfg?.agents?.list) ? cfg.agents.list : [];
8500
+ let applied = 0;
8501
+ for (const u of updates) {
8502
+ const idx = list.findIndex((a) => a?.id === u.agentId);
8503
+ if (idx < 0)
8504
+ continue;
8505
+ if (u.model === null) {
8506
+ delete list[idx].model;
8507
+ } else {
8508
+ list[idx].model = u.model.trim();
8509
+ }
8510
+ applied++;
8511
+ }
8512
+ writeConfig(cfg);
8513
+ respond(true, { ok: true, applied });
8514
+ } catch (err) {
8515
+ respond(false, { error: err?.message ?? String(err) });
8516
+ }
8517
+ }, { scope: "operator.write" });
8518
+ }
8519
+
8201
8520
  // index.ts
8202
8521
  var currentState = null;
8203
8522
  var registered = false;
@@ -8207,7 +8526,7 @@ var stopQualityCheckPoller = null;
8207
8526
  var stopCloudflared = null;
8208
8527
  function resolveInternalModel(api) {
8209
8528
  try {
8210
- const pluginCfgPath = path15.join(homedir11(), ".openclaw", "agentlife", "plugin-config.json");
8529
+ const pluginCfgPath = path17.join(homedir13(), ".openclaw", "agentlife", "plugin-config.json");
8211
8530
  try {
8212
8531
  const raw = __require("node:fs").readFileSync(pluginCfgPath, "utf-8");
8213
8532
  const pluginCfg = JSON.parse(raw);
@@ -8243,7 +8562,7 @@ function register(api) {
8243
8562
  return;
8244
8563
  }
8245
8564
  registered = true;
8246
- const fallbackDir = path15.join(homedir11(), ".openclaw", "agentlife");
8565
+ const fallbackDir = path17.join(homedir13(), ".openclaw", "agentlife");
8247
8566
  const state2 = {
8248
8567
  surfaceDb: null,
8249
8568
  agentRegistry: new Map,
@@ -8253,9 +8572,9 @@ function register(api) {
8253
8572
  agentDbs: new Map,
8254
8573
  historyDb: null,
8255
8574
  agentlifeStateDir: fallbackDir,
8256
- registryFilePath: path15.join(fallbackDir, "agent-registry.json"),
8257
- dbBaseDir: path15.join(fallbackDir, "db"),
8258
- historyDbPath: path15.join(fallbackDir, "agentlife.db"),
8575
+ registryFilePath: path17.join(fallbackDir, "agent-registry.json"),
8576
+ dbBaseDir: path17.join(fallbackDir, "db"),
8577
+ historyDbPath: path17.join(fallbackDir, "agentlife.db"),
8259
8578
  runCommand: api.runtime.system?.runCommandWithTimeout ?? null,
8260
8579
  enqueueSystemEvent: null,
8261
8580
  requestHeartbeatNow: null,
@@ -8296,7 +8615,7 @@ function register(api) {
8296
8615
  id: "agentlife-shutdown",
8297
8616
  start: () => {},
8298
8617
  stop: () => {
8299
- stopFollowupSystem();
8618
+ stopFollowupSystem(state2);
8300
8619
  if (stopObservability) {
8301
8620
  stopObservability();
8302
8621
  stopObservability = null;
@@ -8331,8 +8650,9 @@ function register(api) {
8331
8650
  registerFollowupsGateway(api, state2);
8332
8651
  registerAdminGateway(api, state2);
8333
8652
  registerProvidersGateway(api, state2);
8653
+ registerModelsConfigGateway(api);
8334
8654
  registerWebApp(api);
8335
- const notifyConfigPath = path15.join(fallbackDir, "notification-config.json");
8655
+ const notifyConfigPath = path17.join(fallbackDir, "notification-config.json");
8336
8656
  api.registerGatewayMethod("agentlife.notifications.register", ({ params, respond }) => {
8337
8657
  const serverUrl = typeof params?.serverUrl === "string" ? params.serverUrl.trim() : "";
8338
8658
  const apiKey = typeof params?.apiKey === "string" ? params.apiKey.trim() : "";
@@ -8340,9 +8660,9 @@ function register(api) {
8340
8660
  return respond(false, { error: "missing serverUrl or apiKey" });
8341
8661
  }
8342
8662
  try {
8343
- const { writeFileSync: writeFileSync8, mkdirSync: mkdirSync6 } = __require("node:fs");
8344
- mkdirSync6(path15.dirname(notifyConfigPath), { recursive: true });
8345
- writeFileSync8(notifyConfigPath, JSON.stringify({ serverUrl, apiKey }));
8663
+ const { writeFileSync: writeFileSync10, mkdirSync: mkdirSync7 } = __require("node:fs");
8664
+ mkdirSync7(path17.dirname(notifyConfigPath), { recursive: true });
8665
+ writeFileSync10(notifyConfigPath, JSON.stringify({ serverUrl, apiKey }));
8346
8666
  } catch {}
8347
8667
  respond(true, { registered: true });
8348
8668
  }, { scope: "operator.write" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentlife",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "bun build index.ts --outfile dist/index.js --target node --external openclaw/plugin-sdk",