adp-openclaw 0.0.57 → 0.0.58
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/package.json +1 -1
- package/src/monitor.ts +3 -126
package/package.json
CHANGED
package/src/monitor.ts
CHANGED
|
@@ -24,7 +24,6 @@ import {
|
|
|
24
24
|
} from "./tool-result-message-blocks.js";
|
|
25
25
|
import crypto from "crypto";
|
|
26
26
|
import fs from "fs";
|
|
27
|
-
import path from "path";
|
|
28
27
|
// @ts-ignore - import JSON file
|
|
29
28
|
import packageJson from "../package.json" with { type: "json" };
|
|
30
29
|
|
|
@@ -165,120 +164,6 @@ async function markSessionAborted(params: {
|
|
|
165
164
|
}
|
|
166
165
|
}
|
|
167
166
|
|
|
168
|
-
/**
|
|
169
|
-
* After an abort, trim the aborted user message and any partial assistant reply
|
|
170
|
-
* from the JSONL transcript file. This prevents the AI from seeing the cancelled
|
|
171
|
-
* request in its context window and resuming it on the next turn.
|
|
172
|
-
*
|
|
173
|
-
* The JSONL transcript is a tree structure (id + parentId). We find the last
|
|
174
|
-
* user message entry and remove it (plus any subsequent entries like partial
|
|
175
|
-
* assistant replies). This is equivalent to SessionManager.branch(parentId).
|
|
176
|
-
*/
|
|
177
|
-
async function trimAbortedMessagesFromTranscript(params: {
|
|
178
|
-
sessionKey: string;
|
|
179
|
-
runtime: ReturnType<typeof getAdpOpenclawRuntime>;
|
|
180
|
-
cfg?: ClawdbotConfig;
|
|
181
|
-
log?: PluginLogger;
|
|
182
|
-
}): Promise<void> {
|
|
183
|
-
const { sessionKey, runtime, cfg, log } = params;
|
|
184
|
-
try {
|
|
185
|
-
const storePath = runtime.channel.session.resolveStorePath(cfg?.session?.store);
|
|
186
|
-
if (!storePath || !fs.existsSync(storePath)) {
|
|
187
|
-
log?.warn?.(`[adp-openclaw] Cannot trim transcript: store not found at ${storePath}`);
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const raw = fs.readFileSync(storePath, "utf-8");
|
|
192
|
-
const store = JSON.parse(raw) as Record<string, { sessionId?: string; sessionFile?: string; [key: string]: unknown }>;
|
|
193
|
-
|
|
194
|
-
// Find matching session entry
|
|
195
|
-
const candidates = [sessionKey, `agent:main:${sessionKey}`];
|
|
196
|
-
let entry: { sessionId?: string; sessionFile?: string; [key: string]: unknown } | undefined;
|
|
197
|
-
for (const key of candidates) {
|
|
198
|
-
if (store[key]) {
|
|
199
|
-
entry = store[key];
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (!entry?.sessionId) {
|
|
205
|
-
log?.info?.(`[adp-openclaw] Session entry not found for transcript trimming: ${sessionKey}`);
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Resolve transcript file path
|
|
210
|
-
let transcriptPath: string;
|
|
211
|
-
if (entry.sessionFile) {
|
|
212
|
-
transcriptPath = entry.sessionFile;
|
|
213
|
-
} else {
|
|
214
|
-
// Fallback: same directory as sessions.json, filename = <sessionId>.jsonl
|
|
215
|
-
transcriptPath = path.join(path.dirname(storePath), `${entry.sessionId}.jsonl`);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (!fs.existsSync(transcriptPath)) {
|
|
219
|
-
log?.info?.(`[adp-openclaw] Transcript file not found: ${transcriptPath}`);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Read and parse JSONL lines
|
|
224
|
-
const content = fs.readFileSync(transcriptPath, "utf-8");
|
|
225
|
-
const lines = content.split("\n").filter((l) => l.trim());
|
|
226
|
-
|
|
227
|
-
if (lines.length === 0) return;
|
|
228
|
-
|
|
229
|
-
// Parse each line into JSON entries
|
|
230
|
-
type TranscriptEntry = {
|
|
231
|
-
type?: string;
|
|
232
|
-
id?: string;
|
|
233
|
-
parentId?: string | null;
|
|
234
|
-
message?: { role?: string; content?: unknown };
|
|
235
|
-
[key: string]: unknown;
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
const entries: TranscriptEntry[] = [];
|
|
239
|
-
for (const line of lines) {
|
|
240
|
-
try {
|
|
241
|
-
entries.push(JSON.parse(line));
|
|
242
|
-
} catch {
|
|
243
|
-
entries.push({ _raw: line } as unknown as TranscriptEntry);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Find the last user message entry (searching from the end)
|
|
248
|
-
let lastUserMsgIdx = -1;
|
|
249
|
-
for (let i = entries.length - 1; i >= 0; i--) {
|
|
250
|
-
const e = entries[i];
|
|
251
|
-
if (e.type === "message" && e.message?.role === "user") {
|
|
252
|
-
lastUserMsgIdx = i;
|
|
253
|
-
break;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (lastUserMsgIdx < 0) {
|
|
258
|
-
log?.info?.(`[adp-openclaw] No user message found in transcript to trim`);
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Check if the last user message is at or near the end (within last few entries)
|
|
263
|
-
// This ensures we only trim the most recent aborted conversation, not old ones
|
|
264
|
-
if (lastUserMsgIdx < entries.length - 5) {
|
|
265
|
-
log?.info?.(`[adp-openclaw] Last user message is not recent enough to trim (idx=${lastUserMsgIdx}, total=${entries.length})`);
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Truncate: keep everything before the last user message
|
|
270
|
-
const trimmedLines = lines.slice(0, lastUserMsgIdx);
|
|
271
|
-
const trimmedContent = trimmedLines.join("\n") + "\n";
|
|
272
|
-
|
|
273
|
-
fs.writeFileSync(transcriptPath, trimmedContent, "utf-8");
|
|
274
|
-
|
|
275
|
-
const removedCount = lines.length - lastUserMsgIdx;
|
|
276
|
-
log?.info?.(`[adp-openclaw] Trimmed ${removedCount} aborted entries from transcript (kept ${lastUserMsgIdx} entries)`);
|
|
277
|
-
} catch (err) {
|
|
278
|
-
log?.error?.(`[adp-openclaw] Failed to trim aborted messages from transcript: ${err}`);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
167
|
export async function monitorAdpOpenclaw(params: MonitorParams): Promise<void> {
|
|
283
168
|
const { wsUrl, clientToken, signKey, abortSignal, log, cfg } = params;
|
|
284
169
|
const runtime = getAdpOpenclawRuntime();
|
|
@@ -748,23 +633,15 @@ async function connectAndHandle(params: ConnectParams): Promise<void> {
|
|
|
748
633
|
sendOutboundEnd(cancelText);
|
|
749
634
|
|
|
750
635
|
// Mark the session as aborted so the SDK injects an "abort hint"
|
|
751
|
-
// on the next message, preventing the AI from resuming the cancelled task
|
|
636
|
+
// on the next message, preventing the AI from resuming the cancelled task.
|
|
637
|
+
// This aligns with openclaw's behavior: keep all transcript history intact,
|
|
638
|
+
// only set abortedLastRun=true so next turn gets "Resume carefully" hint.
|
|
752
639
|
await markSessionAborted({
|
|
753
640
|
sessionKey: route.sessionKey,
|
|
754
641
|
runtime,
|
|
755
642
|
cfg,
|
|
756
643
|
log,
|
|
757
644
|
});
|
|
758
|
-
|
|
759
|
-
// Remove the aborted user message and partial assistant reply from
|
|
760
|
-
// the JSONL transcript. Without this, the AI sees the old cancelled
|
|
761
|
-
// request in its context and may resume it instead of answering the new one.
|
|
762
|
-
await trimAbortedMessagesFromTranscript({
|
|
763
|
-
sessionKey: route.sessionKey,
|
|
764
|
-
runtime,
|
|
765
|
-
cfg,
|
|
766
|
-
log,
|
|
767
|
-
});
|
|
768
645
|
}
|
|
769
646
|
|
|
770
647
|
// IMPORTANT: After dispatchReplyWithBufferedBlockDispatcher completes,
|