agenr 0.9.21 → 0.9.23
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/CHANGELOG.md +20 -0
- package/dist/chunk-56GW7EIS.js +2821 -0
- package/dist/chunk-DVNOWSKK.js +2820 -0
- package/dist/chunk-RM5SLLEM.js +241 -0
- package/dist/cli-main.js +52 -4
- package/dist/co-recall-2UNFBE7S.js +16 -0
- package/dist/openclaw-plugin/index.js +42 -359
- package/package.json +1 -1
|
@@ -3,19 +3,18 @@ import {
|
|
|
3
3
|
SCOPE_LEVELS,
|
|
4
4
|
checkAndFlagLowQuality,
|
|
5
5
|
closeDb,
|
|
6
|
+
computeRecallFeedback,
|
|
6
7
|
createLlmClient,
|
|
7
|
-
embed,
|
|
8
8
|
getDb,
|
|
9
9
|
initDb,
|
|
10
10
|
readConfig,
|
|
11
|
-
resolveEmbeddingApiKey,
|
|
12
11
|
runSimpleStream
|
|
13
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-56GW7EIS.js";
|
|
14
13
|
import {
|
|
15
14
|
strengthenCoRecallEdges,
|
|
16
15
|
toNumber,
|
|
17
16
|
toStringValue
|
|
18
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-RM5SLLEM.js";
|
|
19
18
|
|
|
20
19
|
// src/openclaw-plugin/index.ts
|
|
21
20
|
import { Type } from "@sinclair/typebox";
|
|
@@ -24,327 +23,6 @@ import os from "os";
|
|
|
24
23
|
import path3 from "path";
|
|
25
24
|
import { createInterface as createInterface2 } from "readline";
|
|
26
25
|
|
|
27
|
-
// src/db/feedback.ts
|
|
28
|
-
var RESPONSE_MIN_CHARS = 50;
|
|
29
|
-
var RESPONSE_MAX_CHARS = 8e3;
|
|
30
|
-
var SIGNAL_USED = 1;
|
|
31
|
-
var SIGNAL_UNCLEAR = 0.4;
|
|
32
|
-
var SIGNAL_CORRECTED = 0;
|
|
33
|
-
var RESPONSE_USED_THRESHOLD = 0.5;
|
|
34
|
-
var CORRECTION_THRESHOLD = 0.6;
|
|
35
|
-
function isRecord(value) {
|
|
36
|
-
return typeof value === "object" && value !== null;
|
|
37
|
-
}
|
|
38
|
-
function clamp01(value) {
|
|
39
|
-
if (!Number.isFinite(value)) {
|
|
40
|
-
return 0;
|
|
41
|
-
}
|
|
42
|
-
if (value <= 0) {
|
|
43
|
-
return 0;
|
|
44
|
-
}
|
|
45
|
-
if (value >= 1) {
|
|
46
|
-
return 1;
|
|
47
|
-
}
|
|
48
|
-
return value;
|
|
49
|
-
}
|
|
50
|
-
function mapBufferToVector(value) {
|
|
51
|
-
if (value instanceof ArrayBuffer) {
|
|
52
|
-
return Array.from(new Float32Array(value));
|
|
53
|
-
}
|
|
54
|
-
if (ArrayBuffer.isView(value)) {
|
|
55
|
-
const view = value;
|
|
56
|
-
return Array.from(
|
|
57
|
-
new Float32Array(view.buffer, view.byteOffset, Math.floor(view.byteLength / Float32Array.BYTES_PER_ELEMENT))
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
return [];
|
|
61
|
-
}
|
|
62
|
-
function cosineSimilarity(a, b) {
|
|
63
|
-
const size = Math.min(a.length, b.length);
|
|
64
|
-
if (size === 0) {
|
|
65
|
-
return 0;
|
|
66
|
-
}
|
|
67
|
-
let dot = 0;
|
|
68
|
-
let normA = 0;
|
|
69
|
-
let normB = 0;
|
|
70
|
-
for (let i = 0; i < size; i += 1) {
|
|
71
|
-
const av = a[i] ?? 0;
|
|
72
|
-
const bv = b[i] ?? 0;
|
|
73
|
-
dot += av * bv;
|
|
74
|
-
normA += av * av;
|
|
75
|
-
normB += bv * bv;
|
|
76
|
-
}
|
|
77
|
-
if (normA <= 0 || normB <= 0) {
|
|
78
|
-
return 0;
|
|
79
|
-
}
|
|
80
|
-
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
81
|
-
}
|
|
82
|
-
function extractTextFromContent(content, separator) {
|
|
83
|
-
if (typeof content === "string") {
|
|
84
|
-
return content.trim();
|
|
85
|
-
}
|
|
86
|
-
if (!Array.isArray(content)) {
|
|
87
|
-
return "";
|
|
88
|
-
}
|
|
89
|
-
const parts = [];
|
|
90
|
-
for (const block of content) {
|
|
91
|
-
if (!isRecord(block) || block.type !== "text") {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
const text = block.text;
|
|
95
|
-
if (typeof text !== "string") {
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
const trimmed = text.trim();
|
|
99
|
-
if (trimmed) {
|
|
100
|
-
parts.push(trimmed);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return parts.join(separator).trim();
|
|
104
|
-
}
|
|
105
|
-
function collectAssistantText(messages) {
|
|
106
|
-
const parts = [];
|
|
107
|
-
for (const message of messages) {
|
|
108
|
-
if (!isRecord(message) || message.role !== "assistant") {
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
const text = extractTextFromContent(message.content, "\n");
|
|
112
|
-
if (text) {
|
|
113
|
-
parts.push(text);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return parts.join("\n").trim();
|
|
117
|
-
}
|
|
118
|
-
function extractStoreContentsFromInput(input) {
|
|
119
|
-
if (!isRecord(input)) {
|
|
120
|
-
return [];
|
|
121
|
-
}
|
|
122
|
-
const out = [];
|
|
123
|
-
const directContent = input.content;
|
|
124
|
-
if (typeof directContent === "string" && directContent.trim()) {
|
|
125
|
-
out.push(directContent.trim());
|
|
126
|
-
}
|
|
127
|
-
const entries = input.entries;
|
|
128
|
-
if (Array.isArray(entries)) {
|
|
129
|
-
for (const item of entries) {
|
|
130
|
-
if (!isRecord(item)) {
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
const content = item.content;
|
|
134
|
-
if (typeof content === "string" && content.trim()) {
|
|
135
|
-
out.push(content.trim());
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return out;
|
|
140
|
-
}
|
|
141
|
-
function parseFunctionArguments(rawArgs) {
|
|
142
|
-
if (isRecord(rawArgs)) {
|
|
143
|
-
return rawArgs;
|
|
144
|
-
}
|
|
145
|
-
if (typeof rawArgs !== "string" || !rawArgs.trim()) {
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
try {
|
|
149
|
-
const parsed = JSON.parse(rawArgs);
|
|
150
|
-
return isRecord(parsed) ? parsed : null;
|
|
151
|
-
} catch {
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
function collectAgenrStoreContents(messages) {
|
|
156
|
-
const contents = [];
|
|
157
|
-
for (const message of messages) {
|
|
158
|
-
if (!isRecord(message) || message.role !== "assistant") {
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
const contentBlocks = message.content;
|
|
162
|
-
if (Array.isArray(contentBlocks)) {
|
|
163
|
-
for (const block of contentBlocks) {
|
|
164
|
-
if (!isRecord(block) || block.type !== "tool_use" || block.name !== "agenr_store") {
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
contents.push(...extractStoreContentsFromInput(block.input));
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
const toolCalls = message.tool_calls;
|
|
171
|
-
if (!Array.isArray(toolCalls)) {
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
for (const toolCall of toolCalls) {
|
|
175
|
-
if (!isRecord(toolCall)) {
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
if (typeof toolCall.name === "string" && toolCall.name === "agenr_store") {
|
|
179
|
-
const namedArgs = parseFunctionArguments(toolCall.arguments);
|
|
180
|
-
if (namedArgs) {
|
|
181
|
-
contents.push(...extractStoreContentsFromInput(namedArgs));
|
|
182
|
-
} else {
|
|
183
|
-
contents.push(...extractStoreContentsFromInput(toolCall.input));
|
|
184
|
-
}
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
const fn = toolCall.function;
|
|
188
|
-
if (!isRecord(fn) || fn.name !== "agenr_store") {
|
|
189
|
-
continue;
|
|
190
|
-
}
|
|
191
|
-
const args = parseFunctionArguments(fn.arguments);
|
|
192
|
-
if (args) {
|
|
193
|
-
contents.push(...extractStoreContentsFromInput(args));
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return Array.from(new Set(contents));
|
|
198
|
-
}
|
|
199
|
-
async function fetchEmbeddedEntries(db, ids) {
|
|
200
|
-
const idList = Array.from(ids).filter((id) => id.trim().length > 0);
|
|
201
|
-
if (idList.length === 0) {
|
|
202
|
-
return [];
|
|
203
|
-
}
|
|
204
|
-
const placeholders = idList.map(() => "?").join(", ");
|
|
205
|
-
const result = await db.execute({
|
|
206
|
-
sql: `
|
|
207
|
-
SELECT id, embedding
|
|
208
|
-
FROM entries
|
|
209
|
-
WHERE id IN (${placeholders})
|
|
210
|
-
AND embedding IS NOT NULL
|
|
211
|
-
`,
|
|
212
|
-
args: idList
|
|
213
|
-
});
|
|
214
|
-
const embeddedEntries = [];
|
|
215
|
-
for (const row of result.rows) {
|
|
216
|
-
const id = toStringValue(row.id);
|
|
217
|
-
const embedding = mapBufferToVector(row.embedding);
|
|
218
|
-
if (!id || embedding.length === 0) {
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
embeddedEntries.push({ id, embedding });
|
|
222
|
-
}
|
|
223
|
-
return embeddedEntries;
|
|
224
|
-
}
|
|
225
|
-
async function updateQualityScores(db, updates) {
|
|
226
|
-
if (updates.length === 0) {
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
const normalizedUpdates = /* @__PURE__ */ new Map();
|
|
230
|
-
for (const update of updates) {
|
|
231
|
-
const id = update.id.trim();
|
|
232
|
-
if (!id) {
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
normalizedUpdates.set(id, clamp01(update.signal));
|
|
236
|
-
}
|
|
237
|
-
if (normalizedUpdates.size === 0) {
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
const sql = `
|
|
241
|
-
UPDATE entries
|
|
242
|
-
SET quality_score = MIN(
|
|
243
|
-
1.0,
|
|
244
|
-
MAX(
|
|
245
|
-
0.8 * COALESCE(quality_score, 0.5) + 0.2 * ?,
|
|
246
|
-
CASE WHEN type IN ('fact', 'preference') THEN 0.35 ELSE 0.1 END
|
|
247
|
-
)
|
|
248
|
-
)
|
|
249
|
-
WHERE id = ?
|
|
250
|
-
`;
|
|
251
|
-
await db.execute("BEGIN");
|
|
252
|
-
try {
|
|
253
|
-
for (const [id, signal] of normalizedUpdates.entries()) {
|
|
254
|
-
await db.execute({ sql, args: [signal, id] });
|
|
255
|
-
}
|
|
256
|
-
await db.execute("COMMIT");
|
|
257
|
-
} catch (error) {
|
|
258
|
-
try {
|
|
259
|
-
await db.execute("ROLLBACK");
|
|
260
|
-
} catch {
|
|
261
|
-
}
|
|
262
|
-
throw error;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
async function computeRecallFeedback(db, sessionKey, messages, recalledEntryIds, config, logger) {
|
|
266
|
-
const emptyResult = {
|
|
267
|
-
usedIds: [],
|
|
268
|
-
correctedIds: [],
|
|
269
|
-
updatedIds: []
|
|
270
|
-
};
|
|
271
|
-
if (recalledEntryIds.size === 0) {
|
|
272
|
-
return emptyResult;
|
|
273
|
-
}
|
|
274
|
-
const assistantText = collectAssistantText(messages);
|
|
275
|
-
if (assistantText.length < RESPONSE_MIN_CHARS) {
|
|
276
|
-
return emptyResult;
|
|
277
|
-
}
|
|
278
|
-
const responseCorpus = assistantText.slice(0, RESPONSE_MAX_CHARS);
|
|
279
|
-
let apiKey;
|
|
280
|
-
try {
|
|
281
|
-
apiKey = resolveEmbeddingApiKey(config, process.env);
|
|
282
|
-
} catch (error) {
|
|
283
|
-
logger.warn(
|
|
284
|
-
`[agenr] before_reset: feedback skipped for session=${sessionKey} - ${error instanceof Error ? error.message : String(error)}`
|
|
285
|
-
);
|
|
286
|
-
return emptyResult;
|
|
287
|
-
}
|
|
288
|
-
let responseEmbedding = null;
|
|
289
|
-
try {
|
|
290
|
-
const vectors = await embed([responseCorpus], apiKey);
|
|
291
|
-
responseEmbedding = vectors[0] ?? null;
|
|
292
|
-
} catch (error) {
|
|
293
|
-
logger.warn(
|
|
294
|
-
`[agenr] before_reset: feedback embedding failed for session=${sessionKey}: ${error instanceof Error ? error.message : String(error)}`
|
|
295
|
-
);
|
|
296
|
-
return emptyResult;
|
|
297
|
-
}
|
|
298
|
-
if (!responseEmbedding || responseEmbedding.length === 0) {
|
|
299
|
-
return emptyResult;
|
|
300
|
-
}
|
|
301
|
-
const recalledEntries = await fetchEmbeddedEntries(db, recalledEntryIds);
|
|
302
|
-
if (recalledEntries.length === 0) {
|
|
303
|
-
return emptyResult;
|
|
304
|
-
}
|
|
305
|
-
const storeContents = collectAgenrStoreContents(messages);
|
|
306
|
-
let correctionEmbeddings = [];
|
|
307
|
-
if (storeContents.length > 0) {
|
|
308
|
-
try {
|
|
309
|
-
correctionEmbeddings = await embed(storeContents, apiKey);
|
|
310
|
-
} catch (error) {
|
|
311
|
-
logger.warn(
|
|
312
|
-
`[agenr] before_reset: correction embedding failed for session=${sessionKey}: ${error instanceof Error ? error.message : String(error)}`
|
|
313
|
-
);
|
|
314
|
-
correctionEmbeddings = [];
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
const correctedIds = /* @__PURE__ */ new Set();
|
|
318
|
-
if (correctionEmbeddings.length > 0) {
|
|
319
|
-
for (const entry of recalledEntries) {
|
|
320
|
-
for (const correctionEmbedding of correctionEmbeddings) {
|
|
321
|
-
if (cosineSimilarity(entry.embedding, correctionEmbedding) >= CORRECTION_THRESHOLD) {
|
|
322
|
-
correctedIds.add(entry.id);
|
|
323
|
-
break;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
const updates = recalledEntries.map((entry) => {
|
|
329
|
-
if (correctedIds.has(entry.id)) {
|
|
330
|
-
return { id: entry.id, signal: SIGNAL_CORRECTED };
|
|
331
|
-
}
|
|
332
|
-
const sim = cosineSimilarity(entry.embedding, responseEmbedding ?? []);
|
|
333
|
-
return {
|
|
334
|
-
id: entry.id,
|
|
335
|
-
signal: sim >= RESPONSE_USED_THRESHOLD ? SIGNAL_USED : SIGNAL_UNCLEAR
|
|
336
|
-
};
|
|
337
|
-
});
|
|
338
|
-
if (updates.length > 0) {
|
|
339
|
-
await updateQualityScores(db, updates);
|
|
340
|
-
}
|
|
341
|
-
return {
|
|
342
|
-
usedIds: updates.filter((update) => update.signal === SIGNAL_USED).map((update) => update.id),
|
|
343
|
-
correctedIds: Array.from(correctedIds),
|
|
344
|
-
updatedIds: updates.map((update) => update.id)
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
|
|
348
26
|
// src/openclaw-plugin/mid-session-recall.ts
|
|
349
27
|
var TRIVIAL_EXACT = /* @__PURE__ */ new Set([
|
|
350
28
|
"yes",
|
|
@@ -404,6 +82,7 @@ var FALSE_POSITIVE_NOUNS = /* @__PURE__ */ new Set([
|
|
|
404
82
|
"Who",
|
|
405
83
|
"Which",
|
|
406
84
|
"Can",
|
|
85
|
+
"Check",
|
|
407
86
|
"Could",
|
|
408
87
|
"Would",
|
|
409
88
|
"Should",
|
|
@@ -436,6 +115,7 @@ var FALSE_POSITIVE_NOUNS = /* @__PURE__ */ new Set([
|
|
|
436
115
|
"Thanks",
|
|
437
116
|
"So",
|
|
438
117
|
"Now",
|
|
118
|
+
"Really",
|
|
439
119
|
"Well",
|
|
440
120
|
"Still",
|
|
441
121
|
"Yet",
|
|
@@ -456,6 +136,9 @@ var FALSE_POSITIVE_NOUNS = /* @__PURE__ */ new Set([
|
|
|
456
136
|
"Her",
|
|
457
137
|
"Its",
|
|
458
138
|
"Their",
|
|
139
|
+
"She",
|
|
140
|
+
"They",
|
|
141
|
+
"You",
|
|
459
142
|
"Some",
|
|
460
143
|
"Any",
|
|
461
144
|
"All",
|
|
@@ -659,15 +342,15 @@ function clearMidSessionStates() {
|
|
|
659
342
|
function clearMidSessionState(key) {
|
|
660
343
|
midSessionStates.delete(key.trim());
|
|
661
344
|
}
|
|
662
|
-
function
|
|
345
|
+
function isRecord(value) {
|
|
663
346
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
664
347
|
}
|
|
665
348
|
function toRecallRow(item) {
|
|
666
|
-
if (!
|
|
349
|
+
if (!isRecord(item)) {
|
|
667
350
|
return null;
|
|
668
351
|
}
|
|
669
352
|
const rawEntry = item["entry"];
|
|
670
|
-
if (!
|
|
353
|
+
if (!isRecord(rawEntry)) {
|
|
671
354
|
return null;
|
|
672
355
|
}
|
|
673
356
|
const subject = typeof rawEntry["subject"] === "string" ? rawEntry["subject"].trim() : "";
|
|
@@ -840,11 +523,11 @@ var RECENT_TURN_MAX_CHARS = 300;
|
|
|
840
523
|
var SEMANTIC_SEED_PREVIOUS_TURNS_MAX_CHARS = 400;
|
|
841
524
|
var DEFAULT_RECENT_TURN_LIMIT = 7;
|
|
842
525
|
var CONVERSATION_METADATA_BLOCK_PATTERN = /(?:^|\r?\n)\s*Conversation info \(untrusted metadata\):\s*\r?\n\s*```json\s*\r?\n[\s\S]*?\r?\n\s*```\s*/g;
|
|
843
|
-
function
|
|
526
|
+
function isRecord2(value) {
|
|
844
527
|
return typeof value === "object" && value !== null;
|
|
845
528
|
}
|
|
846
529
|
function extractTextFromUserMessage(message) {
|
|
847
|
-
if (!
|
|
530
|
+
if (!isRecord2(message) || message["role"] !== "user") {
|
|
848
531
|
return "";
|
|
849
532
|
}
|
|
850
533
|
const content = message["content"];
|
|
@@ -856,7 +539,7 @@ function extractTextFromUserMessage(message) {
|
|
|
856
539
|
}
|
|
857
540
|
const textParts = [];
|
|
858
541
|
for (const part of content) {
|
|
859
|
-
if (!
|
|
542
|
+
if (!isRecord2(part) || part["type"] !== "text") {
|
|
860
543
|
continue;
|
|
861
544
|
}
|
|
862
545
|
const partText = part["text"];
|
|
@@ -871,7 +554,7 @@ function extractTextFromUserMessage(message) {
|
|
|
871
554
|
return textParts.join(" ").trim();
|
|
872
555
|
}
|
|
873
556
|
function extractTextFromAssistantMessage(message) {
|
|
874
|
-
if (!
|
|
557
|
+
if (!isRecord2(message) || message["role"] !== "assistant") {
|
|
875
558
|
return "";
|
|
876
559
|
}
|
|
877
560
|
const content = message["content"];
|
|
@@ -883,7 +566,7 @@ function extractTextFromAssistantMessage(message) {
|
|
|
883
566
|
}
|
|
884
567
|
const textParts = [];
|
|
885
568
|
for (const part of content) {
|
|
886
|
-
if (!
|
|
569
|
+
if (!isRecord2(part) || part["type"] !== "text") {
|
|
887
570
|
continue;
|
|
888
571
|
}
|
|
889
572
|
const partText = part["text"];
|
|
@@ -1039,7 +722,7 @@ async function extractRecentTurns(filePath, maxTurns = DEFAULT_RECENT_TURN_LIMIT
|
|
|
1039
722
|
} catch {
|
|
1040
723
|
return;
|
|
1041
724
|
}
|
|
1042
|
-
if (!
|
|
725
|
+
if (!isRecord2(record) || record["type"] !== "message") {
|
|
1043
726
|
return;
|
|
1044
727
|
}
|
|
1045
728
|
const message = record["message"];
|
|
@@ -1233,7 +916,7 @@ function resolveWarn(pluginConfig) {
|
|
|
1233
916
|
}
|
|
1234
917
|
}
|
|
1235
918
|
return (message) => {
|
|
1236
|
-
console.warn(message);
|
|
919
|
+
console.warn(`[AGENR] ${message}`);
|
|
1237
920
|
};
|
|
1238
921
|
}
|
|
1239
922
|
function sourceStringFromEntry(entry) {
|
|
@@ -1608,7 +1291,7 @@ var MAX_RECALLED_SESSIONS = 200;
|
|
|
1608
1291
|
var DEFAULT_MID_SESSION_RECALL_LIMIT = 8;
|
|
1609
1292
|
var DEFAULT_MID_SESSION_QUERY_SIMILARITY_THRESHOLD = 0.85;
|
|
1610
1293
|
var DEFAULT_STORE_NUDGE_THRESHOLD = 8;
|
|
1611
|
-
var DEFAULT_STORE_NUDGE_MAX_PER_SESSION =
|
|
1294
|
+
var DEFAULT_STORE_NUDGE_MAX_PER_SESSION = 5;
|
|
1612
1295
|
var sessionRecalledEntries = /* @__PURE__ */ new Map();
|
|
1613
1296
|
var sessionRef = { current: "" };
|
|
1614
1297
|
function isDebugEnabled(config) {
|
|
@@ -1616,7 +1299,7 @@ function isDebugEnabled(config) {
|
|
|
1616
1299
|
}
|
|
1617
1300
|
function debugLog(enabled, tag, message) {
|
|
1618
1301
|
if (enabled) {
|
|
1619
|
-
console.error(`[
|
|
1302
|
+
console.error(`[AGENR:${tag}] ${message}`);
|
|
1620
1303
|
}
|
|
1621
1304
|
}
|
|
1622
1305
|
var sessionSignalState = /* @__PURE__ */ new Map();
|
|
@@ -1840,10 +1523,10 @@ env states, config values. Do NOT repeat decisions already in KEY
|
|
|
1840
1523
|
FINDINGS. Write "None" if nothing new.
|
|
1841
1524
|
|
|
1842
1525
|
Keep the total response under 500 words. Plain text only.`;
|
|
1843
|
-
function
|
|
1526
|
+
function isRecord3(value) {
|
|
1844
1527
|
return typeof value === "object" && value !== null;
|
|
1845
1528
|
}
|
|
1846
|
-
function
|
|
1529
|
+
function extractTextFromContent(content, separator) {
|
|
1847
1530
|
if (typeof content === "string") {
|
|
1848
1531
|
return content.trim();
|
|
1849
1532
|
}
|
|
@@ -1852,7 +1535,7 @@ function extractTextFromContent2(content, separator) {
|
|
|
1852
1535
|
}
|
|
1853
1536
|
const textParts = [];
|
|
1854
1537
|
for (const block of content) {
|
|
1855
|
-
if (!
|
|
1538
|
+
if (!isRecord3(block) || block["type"] !== "text") {
|
|
1856
1539
|
continue;
|
|
1857
1540
|
}
|
|
1858
1541
|
const blockText = block["text"];
|
|
@@ -1867,7 +1550,7 @@ function extractTextFromContent2(content, separator) {
|
|
|
1867
1550
|
return textParts.join(separator).trim();
|
|
1868
1551
|
}
|
|
1869
1552
|
function extractHandoffContent(content) {
|
|
1870
|
-
return
|
|
1553
|
+
return extractTextFromContent(content, " ");
|
|
1871
1554
|
}
|
|
1872
1555
|
function stripInjectedContext(text) {
|
|
1873
1556
|
if (!text) {
|
|
@@ -1918,7 +1601,7 @@ async function readSessionsJson(sessionsDir) {
|
|
|
1918
1601
|
const sessionsJsonPath = path3.join(sessionsDir, "sessions.json");
|
|
1919
1602
|
const raw = await fs.promises.readFile(sessionsJsonPath, "utf8");
|
|
1920
1603
|
const parsed = JSON.parse(raw);
|
|
1921
|
-
return
|
|
1604
|
+
return isRecord3(parsed) ? parsed : {};
|
|
1922
1605
|
} catch {
|
|
1923
1606
|
return {};
|
|
1924
1607
|
}
|
|
@@ -1947,7 +1630,7 @@ function getSurfaceForSessionFile(sessionFilePath, sessionsJson) {
|
|
|
1947
1630
|
try {
|
|
1948
1631
|
const normalizedTarget = path3.resolve(sessionFilePath);
|
|
1949
1632
|
for (const value of Object.values(sessionsJson)) {
|
|
1950
|
-
if (!
|
|
1633
|
+
if (!isRecord3(value)) {
|
|
1951
1634
|
continue;
|
|
1952
1635
|
}
|
|
1953
1636
|
const entrySessionFile = value["sessionFile"];
|
|
@@ -1957,12 +1640,12 @@ function getSurfaceForSessionFile(sessionFilePath, sessionsJson) {
|
|
|
1957
1640
|
if (path3.resolve(entrySessionFile) !== normalizedTarget) {
|
|
1958
1641
|
continue;
|
|
1959
1642
|
}
|
|
1960
|
-
const origin =
|
|
1643
|
+
const origin = isRecord3(value["origin"]) ? value["origin"] : null;
|
|
1961
1644
|
const originSurface = origin && typeof origin["surface"] === "string" ? origin["surface"].trim() : "";
|
|
1962
1645
|
if (originSurface) {
|
|
1963
1646
|
return originSurface;
|
|
1964
1647
|
}
|
|
1965
|
-
const deliveryContext =
|
|
1648
|
+
const deliveryContext = isRecord3(value["deliveryContext"]) ? value["deliveryContext"] : null;
|
|
1966
1649
|
const channel = deliveryContext && typeof deliveryContext["channel"] === "string" ? deliveryContext["channel"].trim() : "";
|
|
1967
1650
|
return channel || "prior session";
|
|
1968
1651
|
}
|
|
@@ -1989,11 +1672,11 @@ async function readMessagesFromJsonl(filePath) {
|
|
|
1989
1672
|
} catch {
|
|
1990
1673
|
continue;
|
|
1991
1674
|
}
|
|
1992
|
-
if (!
|
|
1675
|
+
if (!isRecord3(parsed) || parsed["type"] !== "message") {
|
|
1993
1676
|
continue;
|
|
1994
1677
|
}
|
|
1995
1678
|
const message = parsed["message"];
|
|
1996
|
-
if (!
|
|
1679
|
+
if (!isRecord3(message)) {
|
|
1997
1680
|
continue;
|
|
1998
1681
|
}
|
|
1999
1682
|
const role = message["role"];
|
|
@@ -2105,13 +1788,13 @@ function capTranscriptLength(params) {
|
|
|
2105
1788
|
return transcript;
|
|
2106
1789
|
}
|
|
2107
1790
|
function extractAssistantSummaryText(message) {
|
|
2108
|
-
if (!
|
|
1791
|
+
if (!isRecord3(message)) {
|
|
2109
1792
|
return "";
|
|
2110
1793
|
}
|
|
2111
|
-
return
|
|
1794
|
+
return extractTextFromContent(message["content"], "\n");
|
|
2112
1795
|
}
|
|
2113
1796
|
function mapCurrentSessionMessage(message) {
|
|
2114
|
-
if (!
|
|
1797
|
+
if (!isRecord3(message)) {
|
|
2115
1798
|
return null;
|
|
2116
1799
|
}
|
|
2117
1800
|
const role = message["role"];
|
|
@@ -2271,7 +1954,7 @@ async function summarizeSessionForHandoff(currentRawMessages, sessionsDir, curre
|
|
|
2271
1954
|
debugLog(debugEnabled, "handoff", `logged LLM request/response to ${normalizedLogDir}`);
|
|
2272
1955
|
} catch (err) {
|
|
2273
1956
|
console.error(
|
|
2274
|
-
`[
|
|
1957
|
+
`[AGENR:handoff] failed to write LLM request/response logs: ${err instanceof Error ? err.message : String(err)}`
|
|
2275
1958
|
);
|
|
2276
1959
|
}
|
|
2277
1960
|
}
|
|
@@ -2279,7 +1962,7 @@ async function summarizeSessionForHandoff(currentRawMessages, sessionsDir, curre
|
|
|
2279
1962
|
return summaryText;
|
|
2280
1963
|
} catch (err) {
|
|
2281
1964
|
console.error(
|
|
2282
|
-
`[
|
|
1965
|
+
`[AGENR:before_reset] summarize handoff failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2283
1966
|
);
|
|
2284
1967
|
return null;
|
|
2285
1968
|
}
|
|
@@ -2326,7 +2009,7 @@ async function retireFallbackHandoffEntries(params) {
|
|
|
2326
2009
|
}
|
|
2327
2010
|
const retirePromises = [];
|
|
2328
2011
|
for (const item of browseResult.results) {
|
|
2329
|
-
const entryRecord =
|
|
2012
|
+
const entryRecord = isRecord3(item.entry) ? item.entry : null;
|
|
2330
2013
|
if (!entryRecord) {
|
|
2331
2014
|
continue;
|
|
2332
2015
|
}
|
|
@@ -2368,13 +2051,13 @@ async function retireFallbackHandoffEntries(params) {
|
|
|
2368
2051
|
}
|
|
2369
2052
|
function normalizeHandoffMessages(messages) {
|
|
2370
2053
|
return messages.map((message) => {
|
|
2371
|
-
if (!
|
|
2054
|
+
if (!isRecord3(message)) {
|
|
2372
2055
|
return message;
|
|
2373
2056
|
}
|
|
2374
2057
|
if (message["role"] === "user" || message["role"] === "assistant") {
|
|
2375
2058
|
return message;
|
|
2376
2059
|
}
|
|
2377
|
-
if (message["type"] !== "message" || !
|
|
2060
|
+
if (message["type"] !== "message" || !isRecord3(message["message"])) {
|
|
2378
2061
|
return message;
|
|
2379
2062
|
}
|
|
2380
2063
|
const parsedMessage = { ...message["message"] };
|
|
@@ -2425,7 +2108,7 @@ async function runHandoffForSession(opts) {
|
|
|
2425
2108
|
debugLog(Boolean(opts.debugEnabled), opts.source, "fallback handoff stored");
|
|
2426
2109
|
} catch (err) {
|
|
2427
2110
|
console.error(
|
|
2428
|
-
`[
|
|
2111
|
+
`[AGENR:${opts.source}] fallback store failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2429
2112
|
);
|
|
2430
2113
|
fallbackEntrySubject = null;
|
|
2431
2114
|
}
|
|
@@ -2479,7 +2162,7 @@ async function runHandoffForSession(opts) {
|
|
|
2479
2162
|
debugLog(Boolean(opts.debugEnabled), opts.source, "LLM handoff stored");
|
|
2480
2163
|
} catch (err) {
|
|
2481
2164
|
console.error(
|
|
2482
|
-
`[
|
|
2165
|
+
`[AGENR:${opts.source}] LLM handoff store failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2483
2166
|
);
|
|
2484
2167
|
}
|
|
2485
2168
|
}
|
|
@@ -2602,7 +2285,7 @@ var plugin = {
|
|
|
2602
2285
|
debugLog(debug, "session-start", "runHandoffForSession completed");
|
|
2603
2286
|
} catch (err) {
|
|
2604
2287
|
console.error(
|
|
2605
|
-
`[
|
|
2288
|
+
`[AGENR:session_start] handoff failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2606
2289
|
);
|
|
2607
2290
|
}
|
|
2608
2291
|
}
|
|
@@ -2654,7 +2337,7 @@ var plugin = {
|
|
|
2654
2337
|
debugLog(debug, "session-start", `retired handoff ${entryId}`);
|
|
2655
2338
|
}).catch((err) => {
|
|
2656
2339
|
console.error(
|
|
2657
|
-
`[
|
|
2340
|
+
`[AGENR:session-start] retire handoff ${entryId} failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2658
2341
|
);
|
|
2659
2342
|
})
|
|
2660
2343
|
);
|