openclaw-lark-multi-agent 1.8.21 → 1.8.22

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.
package/dist/config.d.ts CHANGED
@@ -13,13 +13,16 @@ export interface BotConfig {
13
13
  locale?: Locale;
14
14
  /** Optional per-bot thinking level (informational fallback for footers). */
15
15
  thinking?: string;
16
- /** OpenClaw agent/profile that owns this bot's sessions.
16
+ /** OpenClaw agent that owns this bot's sessions.
17
17
  *
18
- * Optional for backward compatibility: a bot that does not name a profile
19
- * keeps the historical `main` profile, so existing configs behave exactly
20
- * as before. When set, the bot's sessions are addressed under that
21
- * profile, giving it that profile's own workspace, memory and identity.
18
+ * Selects which agent entry (from agents.entries in openclaw.json) owns
19
+ * this bot's sessions — its workspace, memory, identity and model routing.
20
+ * Optional: a bot that does not name an agent keeps the historical `main`
21
+ * agent, so existing configs behave exactly as before.
22
+ * The legacy field name `profile` is accepted as an alias and migrated.
22
23
  * Defaults to "main" when absent or blank. */
24
+ agent?: string;
25
+ /** @deprecated Use `agent` instead. Accepted as an alias. */
23
26
  profile?: string;
24
27
  }
25
28
  export interface OpenClawConfig {
package/dist/config.js CHANGED
@@ -23,11 +23,10 @@ export function loadConfig(path) {
23
23
  config.locale = normalizeLocale(config.locale);
24
24
  for (const bot of config.bots) {
25
25
  bot.locale = normalizeLocale(bot.locale || config.locale);
26
- // A bot without a profile keeps the historical `main` profile. Older
27
- // configs stay byte-identical in behaviour; a profile is only a routing
28
- // choice, never a required field.
29
- const profile = String(bot.profile == null ? "" : bot.profile).trim();
30
- bot.profile = profile || DEFAULT_BOT_PROFILE;
26
+ // `agent` is the canonical field; `profile` is a legacy alias.
27
+ const agent = String(bot.agent ?? bot.profile ?? "").trim();
28
+ bot.agent = agent || DEFAULT_BOT_PROFILE;
29
+ bot.profile = bot.agent;
31
30
  // An empty model means "follow the profile's own model".
32
31
  const model = String(bot.model == null ? "" : bot.model).trim();
33
32
  bot.model = model || undefined;
@@ -400,7 +400,7 @@ export class FeishuBot {
400
400
  this.goController = new GoController({
401
401
  botName: config.name,
402
402
  fallbackModel: config.model || "",
403
- profile: this.profile,
403
+ agent: this.profile,
404
404
  store,
405
405
  client: openclawClient,
406
406
  executorSessionKeyFor: (chatId) => this.physicalSessionKey(chatId),
@@ -487,7 +487,7 @@ export class FeishuBot {
487
487
  * Defaults to "main" so a configuration written before profiles existed
488
488
  * keeps its historical behaviour exactly. */
489
489
  get profile() {
490
- return String(this.config.profile || "main").trim() || "main";
490
+ return String(this.config.agent || this.config.profile || "main").trim() || "main";
491
491
  }
492
492
  getSessionKey(chatId) {
493
493
  return `lma-${this.config.name.toLowerCase()}-${chatId}`;
@@ -702,7 +702,7 @@ export class FeishuBot {
702
702
  await this.wsClient.start({ eventDispatcher: this.eventDispatcher });
703
703
  if (this.identityClosed)
704
704
  return;
705
- console.log(`[${this.config.name}] Bot started (model: ${this.config.model || `profile ${this.profile}`}, open_id: ${this.botOpenId || "unknown"})`);
705
+ console.log(`[${this.config.name}] Bot started (model: ${this.config.model || `agent ${this.profile}`}, open_id: ${this.botOpenId || "unknown"})`);
706
706
  // Drain any unsynced messages left from previous run
707
707
  this.drainOnStartup();
708
708
  void this.drainIdentityIngress().catch(err => console.warn(`[${this.config.name}] Identity ingress recovery failed:`, err.message));
@@ -5998,7 +5998,7 @@ export class FeishuBot {
5998
5998
  return;
5999
5999
  }
6000
6000
  if (nextModel === this.config.model) {
6001
- await this.replyMessage(messageId, `🤖 ${this.config.name} 已经在使用:${this.config.model || `profile ${this.profile}`}`);
6001
+ await this.replyMessage(messageId, `🤖 ${this.config.name} 已经在使用:${this.config.model || `agent ${this.profile}`}`);
6002
6002
  return;
6003
6003
  }
6004
6004
  if (!this.configPath) {
@@ -75,8 +75,8 @@ export type GoClient = {
75
75
  export type GoControllerDeps = {
76
76
  botName: string;
77
77
  fallbackModel: string;
78
- /** OpenClaw profile that owns this bot's sessions (default "main"). */
79
- profile?: string;
78
+ /** OpenClaw agent that owns this bot's sessions (default "main"). */
79
+ agent?: string;
80
80
  store: import("./message-store.js").MessageStore;
81
81
  client: GoClient;
82
82
  /** Executor session key for a chat (e.g. lma-<bot>-<chatId>). */
@@ -1,13 +1,13 @@
1
1
  /** Independent LMA supervision. MessageStore owns objective, criteria and completion. */
2
2
  import { goSnapshotBlocked } from "./go-runtime-gate.js";
3
- /** Logical (profile-free) part of a session key. */
3
+ /** Logical (agent-free) part of a session key. */
4
4
  const withoutAgentPrefix = (key) => key.replace(/^agent:[^:]+:/, '');
5
- /** Physical session key for a logical executor key under this bot's profile. */
6
- const physicalKey = (key, profile) => {
5
+ /** Physical session key for a logical executor key under this bot's agent. */
6
+ const physicalKey = (key, agentName) => {
7
7
  if (/^agent:[^:]+:/.test(key))
8
8
  return key;
9
- const agent = String(profile || "main").trim() || "main";
10
- return `agent:${agent}:${key}`;
9
+ const resolved = String(agentName || "main").trim() || "main";
10
+ return `agent:${resolved}:${key}`;
11
11
  };
12
12
  const CHECK_DELAY_MS = Number(process.env.OPENCLAW_LARK_MULTI_AGENT_GO_CHECK_DELAY_MS || 20000);
13
13
  const CHECKER_TIMEOUT_MS = Number(process.env.OPENCLAW_LARK_MULTI_AGENT_GO_CHECKER_TIMEOUT_MS || 10 * 60 * 1000);
@@ -129,7 +129,7 @@ export class GoController {
129
129
  const executor = sessionKey === job.executorSessionKey;
130
130
  const result = executor ? await client.collectGoExecutorRun({ runId: receipt.runId, sessionKey, sessionId: expectedSessionId, timeoutMs: CHECKER_TIMEOUT_MS }) : null;
131
131
  if (result && (result.runId !== receipt.runId || result.sessionId !== expectedSessionId ||
132
- (result.sessionKey !== sessionKey && result.sessionKey !== physicalKey(sessionKey, this.d.profile))))
132
+ (result.sessionKey !== sessionKey && result.sessionKey !== physicalKey(sessionKey, this.d.agent))))
133
133
  throw new Error("Executor result identity mismatch");
134
134
  const text = result ? result.text : await client.collectGoRun({ runId: receipt.runId, sessionKey, sessionId: expectedSessionId, timeoutMs: CHECKER_TIMEOUT_MS });
135
135
  this.d.store.recordGoRunResult(jobId, actionKey, { state: "complete", runId: receipt.runId, text, ...(result ? { executorResult: result } : {}) });
@@ -214,9 +214,9 @@ export class GoController {
214
214
  return;
215
215
  }
216
216
  // The Go supervision path talks to the Gateway directly, so it uses the
217
- // PHYSICAL key throughout (profile included) exactly like the executor
217
+ // PHYSICAL key throughout (agent included) exactly like the executor
218
218
  // session itself.
219
- const executorKey = physicalKey(this.d.executorSessionKeyFor(chatId), this.d.profile);
219
+ const executorKey = physicalKey(this.d.executorSessionKeyFor(chatId), this.d.agent);
220
220
  if (await this.safetyUnavailable(executorKey)) {
221
221
  await this.d.reply(messageId, "❌ Go 未启动:当前运行时尚未验证 Checker 工具隔离、精确子孙任务/投递门禁及条件发送。不能仅凭提示词安全开启自动监督。独立模式无需原生 Goal;普通聊天不受影响。");
222
222
  return;
@@ -242,10 +242,10 @@ export class GoController {
242
242
  || (typeof session.model === "string" && session.model
243
243
  ? (typeof session.modelProvider === "string" && session.modelProvider && !session.model.includes("/") ? `${session.modelProvider}/${session.model}` : session.model)
244
244
  : this.d.fallbackModel);
245
- // The checker session NAME stays profile-free (lma- -> lma-go-), exactly like
245
+ // The checker session NAME stays agent-free (lma- -> lma-go-), exactly like
246
246
  // every other logical key LMA stores. It is addressed under the bot's
247
- // profile only when it is actually handed to the Gateway.
248
- const checkerKey = physicalKey(`${withoutAgentPrefix(executorKey).replace(/^lma-/, "lma-go-")}-${crypto.randomUUID()}`, this.d.profile);
247
+ // agent only when it is actually handed to the Gateway.
248
+ const checkerKey = physicalKey(`${withoutAgentPrefix(executorKey).replace(/^lma-/, "lma-go-")}-${crypto.randomUUID()}`, this.d.agent);
249
249
  try {
250
250
  await this.d.client.createSession({ key: checkerKey, model: resolvedModel, label: `Go Checker: ${this.d.botName} ${chatId.slice(-6)}` });
251
251
  }
@@ -364,7 +364,7 @@ export class GoController {
364
364
  if (saved?.state !== "complete") {
365
365
  const result = await this.d.client.readGoExecutorRunResult?.({ ...send, runId: receipt.runId });
366
366
  if (!result || result.runId !== receipt.runId || result.sessionId !== job.executorSessionId ||
367
- ![job.executorSessionKey, physicalKey(job.executorSessionKey, this.d.profile)].includes(result.sessionKey)) {
367
+ ![job.executorSessionKey, physicalKey(job.executorSessionKey, this.d.agent)].includes(result.sessionKey)) {
368
368
  this.d.store.recordGoRunResult(job.id, send.actionKey, { state: "unknown", runId: receipt.runId });
369
369
  continue;
370
370
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-lark-multi-agent",
3
- "version": "1.8.21",
3
+ "version": "1.8.22",
4
4
  "description": "Multi-bot Lark/Feishu bridge for OpenClaw, with per-bot model routing and isolated sessions",
5
5
  "type": "module",
6
6
  "scripts": {