@mastra/memory 1.6.0 → 1.6.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/CHANGELOG.md +54 -0
- package/dist/{chunk-5UYAHJVJ.cjs → chunk-D6II7EP4.cjs} +660 -531
- package/dist/chunk-D6II7EP4.cjs.map +1 -0
- package/dist/{chunk-A62BQK35.js → chunk-GBBQIJQF.js} +660 -531
- package/dist/chunk-GBBQIJQF.js.map +1 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +25 -25
- package/dist/docs/references/docs-agents-agent-approval.md +61 -31
- package/dist/docs/references/docs-agents-supervisor-agents.md +1 -1
- package/dist/docs/references/docs-memory-observational-memory.md +9 -0
- package/dist/docs/references/docs-memory-semantic-recall.md +17 -1
- package/dist/docs/references/reference-core-getMemory.md +2 -2
- package/dist/docs/references/reference-core-listMemory.md +1 -1
- package/dist/docs/references/reference-memory-clone-utilities.md +5 -5
- package/dist/docs/references/reference-memory-cloneThread.md +17 -21
- package/dist/docs/references/reference-memory-createThread.md +10 -10
- package/dist/docs/references/reference-memory-getThreadById.md +2 -2
- package/dist/docs/references/reference-memory-listThreads.md +5 -5
- package/dist/docs/references/reference-memory-memory-class.md +12 -14
- package/dist/docs/references/reference-memory-observational-memory.md +102 -94
- package/dist/docs/references/reference-processors-token-limiter-processor.md +11 -13
- package/dist/docs/references/reference-storage-dynamodb.md +9 -9
- package/dist/docs/references/reference-storage-libsql.md +2 -2
- package/dist/docs/references/reference-storage-mongodb.md +5 -5
- package/dist/docs/references/reference-storage-postgresql.md +25 -25
- package/dist/docs/references/reference-storage-upstash.md +3 -3
- package/dist/docs/references/reference-vectors-libsql.md +31 -31
- package/dist/docs/references/reference-vectors-mongodb.md +32 -32
- package/dist/docs/references/reference-vectors-pg.md +60 -44
- package/dist/docs/references/reference-vectors-upstash.md +25 -25
- package/dist/index.cjs +246 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +246 -57
- package/dist/index.js.map +1 -1
- package/dist/{observational-memory-MXI54VC7.cjs → observational-memory-AHVELJX4.cjs} +17 -17
- package/dist/{observational-memory-MXI54VC7.cjs.map → observational-memory-AHVELJX4.cjs.map} +1 -1
- package/dist/{observational-memory-SR6G4HN5.js → observational-memory-QFQUF5EY.js} +3 -3
- package/dist/{observational-memory-SR6G4HN5.js.map → observational-memory-QFQUF5EY.js.map} +1 -1
- package/dist/processors/index.cjs +15 -15
- package/dist/processors/index.js +1 -1
- package/dist/processors/observational-memory/date-utils.d.ts +35 -0
- package/dist/processors/observational-memory/date-utils.d.ts.map +1 -0
- package/dist/processors/observational-memory/markers.d.ts +94 -0
- package/dist/processors/observational-memory/markers.d.ts.map +1 -0
- package/dist/processors/observational-memory/observational-memory.d.ts +0 -76
- package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
- package/dist/processors/observational-memory/operation-registry.d.ts +14 -0
- package/dist/processors/observational-memory/operation-registry.d.ts.map +1 -0
- package/dist/processors/observational-memory/thresholds.d.ts +52 -0
- package/dist/processors/observational-memory/thresholds.d.ts.map +1 -0
- package/dist/processors/observational-memory/token-counter.d.ts +4 -0
- package/dist/processors/observational-memory/token-counter.d.ts.map +1 -1
- package/dist/tools/working-memory.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/chunk-5UYAHJVJ.cjs.map +0 -1
- package/dist/chunk-A62BQK35.js.map +0 -1
|
@@ -7,6 +7,7 @@ var llm = require('@mastra/core/llm');
|
|
|
7
7
|
var memory = require('@mastra/core/memory');
|
|
8
8
|
var processors = require('@mastra/core/processors');
|
|
9
9
|
var xxhash = require('xxhash-wasm');
|
|
10
|
+
var crypto$1 = require('crypto');
|
|
10
11
|
var lite = require('js-tiktoken/lite');
|
|
11
12
|
var o200k_base = require('js-tiktoken/ranks/o200k_base');
|
|
12
13
|
|
|
@@ -17,6 +18,294 @@ var o200k_base__default = /*#__PURE__*/_interopDefault(o200k_base);
|
|
|
17
18
|
|
|
18
19
|
// src/processors/observational-memory/observational-memory.ts
|
|
19
20
|
|
|
21
|
+
// src/processors/observational-memory/date-utils.ts
|
|
22
|
+
function formatRelativeTime(date, currentDate) {
|
|
23
|
+
const diffMs = currentDate.getTime() - date.getTime();
|
|
24
|
+
const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
25
|
+
if (diffDays < 0) {
|
|
26
|
+
const futureDays = Math.abs(diffDays);
|
|
27
|
+
if (futureDays === 1) return "tomorrow";
|
|
28
|
+
if (futureDays < 7) return `in ${futureDays} days`;
|
|
29
|
+
if (futureDays < 14) return "in 1 week";
|
|
30
|
+
if (futureDays < 30) return `in ${Math.floor(futureDays / 7)} weeks`;
|
|
31
|
+
if (futureDays < 60) return "in 1 month";
|
|
32
|
+
if (futureDays < 365) return `in ${Math.floor(futureDays / 30)} months`;
|
|
33
|
+
const years = Math.floor(futureDays / 365);
|
|
34
|
+
return `in ${years} year${years > 1 ? "s" : ""}`;
|
|
35
|
+
}
|
|
36
|
+
if (diffDays === 0) return "today";
|
|
37
|
+
if (diffDays === 1) return "yesterday";
|
|
38
|
+
if (diffDays < 7) return `${diffDays} days ago`;
|
|
39
|
+
if (diffDays < 14) return "1 week ago";
|
|
40
|
+
if (diffDays < 30) return `${Math.floor(diffDays / 7)} weeks ago`;
|
|
41
|
+
if (diffDays < 60) return "1 month ago";
|
|
42
|
+
if (diffDays < 365) return `${Math.floor(diffDays / 30)} months ago`;
|
|
43
|
+
return `${Math.floor(diffDays / 365)} year${Math.floor(diffDays / 365) > 1 ? "s" : ""} ago`;
|
|
44
|
+
}
|
|
45
|
+
function formatGapBetweenDates(prevDate, currDate) {
|
|
46
|
+
const diffMs = currDate.getTime() - prevDate.getTime();
|
|
47
|
+
const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
48
|
+
if (diffDays <= 1) {
|
|
49
|
+
return null;
|
|
50
|
+
} else if (diffDays < 7) {
|
|
51
|
+
return `[${diffDays} days later]`;
|
|
52
|
+
} else if (diffDays < 14) {
|
|
53
|
+
return `[1 week later]`;
|
|
54
|
+
} else if (diffDays < 30) {
|
|
55
|
+
const weeks = Math.floor(diffDays / 7);
|
|
56
|
+
return `[${weeks} weeks later]`;
|
|
57
|
+
} else if (diffDays < 60) {
|
|
58
|
+
return `[1 month later]`;
|
|
59
|
+
} else {
|
|
60
|
+
const months = Math.floor(diffDays / 30);
|
|
61
|
+
return `[${months} months later]`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function parseDateFromContent(dateContent) {
|
|
65
|
+
let targetDate = null;
|
|
66
|
+
const simpleDateMatch = dateContent.match(/([A-Z][a-z]+)\s+(\d{1,2}),?\s+(\d{4})/);
|
|
67
|
+
if (simpleDateMatch) {
|
|
68
|
+
const parsed = /* @__PURE__ */ new Date(`${simpleDateMatch[1]} ${simpleDateMatch[2]}, ${simpleDateMatch[3]}`);
|
|
69
|
+
if (!isNaN(parsed.getTime())) {
|
|
70
|
+
targetDate = parsed;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!targetDate) {
|
|
74
|
+
const rangeMatch = dateContent.match(/([A-Z][a-z]+)\s+(\d{1,2})-\d{1,2},?\s+(\d{4})/);
|
|
75
|
+
if (rangeMatch) {
|
|
76
|
+
const parsed = /* @__PURE__ */ new Date(`${rangeMatch[1]} ${rangeMatch[2]}, ${rangeMatch[3]}`);
|
|
77
|
+
if (!isNaN(parsed.getTime())) {
|
|
78
|
+
targetDate = parsed;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (!targetDate) {
|
|
83
|
+
const vagueMatch = dateContent.match(
|
|
84
|
+
/(late|early|mid)[- ]?(?:to[- ]?(?:late|early|mid)[- ]?)?([A-Z][a-z]+)\s+(\d{4})/i
|
|
85
|
+
);
|
|
86
|
+
if (vagueMatch) {
|
|
87
|
+
const month = vagueMatch[2];
|
|
88
|
+
const year = vagueMatch[3];
|
|
89
|
+
const modifier = vagueMatch[1].toLowerCase();
|
|
90
|
+
let day = 15;
|
|
91
|
+
if (modifier === "early") day = 7;
|
|
92
|
+
if (modifier === "late") day = 23;
|
|
93
|
+
const parsed = /* @__PURE__ */ new Date(`${month} ${day}, ${year}`);
|
|
94
|
+
if (!isNaN(parsed.getTime())) {
|
|
95
|
+
targetDate = parsed;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (!targetDate) {
|
|
100
|
+
const crossMonthMatch = dateContent.match(/([A-Z][a-z]+)\s+to\s+(?:early\s+)?([A-Z][a-z]+)\s+(\d{4})/i);
|
|
101
|
+
if (crossMonthMatch) {
|
|
102
|
+
const parsed = /* @__PURE__ */ new Date(`${crossMonthMatch[2]} 1, ${crossMonthMatch[3]}`);
|
|
103
|
+
if (!isNaN(parsed.getTime())) {
|
|
104
|
+
targetDate = parsed;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return targetDate;
|
|
109
|
+
}
|
|
110
|
+
function isFutureIntentObservation(line) {
|
|
111
|
+
const futureIntentPatterns = [
|
|
112
|
+
/\bwill\s+(?:be\s+)?(?:\w+ing|\w+)\b/i,
|
|
113
|
+
/\bplans?\s+to\b/i,
|
|
114
|
+
/\bplanning\s+to\b/i,
|
|
115
|
+
/\blooking\s+forward\s+to\b/i,
|
|
116
|
+
/\bgoing\s+to\b/i,
|
|
117
|
+
/\bintends?\s+to\b/i,
|
|
118
|
+
/\bwants?\s+to\b/i,
|
|
119
|
+
/\bneeds?\s+to\b/i,
|
|
120
|
+
/\babout\s+to\b/i
|
|
121
|
+
];
|
|
122
|
+
return futureIntentPatterns.some((pattern) => pattern.test(line));
|
|
123
|
+
}
|
|
124
|
+
function expandInlineEstimatedDates(observations, currentDate) {
|
|
125
|
+
const inlineDateRegex = /\((estimated|meaning)\s+([^)]+\d{4})\)/gi;
|
|
126
|
+
return observations.replace(inlineDateRegex, (match, prefix, dateContent, offset) => {
|
|
127
|
+
const targetDate = parseDateFromContent(dateContent);
|
|
128
|
+
if (targetDate) {
|
|
129
|
+
const relative = formatRelativeTime(targetDate, currentDate);
|
|
130
|
+
const lineStart = observations.lastIndexOf("\n", offset) + 1;
|
|
131
|
+
const lineBeforeDate = observations.slice(lineStart, offset);
|
|
132
|
+
const isPastDate = targetDate < currentDate;
|
|
133
|
+
const isFutureIntent = isFutureIntentObservation(lineBeforeDate);
|
|
134
|
+
if (isPastDate && isFutureIntent) {
|
|
135
|
+
return `(${prefix} ${dateContent} - ${relative}, likely already happened)`;
|
|
136
|
+
}
|
|
137
|
+
return `(${prefix} ${dateContent} - ${relative})`;
|
|
138
|
+
}
|
|
139
|
+
return match;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function addRelativeTimeToObservations(observations, currentDate) {
|
|
143
|
+
const withInlineDates = expandInlineEstimatedDates(observations, currentDate);
|
|
144
|
+
const dateHeaderRegex = /^(Date:\s*)([A-Z][a-z]+ \d{1,2}, \d{4})$/gm;
|
|
145
|
+
const dates = [];
|
|
146
|
+
let regexMatch;
|
|
147
|
+
while ((regexMatch = dateHeaderRegex.exec(withInlineDates)) !== null) {
|
|
148
|
+
const dateStr = regexMatch[2];
|
|
149
|
+
const parsed = new Date(dateStr);
|
|
150
|
+
if (!isNaN(parsed.getTime())) {
|
|
151
|
+
dates.push({
|
|
152
|
+
index: regexMatch.index,
|
|
153
|
+
date: parsed,
|
|
154
|
+
match: regexMatch[0],
|
|
155
|
+
prefix: regexMatch[1],
|
|
156
|
+
dateStr
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (dates.length === 0) {
|
|
161
|
+
return withInlineDates;
|
|
162
|
+
}
|
|
163
|
+
let result = "";
|
|
164
|
+
let lastIndex = 0;
|
|
165
|
+
for (let i = 0; i < dates.length; i++) {
|
|
166
|
+
const curr = dates[i];
|
|
167
|
+
const prev = i > 0 ? dates[i - 1] : null;
|
|
168
|
+
result += withInlineDates.slice(lastIndex, curr.index);
|
|
169
|
+
if (prev) {
|
|
170
|
+
const gap = formatGapBetweenDates(prev.date, curr.date);
|
|
171
|
+
if (gap) {
|
|
172
|
+
result += `
|
|
173
|
+
${gap}
|
|
174
|
+
|
|
175
|
+
`;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const relative = formatRelativeTime(curr.date, currentDate);
|
|
179
|
+
result += `${curr.prefix}${curr.dateStr} (${relative})`;
|
|
180
|
+
lastIndex = curr.index + curr.match.length;
|
|
181
|
+
}
|
|
182
|
+
result += withInlineDates.slice(lastIndex);
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/processors/observational-memory/markers.ts
|
|
187
|
+
function createObservationStartMarker(params) {
|
|
188
|
+
return {
|
|
189
|
+
type: "data-om-observation-start",
|
|
190
|
+
data: {
|
|
191
|
+
cycleId: params.cycleId,
|
|
192
|
+
operationType: params.operationType,
|
|
193
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
194
|
+
tokensToObserve: params.tokensToObserve,
|
|
195
|
+
recordId: params.recordId,
|
|
196
|
+
threadId: params.threadId,
|
|
197
|
+
threadIds: params.threadIds,
|
|
198
|
+
config: params.config
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function createObservationEndMarker(params) {
|
|
203
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
204
|
+
const durationMs = new Date(completedAt).getTime() - new Date(params.startedAt).getTime();
|
|
205
|
+
return {
|
|
206
|
+
type: "data-om-observation-end",
|
|
207
|
+
data: {
|
|
208
|
+
cycleId: params.cycleId,
|
|
209
|
+
operationType: params.operationType,
|
|
210
|
+
completedAt,
|
|
211
|
+
durationMs,
|
|
212
|
+
tokensObserved: params.tokensObserved,
|
|
213
|
+
observationTokens: params.observationTokens,
|
|
214
|
+
observations: params.observations,
|
|
215
|
+
currentTask: params.currentTask,
|
|
216
|
+
suggestedResponse: params.suggestedResponse,
|
|
217
|
+
recordId: params.recordId,
|
|
218
|
+
threadId: params.threadId
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function createObservationFailedMarker(params) {
|
|
223
|
+
const failedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
224
|
+
const durationMs = new Date(failedAt).getTime() - new Date(params.startedAt).getTime();
|
|
225
|
+
return {
|
|
226
|
+
type: "data-om-observation-failed",
|
|
227
|
+
data: {
|
|
228
|
+
cycleId: params.cycleId,
|
|
229
|
+
operationType: params.operationType,
|
|
230
|
+
failedAt,
|
|
231
|
+
durationMs,
|
|
232
|
+
tokensAttempted: params.tokensAttempted,
|
|
233
|
+
error: params.error,
|
|
234
|
+
recordId: params.recordId,
|
|
235
|
+
threadId: params.threadId
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function createBufferingStartMarker(params) {
|
|
240
|
+
return {
|
|
241
|
+
type: "data-om-buffering-start",
|
|
242
|
+
data: {
|
|
243
|
+
cycleId: params.cycleId,
|
|
244
|
+
operationType: params.operationType,
|
|
245
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
246
|
+
tokensToBuffer: params.tokensToBuffer,
|
|
247
|
+
recordId: params.recordId,
|
|
248
|
+
threadId: params.threadId,
|
|
249
|
+
threadIds: params.threadIds,
|
|
250
|
+
config: params.config
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function createBufferingEndMarker(params) {
|
|
255
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
256
|
+
const durationMs = new Date(completedAt).getTime() - new Date(params.startedAt).getTime();
|
|
257
|
+
return {
|
|
258
|
+
type: "data-om-buffering-end",
|
|
259
|
+
data: {
|
|
260
|
+
cycleId: params.cycleId,
|
|
261
|
+
operationType: params.operationType,
|
|
262
|
+
completedAt,
|
|
263
|
+
durationMs,
|
|
264
|
+
tokensBuffered: params.tokensBuffered,
|
|
265
|
+
bufferedTokens: params.bufferedTokens,
|
|
266
|
+
recordId: params.recordId,
|
|
267
|
+
threadId: params.threadId,
|
|
268
|
+
observations: params.observations
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
function createBufferingFailedMarker(params) {
|
|
273
|
+
const failedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
274
|
+
const durationMs = new Date(failedAt).getTime() - new Date(params.startedAt).getTime();
|
|
275
|
+
return {
|
|
276
|
+
type: "data-om-buffering-failed",
|
|
277
|
+
data: {
|
|
278
|
+
cycleId: params.cycleId,
|
|
279
|
+
operationType: params.operationType,
|
|
280
|
+
failedAt,
|
|
281
|
+
durationMs,
|
|
282
|
+
tokensAttempted: params.tokensAttempted,
|
|
283
|
+
error: params.error,
|
|
284
|
+
recordId: params.recordId,
|
|
285
|
+
threadId: params.threadId
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function createActivationMarker(params) {
|
|
290
|
+
return {
|
|
291
|
+
type: "data-om-activation",
|
|
292
|
+
data: {
|
|
293
|
+
cycleId: params.cycleId,
|
|
294
|
+
operationType: params.operationType,
|
|
295
|
+
activatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
296
|
+
chunksActivated: params.chunksActivated,
|
|
297
|
+
tokensActivated: params.tokensActivated,
|
|
298
|
+
observationTokens: params.observationTokens,
|
|
299
|
+
messagesActivated: params.messagesActivated,
|
|
300
|
+
recordId: params.recordId,
|
|
301
|
+
threadId: params.threadId,
|
|
302
|
+
generationCount: params.generationCount,
|
|
303
|
+
config: params.config,
|
|
304
|
+
observations: params.observations
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
20
309
|
// src/processors/observational-memory/observer-agent.ts
|
|
21
310
|
var OBSERVER_EXTRACTION_INSTRUCTIONS = `CRITICAL: DISTINGUISH USER ASSERTIONS FROM QUESTIONS
|
|
22
311
|
|
|
@@ -688,6 +977,29 @@ function optimizeObservationsForContext(observations) {
|
|
|
688
977
|
return optimized.trim();
|
|
689
978
|
}
|
|
690
979
|
|
|
980
|
+
// src/processors/observational-memory/operation-registry.ts
|
|
981
|
+
var activeOps = /* @__PURE__ */ new Map();
|
|
982
|
+
function opKey(recordId, op) {
|
|
983
|
+
return `${recordId}:${op}`;
|
|
984
|
+
}
|
|
985
|
+
function registerOp(recordId, op) {
|
|
986
|
+
const key = opKey(recordId, op);
|
|
987
|
+
activeOps.set(key, (activeOps.get(key) ?? 0) + 1);
|
|
988
|
+
}
|
|
989
|
+
function unregisterOp(recordId, op) {
|
|
990
|
+
const key = opKey(recordId, op);
|
|
991
|
+
const count = activeOps.get(key);
|
|
992
|
+
if (!count) return;
|
|
993
|
+
if (count <= 1) {
|
|
994
|
+
activeOps.delete(key);
|
|
995
|
+
} else {
|
|
996
|
+
activeOps.set(key, count - 1);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
function isOpActiveInProcess(recordId, op) {
|
|
1000
|
+
return (activeOps.get(opKey(recordId, op)) ?? 0) > 0;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
691
1003
|
// src/processors/observational-memory/reflector-agent.ts
|
|
692
1004
|
function buildReflectorSystemPrompt(instruction) {
|
|
693
1005
|
return `You are the memory consciousness of an AI assistant. Your memory observation reflections will be the ONLY information the assistant has about past interactions with this user.
|
|
@@ -916,6 +1228,91 @@ function extractReflectorListItems(content) {
|
|
|
916
1228
|
function validateCompression(reflectedTokens, targetThreshold) {
|
|
917
1229
|
return reflectedTokens < targetThreshold;
|
|
918
1230
|
}
|
|
1231
|
+
|
|
1232
|
+
// src/processors/observational-memory/thresholds.ts
|
|
1233
|
+
function getMaxThreshold(threshold) {
|
|
1234
|
+
if (typeof threshold === "number") {
|
|
1235
|
+
return threshold;
|
|
1236
|
+
}
|
|
1237
|
+
return threshold.max;
|
|
1238
|
+
}
|
|
1239
|
+
function calculateDynamicThreshold(threshold, currentObservationTokens) {
|
|
1240
|
+
if (typeof threshold === "number") {
|
|
1241
|
+
return threshold;
|
|
1242
|
+
}
|
|
1243
|
+
const totalBudget = threshold.max;
|
|
1244
|
+
const baseThreshold = threshold.min;
|
|
1245
|
+
const effectiveThreshold = Math.max(totalBudget - currentObservationTokens, baseThreshold);
|
|
1246
|
+
return Math.round(effectiveThreshold);
|
|
1247
|
+
}
|
|
1248
|
+
function resolveBufferTokens(bufferTokens, messageTokens) {
|
|
1249
|
+
if (bufferTokens === false) return void 0;
|
|
1250
|
+
if (bufferTokens === void 0) return void 0;
|
|
1251
|
+
if (bufferTokens > 0 && bufferTokens < 1) {
|
|
1252
|
+
return Math.round(getMaxThreshold(messageTokens) * bufferTokens);
|
|
1253
|
+
}
|
|
1254
|
+
return bufferTokens;
|
|
1255
|
+
}
|
|
1256
|
+
function resolveBlockAfter(blockAfter, messageTokens) {
|
|
1257
|
+
if (blockAfter === void 0) return void 0;
|
|
1258
|
+
if (blockAfter >= 1 && blockAfter < 100) {
|
|
1259
|
+
return Math.round(getMaxThreshold(messageTokens) * blockAfter);
|
|
1260
|
+
}
|
|
1261
|
+
return blockAfter;
|
|
1262
|
+
}
|
|
1263
|
+
function resolveRetentionFloor(bufferActivation, messageTokensThreshold) {
|
|
1264
|
+
if (bufferActivation >= 1e3) return bufferActivation;
|
|
1265
|
+
const ratio = Math.max(0, Math.min(1, bufferActivation));
|
|
1266
|
+
return messageTokensThreshold * (1 - ratio);
|
|
1267
|
+
}
|
|
1268
|
+
function resolveActivationRatio(bufferActivation, messageTokensThreshold) {
|
|
1269
|
+
if (bufferActivation >= 1e3) {
|
|
1270
|
+
return Math.max(0, Math.min(1, 1 - bufferActivation / messageTokensThreshold));
|
|
1271
|
+
}
|
|
1272
|
+
return Math.max(0, Math.min(1, bufferActivation));
|
|
1273
|
+
}
|
|
1274
|
+
function calculateProjectedMessageRemoval(chunks, bufferActivation, messageTokensThreshold, currentPendingTokens) {
|
|
1275
|
+
if (chunks.length === 0) return 0;
|
|
1276
|
+
const retentionFloor = resolveRetentionFloor(bufferActivation, messageTokensThreshold);
|
|
1277
|
+
const targetMessageTokens = Math.max(0, currentPendingTokens - retentionFloor);
|
|
1278
|
+
if (targetMessageTokens === 0) return 0;
|
|
1279
|
+
let cumulativeMessageTokens = 0;
|
|
1280
|
+
let bestOverBoundary = 0;
|
|
1281
|
+
let bestOverTokens = 0;
|
|
1282
|
+
let bestUnderBoundary = 0;
|
|
1283
|
+
let bestUnderTokens = 0;
|
|
1284
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
1285
|
+
cumulativeMessageTokens += chunks[i].messageTokens ?? 0;
|
|
1286
|
+
const boundary = i + 1;
|
|
1287
|
+
if (cumulativeMessageTokens >= targetMessageTokens) {
|
|
1288
|
+
if (bestOverBoundary === 0 || cumulativeMessageTokens < bestOverTokens) {
|
|
1289
|
+
bestOverBoundary = boundary;
|
|
1290
|
+
bestOverTokens = cumulativeMessageTokens;
|
|
1291
|
+
}
|
|
1292
|
+
} else {
|
|
1293
|
+
if (cumulativeMessageTokens > bestUnderTokens) {
|
|
1294
|
+
bestUnderBoundary = boundary;
|
|
1295
|
+
bestUnderTokens = cumulativeMessageTokens;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
const maxOvershoot = retentionFloor * 0.95;
|
|
1300
|
+
const overshoot = bestOverTokens - targetMessageTokens;
|
|
1301
|
+
const remainingAfterOver = currentPendingTokens - bestOverTokens;
|
|
1302
|
+
const remainingAfterUnder = currentPendingTokens - bestUnderTokens;
|
|
1303
|
+
const minRemaining = Math.min(1e3, retentionFloor);
|
|
1304
|
+
let bestBoundaryMessageTokens;
|
|
1305
|
+
if (bestOverBoundary > 0 && overshoot <= maxOvershoot && remainingAfterOver >= minRemaining) {
|
|
1306
|
+
bestBoundaryMessageTokens = bestOverTokens;
|
|
1307
|
+
} else if (bestUnderBoundary > 0 && remainingAfterUnder >= minRemaining) {
|
|
1308
|
+
bestBoundaryMessageTokens = bestUnderTokens;
|
|
1309
|
+
} else if (bestOverBoundary > 0) {
|
|
1310
|
+
bestBoundaryMessageTokens = bestOverTokens;
|
|
1311
|
+
} else {
|
|
1312
|
+
return chunks[0]?.messageTokens ?? 0;
|
|
1313
|
+
}
|
|
1314
|
+
return bestBoundaryMessageTokens;
|
|
1315
|
+
}
|
|
919
1316
|
var sharedDefaultEncoder;
|
|
920
1317
|
function getDefaultEncoder() {
|
|
921
1318
|
if (!sharedDefaultEncoder) {
|
|
@@ -923,8 +1320,94 @@ function getDefaultEncoder() {
|
|
|
923
1320
|
}
|
|
924
1321
|
return sharedDefaultEncoder;
|
|
925
1322
|
}
|
|
1323
|
+
var TOKEN_ESTIMATE_CACHE_VERSION = 1;
|
|
1324
|
+
function buildEstimateKey(kind, text) {
|
|
1325
|
+
const payloadHash = crypto$1.createHash("sha1").update(text).digest("hex");
|
|
1326
|
+
return `${kind}:${payloadHash}`;
|
|
1327
|
+
}
|
|
1328
|
+
function resolveEncodingId(encoding) {
|
|
1329
|
+
if (!encoding) return "o200k_base";
|
|
1330
|
+
try {
|
|
1331
|
+
return `custom:${crypto$1.createHash("sha1").update(JSON.stringify(encoding)).digest("hex")}`;
|
|
1332
|
+
} catch {
|
|
1333
|
+
return "custom:unknown";
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
function isTokenEstimateEntry(value) {
|
|
1337
|
+
if (!value || typeof value !== "object") return false;
|
|
1338
|
+
const entry = value;
|
|
1339
|
+
return typeof entry.v === "number" && typeof entry.source === "string" && typeof entry.key === "string" && typeof entry.tokens === "number";
|
|
1340
|
+
}
|
|
1341
|
+
function getCacheEntry(cache, key) {
|
|
1342
|
+
if (!cache || typeof cache !== "object") return void 0;
|
|
1343
|
+
if (isTokenEstimateEntry(cache)) {
|
|
1344
|
+
return cache.key === key ? cache : void 0;
|
|
1345
|
+
}
|
|
1346
|
+
return void 0;
|
|
1347
|
+
}
|
|
1348
|
+
function getPartCacheEntry(part, key) {
|
|
1349
|
+
const cache = part?.providerMetadata?.mastra?.tokenEstimate;
|
|
1350
|
+
return getCacheEntry(cache, key);
|
|
1351
|
+
}
|
|
1352
|
+
function setPartCacheEntry(part, _key, entry) {
|
|
1353
|
+
const mutablePart = part;
|
|
1354
|
+
mutablePart.providerMetadata ??= {};
|
|
1355
|
+
mutablePart.providerMetadata.mastra ??= {};
|
|
1356
|
+
mutablePart.providerMetadata.mastra.tokenEstimate = entry;
|
|
1357
|
+
}
|
|
1358
|
+
function getMessageCacheEntry(message, key) {
|
|
1359
|
+
const content = message.content;
|
|
1360
|
+
if (content && typeof content === "object") {
|
|
1361
|
+
const contentLevelCache = content.metadata?.mastra?.tokenEstimate;
|
|
1362
|
+
const contentLevelEntry = getCacheEntry(contentLevelCache, key);
|
|
1363
|
+
if (contentLevelEntry) return contentLevelEntry;
|
|
1364
|
+
}
|
|
1365
|
+
const messageLevelCache = message?.metadata?.mastra?.tokenEstimate;
|
|
1366
|
+
return getCacheEntry(messageLevelCache, key);
|
|
1367
|
+
}
|
|
1368
|
+
function setMessageCacheEntry(message, _key, entry) {
|
|
1369
|
+
const content = message.content;
|
|
1370
|
+
if (content && typeof content === "object") {
|
|
1371
|
+
content.metadata ??= {};
|
|
1372
|
+
content.metadata.mastra ??= {};
|
|
1373
|
+
content.metadata.mastra.tokenEstimate = entry;
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
message.metadata ??= {};
|
|
1377
|
+
message.metadata.mastra ??= {};
|
|
1378
|
+
message.metadata.mastra.tokenEstimate = entry;
|
|
1379
|
+
}
|
|
1380
|
+
function serializePartForTokenCounting(part) {
|
|
1381
|
+
const hasTokenEstimate = Boolean(part?.providerMetadata?.mastra?.tokenEstimate);
|
|
1382
|
+
if (!hasTokenEstimate) {
|
|
1383
|
+
return JSON.stringify(part);
|
|
1384
|
+
}
|
|
1385
|
+
const clonedPart = {
|
|
1386
|
+
...part,
|
|
1387
|
+
providerMetadata: {
|
|
1388
|
+
...part.providerMetadata ?? {},
|
|
1389
|
+
mastra: {
|
|
1390
|
+
...part.providerMetadata?.mastra ?? {}
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
};
|
|
1394
|
+
delete clonedPart.providerMetadata.mastra.tokenEstimate;
|
|
1395
|
+
if (Object.keys(clonedPart.providerMetadata.mastra).length === 0) {
|
|
1396
|
+
delete clonedPart.providerMetadata.mastra;
|
|
1397
|
+
}
|
|
1398
|
+
if (Object.keys(clonedPart.providerMetadata).length === 0) {
|
|
1399
|
+
delete clonedPart.providerMetadata;
|
|
1400
|
+
}
|
|
1401
|
+
return JSON.stringify(clonedPart);
|
|
1402
|
+
}
|
|
1403
|
+
function isValidCacheEntry(entry, expectedKey, expectedSource) {
|
|
1404
|
+
return Boolean(
|
|
1405
|
+
entry && entry.v === TOKEN_ESTIMATE_CACHE_VERSION && entry.source === expectedSource && entry.key === expectedKey && Number.isFinite(entry.tokens)
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
926
1408
|
var TokenCounter = class _TokenCounter {
|
|
927
1409
|
encoder;
|
|
1410
|
+
cacheSource;
|
|
928
1411
|
// Per-message overhead: accounts for role tokens, message framing, and separators.
|
|
929
1412
|
// Empirically derived from OpenAI's token counting guide (3 tokens per message base +
|
|
930
1413
|
// fractional overhead from name/role encoding). 3.8 is a practical average across models.
|
|
@@ -933,6 +1416,7 @@ var TokenCounter = class _TokenCounter {
|
|
|
933
1416
|
static TOKENS_PER_CONVERSATION = 24;
|
|
934
1417
|
constructor(encoding) {
|
|
935
1418
|
this.encoder = encoding ? new lite.Tiktoken(encoding) : getDefaultEncoder();
|
|
1419
|
+
this.cacheSource = `v${TOKEN_ESTIMATE_CACHE_VERSION}:${resolveEncodingId(encoding)}`;
|
|
936
1420
|
}
|
|
937
1421
|
/**
|
|
938
1422
|
* Count tokens in a plain string
|
|
@@ -941,43 +1425,108 @@ var TokenCounter = class _TokenCounter {
|
|
|
941
1425
|
if (!text) return 0;
|
|
942
1426
|
return this.encoder.encode(text, "all").length;
|
|
943
1427
|
}
|
|
1428
|
+
readOrPersistPartEstimate(part, kind, payload) {
|
|
1429
|
+
const key = buildEstimateKey(kind, payload);
|
|
1430
|
+
const cached = getPartCacheEntry(part, key);
|
|
1431
|
+
if (isValidCacheEntry(cached, key, this.cacheSource)) {
|
|
1432
|
+
return cached.tokens;
|
|
1433
|
+
}
|
|
1434
|
+
const tokens = this.countString(payload);
|
|
1435
|
+
setPartCacheEntry(part, key, {
|
|
1436
|
+
v: TOKEN_ESTIMATE_CACHE_VERSION,
|
|
1437
|
+
source: this.cacheSource,
|
|
1438
|
+
key,
|
|
1439
|
+
tokens
|
|
1440
|
+
});
|
|
1441
|
+
return tokens;
|
|
1442
|
+
}
|
|
1443
|
+
readOrPersistMessageEstimate(message, kind, payload) {
|
|
1444
|
+
const key = buildEstimateKey(kind, payload);
|
|
1445
|
+
const cached = getMessageCacheEntry(message, key);
|
|
1446
|
+
if (isValidCacheEntry(cached, key, this.cacheSource)) {
|
|
1447
|
+
return cached.tokens;
|
|
1448
|
+
}
|
|
1449
|
+
const tokens = this.countString(payload);
|
|
1450
|
+
setMessageCacheEntry(message, key, {
|
|
1451
|
+
v: TOKEN_ESTIMATE_CACHE_VERSION,
|
|
1452
|
+
source: this.cacheSource,
|
|
1453
|
+
key,
|
|
1454
|
+
tokens
|
|
1455
|
+
});
|
|
1456
|
+
return tokens;
|
|
1457
|
+
}
|
|
1458
|
+
resolveToolResultForTokenCounting(part, invocationResult) {
|
|
1459
|
+
const mastraMetadata = part?.providerMetadata?.mastra;
|
|
1460
|
+
if (mastraMetadata && typeof mastraMetadata === "object" && "modelOutput" in mastraMetadata) {
|
|
1461
|
+
return {
|
|
1462
|
+
value: mastraMetadata.modelOutput,
|
|
1463
|
+
usingStoredModelOutput: true
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
return {
|
|
1467
|
+
value: invocationResult,
|
|
1468
|
+
usingStoredModelOutput: false
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
944
1471
|
/**
|
|
945
1472
|
* Count tokens in a single message
|
|
946
1473
|
*/
|
|
947
1474
|
countMessage(message) {
|
|
948
|
-
let
|
|
1475
|
+
let payloadTokens = this.countString(message.role);
|
|
949
1476
|
let overhead = _TokenCounter.TOKENS_PER_MESSAGE;
|
|
950
1477
|
let toolResultCount = 0;
|
|
951
1478
|
if (typeof message.content === "string") {
|
|
952
|
-
|
|
1479
|
+
payloadTokens += this.readOrPersistMessageEstimate(message, "message-content", message.content);
|
|
953
1480
|
} else if (message.content && typeof message.content === "object") {
|
|
954
1481
|
if (message.content.content && !Array.isArray(message.content.parts)) {
|
|
955
|
-
|
|
1482
|
+
payloadTokens += this.readOrPersistMessageEstimate(message, "content-content", message.content.content);
|
|
956
1483
|
} else if (Array.isArray(message.content.parts)) {
|
|
957
1484
|
for (const part of message.content.parts) {
|
|
958
1485
|
if (part.type === "text") {
|
|
959
|
-
|
|
1486
|
+
payloadTokens += this.readOrPersistPartEstimate(part, "text", part.text);
|
|
960
1487
|
} else if (part.type === "tool-invocation") {
|
|
961
1488
|
const invocation = part.toolInvocation;
|
|
962
1489
|
if (invocation.state === "call" || invocation.state === "partial-call") {
|
|
963
1490
|
if (invocation.toolName) {
|
|
964
|
-
|
|
1491
|
+
payloadTokens += this.readOrPersistPartEstimate(
|
|
1492
|
+
part,
|
|
1493
|
+
`tool-${invocation.state}-name`,
|
|
1494
|
+
invocation.toolName
|
|
1495
|
+
);
|
|
965
1496
|
}
|
|
966
1497
|
if (invocation.args) {
|
|
967
1498
|
if (typeof invocation.args === "string") {
|
|
968
|
-
|
|
1499
|
+
payloadTokens += this.readOrPersistPartEstimate(
|
|
1500
|
+
part,
|
|
1501
|
+
`tool-${invocation.state}-args`,
|
|
1502
|
+
invocation.args
|
|
1503
|
+
);
|
|
969
1504
|
} else {
|
|
970
|
-
|
|
1505
|
+
const argsJson = JSON.stringify(invocation.args);
|
|
1506
|
+
payloadTokens += this.readOrPersistPartEstimate(part, `tool-${invocation.state}-args-json`, argsJson);
|
|
971
1507
|
overhead -= 12;
|
|
972
1508
|
}
|
|
973
1509
|
}
|
|
974
1510
|
} else if (invocation.state === "result") {
|
|
975
1511
|
toolResultCount++;
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1512
|
+
const { value: resultForCounting, usingStoredModelOutput } = this.resolveToolResultForTokenCounting(
|
|
1513
|
+
part,
|
|
1514
|
+
invocation.result
|
|
1515
|
+
);
|
|
1516
|
+
if (resultForCounting !== void 0) {
|
|
1517
|
+
if (typeof resultForCounting === "string") {
|
|
1518
|
+
payloadTokens += this.readOrPersistPartEstimate(
|
|
1519
|
+
part,
|
|
1520
|
+
usingStoredModelOutput ? "tool-result-model-output" : "tool-result",
|
|
1521
|
+
resultForCounting
|
|
1522
|
+
);
|
|
979
1523
|
} else {
|
|
980
|
-
|
|
1524
|
+
const resultJson = JSON.stringify(resultForCounting);
|
|
1525
|
+
payloadTokens += this.readOrPersistPartEstimate(
|
|
1526
|
+
part,
|
|
1527
|
+
usingStoredModelOutput ? "tool-result-model-output-json" : "tool-result-json",
|
|
1528
|
+
resultJson
|
|
1529
|
+
);
|
|
981
1530
|
overhead -= 12;
|
|
982
1531
|
}
|
|
983
1532
|
}
|
|
@@ -987,7 +1536,8 @@ var TokenCounter = class _TokenCounter {
|
|
|
987
1536
|
);
|
|
988
1537
|
}
|
|
989
1538
|
} else if (typeof part.type === "string" && part.type.startsWith("data-")) ; else if (part.type === "reasoning") ; else {
|
|
990
|
-
|
|
1539
|
+
const serialized = serializePartForTokenCounting(part);
|
|
1540
|
+
payloadTokens += this.readOrPersistPartEstimate(part, `part-${part.type}`, serialized);
|
|
991
1541
|
}
|
|
992
1542
|
}
|
|
993
1543
|
}
|
|
@@ -995,7 +1545,7 @@ var TokenCounter = class _TokenCounter {
|
|
|
995
1545
|
if (toolResultCount > 0) {
|
|
996
1546
|
overhead += toolResultCount * _TokenCounter.TOKENS_PER_MESSAGE;
|
|
997
1547
|
}
|
|
998
|
-
return Math.round(
|
|
1548
|
+
return Math.round(payloadTokens + overhead);
|
|
999
1549
|
}
|
|
1000
1550
|
/**
|
|
1001
1551
|
* Count tokens in an array of messages
|
|
@@ -1032,19 +1582,6 @@ function omError(msg, err) {
|
|
|
1032
1582
|
omDebug(`[OM:ERROR] ${full}`);
|
|
1033
1583
|
}
|
|
1034
1584
|
omDebug(`[OM:process-start] OM module loaded, pid=${process.pid}`);
|
|
1035
|
-
var activeOps = /* @__PURE__ */ new Set();
|
|
1036
|
-
function opKey(recordId, op) {
|
|
1037
|
-
return `${recordId}:${op}`;
|
|
1038
|
-
}
|
|
1039
|
-
function registerOp(recordId, op) {
|
|
1040
|
-
activeOps.add(opKey(recordId, op));
|
|
1041
|
-
}
|
|
1042
|
-
function unregisterOp(recordId, op) {
|
|
1043
|
-
activeOps.delete(opKey(recordId, op));
|
|
1044
|
-
}
|
|
1045
|
-
function isOpActiveInProcess(recordId, op) {
|
|
1046
|
-
return activeOps.has(opKey(recordId, op));
|
|
1047
|
-
}
|
|
1048
1585
|
if (OM_DEBUG_LOG) {
|
|
1049
1586
|
const _origConsoleError = console.error;
|
|
1050
1587
|
console.error = (...args) => {
|
|
@@ -1054,159 +1591,6 @@ if (OM_DEBUG_LOG) {
|
|
|
1054
1591
|
_origConsoleError.apply(console, args);
|
|
1055
1592
|
};
|
|
1056
1593
|
}
|
|
1057
|
-
function formatRelativeTime(date, currentDate) {
|
|
1058
|
-
const diffMs = currentDate.getTime() - date.getTime();
|
|
1059
|
-
const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
1060
|
-
if (diffDays === 0) return "today";
|
|
1061
|
-
if (diffDays === 1) return "yesterday";
|
|
1062
|
-
if (diffDays < 7) return `${diffDays} days ago`;
|
|
1063
|
-
if (diffDays < 14) return "1 week ago";
|
|
1064
|
-
if (diffDays < 30) return `${Math.floor(diffDays / 7)} weeks ago`;
|
|
1065
|
-
if (diffDays < 60) return "1 month ago";
|
|
1066
|
-
if (diffDays < 365) return `${Math.floor(diffDays / 30)} months ago`;
|
|
1067
|
-
return `${Math.floor(diffDays / 365)} year${Math.floor(diffDays / 365) > 1 ? "s" : ""} ago`;
|
|
1068
|
-
}
|
|
1069
|
-
function formatGapBetweenDates(prevDate, currDate) {
|
|
1070
|
-
const diffMs = currDate.getTime() - prevDate.getTime();
|
|
1071
|
-
const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
1072
|
-
if (diffDays <= 1) {
|
|
1073
|
-
return null;
|
|
1074
|
-
} else if (diffDays < 7) {
|
|
1075
|
-
return `[${diffDays} days later]`;
|
|
1076
|
-
} else if (diffDays < 14) {
|
|
1077
|
-
return `[1 week later]`;
|
|
1078
|
-
} else if (diffDays < 30) {
|
|
1079
|
-
const weeks = Math.floor(diffDays / 7);
|
|
1080
|
-
return `[${weeks} weeks later]`;
|
|
1081
|
-
} else if (diffDays < 60) {
|
|
1082
|
-
return `[1 month later]`;
|
|
1083
|
-
} else {
|
|
1084
|
-
const months = Math.floor(diffDays / 30);
|
|
1085
|
-
return `[${months} months later]`;
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
function parseDateFromContent(dateContent) {
|
|
1089
|
-
let targetDate = null;
|
|
1090
|
-
const simpleDateMatch = dateContent.match(/([A-Z][a-z]+)\s+(\d{1,2}),?\s+(\d{4})/);
|
|
1091
|
-
if (simpleDateMatch) {
|
|
1092
|
-
const parsed = /* @__PURE__ */ new Date(`${simpleDateMatch[1]} ${simpleDateMatch[2]}, ${simpleDateMatch[3]}`);
|
|
1093
|
-
if (!isNaN(parsed.getTime())) {
|
|
1094
|
-
targetDate = parsed;
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
if (!targetDate) {
|
|
1098
|
-
const rangeMatch = dateContent.match(/([A-Z][a-z]+)\s+(\d{1,2})-\d{1,2},?\s+(\d{4})/);
|
|
1099
|
-
if (rangeMatch) {
|
|
1100
|
-
const parsed = /* @__PURE__ */ new Date(`${rangeMatch[1]} ${rangeMatch[2]}, ${rangeMatch[3]}`);
|
|
1101
|
-
if (!isNaN(parsed.getTime())) {
|
|
1102
|
-
targetDate = parsed;
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
if (!targetDate) {
|
|
1107
|
-
const vagueMatch = dateContent.match(
|
|
1108
|
-
/(late|early|mid)[- ]?(?:to[- ]?(?:late|early|mid)[- ]?)?([A-Z][a-z]+)\s+(\d{4})/i
|
|
1109
|
-
);
|
|
1110
|
-
if (vagueMatch) {
|
|
1111
|
-
const month = vagueMatch[2];
|
|
1112
|
-
const year = vagueMatch[3];
|
|
1113
|
-
const modifier = vagueMatch[1].toLowerCase();
|
|
1114
|
-
let day = 15;
|
|
1115
|
-
if (modifier === "early") day = 7;
|
|
1116
|
-
if (modifier === "late") day = 23;
|
|
1117
|
-
const parsed = /* @__PURE__ */ new Date(`${month} ${day}, ${year}`);
|
|
1118
|
-
if (!isNaN(parsed.getTime())) {
|
|
1119
|
-
targetDate = parsed;
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
if (!targetDate) {
|
|
1124
|
-
const crossMonthMatch = dateContent.match(/([A-Z][a-z]+)\s+to\s+(?:early\s+)?([A-Z][a-z]+)\s+(\d{4})/i);
|
|
1125
|
-
if (crossMonthMatch) {
|
|
1126
|
-
const parsed = /* @__PURE__ */ new Date(`${crossMonthMatch[2]} 1, ${crossMonthMatch[3]}`);
|
|
1127
|
-
if (!isNaN(parsed.getTime())) {
|
|
1128
|
-
targetDate = parsed;
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
return targetDate;
|
|
1133
|
-
}
|
|
1134
|
-
function isFutureIntentObservation(line) {
|
|
1135
|
-
const futureIntentPatterns = [
|
|
1136
|
-
/\bwill\s+(?:be\s+)?(?:\w+ing|\w+)\b/i,
|
|
1137
|
-
/\bplans?\s+to\b/i,
|
|
1138
|
-
/\bplanning\s+to\b/i,
|
|
1139
|
-
/\blooking\s+forward\s+to\b/i,
|
|
1140
|
-
/\bgoing\s+to\b/i,
|
|
1141
|
-
/\bintends?\s+to\b/i,
|
|
1142
|
-
/\bwants?\s+to\b/i,
|
|
1143
|
-
/\bneeds?\s+to\b/i,
|
|
1144
|
-
/\babout\s+to\b/i
|
|
1145
|
-
];
|
|
1146
|
-
return futureIntentPatterns.some((pattern) => pattern.test(line));
|
|
1147
|
-
}
|
|
1148
|
-
function expandInlineEstimatedDates(observations, currentDate) {
|
|
1149
|
-
const inlineDateRegex = /\((estimated|meaning)\s+([^)]+\d{4})\)/gi;
|
|
1150
|
-
return observations.replace(inlineDateRegex, (match, prefix, dateContent) => {
|
|
1151
|
-
const targetDate = parseDateFromContent(dateContent);
|
|
1152
|
-
if (targetDate) {
|
|
1153
|
-
const relative = formatRelativeTime(targetDate, currentDate);
|
|
1154
|
-
const matchIndex = observations.indexOf(match);
|
|
1155
|
-
const lineStart = observations.lastIndexOf("\n", matchIndex) + 1;
|
|
1156
|
-
const lineBeforeDate = observations.substring(lineStart, matchIndex);
|
|
1157
|
-
const isPastDate = targetDate < currentDate;
|
|
1158
|
-
const isFutureIntent = isFutureIntentObservation(lineBeforeDate);
|
|
1159
|
-
if (isPastDate && isFutureIntent) {
|
|
1160
|
-
return `(${prefix} ${dateContent} - ${relative}, likely already happened)`;
|
|
1161
|
-
}
|
|
1162
|
-
return `(${prefix} ${dateContent} - ${relative})`;
|
|
1163
|
-
}
|
|
1164
|
-
return match;
|
|
1165
|
-
});
|
|
1166
|
-
}
|
|
1167
|
-
function addRelativeTimeToObservations(observations, currentDate) {
|
|
1168
|
-
const withInlineDates = expandInlineEstimatedDates(observations, currentDate);
|
|
1169
|
-
const dateHeaderRegex = /^(Date:\s*)([A-Z][a-z]+ \d{1,2}, \d{4})$/gm;
|
|
1170
|
-
const dates = [];
|
|
1171
|
-
let regexMatch;
|
|
1172
|
-
while ((regexMatch = dateHeaderRegex.exec(withInlineDates)) !== null) {
|
|
1173
|
-
const dateStr = regexMatch[2];
|
|
1174
|
-
const parsed = new Date(dateStr);
|
|
1175
|
-
if (!isNaN(parsed.getTime())) {
|
|
1176
|
-
dates.push({
|
|
1177
|
-
index: regexMatch.index,
|
|
1178
|
-
date: parsed,
|
|
1179
|
-
match: regexMatch[0],
|
|
1180
|
-
prefix: regexMatch[1],
|
|
1181
|
-
dateStr
|
|
1182
|
-
});
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
if (dates.length === 0) {
|
|
1186
|
-
return withInlineDates;
|
|
1187
|
-
}
|
|
1188
|
-
let result = "";
|
|
1189
|
-
let lastIndex = 0;
|
|
1190
|
-
for (let i = 0; i < dates.length; i++) {
|
|
1191
|
-
const curr = dates[i];
|
|
1192
|
-
const prev = i > 0 ? dates[i - 1] : null;
|
|
1193
|
-
result += withInlineDates.slice(lastIndex, curr.index);
|
|
1194
|
-
if (prev) {
|
|
1195
|
-
const gap = formatGapBetweenDates(prev.date, curr.date);
|
|
1196
|
-
if (gap) {
|
|
1197
|
-
result += `
|
|
1198
|
-
${gap}
|
|
1199
|
-
|
|
1200
|
-
`;
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
const relative = formatRelativeTime(curr.date, currentDate);
|
|
1204
|
-
result += `${curr.prefix}${curr.dateStr} (${relative})`;
|
|
1205
|
-
lastIndex = curr.index + curr.match.length;
|
|
1206
|
-
}
|
|
1207
|
-
result += withInlineDates.slice(lastIndex);
|
|
1208
|
-
return result;
|
|
1209
|
-
}
|
|
1210
1594
|
var OBSERVATIONAL_MEMORY_DEFAULTS = {
|
|
1211
1595
|
observation: {
|
|
1212
1596
|
model: "google/gemini-2.5-flash",
|
|
@@ -1431,71 +1815,6 @@ var ObservationalMemory = class _ObservationalMemory {
|
|
|
1431
1815
|
}
|
|
1432
1816
|
return [];
|
|
1433
1817
|
}
|
|
1434
|
-
/**
|
|
1435
|
-
* Resolve bufferActivation config into an absolute retention floor (tokens to keep).
|
|
1436
|
-
* - Value in (0, 1]: ratio → retentionFloor = threshold * (1 - value)
|
|
1437
|
-
* - Value >= 1000: absolute token count → retentionFloor = value
|
|
1438
|
-
*/
|
|
1439
|
-
resolveRetentionFloor(bufferActivation, messageTokensThreshold) {
|
|
1440
|
-
if (bufferActivation >= 1e3) return bufferActivation;
|
|
1441
|
-
return messageTokensThreshold * (1 - bufferActivation);
|
|
1442
|
-
}
|
|
1443
|
-
/**
|
|
1444
|
-
* Convert bufferActivation to the equivalent ratio (0-1) for the storage layer.
|
|
1445
|
-
* When bufferActivation >= 1000, it's an absolute retention target, so we compute
|
|
1446
|
-
* the equivalent ratio: 1 - (bufferActivation / threshold).
|
|
1447
|
-
*/
|
|
1448
|
-
resolveActivationRatio(bufferActivation, messageTokensThreshold) {
|
|
1449
|
-
if (bufferActivation >= 1e3) {
|
|
1450
|
-
return Math.max(0, Math.min(1, 1 - bufferActivation / messageTokensThreshold));
|
|
1451
|
-
}
|
|
1452
|
-
return bufferActivation;
|
|
1453
|
-
}
|
|
1454
|
-
/**
|
|
1455
|
-
* Calculate the projected message tokens that would be removed if activation happened now.
|
|
1456
|
-
* This replicates the chunk boundary logic in swapBufferedToActive without actually activating.
|
|
1457
|
-
*/
|
|
1458
|
-
calculateProjectedMessageRemoval(chunks, bufferActivation, messageTokensThreshold, currentPendingTokens) {
|
|
1459
|
-
if (chunks.length === 0) return 0;
|
|
1460
|
-
const retentionFloor = this.resolveRetentionFloor(bufferActivation, messageTokensThreshold);
|
|
1461
|
-
const targetMessageTokens = Math.max(0, currentPendingTokens - retentionFloor);
|
|
1462
|
-
let cumulativeMessageTokens = 0;
|
|
1463
|
-
let bestOverBoundary = 0;
|
|
1464
|
-
let bestOverTokens = 0;
|
|
1465
|
-
let bestUnderBoundary = 0;
|
|
1466
|
-
let bestUnderTokens = 0;
|
|
1467
|
-
for (let i = 0; i < chunks.length; i++) {
|
|
1468
|
-
cumulativeMessageTokens += chunks[i].messageTokens ?? 0;
|
|
1469
|
-
const boundary = i + 1;
|
|
1470
|
-
if (cumulativeMessageTokens >= targetMessageTokens) {
|
|
1471
|
-
if (bestOverBoundary === 0 || cumulativeMessageTokens < bestOverTokens) {
|
|
1472
|
-
bestOverBoundary = boundary;
|
|
1473
|
-
bestOverTokens = cumulativeMessageTokens;
|
|
1474
|
-
}
|
|
1475
|
-
} else {
|
|
1476
|
-
if (cumulativeMessageTokens > bestUnderTokens) {
|
|
1477
|
-
bestUnderBoundary = boundary;
|
|
1478
|
-
bestUnderTokens = cumulativeMessageTokens;
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
const maxOvershoot = retentionFloor * 0.95;
|
|
1483
|
-
const overshoot = bestOverTokens - targetMessageTokens;
|
|
1484
|
-
const remainingAfterOver = currentPendingTokens - bestOverTokens;
|
|
1485
|
-
const remainingAfterUnder = currentPendingTokens - bestUnderTokens;
|
|
1486
|
-
const minRemaining = Math.min(1e3, retentionFloor);
|
|
1487
|
-
let bestBoundaryMessageTokens;
|
|
1488
|
-
if (bestOverBoundary > 0 && overshoot <= maxOvershoot && remainingAfterOver >= minRemaining) {
|
|
1489
|
-
bestBoundaryMessageTokens = bestOverTokens;
|
|
1490
|
-
} else if (bestUnderBoundary > 0 && remainingAfterUnder >= minRemaining) {
|
|
1491
|
-
bestBoundaryMessageTokens = bestUnderTokens;
|
|
1492
|
-
} else if (bestOverBoundary > 0) {
|
|
1493
|
-
bestBoundaryMessageTokens = bestOverTokens;
|
|
1494
|
-
} else {
|
|
1495
|
-
return chunks[0]?.messageTokens ?? 0;
|
|
1496
|
-
}
|
|
1497
|
-
return bestBoundaryMessageTokens;
|
|
1498
|
-
}
|
|
1499
1818
|
/**
|
|
1500
1819
|
* Check if we've crossed a new bufferTokens interval boundary.
|
|
1501
1820
|
* Returns true if async buffering should be triggered.
|
|
@@ -1545,7 +1864,7 @@ var ObservationalMemory = class _ObservationalMemory {
|
|
|
1545
1864
|
if (this.isAsyncBufferingInProgress(bufferKey)) return false;
|
|
1546
1865
|
if (_ObservationalMemory.lastBufferedBoundary.has(bufferKey)) return false;
|
|
1547
1866
|
if (record.bufferedReflection) return false;
|
|
1548
|
-
const reflectThreshold =
|
|
1867
|
+
const reflectThreshold = getMaxThreshold(this.reflectionConfig.observationTokens);
|
|
1549
1868
|
const activationPoint = reflectThreshold * this.reflectionConfig.bufferActivation;
|
|
1550
1869
|
const shouldTrigger = currentObservationTokens >= activationPoint;
|
|
1551
1870
|
omDebug(
|
|
@@ -1662,12 +1981,12 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
1662
1981
|
},
|
|
1663
1982
|
providerOptions: config.observation?.providerOptions ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.providerOptions,
|
|
1664
1983
|
maxTokensPerBatch: config.observation?.maxTokensPerBatch ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.maxTokensPerBatch,
|
|
1665
|
-
bufferTokens: asyncBufferingDisabled ? void 0 :
|
|
1984
|
+
bufferTokens: asyncBufferingDisabled ? void 0 : resolveBufferTokens(
|
|
1666
1985
|
config.observation?.bufferTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.bufferTokens,
|
|
1667
1986
|
config.observation?.messageTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.messageTokens
|
|
1668
1987
|
),
|
|
1669
1988
|
bufferActivation: asyncBufferingDisabled ? void 0 : config.observation?.bufferActivation ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.bufferActivation,
|
|
1670
|
-
blockAfter: asyncBufferingDisabled ? void 0 :
|
|
1989
|
+
blockAfter: asyncBufferingDisabled ? void 0 : resolveBlockAfter(
|
|
1671
1990
|
config.observation?.blockAfter ?? (config.observation?.bufferTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.bufferTokens ? 1.2 : void 0),
|
|
1672
1991
|
config.observation?.messageTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.messageTokens
|
|
1673
1992
|
),
|
|
@@ -1683,7 +2002,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
1683
2002
|
},
|
|
1684
2003
|
providerOptions: config.reflection?.providerOptions ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.providerOptions,
|
|
1685
2004
|
bufferActivation: asyncBufferingDisabled ? void 0 : config?.reflection?.bufferActivation ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.bufferActivation,
|
|
1686
|
-
blockAfter: asyncBufferingDisabled ? void 0 :
|
|
2005
|
+
blockAfter: asyncBufferingDisabled ? void 0 : resolveBlockAfter(
|
|
1687
2006
|
config.reflection?.blockAfter ?? (config.reflection?.bufferActivation ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.bufferActivation ? 1.2 : void 0),
|
|
1688
2007
|
config.reflection?.observationTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.observationTokens
|
|
1689
2008
|
),
|
|
@@ -1778,7 +2097,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
1778
2097
|
`Async buffering is not yet supported with scope: 'resource'. Use scope: 'thread', or set observation: { bufferTokens: false } to disable async buffering.`
|
|
1779
2098
|
);
|
|
1780
2099
|
}
|
|
1781
|
-
const observationThreshold =
|
|
2100
|
+
const observationThreshold = getMaxThreshold(this.observationConfig.messageTokens);
|
|
1782
2101
|
if (this.observationConfig.bufferTokens !== void 0) {
|
|
1783
2102
|
if (this.observationConfig.bufferTokens <= 0) {
|
|
1784
2103
|
throw new Error(`observation.bufferTokens must be > 0, got ${this.observationConfig.bufferTokens}`);
|
|
@@ -1824,7 +2143,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
1824
2143
|
}
|
|
1825
2144
|
}
|
|
1826
2145
|
if (this.reflectionConfig.blockAfter !== void 0) {
|
|
1827
|
-
const reflectionThreshold =
|
|
2146
|
+
const reflectionThreshold = getMaxThreshold(this.reflectionConfig.observationTokens);
|
|
1828
2147
|
if (this.reflectionConfig.blockAfter < reflectionThreshold) {
|
|
1829
2148
|
throw new Error(
|
|
1830
2149
|
`reflection.blockAfter (${this.reflectionConfig.blockAfter}) must be >= reflection.observationTokens (${reflectionThreshold})`
|
|
@@ -1837,65 +2156,6 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
1837
2156
|
}
|
|
1838
2157
|
}
|
|
1839
2158
|
}
|
|
1840
|
-
/**
|
|
1841
|
-
* Resolve bufferTokens: if it's a fraction (0 < value < 1), multiply by messageTokens threshold.
|
|
1842
|
-
* Otherwise return the absolute token count.
|
|
1843
|
-
*/
|
|
1844
|
-
resolveBufferTokens(bufferTokens, messageTokens) {
|
|
1845
|
-
if (bufferTokens === false) return void 0;
|
|
1846
|
-
if (bufferTokens === void 0) return void 0;
|
|
1847
|
-
if (bufferTokens > 0 && bufferTokens < 1) {
|
|
1848
|
-
const threshold = typeof messageTokens === "number" ? messageTokens : messageTokens.max;
|
|
1849
|
-
return Math.round(threshold * bufferTokens);
|
|
1850
|
-
}
|
|
1851
|
-
return bufferTokens;
|
|
1852
|
-
}
|
|
1853
|
-
/**
|
|
1854
|
-
* Resolve blockAfter config value.
|
|
1855
|
-
* Values in [1, 100) are treated as multipliers of the threshold.
|
|
1856
|
-
* e.g. blockAfter: 1.5 with messageTokens: 20_000 → 30_000
|
|
1857
|
-
* Values >= 100 are treated as absolute token counts.
|
|
1858
|
-
* Defaults to 1.2 (120% of threshold) when async buffering is enabled but blockAfter is omitted.
|
|
1859
|
-
*/
|
|
1860
|
-
resolveBlockAfter(blockAfter, messageTokens) {
|
|
1861
|
-
if (blockAfter === void 0) return void 0;
|
|
1862
|
-
if (blockAfter >= 1 && blockAfter < 100) {
|
|
1863
|
-
const threshold = typeof messageTokens === "number" ? messageTokens : messageTokens.max;
|
|
1864
|
-
return Math.round(threshold * blockAfter);
|
|
1865
|
-
}
|
|
1866
|
-
return blockAfter;
|
|
1867
|
-
}
|
|
1868
|
-
/**
|
|
1869
|
-
* Get the maximum value from a threshold (simple number or range)
|
|
1870
|
-
*/
|
|
1871
|
-
getMaxThreshold(threshold) {
|
|
1872
|
-
if (typeof threshold === "number") {
|
|
1873
|
-
return threshold;
|
|
1874
|
-
}
|
|
1875
|
-
return threshold.max;
|
|
1876
|
-
}
|
|
1877
|
-
/**
|
|
1878
|
-
* Calculate dynamic threshold based on observation space.
|
|
1879
|
-
* When shareTokenBudget is enabled, the message threshold can expand
|
|
1880
|
-
* into unused observation space, up to the total context budget.
|
|
1881
|
-
*
|
|
1882
|
-
* Total budget = messageTokens + observationTokens
|
|
1883
|
-
* Effective threshold = totalBudget - currentObservationTokens
|
|
1884
|
-
*
|
|
1885
|
-
* Example with 30k:40k thresholds (70k total):
|
|
1886
|
-
* - 0 observations → messages can use ~70k
|
|
1887
|
-
* - 10k observations → messages can use ~60k
|
|
1888
|
-
* - 40k observations → messages back to ~30k
|
|
1889
|
-
*/
|
|
1890
|
-
calculateDynamicThreshold(threshold, currentObservationTokens) {
|
|
1891
|
-
if (typeof threshold === "number") {
|
|
1892
|
-
return threshold;
|
|
1893
|
-
}
|
|
1894
|
-
const totalBudget = threshold.max;
|
|
1895
|
-
const baseThreshold = threshold.min;
|
|
1896
|
-
const effectiveThreshold = Math.max(totalBudget - currentObservationTokens, baseThreshold);
|
|
1897
|
-
return Math.round(effectiveThreshold);
|
|
1898
|
-
}
|
|
1899
2159
|
/**
|
|
1900
2160
|
* Check whether the unobserved message tokens meet the observation threshold.
|
|
1901
2161
|
*/
|
|
@@ -1903,7 +2163,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
1903
2163
|
const { record, unobservedTokens, extraTokens = 0 } = opts;
|
|
1904
2164
|
const pendingTokens = (record.pendingMessageTokens ?? 0) + unobservedTokens + extraTokens;
|
|
1905
2165
|
const currentObservationTokens = record.observationTokenCount ?? 0;
|
|
1906
|
-
const threshold =
|
|
2166
|
+
const threshold = calculateDynamicThreshold(this.observationConfig.messageTokens, currentObservationTokens);
|
|
1907
2167
|
return pendingTokens >= threshold;
|
|
1908
2168
|
}
|
|
1909
2169
|
/**
|
|
@@ -1983,7 +2243,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
1983
2243
|
* Check if we need to trigger reflection.
|
|
1984
2244
|
*/
|
|
1985
2245
|
shouldReflect(observationTokens) {
|
|
1986
|
-
const threshold =
|
|
2246
|
+
const threshold = getMaxThreshold(this.reflectionConfig.observationTokens);
|
|
1987
2247
|
return observationTokens > threshold;
|
|
1988
2248
|
}
|
|
1989
2249
|
// ════════════════════════════════════════════════════════════════════════════
|
|
@@ -2004,153 +2264,11 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
2004
2264
|
*/
|
|
2005
2265
|
getObservationMarkerConfig() {
|
|
2006
2266
|
return {
|
|
2007
|
-
messageTokens:
|
|
2008
|
-
observationTokens:
|
|
2267
|
+
messageTokens: getMaxThreshold(this.observationConfig.messageTokens),
|
|
2268
|
+
observationTokens: getMaxThreshold(this.reflectionConfig.observationTokens),
|
|
2009
2269
|
scope: this.scope
|
|
2010
2270
|
};
|
|
2011
2271
|
}
|
|
2012
|
-
/**
|
|
2013
|
-
* Create a start marker for when observation begins.
|
|
2014
|
-
*/
|
|
2015
|
-
createObservationStartMarker(params) {
|
|
2016
|
-
return {
|
|
2017
|
-
type: "data-om-observation-start",
|
|
2018
|
-
data: {
|
|
2019
|
-
cycleId: params.cycleId,
|
|
2020
|
-
operationType: params.operationType,
|
|
2021
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2022
|
-
tokensToObserve: params.tokensToObserve,
|
|
2023
|
-
recordId: params.recordId,
|
|
2024
|
-
threadId: params.threadId,
|
|
2025
|
-
threadIds: params.threadIds,
|
|
2026
|
-
config: this.getObservationMarkerConfig()
|
|
2027
|
-
}
|
|
2028
|
-
};
|
|
2029
|
-
}
|
|
2030
|
-
/**
|
|
2031
|
-
* Create an end marker for when observation completes successfully.
|
|
2032
|
-
*/
|
|
2033
|
-
createObservationEndMarker(params) {
|
|
2034
|
-
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2035
|
-
const durationMs = new Date(completedAt).getTime() - new Date(params.startedAt).getTime();
|
|
2036
|
-
return {
|
|
2037
|
-
type: "data-om-observation-end",
|
|
2038
|
-
data: {
|
|
2039
|
-
cycleId: params.cycleId,
|
|
2040
|
-
operationType: params.operationType,
|
|
2041
|
-
completedAt,
|
|
2042
|
-
durationMs,
|
|
2043
|
-
tokensObserved: params.tokensObserved,
|
|
2044
|
-
observationTokens: params.observationTokens,
|
|
2045
|
-
observations: params.observations,
|
|
2046
|
-
currentTask: params.currentTask,
|
|
2047
|
-
suggestedResponse: params.suggestedResponse,
|
|
2048
|
-
recordId: params.recordId,
|
|
2049
|
-
threadId: params.threadId
|
|
2050
|
-
}
|
|
2051
|
-
};
|
|
2052
|
-
}
|
|
2053
|
-
/**
|
|
2054
|
-
* Create a failed marker for when observation fails.
|
|
2055
|
-
*/
|
|
2056
|
-
createObservationFailedMarker(params) {
|
|
2057
|
-
const failedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2058
|
-
const durationMs = new Date(failedAt).getTime() - new Date(params.startedAt).getTime();
|
|
2059
|
-
return {
|
|
2060
|
-
type: "data-om-observation-failed",
|
|
2061
|
-
data: {
|
|
2062
|
-
cycleId: params.cycleId,
|
|
2063
|
-
operationType: params.operationType,
|
|
2064
|
-
failedAt,
|
|
2065
|
-
durationMs,
|
|
2066
|
-
tokensAttempted: params.tokensAttempted,
|
|
2067
|
-
error: params.error,
|
|
2068
|
-
recordId: params.recordId,
|
|
2069
|
-
threadId: params.threadId
|
|
2070
|
-
}
|
|
2071
|
-
};
|
|
2072
|
-
}
|
|
2073
|
-
/**
|
|
2074
|
-
* Create a start marker for when async buffering begins.
|
|
2075
|
-
*/
|
|
2076
|
-
createBufferingStartMarker(params) {
|
|
2077
|
-
return {
|
|
2078
|
-
type: "data-om-buffering-start",
|
|
2079
|
-
data: {
|
|
2080
|
-
cycleId: params.cycleId,
|
|
2081
|
-
operationType: params.operationType,
|
|
2082
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2083
|
-
tokensToBuffer: params.tokensToBuffer,
|
|
2084
|
-
recordId: params.recordId,
|
|
2085
|
-
threadId: params.threadId,
|
|
2086
|
-
threadIds: params.threadIds,
|
|
2087
|
-
config: this.getObservationMarkerConfig()
|
|
2088
|
-
}
|
|
2089
|
-
};
|
|
2090
|
-
}
|
|
2091
|
-
/**
|
|
2092
|
-
* Create an end marker for when async buffering completes successfully.
|
|
2093
|
-
*/
|
|
2094
|
-
createBufferingEndMarker(params) {
|
|
2095
|
-
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2096
|
-
const durationMs = new Date(completedAt).getTime() - new Date(params.startedAt).getTime();
|
|
2097
|
-
return {
|
|
2098
|
-
type: "data-om-buffering-end",
|
|
2099
|
-
data: {
|
|
2100
|
-
cycleId: params.cycleId,
|
|
2101
|
-
operationType: params.operationType,
|
|
2102
|
-
completedAt,
|
|
2103
|
-
durationMs,
|
|
2104
|
-
tokensBuffered: params.tokensBuffered,
|
|
2105
|
-
bufferedTokens: params.bufferedTokens,
|
|
2106
|
-
recordId: params.recordId,
|
|
2107
|
-
threadId: params.threadId,
|
|
2108
|
-
observations: params.observations
|
|
2109
|
-
}
|
|
2110
|
-
};
|
|
2111
|
-
}
|
|
2112
|
-
/**
|
|
2113
|
-
* Create a failed marker for when async buffering fails.
|
|
2114
|
-
*/
|
|
2115
|
-
createBufferingFailedMarker(params) {
|
|
2116
|
-
const failedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2117
|
-
const durationMs = new Date(failedAt).getTime() - new Date(params.startedAt).getTime();
|
|
2118
|
-
return {
|
|
2119
|
-
type: "data-om-buffering-failed",
|
|
2120
|
-
data: {
|
|
2121
|
-
cycleId: params.cycleId,
|
|
2122
|
-
operationType: params.operationType,
|
|
2123
|
-
failedAt,
|
|
2124
|
-
durationMs,
|
|
2125
|
-
tokensAttempted: params.tokensAttempted,
|
|
2126
|
-
error: params.error,
|
|
2127
|
-
recordId: params.recordId,
|
|
2128
|
-
threadId: params.threadId
|
|
2129
|
-
}
|
|
2130
|
-
};
|
|
2131
|
-
}
|
|
2132
|
-
/**
|
|
2133
|
-
* Create an activation marker for when buffered observations are activated.
|
|
2134
|
-
*/
|
|
2135
|
-
createActivationMarker(params) {
|
|
2136
|
-
return {
|
|
2137
|
-
type: "data-om-activation",
|
|
2138
|
-
data: {
|
|
2139
|
-
cycleId: params.cycleId,
|
|
2140
|
-
operationType: params.operationType,
|
|
2141
|
-
activatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2142
|
-
chunksActivated: params.chunksActivated,
|
|
2143
|
-
tokensActivated: params.tokensActivated,
|
|
2144
|
-
observationTokens: params.observationTokens,
|
|
2145
|
-
messagesActivated: params.messagesActivated,
|
|
2146
|
-
recordId: params.recordId,
|
|
2147
|
-
threadId: params.threadId,
|
|
2148
|
-
generationCount: params.generationCount,
|
|
2149
|
-
config: this.getObservationMarkerConfig(),
|
|
2150
|
-
observations: params.observations
|
|
2151
|
-
}
|
|
2152
|
-
};
|
|
2153
|
-
}
|
|
2154
2272
|
/**
|
|
2155
2273
|
* Persist a data-om-* marker part on the last assistant message in messageList
|
|
2156
2274
|
* AND save the updated message to the DB so it survives page reload.
|
|
@@ -2531,7 +2649,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
2531
2649
|
async callReflector(observations, manualPrompt, streamContext, observationTokensThreshold, abortSignal, skipContinuationHints, compressionStartLevel, requestContext) {
|
|
2532
2650
|
const agent = this.getReflectorAgent();
|
|
2533
2651
|
const originalTokens = this.tokenCounter.countObservations(observations);
|
|
2534
|
-
const targetThreshold = observationTokensThreshold ??
|
|
2652
|
+
const targetThreshold = observationTokensThreshold ?? getMaxThreshold(this.reflectionConfig.observationTokens);
|
|
2535
2653
|
let totalUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
2536
2654
|
let currentLevel = compressionStartLevel ?? 0;
|
|
2537
2655
|
const maxLevel = 3;
|
|
@@ -2606,7 +2724,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
2606
2724
|
break;
|
|
2607
2725
|
}
|
|
2608
2726
|
if (streamContext?.writer) {
|
|
2609
|
-
const failedMarker =
|
|
2727
|
+
const failedMarker = createObservationFailedMarker({
|
|
2610
2728
|
cycleId: streamContext.cycleId,
|
|
2611
2729
|
operationType: "reflection",
|
|
2612
2730
|
startedAt: streamContext.startedAt,
|
|
@@ -2619,13 +2737,14 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
2619
2737
|
});
|
|
2620
2738
|
const retryCycleId = crypto.randomUUID();
|
|
2621
2739
|
streamContext.cycleId = retryCycleId;
|
|
2622
|
-
const startMarker =
|
|
2740
|
+
const startMarker = createObservationStartMarker({
|
|
2623
2741
|
cycleId: retryCycleId,
|
|
2624
2742
|
operationType: "reflection",
|
|
2625
2743
|
tokensToObserve: originalTokens,
|
|
2626
2744
|
recordId: streamContext.recordId,
|
|
2627
2745
|
threadId: streamContext.threadId,
|
|
2628
|
-
threadIds: [streamContext.threadId]
|
|
2746
|
+
threadIds: [streamContext.threadId],
|
|
2747
|
+
config: this.getObservationMarkerConfig()
|
|
2629
2748
|
});
|
|
2630
2749
|
streamContext.startedAt = startMarker.data.startedAt;
|
|
2631
2750
|
await streamContext.writer.custom(startMarker).catch(() => {
|
|
@@ -2759,8 +2878,8 @@ ${suggestedResponse}
|
|
|
2759
2878
|
calculateObservationThresholds(_allMessages, unobservedMessages, _pendingTokens, otherThreadTokens, currentObservationTokens, _record) {
|
|
2760
2879
|
const contextWindowTokens = this.tokenCounter.countMessages(unobservedMessages);
|
|
2761
2880
|
const totalPendingTokens = Math.max(0, contextWindowTokens + otherThreadTokens);
|
|
2762
|
-
const threshold =
|
|
2763
|
-
const baseReflectionThreshold =
|
|
2881
|
+
const threshold = calculateDynamicThreshold(this.observationConfig.messageTokens, currentObservationTokens);
|
|
2882
|
+
const baseReflectionThreshold = getMaxThreshold(this.reflectionConfig.observationTokens);
|
|
2764
2883
|
const isSharedBudget = typeof this.observationConfig.messageTokens !== "number";
|
|
2765
2884
|
const totalBudget = isSharedBudget ? this.observationConfig.messageTokens.max : 0;
|
|
2766
2885
|
const effectiveObservationTokensThreshold = isSharedBudget ? Math.max(totalBudget - threshold, 1e3) : baseReflectionThreshold;
|
|
@@ -2794,10 +2913,10 @@ ${suggestedResponse}
|
|
|
2794
2913
|
const bufferedObservationTokens = bufferedChunks.reduce((sum, chunk) => sum + (chunk.tokenCount ?? 0), 0);
|
|
2795
2914
|
const rawBufferedMessageTokens = bufferedChunks.reduce((sum, chunk) => sum + (chunk.messageTokens ?? 0), 0);
|
|
2796
2915
|
const bufferedMessageTokens = Math.min(rawBufferedMessageTokens, totalPendingTokens);
|
|
2797
|
-
const projectedMessageRemoval =
|
|
2916
|
+
const projectedMessageRemoval = calculateProjectedMessageRemoval(
|
|
2798
2917
|
bufferedChunks,
|
|
2799
2918
|
this.observationConfig.bufferActivation ?? 1,
|
|
2800
|
-
|
|
2919
|
+
getMaxThreshold(this.observationConfig.messageTokens),
|
|
2801
2920
|
totalPendingTokens
|
|
2802
2921
|
);
|
|
2803
2922
|
let obsBufferStatus = "idle";
|
|
@@ -3006,7 +3125,39 @@ ${suggestedResponse}
|
|
|
3006
3125
|
omDebug(
|
|
3007
3126
|
`[OM:cleanupBranch] allMsgs=${allMsgs.length}, markerFound=${markerIdx !== -1}, markerIdx=${markerIdx}, observedMessageIds=${observedMessageIds?.length ?? "undefined"}, allIds=${allMsgs.map((m) => m.id?.slice(0, 8)).join(",")}`
|
|
3008
3127
|
);
|
|
3009
|
-
if (
|
|
3128
|
+
if (observedMessageIds && observedMessageIds.length > 0) {
|
|
3129
|
+
const observedSet = new Set(observedMessageIds);
|
|
3130
|
+
const idsToRemove = /* @__PURE__ */ new Set();
|
|
3131
|
+
let skipped = 0;
|
|
3132
|
+
let backoffTriggered = false;
|
|
3133
|
+
for (const msg of allMsgs) {
|
|
3134
|
+
if (!msg?.id || msg.id === "om-continuation" || !observedSet.has(msg.id)) {
|
|
3135
|
+
continue;
|
|
3136
|
+
}
|
|
3137
|
+
if (typeof minRemaining === "number") {
|
|
3138
|
+
const nextRemainingMessages = allMsgs.filter(
|
|
3139
|
+
(m) => m?.id && m.id !== "om-continuation" && !idsToRemove.has(m.id) && m.id !== msg.id
|
|
3140
|
+
);
|
|
3141
|
+
const remainingIfRemoved = this.tokenCounter.countMessages(nextRemainingMessages);
|
|
3142
|
+
if (remainingIfRemoved < minRemaining) {
|
|
3143
|
+
skipped += 1;
|
|
3144
|
+
backoffTriggered = true;
|
|
3145
|
+
break;
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
idsToRemove.add(msg.id);
|
|
3149
|
+
}
|
|
3150
|
+
omDebug(
|
|
3151
|
+
`[OM:cleanupActivation] observedSet=${[...observedSet].map((id) => id.slice(0, 8)).join(",")}, matched=${idsToRemove.size}, skipped=${skipped}, backoffTriggered=${backoffTriggered}, idsToRemove=${[...idsToRemove].map((id) => id.slice(0, 8)).join(",")}`
|
|
3152
|
+
);
|
|
3153
|
+
const idsToRemoveList = [...idsToRemove];
|
|
3154
|
+
if (idsToRemoveList.length > 0) {
|
|
3155
|
+
messageList.removeByIds(idsToRemoveList);
|
|
3156
|
+
omDebug(
|
|
3157
|
+
`[OM:cleanupActivation] removed ${idsToRemoveList.length} messages, remaining=${messageList.get.all.db().length}`
|
|
3158
|
+
);
|
|
3159
|
+
}
|
|
3160
|
+
} else if (markerMsg && markerIdx !== -1) {
|
|
3010
3161
|
const idsToRemove = [];
|
|
3011
3162
|
const messagesToSave = [];
|
|
3012
3163
|
for (let i = 0; i < markerIdx; i++) {
|
|
@@ -3031,35 +3182,6 @@ ${suggestedResponse}
|
|
|
3031
3182
|
if (messagesToSave.length > 0) {
|
|
3032
3183
|
await this.saveMessagesWithSealedIdTracking(messagesToSave, sealedIds, threadId, resourceId, state);
|
|
3033
3184
|
}
|
|
3034
|
-
} else if (observedMessageIds && observedMessageIds.length > 0) {
|
|
3035
|
-
const observedSet = new Set(observedMessageIds);
|
|
3036
|
-
const idsToRemove = [];
|
|
3037
|
-
const totalTokens = typeof minRemaining === "number" ? this.tokenCounter.countMessages(allMsgs) : void 0;
|
|
3038
|
-
let removedTokens = 0;
|
|
3039
|
-
let skipped = 0;
|
|
3040
|
-
for (const msg of allMsgs) {
|
|
3041
|
-
if (msg?.id && msg.id !== "om-continuation" && observedSet.has(msg.id)) {
|
|
3042
|
-
if (typeof minRemaining === "number") {
|
|
3043
|
-
const msgTokens = this.tokenCounter.countMessage(msg);
|
|
3044
|
-
const remainingIfRemoved = (totalTokens ?? 0) - removedTokens - msgTokens;
|
|
3045
|
-
if (remainingIfRemoved < minRemaining) {
|
|
3046
|
-
skipped += 1;
|
|
3047
|
-
continue;
|
|
3048
|
-
}
|
|
3049
|
-
removedTokens += msgTokens;
|
|
3050
|
-
}
|
|
3051
|
-
idsToRemove.push(msg.id);
|
|
3052
|
-
}
|
|
3053
|
-
}
|
|
3054
|
-
omDebug(
|
|
3055
|
-
`[OM:cleanupActivation] observedSet=${[...observedSet].map((id) => id.slice(0, 8)).join(",")}, matched=${idsToRemove.length}, skipped=${skipped}, idsToRemove=${idsToRemove.map((id) => id.slice(0, 8)).join(",")}`
|
|
3056
|
-
);
|
|
3057
|
-
if (idsToRemove.length > 0) {
|
|
3058
|
-
messageList.removeByIds(idsToRemove);
|
|
3059
|
-
omDebug(
|
|
3060
|
-
`[OM:cleanupActivation] removed ${idsToRemove.length} messages, remaining=${messageList.get.all.db().length}`
|
|
3061
|
-
);
|
|
3062
|
-
}
|
|
3063
3185
|
} else {
|
|
3064
3186
|
const newInput = messageList.clear.input.db();
|
|
3065
3187
|
const newOutput = messageList.clear.response.db();
|
|
@@ -3401,7 +3523,7 @@ ${suggestedResponse}
|
|
|
3401
3523
|
);
|
|
3402
3524
|
if (observationSucceeded) {
|
|
3403
3525
|
const observedIds = activatedMessageIds?.length ? activatedMessageIds : Array.isArray(updatedRecord.observedMessageIds) ? updatedRecord.observedMessageIds : void 0;
|
|
3404
|
-
const minRemaining = typeof this.observationConfig.bufferActivation === "number" ?
|
|
3526
|
+
const minRemaining = typeof this.observationConfig.bufferActivation === "number" ? resolveRetentionFloor(this.observationConfig.bufferActivation, threshold) : void 0;
|
|
3405
3527
|
omDebug(
|
|
3406
3528
|
`[OM:cleanup] observedIds=${observedIds?.length ?? "undefined"}, ids=${observedIds?.join(",") ?? "none"}, updatedRecord.observedMessageIds=${JSON.stringify(updatedRecord.observedMessageIds)}, minRemaining=${minRemaining ?? "n/a"}`
|
|
3407
3529
|
);
|
|
@@ -3445,8 +3567,8 @@ ${suggestedResponse}
|
|
|
3445
3567
|
const freshUnobservedTokens = this.tokenCounter.countMessages(contextMessages);
|
|
3446
3568
|
const otherThreadTokens = unobservedContextBlocks ? this.tokenCounter.countString(unobservedContextBlocks) : 0;
|
|
3447
3569
|
const currentObservationTokens = freshRecord.observationTokenCount ?? 0;
|
|
3448
|
-
const threshold =
|
|
3449
|
-
const baseReflectionThreshold =
|
|
3570
|
+
const threshold = calculateDynamicThreshold(this.observationConfig.messageTokens, currentObservationTokens);
|
|
3571
|
+
const baseReflectionThreshold = getMaxThreshold(this.reflectionConfig.observationTokens);
|
|
3450
3572
|
const isSharedBudget = typeof this.observationConfig.messageTokens !== "number";
|
|
3451
3573
|
const totalBudget = isSharedBudget ? this.observationConfig.messageTokens.max : 0;
|
|
3452
3574
|
const effectiveObservationTokensThreshold = isSharedBudget ? Math.max(totalBudget - threshold, 1e3) : baseReflectionThreshold;
|
|
@@ -3763,13 +3885,14 @@ ${newThreadSection}`;
|
|
|
3763
3885
|
const lastMessage = unobservedMessages[unobservedMessages.length - 1];
|
|
3764
3886
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3765
3887
|
if (lastMessage?.id) {
|
|
3766
|
-
const startMarker =
|
|
3888
|
+
const startMarker = createObservationStartMarker({
|
|
3767
3889
|
cycleId,
|
|
3768
3890
|
operationType: "observation",
|
|
3769
3891
|
tokensToObserve,
|
|
3770
3892
|
recordId: record.id,
|
|
3771
3893
|
threadId,
|
|
3772
|
-
threadIds: [threadId]
|
|
3894
|
+
threadIds: [threadId],
|
|
3895
|
+
config: this.getObservationMarkerConfig()
|
|
3773
3896
|
});
|
|
3774
3897
|
if (writer) {
|
|
3775
3898
|
await writer.custom(startMarker).catch(() => {
|
|
@@ -3837,7 +3960,7 @@ ${result.observations}` : result.observations;
|
|
|
3837
3960
|
});
|
|
3838
3961
|
const actualTokensObserved = this.tokenCounter.countMessages(messagesToObserve);
|
|
3839
3962
|
if (lastMessage?.id) {
|
|
3840
|
-
const endMarker =
|
|
3963
|
+
const endMarker = createObservationEndMarker({
|
|
3841
3964
|
cycleId,
|
|
3842
3965
|
operationType: "observation",
|
|
3843
3966
|
startedAt,
|
|
@@ -3879,7 +4002,7 @@ ${result.observations}` : result.observations;
|
|
|
3879
4002
|
});
|
|
3880
4003
|
} catch (error) {
|
|
3881
4004
|
if (lastMessage?.id) {
|
|
3882
|
-
const failedMarker =
|
|
4005
|
+
const failedMarker = createObservationFailedMarker({
|
|
3883
4006
|
cycleId,
|
|
3884
4007
|
operationType: "observation",
|
|
3885
4008
|
startedAt,
|
|
@@ -4001,13 +4124,14 @@ ${result.observations}` : result.observations;
|
|
|
4001
4124
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4002
4125
|
const tokensToBuffer = this.tokenCounter.countMessages(messagesToBuffer);
|
|
4003
4126
|
if (writer) {
|
|
4004
|
-
const startMarker =
|
|
4127
|
+
const startMarker = createBufferingStartMarker({
|
|
4005
4128
|
cycleId,
|
|
4006
4129
|
operationType: "observation",
|
|
4007
4130
|
tokensToBuffer,
|
|
4008
4131
|
recordId: freshRecord.id,
|
|
4009
4132
|
threadId,
|
|
4010
|
-
threadIds: [threadId]
|
|
4133
|
+
threadIds: [threadId],
|
|
4134
|
+
config: this.getObservationMarkerConfig()
|
|
4011
4135
|
});
|
|
4012
4136
|
void writer.custom(startMarker).catch(() => {
|
|
4013
4137
|
});
|
|
@@ -4030,7 +4154,7 @@ ${result.observations}` : result.observations;
|
|
|
4030
4154
|
_ObservationalMemory.lastBufferedAtTime.set(bufferKey, cursor);
|
|
4031
4155
|
} catch (error) {
|
|
4032
4156
|
if (writer) {
|
|
4033
|
-
const failedMarker =
|
|
4157
|
+
const failedMarker = createBufferingFailedMarker({
|
|
4034
4158
|
cycleId,
|
|
4035
4159
|
operationType: "observation",
|
|
4036
4160
|
startedAt,
|
|
@@ -4098,7 +4222,7 @@ ${result.observations}` : result.observations;
|
|
|
4098
4222
|
const updatedRecord = await this.storage.getObservationalMemory(record.threadId, record.resourceId);
|
|
4099
4223
|
const updatedChunks = this.getBufferedChunks(updatedRecord);
|
|
4100
4224
|
const totalBufferedTokens = updatedChunks.reduce((sum, c) => sum + (c.tokenCount ?? 0), 0) || newTokenCount;
|
|
4101
|
-
const endMarker =
|
|
4225
|
+
const endMarker = createBufferingEndMarker({
|
|
4102
4226
|
cycleId,
|
|
4103
4227
|
operationType: "observation",
|
|
4104
4228
|
startedAt,
|
|
@@ -4167,7 +4291,7 @@ ${bufferedObservations}`;
|
|
|
4167
4291
|
if (!freshChunks.length) {
|
|
4168
4292
|
return { success: false };
|
|
4169
4293
|
}
|
|
4170
|
-
const messageTokensThreshold =
|
|
4294
|
+
const messageTokensThreshold = getMaxThreshold(this.observationConfig.messageTokens);
|
|
4171
4295
|
let effectivePendingTokens = currentPendingTokens;
|
|
4172
4296
|
if (messageList) {
|
|
4173
4297
|
effectivePendingTokens = this.tokenCounter.countMessages(messageList.get.all.db());
|
|
@@ -4179,11 +4303,11 @@ ${bufferedObservations}`;
|
|
|
4179
4303
|
}
|
|
4180
4304
|
}
|
|
4181
4305
|
const bufferActivation = this.observationConfig.bufferActivation ?? 0.7;
|
|
4182
|
-
const activationRatio =
|
|
4306
|
+
const activationRatio = resolveActivationRatio(bufferActivation, messageTokensThreshold);
|
|
4183
4307
|
const forceMaxActivation = !!(this.observationConfig.blockAfter && effectivePendingTokens >= this.observationConfig.blockAfter);
|
|
4184
4308
|
const bufferTokens = this.observationConfig.bufferTokens ?? 0;
|
|
4185
|
-
const retentionFloor =
|
|
4186
|
-
const projectedMessageRemoval =
|
|
4309
|
+
const retentionFloor = resolveRetentionFloor(bufferActivation, messageTokensThreshold);
|
|
4310
|
+
const projectedMessageRemoval = calculateProjectedMessageRemoval(
|
|
4187
4311
|
freshChunks,
|
|
4188
4312
|
bufferActivation,
|
|
4189
4313
|
messageTokensThreshold,
|
|
@@ -4217,7 +4341,7 @@ ${bufferedObservations}`;
|
|
|
4217
4341
|
const perChunkMap = new Map(activationResult.perChunk?.map((c) => [c.cycleId, c]));
|
|
4218
4342
|
for (const cycleId of activationResult.activatedCycleIds) {
|
|
4219
4343
|
const chunkData = perChunkMap.get(cycleId);
|
|
4220
|
-
const activationMarker =
|
|
4344
|
+
const activationMarker = createActivationMarker({
|
|
4221
4345
|
cycleId,
|
|
4222
4346
|
// Use the original buffering cycleId so UI can link them
|
|
4223
4347
|
operationType: "observation",
|
|
@@ -4228,7 +4352,8 @@ ${bufferedObservations}`;
|
|
|
4228
4352
|
recordId: updatedRecord.id,
|
|
4229
4353
|
threadId: updatedRecord.threadId ?? record.threadId ?? "",
|
|
4230
4354
|
generationCount: updatedRecord.generationCount ?? 0,
|
|
4231
|
-
observations: chunkData?.observations ?? activationResult.observations
|
|
4355
|
+
observations: chunkData?.observations ?? activationResult.observations,
|
|
4356
|
+
config: this.getObservationMarkerConfig()
|
|
4232
4357
|
});
|
|
4233
4358
|
void writer.custom(activationMarker).catch(() => {
|
|
4234
4359
|
});
|
|
@@ -4270,7 +4395,7 @@ ${bufferedObservations}`;
|
|
|
4270
4395
|
});
|
|
4271
4396
|
const asyncOp = this.doAsyncBufferedReflection(record, bufferKey, writer, requestContext).catch(async (error) => {
|
|
4272
4397
|
if (writer) {
|
|
4273
|
-
const failedMarker =
|
|
4398
|
+
const failedMarker = createBufferingFailedMarker({
|
|
4274
4399
|
cycleId: `reflect-buf-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,
|
|
4275
4400
|
operationType: "reflection",
|
|
4276
4401
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -4301,7 +4426,7 @@ ${bufferedObservations}`;
|
|
|
4301
4426
|
const freshRecord = await this.storage.getObservationalMemory(record.threadId, record.resourceId);
|
|
4302
4427
|
const currentRecord = freshRecord ?? record;
|
|
4303
4428
|
const observationTokens = currentRecord.observationTokenCount ?? 0;
|
|
4304
|
-
const reflectThreshold =
|
|
4429
|
+
const reflectThreshold = getMaxThreshold(this.reflectionConfig.observationTokens);
|
|
4305
4430
|
const bufferActivation = this.reflectionConfig.bufferActivation ?? 0.5;
|
|
4306
4431
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4307
4432
|
const cycleId = `reflect-buf-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
@@ -4323,13 +4448,14 @@ ${bufferedObservations}`;
|
|
|
4323
4448
|
`[OM:reflect] doAsyncBufferedReflection: starting reflector call, recordId=${currentRecord.id}, observationTokens=${sliceTokenEstimate}, compressionTarget=${compressionTarget} (inputTokens), activeObsLength=${activeObservations.length}, reflectedLineCount=${reflectedObservationLineCount}`
|
|
4324
4449
|
);
|
|
4325
4450
|
if (writer) {
|
|
4326
|
-
const startMarker =
|
|
4451
|
+
const startMarker = createBufferingStartMarker({
|
|
4327
4452
|
cycleId,
|
|
4328
4453
|
operationType: "reflection",
|
|
4329
4454
|
tokensToBuffer: sliceTokenEstimate,
|
|
4330
4455
|
recordId: record.id,
|
|
4331
4456
|
threadId: record.threadId ?? "",
|
|
4332
|
-
threadIds: record.threadId ? [record.threadId] : []
|
|
4457
|
+
threadIds: record.threadId ? [record.threadId] : [],
|
|
4458
|
+
config: this.getObservationMarkerConfig()
|
|
4333
4459
|
});
|
|
4334
4460
|
void writer.custom(startMarker).catch(() => {
|
|
4335
4461
|
});
|
|
@@ -4364,7 +4490,7 @@ ${bufferedObservations}`;
|
|
|
4364
4490
|
`[OM:reflect] doAsyncBufferedReflection: bufferedReflection saved with lineCount=${reflectedObservationLineCount}`
|
|
4365
4491
|
);
|
|
4366
4492
|
if (writer) {
|
|
4367
|
-
const endMarker =
|
|
4493
|
+
const endMarker = createBufferingEndMarker({
|
|
4368
4494
|
cycleId,
|
|
4369
4495
|
operationType: "reflection",
|
|
4370
4496
|
startedAt,
|
|
@@ -4435,7 +4561,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
4435
4561
|
);
|
|
4436
4562
|
if (writer) {
|
|
4437
4563
|
const originalCycleId = _ObservationalMemory.reflectionBufferCycleIds.get(bufferKey);
|
|
4438
|
-
const activationMarker =
|
|
4564
|
+
const activationMarker = createActivationMarker({
|
|
4439
4565
|
cycleId: originalCycleId ?? `reflect-act-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`,
|
|
4440
4566
|
operationType: "reflection",
|
|
4441
4567
|
chunksActivated: 1,
|
|
@@ -4445,7 +4571,8 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
4445
4571
|
recordId: freshRecord.id,
|
|
4446
4572
|
threadId: freshRecord.threadId ?? "",
|
|
4447
4573
|
generationCount: afterRecord?.generationCount ?? freshRecord.generationCount ?? 0,
|
|
4448
|
-
observations: afterRecord?.activeObservations
|
|
4574
|
+
observations: afterRecord?.activeObservations,
|
|
4575
|
+
config: this.getObservationMarkerConfig()
|
|
4449
4576
|
});
|
|
4450
4577
|
void writer.custom(activationMarker).catch(() => {
|
|
4451
4578
|
});
|
|
@@ -4527,7 +4654,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
4527
4654
|
if (totalMessages === 0) {
|
|
4528
4655
|
return;
|
|
4529
4656
|
}
|
|
4530
|
-
const threshold =
|
|
4657
|
+
const threshold = getMaxThreshold(this.observationConfig.messageTokens);
|
|
4531
4658
|
const threadTokenCounts = /* @__PURE__ */ new Map();
|
|
4532
4659
|
for (const [threadId, msgs] of messagesByThread) {
|
|
4533
4660
|
let tokens = 0;
|
|
@@ -4593,13 +4720,14 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
4593
4720
|
const tokensToObserve = this.tokenCounter.countMessages(msgs);
|
|
4594
4721
|
threadTokensToObserve.set(threadId, tokensToObserve);
|
|
4595
4722
|
if (lastMessage?.id) {
|
|
4596
|
-
const startMarker =
|
|
4723
|
+
const startMarker = createObservationStartMarker({
|
|
4597
4724
|
cycleId,
|
|
4598
4725
|
operationType: "observation",
|
|
4599
4726
|
tokensToObserve,
|
|
4600
4727
|
recordId: record.id,
|
|
4601
4728
|
threadId,
|
|
4602
|
-
threadIds: allThreadIds
|
|
4729
|
+
threadIds: allThreadIds,
|
|
4730
|
+
config: this.getObservationMarkerConfig()
|
|
4603
4731
|
});
|
|
4604
4732
|
if (writer) {
|
|
4605
4733
|
await writer.custom(startMarker).catch(() => {
|
|
@@ -4725,7 +4853,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
4725
4853
|
const lastMessage = threadMessages[threadMessages.length - 1];
|
|
4726
4854
|
if (lastMessage?.id) {
|
|
4727
4855
|
const tokensObserved = threadTokensToObserve.get(threadId) ?? this.tokenCounter.countMessages(threadMessages);
|
|
4728
|
-
const endMarker =
|
|
4856
|
+
const endMarker = createObservationEndMarker({
|
|
4729
4857
|
cycleId,
|
|
4730
4858
|
operationType: "observation",
|
|
4731
4859
|
startedAt: observationStartedAt,
|
|
@@ -4757,7 +4885,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
4757
4885
|
const lastMessage = msgs[msgs.length - 1];
|
|
4758
4886
|
if (lastMessage?.id) {
|
|
4759
4887
|
const tokensAttempted = threadTokensToObserve.get(threadId) ?? 0;
|
|
4760
|
-
const failedMarker =
|
|
4888
|
+
const failedMarker = createObservationFailedMarker({
|
|
4761
4889
|
cycleId,
|
|
4762
4890
|
operationType: "observation",
|
|
4763
4891
|
startedAt: observationStartedAt,
|
|
@@ -4789,7 +4917,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
4789
4917
|
async maybeAsyncReflect(record, observationTokens, writer, messageList, requestContext) {
|
|
4790
4918
|
if (!this.isAsyncReflectionEnabled()) return;
|
|
4791
4919
|
const lockKey = this.getLockKey(record.threadId, record.resourceId);
|
|
4792
|
-
const reflectThreshold =
|
|
4920
|
+
const reflectThreshold = getMaxThreshold(this.reflectionConfig.observationTokens);
|
|
4793
4921
|
omDebug(
|
|
4794
4922
|
`[OM:reflect] maybeAsyncReflect: observationTokens=${observationTokens}, reflectThreshold=${reflectThreshold}, isReflecting=${record.isReflecting}, bufferedReflection=${record.bufferedReflection ? "present (" + record.bufferedReflection.length + " chars)" : "empty"}, recordId=${record.id}, genCount=${record.generationCount}`
|
|
4795
4923
|
);
|
|
@@ -4825,7 +4953,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
4825
4953
|
async maybeReflect(opts) {
|
|
4826
4954
|
const { record, observationTokens, writer, abortSignal, messageList, reflectionHooks, requestContext } = opts;
|
|
4827
4955
|
const lockKey = this.getLockKey(record.threadId, record.resourceId);
|
|
4828
|
-
const reflectThreshold =
|
|
4956
|
+
const reflectThreshold = getMaxThreshold(this.reflectionConfig.observationTokens);
|
|
4829
4957
|
if (this.isAsyncReflectionEnabled() && observationTokens < reflectThreshold) {
|
|
4830
4958
|
if (this.shouldTriggerAsyncReflection(observationTokens, lockKey, record)) {
|
|
4831
4959
|
this.startAsyncBufferedReflection(record, observationTokens, lockKey, writer, requestContext);
|
|
@@ -4866,13 +4994,14 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
4866
4994
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4867
4995
|
const threadId = opts.threadId ?? "unknown";
|
|
4868
4996
|
if (writer) {
|
|
4869
|
-
const startMarker =
|
|
4997
|
+
const startMarker = createObservationStartMarker({
|
|
4870
4998
|
cycleId,
|
|
4871
4999
|
operationType: "reflection",
|
|
4872
5000
|
tokensToObserve: observationTokens,
|
|
4873
5001
|
recordId: record.id,
|
|
4874
5002
|
threadId,
|
|
4875
|
-
threadIds: [threadId]
|
|
5003
|
+
threadIds: [threadId],
|
|
5004
|
+
config: this.getObservationMarkerConfig()
|
|
4876
5005
|
});
|
|
4877
5006
|
await writer.custom(startMarker).catch(() => {
|
|
4878
5007
|
});
|
|
@@ -4910,7 +5039,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
4910
5039
|
tokenCount: reflectionTokenCount
|
|
4911
5040
|
});
|
|
4912
5041
|
if (writer && streamContext) {
|
|
4913
|
-
const endMarker =
|
|
5042
|
+
const endMarker = createObservationEndMarker({
|
|
4914
5043
|
cycleId: streamContext.cycleId,
|
|
4915
5044
|
operationType: "reflection",
|
|
4916
5045
|
startedAt: streamContext.startedAt,
|
|
@@ -4935,7 +5064,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
4935
5064
|
});
|
|
4936
5065
|
} catch (error) {
|
|
4937
5066
|
if (writer && streamContext) {
|
|
4938
|
-
const failedMarker =
|
|
5067
|
+
const failedMarker = createObservationFailedMarker({
|
|
4939
5068
|
cycleId: streamContext.cycleId,
|
|
4940
5069
|
operationType: "reflection",
|
|
4941
5070
|
startedAt: streamContext.startedAt,
|
|
@@ -5040,7 +5169,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
5040
5169
|
await this.storage.setReflectingFlag(record.id, true);
|
|
5041
5170
|
registerOp(record.id, "reflecting");
|
|
5042
5171
|
try {
|
|
5043
|
-
const reflectThreshold =
|
|
5172
|
+
const reflectThreshold = getMaxThreshold(this.reflectionConfig.observationTokens);
|
|
5044
5173
|
const reflectResult = await this.callReflector(
|
|
5045
5174
|
record.activeObservations,
|
|
5046
5175
|
prompt,
|
|
@@ -5132,5 +5261,5 @@ exports.formatMessagesForObserver = formatMessagesForObserver;
|
|
|
5132
5261
|
exports.hasCurrentTaskSection = hasCurrentTaskSection;
|
|
5133
5262
|
exports.optimizeObservationsForContext = optimizeObservationsForContext;
|
|
5134
5263
|
exports.parseObserverOutput = parseObserverOutput;
|
|
5135
|
-
//# sourceMappingURL=chunk-
|
|
5136
|
-
//# sourceMappingURL=chunk-
|
|
5264
|
+
//# sourceMappingURL=chunk-D6II7EP4.cjs.map
|
|
5265
|
+
//# sourceMappingURL=chunk-D6II7EP4.cjs.map
|