agentlife 2.6.31 → 2.6.32

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 +100 -83
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1838,12 +1838,15 @@ async function provisionAgents(state, cfg, runtime, log) {
1838
1838
  }
1839
1839
  }
1840
1840
  const provisionedIds = new Set(PROVISIONED_AGENTS.map((a) => a.id));
1841
+ const backfilledSubagentIds = [];
1841
1842
  for (const agent of currentList) {
1842
1843
  if (provisionedIds.has(agent.id))
1843
1844
  continue;
1844
1845
  if (!agent.subagents) {
1845
1846
  agent.subagents = { allowAgents: ["*"] };
1846
1847
  configChanged = true;
1848
+ if (agent.id)
1849
+ backfilledSubagentIds.push(agent.id);
1847
1850
  log(`[agentlife] backfilled subagents for ${agent.id}`);
1848
1851
  }
1849
1852
  }
@@ -1856,6 +1859,18 @@ async function provisionAgents(state, cfg, runtime, log) {
1856
1859
  const configPath = path4.join(os.homedir(), ".openclaw", "openclaw.json");
1857
1860
  const rawCfgForVisibility = JSON.parse(readFileSync2(configPath, "utf-8"));
1858
1861
  const backupPath = path4.join(os.homedir(), ".openclaw", "agentlife", "config-backup.json");
1862
+ if (backfilledSubagentIds.length > 0) {
1863
+ try {
1864
+ let backup = {};
1865
+ try {
1866
+ backup = JSON.parse(readFileSync2(backupPath, "utf-8"));
1867
+ } catch {}
1868
+ const existing = Array.isArray(backup.subagentsBackfilledIds) ? backup.subagentsBackfilledIds : [];
1869
+ backup.subagentsBackfilledIds = [...new Set([...existing, ...backfilledSubagentIds])];
1870
+ writeFileSync(backupPath, JSON.stringify(backup, null, 2) + `
1871
+ `, "utf-8");
1872
+ } catch {}
1873
+ }
1859
1874
  let visibilityWritten = false;
1860
1875
  const currentVisibility = rawCfgForVisibility?.tools?.sessions?.visibility;
1861
1876
  if (currentVisibility !== "all") {
@@ -3277,17 +3292,21 @@ function pollFollowups(state) {
3277
3292
  }
3278
3293
  sweepCounter++;
3279
3294
  if (sweepCounter % 5 === 0 && state.surfaceIndex && state.followupQueue && state.fileSurfaceStorage) {
3280
- sweepExpiredSurfaces({
3281
- index: state.surfaceIndex,
3282
- queue: state.followupQueue,
3283
- storage: state.fileSurfaceStorage
3284
- }).then((r) => {
3285
- for (const sid of r.purged)
3286
- broadcastDelete(sid);
3287
- if (r.purged.length > 0) {
3288
- console.log("[agentlife:sweep] purged %d expired surfaces", r.purged.length);
3289
- }
3290
- }).catch((e) => console.warn("[agentlife:sweep] error: %s", e?.message));
3295
+ try {
3296
+ sweepExpiredSurfaces({
3297
+ index: state.surfaceIndex,
3298
+ queue: state.followupQueue,
3299
+ storage: state.fileSurfaceStorage
3300
+ }).then((r) => {
3301
+ for (const sid of r.purged)
3302
+ broadcastDelete(sid);
3303
+ if (r.purged.length > 0) {
3304
+ console.log("[agentlife:sweep] purged %d expired surfaces", r.purged.length);
3305
+ }
3306
+ }).catch((e) => console.warn("[agentlife:sweep] error: %s", e?.message));
3307
+ } catch (e) {
3308
+ console.warn("[agentlife] sweep invocation failed synchronously: %s", e?.message);
3309
+ }
3291
3310
  }
3292
3311
  }
3293
3312
 
@@ -3983,7 +4002,6 @@ async function restoreConfigFromBackup(api, backupPath) {
3983
4002
  delete fileCfg.agents?.defaults?.maxConcurrent;
3984
4003
  }
3985
4004
  await writeRawConfigToDisk(fileCfg);
3986
- await fs5.unlink(backupPath);
3987
4005
  console.log("[agentlife] restored config: maxPingPongTurns=%s, maxConcurrent=%s", backup.maxPingPongTurns ?? "default", backup.maxConcurrent ?? "default");
3988
4006
  return `config restored`;
3989
4007
  }
@@ -7462,11 +7480,11 @@ function registerAgentGateway(api, state2) {
7462
7480
  const subagents = params?.subagents && typeof params.subagents === "object" ? params.subagents : undefined;
7463
7481
  const identity = params?.identity && typeof params.identity === "object" ? params.identity : undefined;
7464
7482
  if (!id) {
7465
- respond(false, { error: "missing agent id" });
7483
+ respond(false, undefined, { code: "INVALID_REQUEST", message: "missing agent id" });
7466
7484
  return;
7467
7485
  }
7468
7486
  if (!workspace) {
7469
- respond(false, { error: "missing workspace path" });
7487
+ respond(false, undefined, { code: "INVALID_REQUEST", message: "missing workspace path" });
7470
7488
  return;
7471
7489
  }
7472
7490
  const cfg = api.runtime.config.loadConfig();
@@ -7474,9 +7492,9 @@ function registerAgentGateway(api, state2) {
7474
7492
  const providerInConfig = provider ? authenticatedProvidersFromConfig(cfg).has(provider) : false;
7475
7493
  const siblingAuth = provider ? findSiblingAuthProfile(provider, id) : null;
7476
7494
  if (provider && !providerInConfig && !siblingAuth) {
7477
- respond(false, {
7478
- error: `missing provider credentials for ${provider}; configure ${provider} before creating an agent with ${model}`,
7495
+ respond(false, undefined, {
7479
7496
  code: "missing_provider_auth",
7497
+ message: `missing provider credentials for ${provider}; configure ${provider} before creating an agent with ${model}`,
7480
7498
  provider,
7481
7499
  model
7482
7500
  });
@@ -7562,16 +7580,16 @@ function registerAgentGateway(api, state2) {
7562
7580
  }
7563
7581
  }
7564
7582
  respond(true, { status, id, name, model, workspace, description, ...authCopied ? { authCopied: true } : {}, ...configFields.length ? { configFields } : {} });
7565
- });
7583
+ }, { scope: "operator.admin" });
7566
7584
  api.registerGatewayMethod("agentlife.deleteAgent", async ({ params, respond }) => {
7567
7585
  const id = typeof params?.id === "string" ? params.id.trim() : "";
7568
7586
  if (!id) {
7569
- respond(false, { error: "missing agent id" });
7587
+ respond(false, undefined, { code: "INVALID_REQUEST", message: "missing agent id" });
7570
7588
  return;
7571
7589
  }
7572
7590
  const provisionedIds = new Set(PROVISIONED_AGENTS.map((a) => a.id));
7573
7591
  if (provisionedIds.has(id)) {
7574
- respond(false, { error: "cannot delete provisioned agent" });
7592
+ respond(false, undefined, { code: "FAILED", message: "cannot delete provisioned agent" });
7575
7593
  return;
7576
7594
  }
7577
7595
  const cleanup = {
@@ -7709,7 +7727,7 @@ function registerAgentGateway(api, state2) {
7709
7727
  }
7710
7728
  console.log("[agentlife] deleted agent: %s (config=%s, registry=%s, surfaces=%d, sessions=%d, cron=%d, historyRows=%d, agentDb=%s, state=%s, workspace=%s)", id, removedFromConfig, removedFromRegistry, cleanup.surfacesCleared, cleanup.sessions, cleanup.cronJobs, cleanup.historyRows, cleanup.agentDbDeleted, cleanup.stateDeleted, cleanup.workspaceDeleted);
7711
7729
  respond(true, { status: "deleted", id, removedFromConfig, removedFromRegistry, cleanup });
7712
- });
7730
+ }, { scope: "operator.admin" });
7713
7731
  api.registerGatewayMethod("agentlife.agents", ({ respond }) => {
7714
7732
  const agents = {};
7715
7733
  for (const [id, entry] of state2.agentRegistry.entries()) {
@@ -7726,11 +7744,11 @@ function registerDbGateway(api, state2) {
7726
7744
  const sql = typeof params?.sql === "string" ? params.sql.trim() : "";
7727
7745
  const sqlParams = Array.isArray(params?.params) ? params.params : [];
7728
7746
  if (!agentId)
7729
- return respond(false, { error: "missing agentId" });
7747
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "missing agentId" });
7730
7748
  if (!sql)
7731
- return respond(false, { error: "missing sql" });
7749
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "missing sql" });
7732
7750
  if (/^\s*SELECT\b/i.test(sql))
7733
- return respond(false, { error: "use agentlife.db.query for SELECT" });
7751
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "use agentlife.db.query for SELECT" });
7734
7752
  try {
7735
7753
  const db = getOrCreateAgentDb(state2, agentId);
7736
7754
  if (sqlParams.length > 0) {
@@ -7741,19 +7759,19 @@ function registerDbGateway(api, state2) {
7741
7759
  respond(true, { changes: 0, lastInsertRowid: 0 });
7742
7760
  }
7743
7761
  } catch (err) {
7744
- respond(false, { error: err?.message ?? "db error" });
7762
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "db error" });
7745
7763
  }
7746
- });
7764
+ }, { scope: "operator.admin" });
7747
7765
  api.registerGatewayMethod("agentlife.db.query", ({ params, respond }) => {
7748
7766
  const agentId = typeof params?.agentId === "string" ? params.agentId.trim() : "";
7749
7767
  const sql = typeof params?.sql === "string" ? params.sql.trim() : "";
7750
7768
  const sqlParams = Array.isArray(params?.params) ? params.params : [];
7751
7769
  if (!agentId)
7752
- return respond(false, { error: "missing agentId" });
7770
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "missing agentId" });
7753
7771
  if (!sql)
7754
- return respond(false, { error: "missing sql" });
7772
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "missing sql" });
7755
7773
  if (!/^\s*SELECT\b/i.test(sql))
7756
- return respond(false, { error: "use agentlife.db.exec for non-SELECT" });
7774
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "use agentlife.db.exec for non-SELECT" });
7757
7775
  try {
7758
7776
  const db = getOrCreateAgentDb(state2, agentId);
7759
7777
  const rows = db.prepare(sql).all(...sqlParams);
@@ -7763,9 +7781,9 @@ function registerDbGateway(api, state2) {
7763
7781
  const columns = result.length > 0 ? Object.keys(result[0]) : [];
7764
7782
  respond(true, { rows: result, columns, count: result.length, truncated });
7765
7783
  } catch (err) {
7766
- respond(false, { error: err?.message ?? "db error" });
7784
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "db error" });
7767
7785
  }
7768
- });
7786
+ }, { scope: "operator.admin" });
7769
7787
  }
7770
7788
 
7771
7789
  // gateway/history.ts
@@ -7806,7 +7824,7 @@ function registerHistoryGateway(api, state2) {
7806
7824
  const rows = db.prepare(`SELECT * FROM surface_events ${where} ORDER BY createdAt DESC LIMIT ? OFFSET ?`).all(...bind);
7807
7825
  respond(true, { events: rows, count: rows.length });
7808
7826
  } catch (err) {
7809
- respond(false, { error: err?.message ?? "history error" });
7827
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "history error" });
7810
7828
  }
7811
7829
  }, { scope: "operator.read" });
7812
7830
  api.registerGatewayMethod("agentlife.history.widgets", ({ params, respond }) => {
@@ -7847,7 +7865,7 @@ function registerHistoryGateway(api, state2) {
7847
7865
  `).all(...bind, limit, offset);
7848
7866
  respond(true, { widgets: rows, count: rows.length, hasMore: rows.length >= limit });
7849
7867
  } catch (err) {
7850
- respond(false, { error: err?.message ?? "history.widgets error" });
7868
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "history.widgets error" });
7851
7869
  }
7852
7870
  }, { scope: "operator.read" });
7853
7871
  api.registerGatewayMethod("agentlife.trace", ({ params, respond }) => {
@@ -7904,7 +7922,7 @@ function registerHistoryGateway(api, state2) {
7904
7922
  }));
7905
7923
  respond(true, { entries, hasMore });
7906
7924
  } catch (err) {
7907
- respond(false, { error: err?.message ?? "trace query failed" });
7925
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "trace query failed" });
7908
7926
  }
7909
7927
  }, { scope: "operator.read" });
7910
7928
  }
@@ -7977,13 +7995,13 @@ function registerUsageGateway(api, state2) {
7977
7995
  bySession: bySessionRows
7978
7996
  });
7979
7997
  } catch (err) {
7980
- respond(false, { error: err?.message ?? "usage query error" });
7998
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "usage query error" });
7981
7999
  }
7982
8000
  }, { scope: "operator.read" });
7983
8001
  api.registerGatewayMethod("agentlife.surfaceUsage", ({ params, respond }) => {
7984
8002
  const surfaceId = typeof params?.surfaceId === "string" ? params.surfaceId.trim() : "";
7985
8003
  if (!surfaceId)
7986
- return respond(false, { error: "missing surfaceId" });
8004
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "missing surfaceId" });
7987
8005
  try {
7988
8006
  const db = getOrCreateHistoryDb(state2);
7989
8007
  const rows = db.prepare(`SELECT * FROM surface_usage WHERE surfaceId = ? ORDER BY createdAt DESC`).all(surfaceId);
@@ -7999,7 +8017,7 @@ function registerUsageGateway(api, state2) {
7999
8017
  }, { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, totalTokens: 0, estimatedCost: 0, llmCalls: 0 });
8000
8018
  respond(true, { surfaceId, entries: rows, totals });
8001
8019
  } catch (err) {
8002
- respond(false, { error: err?.message ?? "surface usage error" });
8020
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "surface usage error" });
8003
8021
  }
8004
8022
  }, { scope: "operator.read" });
8005
8023
  }
@@ -8048,7 +8066,7 @@ function registerSurfacesGateway(api, state2) {
8048
8066
  api.registerGatewayMethod("agentlife.dismiss", async ({ params, respond }) => {
8049
8067
  const surfaceId = params?.surfaceId;
8050
8068
  if (!surfaceId || typeof surfaceId !== "string") {
8051
- respond(false, { error: "missing surfaceId" });
8069
+ respond(false, undefined, { code: "INVALID_REQUEST", message: "missing surfaceId" });
8052
8070
  return;
8053
8071
  }
8054
8072
  const view2 = getSurface(state2, surfaceId);
@@ -8119,7 +8137,7 @@ function registerSurfacesGateway(api, state2) {
8119
8137
  const surfaceId = typeof params?.surfaceId === "string" ? params.surfaceId.trim() : "";
8120
8138
  const event = typeof params?.event === "string" ? params.event.trim() : "";
8121
8139
  if (!surfaceId || !event) {
8122
- respond(false, { error: "missing surfaceId or event" });
8140
+ respond(false, undefined, { code: "INVALID_REQUEST", message: "missing surfaceId or event" });
8123
8141
  return;
8124
8142
  }
8125
8143
  const agentId = getAgentId(state2, surfaceId) ?? undefined;
@@ -8131,7 +8149,7 @@ function registerSurfacesGateway(api, state2) {
8131
8149
  const message = typeof params?.message === "string" ? params.message : "";
8132
8150
  const sessionKey = typeof params?.sessionKey === "string" ? params.sessionKey : "";
8133
8151
  if (!message) {
8134
- respond(false, { error: "missing message" });
8152
+ respond(false, undefined, { code: "INVALID_REQUEST", message: "missing message" });
8135
8153
  return;
8136
8154
  }
8137
8155
  broadcastInput(message, sessionKey);
@@ -8140,7 +8158,7 @@ function registerSurfacesGateway(api, state2) {
8140
8158
  api.registerGatewayMethod("agentlife.chain.get", ({ params, respond }) => {
8141
8159
  const root = typeof params?.root === "string" ? params.root.trim() : "";
8142
8160
  if (!root) {
8143
- respond(false, { error: "missing root" });
8161
+ respond(false, undefined, { code: "INVALID_REQUEST", message: "missing root" });
8144
8162
  return;
8145
8163
  }
8146
8164
  if (!state2.surfaceIndex) {
@@ -8164,7 +8182,7 @@ function registerSurfacesGateway(api, state2) {
8164
8182
  api.registerGatewayMethod("agentlife.action", ({ params, respond }) => {
8165
8183
  const surfaceId = typeof params?.surfaceId === "string" ? params.surfaceId.trim() : "";
8166
8184
  if (!surfaceId) {
8167
- respond(false, { error: "missing surfaceId" });
8185
+ respond(false, undefined, { code: "INVALID_REQUEST", message: "missing surfaceId" });
8168
8186
  return;
8169
8187
  }
8170
8188
  const view2 = getSurface(state2, surfaceId);
@@ -8255,7 +8273,7 @@ function registerAutomationsGateway(api, state2) {
8255
8273
  const name = typeof params?.name === "string" ? params.name.trim() : "";
8256
8274
  const automationPath = typeof params?.path === "string" ? params.path.trim() : "";
8257
8275
  if (!type || !name || !automationPath) {
8258
- respond(false, { error: "missing required fields: type, name, path" });
8276
+ respond(false, undefined, { code: "INVALID_REQUEST", message: "missing required fields: type, name, path" });
8259
8277
  return;
8260
8278
  }
8261
8279
  const surfaceId = typeof params?.surfaceId === "string" ? params.surfaceId.trim() : "";
@@ -8263,7 +8281,7 @@ function registerAutomationsGateway(api, state2) {
8263
8281
  const id = registerAutomation(state2, { surfaceId, agentId, type, name, path: automationPath });
8264
8282
  respond(true, { id, surfaceId, agentId, type, name, path: automationPath, status: "running" });
8265
8283
  } catch (err) {
8266
- respond(false, { error: err?.message ?? "register failed" });
8284
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "register failed" });
8267
8285
  }
8268
8286
  }, { scope: "operator.write" });
8269
8287
  api.registerGatewayMethod("agentlife.automations.list", ({ params, respond }) => {
@@ -8304,7 +8322,7 @@ function registerAutomationsGateway(api, state2) {
8304
8322
  }))
8305
8323
  });
8306
8324
  } catch (err) {
8307
- respond(false, { error: err?.message ?? "list failed" });
8325
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "list failed" });
8308
8326
  }
8309
8327
  }, { scope: "operator.read" });
8310
8328
  api.registerGatewayMethod("agentlife.automations.update", ({ params, respond }) => {
@@ -8312,28 +8330,28 @@ function registerAutomationsGateway(api, state2) {
8312
8330
  const id = typeof params?.id === "number" ? params.id : parseInt(params?.id, 10);
8313
8331
  const status = typeof params?.status === "string" ? params.status.trim() : "";
8314
8332
  if (!id || !status || !["running", "stopped", "error"].includes(status)) {
8315
- respond(false, { error: "missing id or invalid status (running|stopped|error)" });
8333
+ respond(false, undefined, { code: "INVALID_REQUEST", message: "missing id or invalid status (running|stopped|error)" });
8316
8334
  return;
8317
8335
  }
8318
8336
  const db = getOrCreateHistoryDb(state2);
8319
8337
  db.prepare("UPDATE automations SET status = ?, updatedAt = ? WHERE id = ?").run(status, Date.now(), id);
8320
8338
  respond(true, { id, status });
8321
8339
  } catch (err) {
8322
- respond(false, { error: err?.message ?? "update failed" });
8340
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "update failed" });
8323
8341
  }
8324
8342
  }, { scope: "operator.write" });
8325
8343
  api.registerGatewayMethod("agentlife.automations.remove", ({ params, respond }) => {
8326
8344
  try {
8327
8345
  const id = typeof params?.id === "number" ? params.id : parseInt(params?.id, 10);
8328
8346
  if (!id) {
8329
- respond(false, { error: "missing id" });
8347
+ respond(false, undefined, { code: "INVALID_REQUEST", message: "missing id" });
8330
8348
  return;
8331
8349
  }
8332
8350
  const db = getOrCreateHistoryDb(state2);
8333
8351
  db.prepare("UPDATE automations SET status = 'removed', updatedAt = ? WHERE id = ?").run(Date.now(), id);
8334
8352
  respond(true, { id, status: "removed" });
8335
8353
  } catch (err) {
8336
- respond(false, { error: err?.message ?? "remove failed" });
8354
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "remove failed" });
8337
8355
  }
8338
8356
  }, { scope: "operator.write" });
8339
8357
  }
@@ -8466,7 +8484,7 @@ function registerAdminGateway(api, state2) {
8466
8484
  cleanup: { pending: cleanupPending, failed: cleanupFailed, exhausted: cleanupExhausted }
8467
8485
  });
8468
8486
  } catch (err) {
8469
- respond(false, { error: err?.message ?? "quality metrics unavailable" });
8487
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "quality metrics unavailable" });
8470
8488
  }
8471
8489
  }, { scope: "operator.read" });
8472
8490
  api.registerGatewayMethod("agentlife.health.list", ({ respond }) => {
@@ -8487,7 +8505,7 @@ function registerAdminGateway(api, state2) {
8487
8505
  const rows = runDailyCycle(db, day);
8488
8506
  respond(true, { day, rows });
8489
8507
  } catch (err) {
8490
- respond(false, { error: err?.message ?? "observability runCycle failed" });
8508
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "observability runCycle failed" });
8491
8509
  }
8492
8510
  }, { scope: "operator.write" });
8493
8511
  api.registerGatewayMethod("agentlife.sweep.run", ({ respond }) => {
@@ -8495,7 +8513,7 @@ function registerAdminGateway(api, state2) {
8495
8513
  const result = runDailySweep(state2);
8496
8514
  respond(true, result);
8497
8515
  } catch (err) {
8498
- respond(false, { error: err?.message ?? "daily sweep failed" });
8516
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "daily sweep failed" });
8499
8517
  }
8500
8518
  }, { scope: "operator.write" });
8501
8519
  api.registerGatewayMethod("agentlife.bootstrap", ({ params, respond }) => {
@@ -8623,7 +8641,6 @@ function registerAdminGateway(api, state2) {
8623
8641
  dbPath,
8624
8642
  dbPath ? `${dbPath}-wal` : null,
8625
8643
  dbPath ? `${dbPath}-shm` : null,
8626
- path15.join(baseDir, "config-backup.json"),
8627
8644
  path15.join(baseDir, "notification-config.json"),
8628
8645
  path15.join(baseDir, "canvas-node-identity.json")
8629
8646
  ].filter(Boolean);
@@ -8662,7 +8679,7 @@ function registerAdminGateway(api, state2) {
8662
8679
  });
8663
8680
  } catch (err) {
8664
8681
  console.error("[agentlife] uninstall failed:", err);
8665
- respond(false, { error: err?.message ?? "unknown error during uninstall" });
8682
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? "unknown error during uninstall" });
8666
8683
  }
8667
8684
  });
8668
8685
  api.registerGatewayMethod("agentlife.config.get", ({ respond }) => {
@@ -9316,20 +9333,20 @@ function registerProvidersGateway(api, state2) {
9316
9333
  }));
9317
9334
  respond(true, { providers });
9318
9335
  } catch (err) {
9319
- respond(false, { error: err?.message ?? String(err) });
9336
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9320
9337
  }
9321
9338
  }, { scope: "operator.read" });
9322
9339
  api.registerGatewayMethod("agentlife.providers.set", async ({ params, respond }) => {
9323
9340
  const provider = typeof params?.provider === "string" ? params.provider.trim() : "";
9324
9341
  const apiKey = typeof params?.apiKey === "string" ? params.apiKey.trim() : "";
9325
9342
  if (!provider)
9326
- return respond(false, { error: "provider is empty" });
9343
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "provider is empty" });
9327
9344
  if (!apiKey)
9328
- return respond(false, { error: "apiKey is empty" });
9345
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "apiKey is empty" });
9329
9346
  try {
9330
9347
  const catalog = await ensureCatalog(run ?? null);
9331
9348
  if (catalog.length > 0 && !catalog.some((e) => e.provider === provider)) {
9332
- return respond(false, { error: `unknown provider: ${provider}` });
9349
+ return respond(false, undefined, { code: "NOT_FOUND", message: `unknown provider: ${provider}` });
9333
9350
  }
9334
9351
  } catch {}
9335
9352
  try {
@@ -9350,13 +9367,13 @@ function registerProvidersGateway(api, state2) {
9350
9367
  writeConfig(nextCfg);
9351
9368
  respond(true, { provider, configured: true, profileId });
9352
9369
  } catch (err) {
9353
- respond(false, { error: err?.message ?? String(err) });
9370
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9354
9371
  }
9355
9372
  }, { scope: "operator.write" });
9356
9373
  api.registerGatewayMethod("agentlife.providers.delete", ({ params, respond }) => {
9357
9374
  const provider = typeof params?.provider === "string" ? params.provider.trim() : "";
9358
9375
  if (!provider)
9359
- return respond(false, { error: "provider is empty" });
9376
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "provider is empty" });
9360
9377
  try {
9361
9378
  const cfg = readConfig();
9362
9379
  const profiles = cfg?.auth?.profiles;
@@ -9395,14 +9412,14 @@ function registerProvidersGateway(api, state2) {
9395
9412
  }
9396
9413
  respond(true, { provider, configured: false });
9397
9414
  } catch (err) {
9398
- respond(false, { error: err?.message ?? String(err) });
9415
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9399
9416
  }
9400
9417
  }, { scope: "operator.write" });
9401
9418
  api.registerGatewayMethod("agentlife.providers.test", async ({ params, respond }) => {
9402
9419
  const provider = typeof params?.provider === "string" ? params.provider.trim() : "";
9403
9420
  const apiKey = typeof params?.apiKey === "string" ? params.apiKey.trim() : "";
9404
9421
  if (!provider)
9405
- return respond(false, { error: "provider is empty" });
9422
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "provider is empty" });
9406
9423
  if (!apiKey)
9407
9424
  return respond(true, { ok: false, error: "apiKey required — type a key before testing" });
9408
9425
  try {
@@ -9428,7 +9445,7 @@ function registerProvidersGateway(api, state2) {
9428
9445
  });
9429
9446
  respond(true, { models: deduped });
9430
9447
  } catch (err) {
9431
- respond(false, { error: err?.message ?? String(err) });
9448
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9432
9449
  }
9433
9450
  }, { scope: "operator.read" });
9434
9451
  api.registerGatewayMethod("agentlife.providers.health", ({ respond }) => {
@@ -9458,23 +9475,23 @@ function registerProvidersGateway(api, state2) {
9458
9475
  }
9459
9476
  respond(true, { probes });
9460
9477
  } catch (err) {
9461
- respond(false, { error: err?.message ?? String(err) });
9478
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9462
9479
  }
9463
9480
  }, { scope: "operator.read" });
9464
9481
  api.registerGatewayMethod("agentlife.providers.loginCodex", async ({ respond }) => {
9465
9482
  if (!run)
9466
- return respond(false, { error: "runCommand unavailable" });
9483
+ return respond(false, undefined, { code: "UNAVAILABLE", message: "runCommand unavailable" });
9467
9484
  try {
9468
9485
  const result = await run(["openclaw", "capability", "model", "auth", "login", "--provider", "openai-codex"], { timeoutMs: 180000 });
9469
9486
  const combined = `${result?.stdout ?? ""}
9470
9487
  ${result?.stderr ?? ""}`;
9471
9488
  const urlMatch = combined.match(/https:\/\/\S+/);
9472
9489
  if ((result?.code ?? 0) !== 0 && !urlMatch) {
9473
- return respond(false, { error: (result?.stderr ?? "").trim() || "codex login failed" });
9490
+ return respond(false, undefined, { code: "FAILED", message: (result?.stderr ?? "").trim() || "codex login failed" });
9474
9491
  }
9475
9492
  respond(true, { url: urlMatch?.[0] ?? null, completed: (result?.code ?? 0) === 0 });
9476
9493
  } catch (err) {
9477
- respond(false, { error: err?.message ?? String(err) });
9494
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9478
9495
  }
9479
9496
  }, { scope: "operator.write" });
9480
9497
  }
@@ -9510,13 +9527,13 @@ function registerModelsConfigGateway(api) {
9510
9527
  fallbacks: Array.isArray(m.fallbacks) ? m.fallbacks.filter((x) => typeof x === "string") : []
9511
9528
  });
9512
9529
  } catch (err) {
9513
- respond(false, { error: err?.message ?? String(err) });
9530
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9514
9531
  }
9515
9532
  }, { scope: "operator.read" });
9516
9533
  api.registerGatewayMethod("agentlife.models.defaults.setPrimary", ({ params, respond }) => {
9517
9534
  const model = typeof params?.model === "string" ? params.model.trim() : "";
9518
9535
  if (!model)
9519
- return respond(false, { error: "model is required" });
9536
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "model is required" });
9520
9537
  try {
9521
9538
  const cfg = readConfig();
9522
9539
  cfg.agents = cfg.agents ?? {};
@@ -9526,26 +9543,26 @@ function registerModelsConfigGateway(api) {
9526
9543
  writeConfig(cfg);
9527
9544
  respond(true, { ok: true });
9528
9545
  } catch (err) {
9529
- respond(false, { error: err?.message ?? String(err) });
9546
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9530
9547
  }
9531
9548
  }, { scope: "operator.write" });
9532
9549
  api.registerGatewayMethod("agentlife.models.defaults.setInternal", ({ params, respond }) => {
9533
9550
  const model = typeof params?.model === "string" ? params.model.trim() : "";
9534
9551
  if (!model)
9535
- return respond(false, { error: "model is required" });
9552
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "model is required" });
9536
9553
  try {
9537
9554
  const cfg = readPluginConfig2();
9538
9555
  cfg.internalModel = model;
9539
9556
  writePluginConfig2(cfg);
9540
9557
  respond(true, { ok: true });
9541
9558
  } catch (err) {
9542
- respond(false, { error: err?.message ?? String(err) });
9559
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9543
9560
  }
9544
9561
  }, { scope: "operator.write" });
9545
9562
  api.registerGatewayMethod("agentlife.models.fallbacks.set", ({ params, respond }) => {
9546
9563
  const models = Array.isArray(params?.models) ? params.models.filter((x) => typeof x === "string") : null;
9547
9564
  if (!models)
9548
- return respond(false, { error: "models must be an array of strings" });
9565
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "models must be an array of strings" });
9549
9566
  try {
9550
9567
  const cfg = readConfig();
9551
9568
  cfg.agents = cfg.agents ?? {};
@@ -9555,7 +9572,7 @@ function registerModelsConfigGateway(api) {
9555
9572
  writeConfig(cfg);
9556
9573
  respond(true, { ok: true });
9557
9574
  } catch (err) {
9558
- respond(false, { error: err?.message ?? String(err) });
9575
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9559
9576
  }
9560
9577
  }, { scope: "operator.write" });
9561
9578
  api.registerGatewayMethod("agentlife.agents.list", ({ respond }) => {
@@ -9569,23 +9586,23 @@ function registerModelsConfigGateway(api) {
9569
9586
  })).filter((a) => a.id !== null && a.name !== null);
9570
9587
  respond(true, { agents });
9571
9588
  } catch (err) {
9572
- respond(false, { error: err?.message ?? String(err) });
9589
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9573
9590
  }
9574
9591
  }, { scope: "operator.read" });
9575
9592
  api.registerGatewayMethod("agentlife.agents.setModel", ({ params, respond }) => {
9576
9593
  const agentId = typeof params?.agentId === "string" ? params.agentId.trim() : "";
9577
9594
  if (!agentId)
9578
- return respond(false, { error: "agentId is required" });
9595
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "agentId is required" });
9579
9596
  const model = params?.model;
9580
9597
  if (model !== null && typeof model !== "string") {
9581
- return respond(false, { error: "model must be string or null" });
9598
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "model must be string or null" });
9582
9599
  }
9583
9600
  try {
9584
9601
  const cfg = readConfig();
9585
9602
  const list = Array.isArray(cfg?.agents?.list) ? cfg.agents.list : [];
9586
9603
  const idx = list.findIndex((a) => a?.id === agentId);
9587
9604
  if (idx < 0)
9588
- return respond(false, { error: `agent not found: ${agentId}` });
9605
+ return respond(false, undefined, { code: "NOT_FOUND", message: `agent not found: ${agentId}` });
9589
9606
  if (model === null) {
9590
9607
  delete list[idx].model;
9591
9608
  } else {
@@ -9594,19 +9611,19 @@ function registerModelsConfigGateway(api) {
9594
9611
  writeConfig(cfg);
9595
9612
  respond(true, { ok: true });
9596
9613
  } catch (err) {
9597
- respond(false, { error: err?.message ?? String(err) });
9614
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9598
9615
  }
9599
9616
  }, { scope: "operator.write" });
9600
9617
  api.registerGatewayMethod("agentlife.agents.setModel.bulk", ({ params, respond }) => {
9601
9618
  const updates = Array.isArray(params?.updates) ? params.updates : null;
9602
9619
  if (!updates)
9603
- return respond(false, { error: "updates must be an array" });
9620
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "updates must be an array" });
9604
9621
  for (const u of updates) {
9605
9622
  if (!u || typeof u.agentId !== "string" || !u.agentId.trim()) {
9606
- return respond(false, { error: "each update needs agentId (string)" });
9623
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "each update needs agentId (string)" });
9607
9624
  }
9608
9625
  if (u.model !== null && typeof u.model !== "string") {
9609
- return respond(false, { error: "each update model must be string or null" });
9626
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "each update model must be string or null" });
9610
9627
  }
9611
9628
  }
9612
9629
  try {
@@ -9627,7 +9644,7 @@ function registerModelsConfigGateway(api) {
9627
9644
  writeConfig(cfg);
9628
9645
  respond(true, { ok: true, applied });
9629
9646
  } catch (err) {
9630
- respond(false, { error: err?.message ?? String(err) });
9647
+ respond(false, undefined, { code: "INTERNAL", message: err?.message ?? String(err) });
9631
9648
  }
9632
9649
  }, { scope: "operator.write" });
9633
9650
  }
@@ -9818,7 +9835,7 @@ function register(api) {
9818
9835
  const serverUrl = typeof params?.serverUrl === "string" ? params.serverUrl.trim() : "";
9819
9836
  const apiKey = typeof params?.apiKey === "string" ? params.apiKey.trim() : "";
9820
9837
  if (!serverUrl || !apiKey) {
9821
- return respond(false, { error: "missing serverUrl or apiKey" });
9838
+ return respond(false, undefined, { code: "INVALID_REQUEST", message: "missing serverUrl or apiKey" });
9822
9839
  }
9823
9840
  try {
9824
9841
  const { writeFileSync: writeFileSync12, mkdirSync: mkdirSync10 } = __require("node:fs");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentlife",
3
- "version": "2.6.31",
3
+ "version": "2.6.32",
4
4
  "description": "Native mobile dashboard for OpenClaw — agents push live widgets, automations, and remote-access surfaces to your phone via the AgentLife plugin relay.",
5
5
  "keywords": [
6
6
  "openclaw",