openclaw-lark-multi-agent 1.2.0 → 1.2.1
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/compact-progress.d.ts +75 -0
- package/dist/compact-progress.js +177 -0
- package/dist/feishu-bot.d.ts +8 -0
- package/dist/feishu-bot.js +111 -16
- package/package.json +1 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** Coarse phase of the compaction flow, drives the card's primary line. */
|
|
2
|
+
export type CompactPhase = "native" | "tool-trim";
|
|
3
|
+
/** Terminal outcome used by the renderer to pick color/emoji. */
|
|
4
|
+
export type CompactState = "running" | "done" | "failed" | "noop";
|
|
5
|
+
/** Structured snapshot the renderer turns into a Feishu interactive card. */
|
|
6
|
+
export type CompactProgressView = {
|
|
7
|
+
state: CompactState;
|
|
8
|
+
/** Current phase while running (ignored once terminal). */
|
|
9
|
+
phase: CompactPhase;
|
|
10
|
+
/** Elapsed time like "0:42". */
|
|
11
|
+
elapsed: string;
|
|
12
|
+
/** Terminal detail line, e.g. "12.3M→4.1M (-67%)" or an error/skip reason. */
|
|
13
|
+
detail?: string;
|
|
14
|
+
};
|
|
15
|
+
export type CompactProgressCallbacks = {
|
|
16
|
+
/** Create the status card; returns the new message id (undefined disables). */
|
|
17
|
+
create: (view: CompactProgressView) => Promise<string | undefined>;
|
|
18
|
+
/** Patch the existing status card. */
|
|
19
|
+
edit: (messageId: string, view: CompactProgressView) => Promise<void>;
|
|
20
|
+
warn?: (message: string, err?: unknown) => void;
|
|
21
|
+
};
|
|
22
|
+
export type CompactProgressOptions = {
|
|
23
|
+
locale?: "zh" | "en";
|
|
24
|
+
/** Delay before the card first appears, to avoid flashing on fast compactions. */
|
|
25
|
+
delayMs?: number;
|
|
26
|
+
/** Footer/auto-refresh cadence in ms. */
|
|
27
|
+
tickMs?: number;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Lifecycle: start() → (optional) toToolTrim() when native gives up → one of
|
|
31
|
+
* done()/noop()/fail(). The card is created lazily after `delayMs` so a fast
|
|
32
|
+
* compaction that finishes first never shows a card at all. All terminal calls
|
|
33
|
+
* are idempotent and safe even if the card was never created.
|
|
34
|
+
*/
|
|
35
|
+
export declare class CompactProgressController {
|
|
36
|
+
private readonly callbacks;
|
|
37
|
+
private readonly opts;
|
|
38
|
+
private messageId?;
|
|
39
|
+
private startedAt;
|
|
40
|
+
private phase;
|
|
41
|
+
private state;
|
|
42
|
+
private detail?;
|
|
43
|
+
private createTimer?;
|
|
44
|
+
private tickTimer?;
|
|
45
|
+
private createPromise?;
|
|
46
|
+
private finalized;
|
|
47
|
+
private disabled;
|
|
48
|
+
private lastSignature;
|
|
49
|
+
constructor(callbacks: CompactProgressCallbacks, opts?: CompactProgressOptions);
|
|
50
|
+
get id(): string | undefined;
|
|
51
|
+
/** Begin the flow; schedules lazy card creation after delayMs. */
|
|
52
|
+
start(): void;
|
|
53
|
+
/** Native compaction gave up (timeout/no-op); switch the card to fast-trim. */
|
|
54
|
+
toToolTrim(): Promise<void>;
|
|
55
|
+
/** Finished successfully; patch the card to the done state with a detail line. */
|
|
56
|
+
done(detail?: string): Promise<void>;
|
|
57
|
+
/** Nothing to compact; patch the card to a neutral "no-op" state. */
|
|
58
|
+
noop(detail?: string): Promise<void>;
|
|
59
|
+
/** Failed; patch the card to the failed state with an error detail line. */
|
|
60
|
+
fail(detail?: string): Promise<void>;
|
|
61
|
+
/** Tear down timers without sending anything (e.g. on unexpected disposal). */
|
|
62
|
+
dispose(): void;
|
|
63
|
+
private finish;
|
|
64
|
+
private refresh;
|
|
65
|
+
private ensureCreatedNow;
|
|
66
|
+
private ensureCreated;
|
|
67
|
+
/** Refresh the elapsed-time footer periodically even with no phase change. */
|
|
68
|
+
private startTicker;
|
|
69
|
+
private safeEdit;
|
|
70
|
+
private stopTimers;
|
|
71
|
+
/** Dedupe key; includes elapsed so the ticking footer still advances. */
|
|
72
|
+
private signature;
|
|
73
|
+
private formatElapsed;
|
|
74
|
+
buildView(): CompactProgressView;
|
|
75
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// A tiny live-status controller dedicated to the /compact (and auto-compact)
|
|
2
|
+
// flow, so the user gets a visible "正在压缩…" card that ticks while a large
|
|
3
|
+
// session is being compacted — instead of staring at nothing for tens of
|
|
4
|
+
// seconds while native compaction grinds (and sometimes times out).
|
|
5
|
+
//
|
|
6
|
+
// It deliberately does NOT reuse LiveStatusController: that one models a tool
|
|
7
|
+
// run (activity window, tool-call count, model footer). Compaction has just a
|
|
8
|
+
// few coarse phases and a single elapsed timer, so a focused, self-contained
|
|
9
|
+
// controller keeps the card clean and the logic trivial to test.
|
|
10
|
+
const DEFAULT_DELAY_MS = Number(process.env.OPENCLAW_LARK_MULTI_AGENT_COMPACT_STATUS_DELAY_MS || 500);
|
|
11
|
+
const DEFAULT_TICK_MS = Number(process.env.OPENCLAW_LARK_MULTI_AGENT_COMPACT_STATUS_TICK_MS || 1000);
|
|
12
|
+
/**
|
|
13
|
+
* Lifecycle: start() → (optional) toToolTrim() when native gives up → one of
|
|
14
|
+
* done()/noop()/fail(). The card is created lazily after `delayMs` so a fast
|
|
15
|
+
* compaction that finishes first never shows a card at all. All terminal calls
|
|
16
|
+
* are idempotent and safe even if the card was never created.
|
|
17
|
+
*/
|
|
18
|
+
export class CompactProgressController {
|
|
19
|
+
callbacks;
|
|
20
|
+
opts;
|
|
21
|
+
messageId;
|
|
22
|
+
startedAt = Date.now();
|
|
23
|
+
phase = "native";
|
|
24
|
+
state = "running";
|
|
25
|
+
detail;
|
|
26
|
+
createTimer;
|
|
27
|
+
tickTimer;
|
|
28
|
+
createPromise;
|
|
29
|
+
finalized = false;
|
|
30
|
+
disabled = false;
|
|
31
|
+
lastSignature = "";
|
|
32
|
+
constructor(callbacks, opts = {}) {
|
|
33
|
+
this.callbacks = callbacks;
|
|
34
|
+
this.opts = opts;
|
|
35
|
+
}
|
|
36
|
+
get id() { return this.messageId; }
|
|
37
|
+
/** Begin the flow; schedules lazy card creation after delayMs. */
|
|
38
|
+
start() {
|
|
39
|
+
if (this.disabled || this.finalized || this.createTimer || this.messageId)
|
|
40
|
+
return;
|
|
41
|
+
this.startedAt = Date.now();
|
|
42
|
+
this.createTimer = setTimeout(() => {
|
|
43
|
+
this.createTimer = undefined;
|
|
44
|
+
this.createPromise = this.ensureCreated();
|
|
45
|
+
}, this.opts.delayMs ?? DEFAULT_DELAY_MS);
|
|
46
|
+
this.createTimer.unref?.();
|
|
47
|
+
}
|
|
48
|
+
/** Native compaction gave up (timeout/no-op); switch the card to fast-trim. */
|
|
49
|
+
async toToolTrim() {
|
|
50
|
+
if (this.finalized || this.phase === "tool-trim")
|
|
51
|
+
return;
|
|
52
|
+
this.phase = "tool-trim";
|
|
53
|
+
await this.refresh();
|
|
54
|
+
}
|
|
55
|
+
/** Finished successfully; patch the card to the done state with a detail line. */
|
|
56
|
+
async done(detail) {
|
|
57
|
+
await this.finish("done", detail);
|
|
58
|
+
}
|
|
59
|
+
/** Nothing to compact; patch the card to a neutral "no-op" state. */
|
|
60
|
+
async noop(detail) {
|
|
61
|
+
await this.finish("noop", detail);
|
|
62
|
+
}
|
|
63
|
+
/** Failed; patch the card to the failed state with an error detail line. */
|
|
64
|
+
async fail(detail) {
|
|
65
|
+
await this.finish("failed", detail);
|
|
66
|
+
}
|
|
67
|
+
/** Tear down timers without sending anything (e.g. on unexpected disposal). */
|
|
68
|
+
dispose() {
|
|
69
|
+
this.finalized = true;
|
|
70
|
+
this.stopTimers();
|
|
71
|
+
}
|
|
72
|
+
async finish(state, detail) {
|
|
73
|
+
if (this.finalized)
|
|
74
|
+
return;
|
|
75
|
+
this.state = state;
|
|
76
|
+
this.detail = detail;
|
|
77
|
+
this.finalized = true;
|
|
78
|
+
this.stopTimers();
|
|
79
|
+
// Wait for any in-flight lazy create so we can patch (not orphan) the card.
|
|
80
|
+
if (this.createPromise)
|
|
81
|
+
await this.createPromise.catch(() => { });
|
|
82
|
+
if (!this.messageId || this.disabled)
|
|
83
|
+
return;
|
|
84
|
+
await this.safeEdit(true);
|
|
85
|
+
}
|
|
86
|
+
async refresh() {
|
|
87
|
+
if (this.finalized || this.disabled)
|
|
88
|
+
return;
|
|
89
|
+
await this.ensureCreatedNow();
|
|
90
|
+
await this.safeEdit();
|
|
91
|
+
}
|
|
92
|
+
async ensureCreatedNow() {
|
|
93
|
+
if (this.createTimer) {
|
|
94
|
+
clearTimeout(this.createTimer);
|
|
95
|
+
this.createTimer = undefined;
|
|
96
|
+
this.createPromise = this.ensureCreated();
|
|
97
|
+
}
|
|
98
|
+
if (this.createPromise)
|
|
99
|
+
await this.createPromise.catch(() => { });
|
|
100
|
+
}
|
|
101
|
+
async ensureCreated() {
|
|
102
|
+
if (this.disabled || this.finalized || this.messageId)
|
|
103
|
+
return;
|
|
104
|
+
try {
|
|
105
|
+
const id = await this.callbacks.create(this.buildView());
|
|
106
|
+
if (!id) {
|
|
107
|
+
this.disabled = true;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.messageId = id;
|
|
111
|
+
this.lastSignature = this.signature();
|
|
112
|
+
this.startTicker();
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
this.disabled = true;
|
|
116
|
+
this.callbacks.warn?.("compact progress create failed", err);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** Refresh the elapsed-time footer periodically even with no phase change. */
|
|
120
|
+
startTicker() {
|
|
121
|
+
if (this.tickTimer || this.disabled || this.finalized)
|
|
122
|
+
return;
|
|
123
|
+
const tickMs = this.opts.tickMs ?? DEFAULT_TICK_MS;
|
|
124
|
+
this.tickTimer = setInterval(() => {
|
|
125
|
+
if (this.finalized || this.disabled || !this.messageId)
|
|
126
|
+
return;
|
|
127
|
+
void this.safeEdit();
|
|
128
|
+
}, tickMs);
|
|
129
|
+
this.tickTimer.unref?.();
|
|
130
|
+
}
|
|
131
|
+
async safeEdit(force = false) {
|
|
132
|
+
if (!this.messageId || this.disabled)
|
|
133
|
+
return;
|
|
134
|
+
if (!force && this.finalized)
|
|
135
|
+
return;
|
|
136
|
+
const sig = this.signature();
|
|
137
|
+
if (!force && sig === this.lastSignature)
|
|
138
|
+
return;
|
|
139
|
+
try {
|
|
140
|
+
await this.callbacks.edit(this.messageId, this.buildView());
|
|
141
|
+
this.lastSignature = sig;
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
this.disabled = true;
|
|
145
|
+
this.stopTimers();
|
|
146
|
+
this.callbacks.warn?.("compact progress edit failed", err);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
stopTimers() {
|
|
150
|
+
if (this.createTimer) {
|
|
151
|
+
clearTimeout(this.createTimer);
|
|
152
|
+
this.createTimer = undefined;
|
|
153
|
+
}
|
|
154
|
+
if (this.tickTimer) {
|
|
155
|
+
clearInterval(this.tickTimer);
|
|
156
|
+
this.tickTimer = undefined;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/** Dedupe key; includes elapsed so the ticking footer still advances. */
|
|
160
|
+
signature() {
|
|
161
|
+
return `${this.state}|${this.phase}|${this.formatElapsed()}|${this.detail || ""}`;
|
|
162
|
+
}
|
|
163
|
+
formatElapsed() {
|
|
164
|
+
const totalSec = Math.max(0, Math.floor((Date.now() - this.startedAt) / 1000));
|
|
165
|
+
const m = Math.floor(totalSec / 60);
|
|
166
|
+
const s = totalSec % 60;
|
|
167
|
+
return `${m}:${String(s).padStart(2, "0")}`;
|
|
168
|
+
}
|
|
169
|
+
buildView() {
|
|
170
|
+
return {
|
|
171
|
+
state: this.state,
|
|
172
|
+
phase: this.phase,
|
|
173
|
+
elapsed: this.formatElapsed(),
|
|
174
|
+
detail: this.detail,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
package/dist/feishu-bot.d.ts
CHANGED
|
@@ -200,6 +200,14 @@ export declare class FeishuBot {
|
|
|
200
200
|
private sendLiveStatusCard;
|
|
201
201
|
private replyLiveStatusCard;
|
|
202
202
|
private patchLiveStatusCard;
|
|
203
|
+
/**
|
|
204
|
+
* Render the /compact progress card. While running it shows a phase line plus a
|
|
205
|
+
* ticking elapsed footer so the user can see compaction is in progress; when
|
|
206
|
+
* terminal it collapses to a single compact line (success/skip/fail).
|
|
207
|
+
*/
|
|
208
|
+
private buildCompactProgressCard;
|
|
209
|
+
private replyCompactCard;
|
|
210
|
+
private patchCompactCard;
|
|
203
211
|
private sendTextMessage;
|
|
204
212
|
private replyTextMessage;
|
|
205
213
|
private editTextMessage;
|
package/dist/feishu-bot.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createRequire } from "module";
|
|
|
3
3
|
import { persistBotModel } from "./config.js";
|
|
4
4
|
import { getI18n, normalizeLocale } from "./i18n.js";
|
|
5
5
|
import { LiveStatusController } from "./live-status.js";
|
|
6
|
+
import { CompactProgressController } from "./compact-progress.js";
|
|
6
7
|
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
7
8
|
import { basename, extname, join, resolve } from "path";
|
|
8
9
|
import { getBridgeAttachmentsDir, getDataDir } from "./paths.js";
|
|
@@ -2339,6 +2340,73 @@ export class FeishuBot {
|
|
|
2339
2340
|
data: { content: JSON.stringify(this.buildLiveStatusCard(view, chatId)) },
|
|
2340
2341
|
});
|
|
2341
2342
|
}
|
|
2343
|
+
/**
|
|
2344
|
+
* Render the /compact progress card. While running it shows a phase line plus a
|
|
2345
|
+
* ticking elapsed footer so the user can see compaction is in progress; when
|
|
2346
|
+
* terminal it collapses to a single compact line (success/skip/fail).
|
|
2347
|
+
*/
|
|
2348
|
+
buildCompactProgressCard(view, chatId) {
|
|
2349
|
+
const en = this.isEn(chatId);
|
|
2350
|
+
if (view.state !== "running") {
|
|
2351
|
+
let line;
|
|
2352
|
+
if (view.state === "done") {
|
|
2353
|
+
line = en
|
|
2354
|
+
? `✅ Session compacted${view.detail ? ` (${view.detail})` : ""} · ⏱ ${view.elapsed}`
|
|
2355
|
+
: `✅ Session 已压缩${view.detail ? `(${view.detail})` : ""} · ⏱ 耗时 ${view.elapsed}`;
|
|
2356
|
+
}
|
|
2357
|
+
else if (view.state === "noop") {
|
|
2358
|
+
line = en
|
|
2359
|
+
? `ℹ️ Session not compacted${view.detail ? ` (${view.detail})` : ""}`
|
|
2360
|
+
: `ℹ️ Session 未压缩${view.detail ? `(${view.detail})` : ""}`;
|
|
2361
|
+
}
|
|
2362
|
+
else {
|
|
2363
|
+
line = en
|
|
2364
|
+
? `❌ Compact failed${view.detail ? `: ${view.detail}` : ""}`
|
|
2365
|
+
: `❌ 压缩失败${view.detail ? `:${view.detail}` : ""}`;
|
|
2366
|
+
}
|
|
2367
|
+
return {
|
|
2368
|
+
schema: "2.0",
|
|
2369
|
+
config: { update_multi: true, width_mode: "fill" },
|
|
2370
|
+
body: { elements: [{ tag: "markdown", content: `<font color='grey'>${this.escapeCardText(line)}</font>` }] },
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
// Running: phase line + ticking elapsed footer.
|
|
2374
|
+
const phaseLine = view.phase === "tool-trim"
|
|
2375
|
+
? (en ? "🧹 Native compaction is slow — switching to fast trim…" : "🧹 原生压缩较慢,已切换快速压缩…")
|
|
2376
|
+
: (en ? "🧹 Compacting session…" : "🧹 正在压缩 session…");
|
|
2377
|
+
const footer = en ? `⏱ ${view.elapsed}` : `⏱ 已用 ${view.elapsed}`;
|
|
2378
|
+
return {
|
|
2379
|
+
schema: "2.0",
|
|
2380
|
+
config: { update_multi: true, width_mode: "fill" },
|
|
2381
|
+
header: {
|
|
2382
|
+
title: { tag: "plain_text", content: en ? "Compacting" : "正在压缩" },
|
|
2383
|
+
template: "blue",
|
|
2384
|
+
},
|
|
2385
|
+
body: {
|
|
2386
|
+
elements: [
|
|
2387
|
+
{ tag: "markdown", content: this.escapeCardText(phaseLine) },
|
|
2388
|
+
{ tag: "hr" },
|
|
2389
|
+
{ tag: "markdown", content: `<font color='grey'>${footer}</font>` },
|
|
2390
|
+
],
|
|
2391
|
+
},
|
|
2392
|
+
};
|
|
2393
|
+
}
|
|
2394
|
+
async replyCompactCard(messageId, view, chatId) {
|
|
2395
|
+
const res = await this.client.im.message.reply({
|
|
2396
|
+
path: { message_id: messageId },
|
|
2397
|
+
data: {
|
|
2398
|
+
content: JSON.stringify(this.buildCompactProgressCard(view, chatId)),
|
|
2399
|
+
msg_type: "interactive",
|
|
2400
|
+
},
|
|
2401
|
+
});
|
|
2402
|
+
return res?.data?.message_id || res?.message_id;
|
|
2403
|
+
}
|
|
2404
|
+
async patchCompactCard(messageId, view, chatId) {
|
|
2405
|
+
await this.client.im.message.patch({
|
|
2406
|
+
path: { message_id: messageId },
|
|
2407
|
+
data: { content: JSON.stringify(this.buildCompactProgressCard(view, chatId)) },
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
2342
2410
|
async sendTextMessage(chatId, text) {
|
|
2343
2411
|
try {
|
|
2344
2412
|
const res = await this.client.im.message.create({
|
|
@@ -2914,7 +2982,7 @@ export class FeishuBot {
|
|
|
2914
2982
|
* into the model). A backup is always written before any file change.
|
|
2915
2983
|
* Returns a structured result describing what happened.
|
|
2916
2984
|
*/
|
|
2917
|
-
async compactWithFallback(sessionKey) {
|
|
2985
|
+
async compactWithFallback(sessionKey, onPhase) {
|
|
2918
2986
|
// 1. Native compaction first.
|
|
2919
2987
|
let nativeReason;
|
|
2920
2988
|
try {
|
|
@@ -2926,7 +2994,10 @@ export class FeishuBot {
|
|
|
2926
2994
|
catch (err) {
|
|
2927
2995
|
nativeReason = err.message;
|
|
2928
2996
|
}
|
|
2929
|
-
// 2. Fall back to tool-trim on the transcript file.
|
|
2997
|
+
// 2. Fall back to tool-trim on the transcript file. Tell the caller so a
|
|
2998
|
+
// progress card can flip from "compacting" to "fast-trim" (this is the
|
|
2999
|
+
// slow→still-working transition the user most needs to see).
|
|
3000
|
+
onPhase?.("tool-trim");
|
|
2930
3001
|
let sessionId;
|
|
2931
3002
|
try {
|
|
2932
3003
|
const info = await this.openclawClient.getSessionInfo(sessionKey);
|
|
@@ -2963,29 +3034,53 @@ export class FeishuBot {
|
|
|
2963
3034
|
async handleCompactCommand(chatId, messageId) {
|
|
2964
3035
|
const sessionKey = this.getSessionKey(chatId);
|
|
2965
3036
|
const en = this.isEn(chatId);
|
|
3037
|
+
// Large sessions can take tens of seconds to compact (native compaction may
|
|
3038
|
+
// even time out before the tool-trim fallback kicks in). Show a ticking
|
|
3039
|
+
// "compacting…" card so the user can SEE it is working instead of staring at
|
|
3040
|
+
// nothing and assuming nothing is happening. The card is created lazily, so
|
|
3041
|
+
// a fast compaction that finishes quickly never flashes a card at all.
|
|
3042
|
+
const progress = new CompactProgressController({
|
|
3043
|
+
create: (view) => this.sendOrdered(chatId, () => this.replyCompactCard(messageId, view, chatId)),
|
|
3044
|
+
edit: (id, view) => this.sendOrdered(chatId, () => this.patchCompactCard(id, view, chatId)),
|
|
3045
|
+
warn: (msg, err) => console.warn(`[${this.config.name}] ${msg}`, err instanceof Error ? err.message : err),
|
|
3046
|
+
}, { locale: en ? "en" : "zh" });
|
|
3047
|
+
progress.start();
|
|
2966
3048
|
try {
|
|
2967
|
-
const r = await this.compactWithFallback(sessionKey)
|
|
3049
|
+
const r = await this.compactWithFallback(sessionKey, (phase) => {
|
|
3050
|
+
if (phase === "tool-trim")
|
|
3051
|
+
void progress.toToolTrim().catch(() => { });
|
|
3052
|
+
});
|
|
2968
3053
|
if (r.compacted) {
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
3054
|
+
// If a card was shown, patch it in place; otherwise (fast finish, no card)
|
|
3055
|
+
// fall back to a normal reply so the user still gets confirmation.
|
|
3056
|
+
const detail = r.method === "tool-trim" && r.detail
|
|
3057
|
+
? (en ? `tool-trim ${r.detail}` : `删工具调用 ${r.detail}`)
|
|
3058
|
+
: (en ? "native" : "原生压缩");
|
|
3059
|
+
await progress.done(detail);
|
|
3060
|
+
if (!progress.id) {
|
|
3061
|
+
await this.replyMessage(messageId, r.method === "tool-trim"
|
|
3062
|
+
? (en ? `✅ Session compacted (tool-trim${r.detail ? " " + r.detail : ""})` : `✅ Session 已压缩(删工具调用${r.detail ? " " + r.detail : ""})`)
|
|
3063
|
+
: (en ? `✅ Session compacted` : `✅ Session 已压缩`));
|
|
2976
3064
|
}
|
|
2977
3065
|
}
|
|
2978
3066
|
else {
|
|
2979
3067
|
const reason = r.reason || (en ? "nothing to compact" : "无需压缩");
|
|
2980
|
-
await
|
|
2981
|
-
|
|
2982
|
-
|
|
3068
|
+
await progress.noop(reason);
|
|
3069
|
+
if (!progress.id) {
|
|
3070
|
+
await this.replyMessage(messageId, en
|
|
3071
|
+
? `ℹ️ Session not compacted (${reason})`
|
|
3072
|
+
: `ℹ️ Session 未压缩(${reason})`);
|
|
3073
|
+
}
|
|
2983
3074
|
}
|
|
2984
3075
|
}
|
|
2985
3076
|
catch (err) {
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
3077
|
+
const reason = err.message;
|
|
3078
|
+
await progress.fail(reason);
|
|
3079
|
+
if (!progress.id) {
|
|
3080
|
+
await this.replyMessage(messageId, en
|
|
3081
|
+
? `❌ Compact failed: ${reason}`
|
|
3082
|
+
: `❌ 压缩失败: ${reason}`);
|
|
3083
|
+
}
|
|
2989
3084
|
}
|
|
2990
3085
|
}
|
|
2991
3086
|
/**
|