openclaw-lark-multi-agent 1.4.3 → 1.4.5
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/README.md +38 -19
- package/README.zh-CN.md +14 -0
- package/dist/cli.js +4 -4
- package/dist/compact-progress.d.ts +4 -4
- package/dist/compact-progress.js +5 -5
- package/dist/feishu-bot.d.ts +28 -14
- package/dist/feishu-bot.js +322 -282
- package/dist/message-store.d.ts +4 -3
- package/dist/openclaw-client.d.ts +32 -25
- package/dist/openclaw-client.js +327 -158
- package/package.json +2 -2
- package/plugins/lma-steer/README.md +23 -30
- package/dist/session-file-compactor.d.ts +0 -39
- package/dist/session-file-compactor.js +0 -176
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ All of them connect to the same OpenClaw Gateway while keeping sessions, queues,
|
|
|
37
37
|
- Feishu image download and OpenClaw multimodal attachment forwarding
|
|
38
38
|
- Bridge attachment marker protocol for generated files/images/documents
|
|
39
39
|
- Feishu CardKit v2 Markdown rendering, including native table elements for pipe tables
|
|
40
|
-
- Live status card: in non-verbose mode each run shows a
|
|
40
|
+
- Live status card: in non-verbose mode each run shows a self-updating Feishu interactive card (title + recent activity window with per-line timestamps + elapsed footer, refreshed once per second), which collapses to tool-call count + elapsed on a clean finish; the final answer is sent separately at the bottom with a model footer
|
|
41
41
|
- Bridge-level slash commands and escaped OpenClaw slash commands
|
|
42
42
|
- `/discuss` mode for barrier-style multi-bot group discussion, including per-round markers and no-reply status notices
|
|
43
43
|
- `/chairman` role: a single per-group chairman that answers plain messages when no bot is in Free mode, and acts as host, challenger, and summarizer inside `/discuss`
|
|
@@ -99,22 +99,20 @@ On Windows, install [NSSM](https://nssm.cc/download), make sure `nssm.exe` is in
|
|
|
99
99
|
lma install-windows-service
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
###
|
|
102
|
+
### Real-time steering
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
When the agent is mid-run and a new message arrives, the bridge submits it via
|
|
105
|
+
OpenClaw's public `chat.send` API with `queueMode: "steer"`. The RPC
|
|
106
|
+
acknowledgment is provisional: LMA retains its durable pending trigger until a
|
|
107
|
+
matching `session.message` proves transcript commitment/consumption, and only
|
|
108
|
+
then switches Feishu from Typing to Get. Async `error`/`aborted` terminals are
|
|
109
|
+
routed by run id, while unconsumed input remains available for normal queue
|
|
110
|
+
fallback. This replaces the deprecated synchronous plugin primitive whose
|
|
111
|
+
boolean could not represent later runtime rejection.
|
|
106
112
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
systemctl --user restart openclaw-gateway.service
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
When the agent is mid-run and a new message arrives, the bridge injects it into
|
|
114
|
-
the active run at the next tool-call boundary (Feishu shows the "Get" reaction).
|
|
115
|
-
Without the plugin, the bridge falls back to queuing the message until the run
|
|
116
|
-
finishes — everything still works, just without real-time steering. See
|
|
117
|
-
`plugins/lma-steer/README.md` for details.
|
|
113
|
+
OpenClaw 2026.8+ no longer requires the bundled `lma-steer` plugin. The
|
|
114
|
+
`install-steer-plugin` command remains temporarily for older installations but
|
|
115
|
+
current LMA releases do not call its private Gateway method.
|
|
118
116
|
|
|
119
117
|
Useful CLI commands:
|
|
120
118
|
|
|
@@ -124,7 +122,7 @@ lma doctor
|
|
|
124
122
|
lma start [config]
|
|
125
123
|
lma init [--state-dir DIR] [--force]
|
|
126
124
|
lma install-systemd [--user|--system] [--state-dir DIR]
|
|
127
|
-
lma install-steer-plugin [--no-force]
|
|
125
|
+
lma install-steer-plugin [--no-force] # legacy; not needed on OpenClaw 2026.8+
|
|
128
126
|
```
|
|
129
127
|
|
|
130
128
|
## Quick start from source
|
|
@@ -450,6 +448,26 @@ Assistant replies are sent as Feishu CardKit v2 cards. Markdown is preprocessed
|
|
|
450
448
|
|
|
451
449
|
For generated files/images/documents, agents should use the bridge attachment marker protocol instead of calling Feishu messaging tools directly. The bridge strips the marker from the visible reply, validates the file path under the configured attachment directory, uploads/sends the attachment, and records it in local context. Markdown documents can be converted into Feishu cloud documents through this path.
|
|
452
450
|
|
|
451
|
+
## OpenClaw 2026.8 compatibility
|
|
452
|
+
|
|
453
|
+
LMA targets Gateway protocol 4 and is built/tested against `openclaw@2026.8.2`.
|
|
454
|
+
OpenClaw 2026.8 moves active session rows and transcripts into the per-agent
|
|
455
|
+
SQLite database. LMA never opens that database or rewrites archived JSONL:
|
|
456
|
+
`/compact` first requests semantic `sessions.compact`, then uses the same
|
|
457
|
+
Gateway RPC with a bounded `maxLines` tail only if semantic compaction cannot
|
|
458
|
+
run. Set `OPENCLAW_LARK_MULTI_AGENT_COMPACT_FALLBACK_MAX_LINES` to change the
|
|
459
|
+
default tail size (`200`, minimum `20`).
|
|
460
|
+
|
|
461
|
+
OpenClaw 2026.8 also separates model metadata from the override allowlist. Every
|
|
462
|
+
model configured in LMA must be permitted by `agents.defaults.modelPolicy.allow`
|
|
463
|
+
when that list is non-empty. Exact refs and `provider/*` wildcards are accepted.
|
|
464
|
+
LMA now surfaces a model-policy rejection instead of logging a false “model
|
|
465
|
+
ensured” success.
|
|
466
|
+
|
|
467
|
+
Mid-run messages use the public `chat.send { queueMode: "steer" }` path. LMA
|
|
468
|
+
keeps the durable trigger until `session.message` confirms consumption; this is
|
|
469
|
+
also the signal for the visible Typing-to-Get transition.
|
|
470
|
+
|
|
453
471
|
## Live status
|
|
454
472
|
|
|
455
473
|
In non-verbose mode, each run shows a single self-updating Feishu interactive
|
|
@@ -463,7 +481,7 @@ While running, the card shows:
|
|
|
463
481
|
- a rolling window of the most recent activity lines (tool start `▸`, tool end
|
|
464
482
|
`✓`, and intermediate assistant text `•`), each prefixed with the relative
|
|
465
483
|
time `mm:ss` since the run started;
|
|
466
|
-
- a footer with elapsed time
|
|
484
|
+
- a footer with elapsed time.
|
|
467
485
|
|
|
468
486
|
The card is created lazily (a fast reply that finishes within the create delay
|
|
469
487
|
never spawns a card, to avoid flicker) and is updated with `im.message.patch`,
|
|
@@ -479,8 +497,9 @@ When the run ends:
|
|
|
479
497
|
header, so the steps leading up to the failure stay visible for debugging.
|
|
480
498
|
|
|
481
499
|
The final answer is always delivered separately through the normal interactive-card
|
|
482
|
-
delivery path, so
|
|
483
|
-
|
|
500
|
+
delivery path, so it is created at completion time and remains below any user messages
|
|
501
|
+
inserted during the run. Its footer shows only the bound model name. The live-status
|
|
502
|
+
card remains a distinct earlier message and owns tool-call count + elapsed time.
|
|
484
503
|
|
|
485
504
|
Live status is on by default and can be toggled per bot/chat with
|
|
486
505
|
`/livestatus [on|off]`. It can be disabled globally by setting
|
package/README.zh-CN.md
CHANGED
|
@@ -408,6 +408,20 @@ v1 行为边界:如果消息已经进入 OpenClaw 正在处理,暂不 abort
|
|
|
408
408
|
|
|
409
409
|
如果 Agent 需要发送生成的文件、图片或文档,应使用 bridge attachment marker 协议,而不是直接调用飞书消息工具。桥接层会从可见回复中剥离 marker,校验文件路径位于配置的附件目录下,然后上传/发送附件,并写入本地上下文。Markdown 文档也可以通过这个路径转换成飞书云文档。
|
|
410
410
|
|
|
411
|
+
## OpenClaw 2026.8 兼容性
|
|
412
|
+
|
|
413
|
+
LMA 以 Gateway protocol 4 为基线,并使用 `openclaw@2026.8.2` 构建和测试。OpenClaw 2026.8 把活动 session row 与 transcript 迁入每个 Agent 的 SQLite 数据库。LMA 不再直接查找或改写 JSONL:`/compact` 先调用语义化 `sessions.compact`,如果语义压缩无法执行,再通过同一个 Gateway RPC 的 `maxLines` 安全保留最近一段转录。可用 `OPENCLAW_LARK_MULTI_AGENT_COMPACT_FALLBACK_MAX_LINES` 调整默认保留数量(默认 `200`,最小 `20`)。
|
|
414
|
+
|
|
415
|
+
新版把模型元数据与模型覆盖允许列表分开。如果 `agents.defaults.modelPolicy.allow` 非空,LMA 配置中的每个模型都必须被该列表的精确模型引用或 `provider/*` 通配符允许。遇到拒绝时,LMA 会直接报告 model policy 错误,不再错误记录“模型已确保”。
|
|
416
|
+
|
|
417
|
+
执行中插入的消息改用公开的 `chat.send { queueMode: "steer" }`。RPC 成功返回只是暂时接受;LMA 会继续保留本地 pending trigger,只有匹配的 `session.message` 确认消息已写入转录并被消费后才清除,同时把飞书标记从 Typing 切换为 Get。异步 `error`/`aborted` 按 runId 投递,未消费的输入仍由普通队列兜底。这样不再依赖无法表达后续异步拒绝的旧同步插件原语。
|
|
418
|
+
|
|
419
|
+
## Live Status 与最终回复
|
|
420
|
+
|
|
421
|
+
非 verbose 模式下,执行过程显示一张可更新的 live status 卡片。运行中显示最近活动和耗时;完成后收缩为“累计工具调用次数 + 总耗时”。
|
|
422
|
+
|
|
423
|
+
最终回复不会覆盖旧的 live status,而是在任务完成时新发一张卡片,因此用户执行途中插入的新消息不会排在最终答案之后。最终回复卡片底部只显示本次使用的模型名;工具调用次数和耗时只保留在 live status 中。
|
|
424
|
+
|
|
411
425
|
## 数据模型
|
|
412
426
|
|
|
413
427
|
SQLite 状态位于配置的数据目录。主要表:
|
package/dist/cli.js
CHANGED
|
@@ -206,12 +206,12 @@ function runCapture(cmd, args) {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
/**
|
|
209
|
-
* Install the bundled lma-steer
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
* ships inside this package under plugins/lma-steer (built to dist).
|
|
209
|
+
* Install the legacy bundled lma-steer plugin. Current LMA uses OpenClaw's
|
|
210
|
+
* public `chat.send { queueMode: "steer" }` API and does not call this plugin;
|
|
211
|
+
* the command remains only for operators maintaining older LMA deployments.
|
|
213
212
|
*/
|
|
214
213
|
function cmdInstallSteerPlugin(args) {
|
|
214
|
+
console.warn("Note: current LMA releases use native chat.send queueMode=steer; this legacy plugin is not required on OpenClaw 2026.8+.");
|
|
215
215
|
// Default to --force so reinstalling an updated bundled plugin overwrites the
|
|
216
216
|
// previously installed copy. Pass --no-force to keep an existing install.
|
|
217
217
|
const noForce = hasFlag(args, "--no-force");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Coarse phase of the compaction flow, drives the card's primary line. */
|
|
2
|
-
export type CompactPhase = "native" | "
|
|
2
|
+
export type CompactPhase = "native" | "transcript-trim";
|
|
3
3
|
/** Terminal outcome used by the renderer to pick color/emoji. */
|
|
4
4
|
export type CompactState = "running" | "done" | "failed" | "noop";
|
|
5
5
|
/** Structured snapshot the renderer turns into a Feishu interactive card. */
|
|
@@ -27,7 +27,7 @@ export type CompactProgressOptions = {
|
|
|
27
27
|
tickMs?: number;
|
|
28
28
|
};
|
|
29
29
|
/**
|
|
30
|
-
* Lifecycle: start() → (optional)
|
|
30
|
+
* Lifecycle: start() → (optional) toTranscriptTrim() when native gives up → one of
|
|
31
31
|
* done()/noop()/fail(). The card is created lazily after `delayMs` so a fast
|
|
32
32
|
* compaction that finishes first never shows a card at all. All terminal calls
|
|
33
33
|
* are idempotent and safe even if the card was never created.
|
|
@@ -50,8 +50,8 @@ export declare class CompactProgressController {
|
|
|
50
50
|
get id(): string | undefined;
|
|
51
51
|
/** Begin the flow; schedules lazy card creation after delayMs. */
|
|
52
52
|
start(): void;
|
|
53
|
-
/** Native compaction gave up
|
|
54
|
-
|
|
53
|
+
/** Native compaction gave up; switch to Gateway-owned transcript-tail trim. */
|
|
54
|
+
toTranscriptTrim(): Promise<void>;
|
|
55
55
|
/** Finished successfully; patch the card to the done state with a detail line. */
|
|
56
56
|
done(detail?: string): Promise<void>;
|
|
57
57
|
/** Nothing to compact; patch the card to a neutral "no-op" state. */
|
package/dist/compact-progress.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
const DEFAULT_DELAY_MS = Number(process.env.OPENCLAW_LARK_MULTI_AGENT_COMPACT_STATUS_DELAY_MS || 500);
|
|
11
11
|
const DEFAULT_TICK_MS = Number(process.env.OPENCLAW_LARK_MULTI_AGENT_COMPACT_STATUS_TICK_MS || 1000);
|
|
12
12
|
/**
|
|
13
|
-
* Lifecycle: start() → (optional)
|
|
13
|
+
* Lifecycle: start() → (optional) toTranscriptTrim() when native gives up → one of
|
|
14
14
|
* done()/noop()/fail(). The card is created lazily after `delayMs` so a fast
|
|
15
15
|
* compaction that finishes first never shows a card at all. All terminal calls
|
|
16
16
|
* are idempotent and safe even if the card was never created.
|
|
@@ -45,11 +45,11 @@ export class CompactProgressController {
|
|
|
45
45
|
}, this.opts.delayMs ?? DEFAULT_DELAY_MS);
|
|
46
46
|
this.createTimer.unref?.();
|
|
47
47
|
}
|
|
48
|
-
/** Native compaction gave up
|
|
49
|
-
async
|
|
50
|
-
if (this.finalized || this.phase === "
|
|
48
|
+
/** Native compaction gave up; switch to Gateway-owned transcript-tail trim. */
|
|
49
|
+
async toTranscriptTrim() {
|
|
50
|
+
if (this.finalized || this.phase === "transcript-trim")
|
|
51
51
|
return;
|
|
52
|
-
this.phase = "
|
|
52
|
+
this.phase = "transcript-trim";
|
|
53
53
|
await this.refresh();
|
|
54
54
|
}
|
|
55
55
|
/** Finished successfully; patch the card to the done state with a detail line. */
|
package/dist/feishu-bot.d.ts
CHANGED
|
@@ -35,14 +35,26 @@ export declare class FeishuBot {
|
|
|
35
35
|
private sendQueue;
|
|
36
36
|
/** Per-chat delayed runtime failure notifications, canceled if a real reply arrives. */
|
|
37
37
|
private delayedFailureTimers;
|
|
38
|
+
/** Ephemeral model footer overrides used by final-message wrappers. Keeping
|
|
39
|
+
* replyMessage/sendMessage two-argument APIs avoids contaminating ordinary
|
|
40
|
+
* command/error/card sends with model attribution. */
|
|
41
|
+
private replyModelFooters;
|
|
42
|
+
private sendModelFooters;
|
|
38
43
|
/** Per-chat durable outbox retry timer. */
|
|
39
44
|
private deliveryRetryTimers;
|
|
40
45
|
/** Last time a real assistant-visible reply was successfully handed to the delivery pipeline. */
|
|
41
46
|
private lastRealDeliveryAt;
|
|
42
47
|
/** Per-chat: whether we've already sent the high-context alert this cycle. */
|
|
43
48
|
private contextAlerted;
|
|
44
|
-
/** Active
|
|
49
|
+
/** Active pre-admission target for the current chat operation. */
|
|
45
50
|
private activeDeliveryTargets;
|
|
51
|
+
/** Stable targets for concurrent runs in one chat. A steer admission can
|
|
52
|
+
* become an ordinary run while another run remains active. */
|
|
53
|
+
private deliveryTargetsByRun;
|
|
54
|
+
/** Provisional native-steer correlations keyed by durable message row. If the
|
|
55
|
+
* message falls back to a normal run, cancel these before submission so a
|
|
56
|
+
* later identical steer cannot consume the stale observer/correlation. */
|
|
57
|
+
private pendingSteerCleanups;
|
|
46
58
|
private adminOpenId;
|
|
47
59
|
private locale;
|
|
48
60
|
private configPath?;
|
|
@@ -122,11 +134,8 @@ export declare class FeishuBot {
|
|
|
122
134
|
private buildMarkdownCard;
|
|
123
135
|
private deliveryOwnsVisiblePayload;
|
|
124
136
|
private completionSummary;
|
|
125
|
-
/**
|
|
126
|
-
|
|
127
|
-
private patchFinalAnswerCard;
|
|
128
|
-
/** Best-effort cleanup when a final-card patch was too large/failed and the
|
|
129
|
-
* answer had to be delivered as a separate message. */
|
|
137
|
+
/** Best-effort terminal cleanup for status-only rows and legacy v1.4.3
|
|
138
|
+
* outbox entries that once targeted the live-status card. */
|
|
130
139
|
private patchLiveStatusDoneSummary;
|
|
131
140
|
private formatUserVisibleError;
|
|
132
141
|
private isBridgeControlReply;
|
|
@@ -179,6 +188,9 @@ export declare class FeishuBot {
|
|
|
179
188
|
*/
|
|
180
189
|
private autoRetryUntilComplete;
|
|
181
190
|
private cancelDelayedFailure;
|
|
191
|
+
private deliveryRunTargetKey;
|
|
192
|
+
private bindRunDeliveryTarget;
|
|
193
|
+
private releaseRunDeliveryTargetAfter;
|
|
182
194
|
private setActiveDeliveryTarget;
|
|
183
195
|
private scheduleDelayedFailure;
|
|
184
196
|
private deliverySessionKey;
|
|
@@ -227,6 +239,7 @@ export declare class FeishuBot {
|
|
|
227
239
|
private replyTextMessage;
|
|
228
240
|
private editTextMessage;
|
|
229
241
|
private deleteMessageById;
|
|
242
|
+
private replyFinalMessage;
|
|
230
243
|
private replyMessage;
|
|
231
244
|
private extractBridgeAttachments;
|
|
232
245
|
/**
|
|
@@ -271,6 +284,7 @@ export declare class FeishuBot {
|
|
|
271
284
|
/**
|
|
272
285
|
* Send a proactive message to a chat (not a reply).
|
|
273
286
|
*/
|
|
287
|
+
private sendFinalMessage;
|
|
274
288
|
private sendMessage;
|
|
275
289
|
/**
|
|
276
290
|
* Enqueue a message send to guarantee ordering per chat.
|
|
@@ -301,14 +315,14 @@ export declare class FeishuBot {
|
|
|
301
315
|
* Handle /compact command: compress session context.
|
|
302
316
|
*/
|
|
303
317
|
/**
|
|
304
|
-
* Compact a session with a fallback chain:
|
|
305
|
-
* 1.
|
|
306
|
-
* 2. If
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
318
|
+
* Compact a session with a Gateway-owned fallback chain:
|
|
319
|
+
* 1. Semantic compaction through `sessions.compact`.
|
|
320
|
+
* 2. If summarization cannot run, ask the same RPC to retain only a bounded
|
|
321
|
+
* transcript tail via `maxLines`. This works with legacy JSONL and the
|
|
322
|
+
* SQLite session store introduced in OpenClaw 2026.8.x, and preserves
|
|
323
|
+
* OpenClaw's write locks, transcript invariants, and migration ownership.
|
|
324
|
+
*
|
|
325
|
+
* LMA deliberately never opens or rewrites OpenClaw transcript storage.
|
|
312
326
|
*/
|
|
313
327
|
private compactWithFallback;
|
|
314
328
|
private handleCompactCommand;
|