blun-king-cli 9.1.76 → 9.1.78
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/LIESMICH.txt +30 -1
- package/README.md +20 -0
- package/bin/compaction-history-archive.cjs +112 -0
- package/bin/micro-compaction-policy.cjs +75 -0
- package/blun.mjs +82 -5
- package/package.json +1 -1
package/LIESMICH.txt
CHANGED
|
@@ -9,7 +9,7 @@ Installation
|
|
|
9
9
|
------------
|
|
10
10
|
Die geprüfte Version exakt global installieren:
|
|
11
11
|
|
|
12
|
-
npm install -g blun-king-cli@9.1.
|
|
12
|
+
npm install -g blun-king-cli@9.1.77
|
|
13
13
|
|
|
14
14
|
Start
|
|
15
15
|
-----
|
|
@@ -72,6 +72,20 @@ parallel geprüft und eingelesen. Die Skills werden weiterhin in der
|
|
|
72
72
|
ursprünglichen, festen Reihenfolge registriert; Priorität und Verhalten bei
|
|
73
73
|
doppelten Namen bleiben unverändert.
|
|
74
74
|
|
|
75
|
+
Kontextentlastung bei langen Sitzungen
|
|
76
|
+
--------------------------------------
|
|
77
|
+
King bewahrt den vollständigen Verlauf weiterhin im Sitzungs-Wire auf. Erreicht
|
|
78
|
+
der aktive Verlauf 75 Prozent des Modellfensters, ersetzt die Modellprojektion
|
|
79
|
+
ältere große Werkzeugergebnisse durch einen kurzen Platzhalter. Die letzten 20
|
|
80
|
+
Nachrichten bleiben unverändert. Solange der Prefix-Cache warm ist, wird der
|
|
81
|
+
Schnitt höchstens nach jeweils 20 weiteren Nachrichten verschoben. Nach einer
|
|
82
|
+
Stunde ohne Modellantwort darf er sofort nachziehen.
|
|
83
|
+
|
|
84
|
+
Dabei werden keine gespeicherten Nachrichten geändert oder gelöscht. Fortsetzen,
|
|
85
|
+
Exportieren und die sichtbare Historie behalten die ursprünglichen
|
|
86
|
+
Werkzeugergebnisse. Das Telemetrieereignis `micro_compaction_finished` nennt den
|
|
87
|
+
Auslöser, den Schnitt und die geschätzte Tokenzahl vor und nach der Entlastung.
|
|
88
|
+
|
|
75
89
|
Zug-Wächter
|
|
76
90
|
-----------
|
|
77
91
|
Läuft ein Zug 20 Minuten ohne neues Werkzeugergebnis, meldet die Konsole den
|
|
@@ -199,6 +213,21 @@ sodass auch kurze Schritte wie Rendern und Speichern in der Produktionskette
|
|
|
199
213
|
sichtbar sind. Aktualisierte Vorschaubilder werden erneuert; Medienpfade und
|
|
200
214
|
Webadressen sind als Terminalverweise anklickbar.
|
|
201
215
|
|
|
216
|
+
Wiederauffindbarer Verdichtungsverlauf
|
|
217
|
+
--------------------------------------
|
|
218
|
+
|
|
219
|
+
Bevor eine erfolgreiche Vollverdichtung ältere Nachrichten ersetzt, schreibt
|
|
220
|
+
King den verdrängten Verlauf in ein privates Markdown-Archiv unter
|
|
221
|
+
~/.blun/conversation-history/. Die Verdichtungszusammenfassung enthält den
|
|
222
|
+
genauen history_path, sodass der Agent mit Read Einzelheiten wiederfinden kann,
|
|
223
|
+
die nicht in der Zusammenfassung stehen.
|
|
224
|
+
|
|
225
|
+
Eingebettete Bild-, Audio- und Videodaten werden im Archiv nicht doppelt
|
|
226
|
+
gespeichert. Der ursprüngliche Sitzungs-Wire bleibt maßgeblich. Kann das Archiv
|
|
227
|
+
nicht geschrieben werden, protokolliert King compaction_history_archive_failed
|
|
228
|
+
und lässt den normalen Verdichtungsweg verfügbar; ein Archivfehler löscht
|
|
229
|
+
niemals den gespeicherten Sitzungsverlauf.
|
|
230
|
+
|
|
202
231
|
Aktualisieren
|
|
203
232
|
-------------
|
|
204
233
|
|
package/README.md
CHANGED
|
@@ -94,6 +94,20 @@ parallel geprüft und eingelesen. Die Skills werden weiterhin in der
|
|
|
94
94
|
ursprünglichen, festen Reihenfolge registriert; Priorität und Verhalten bei
|
|
95
95
|
doppelten Namen bleiben unverändert.
|
|
96
96
|
|
|
97
|
+
## Kontextentlastung bei langen Sitzungen
|
|
98
|
+
|
|
99
|
+
King bewahrt den vollständigen Verlauf weiterhin im Sitzungs-Wire auf. Erreicht
|
|
100
|
+
der aktive Verlauf 75 Prozent des Modellfensters, ersetzt die Modellprojektion
|
|
101
|
+
ältere große Werkzeugergebnisse durch einen kurzen Platzhalter. Die letzten 20
|
|
102
|
+
Nachrichten bleiben unverändert. Solange der Prefix-Cache warm ist, wird der
|
|
103
|
+
Schnitt höchstens nach jeweils 20 weiteren Nachrichten verschoben. Nach einer
|
|
104
|
+
Stunde ohne Modellantwort darf er sofort nachziehen.
|
|
105
|
+
|
|
106
|
+
Dabei werden keine gespeicherten Nachrichten geändert oder gelöscht. Fortsetzen,
|
|
107
|
+
Exportieren und die sichtbare Historie behalten die ursprünglichen
|
|
108
|
+
Werkzeugergebnisse. Das Telemetrieereignis `micro_compaction_finished` nennt den
|
|
109
|
+
Auslöser, den Schnitt und die geschätzte Tokenzahl vor und nach der Entlastung.
|
|
110
|
+
|
|
97
111
|
## Zug-Wächter
|
|
98
112
|
|
|
99
113
|
Läuft ein Zug 20 Minuten ohne neues Werkzeugergebnis, meldet die Konsole den
|
|
@@ -226,6 +240,12 @@ sodass auch kurze Schritte wie Rendern und Speichern in der Produktionskette
|
|
|
226
240
|
sichtbar sind. Aktualisierte Vorschaubilder werden erneuert; Medienpfade und
|
|
227
241
|
Webadressen sind als Terminalverweise anklickbar.
|
|
228
242
|
|
|
243
|
+
## Wiederauffindbarer Verdichtungsverlauf
|
|
244
|
+
|
|
245
|
+
Bevor eine erfolgreiche Vollverdichtung ältere Nachrichten ersetzt, schreibt King den verdrängten Verlauf in ein privates Markdown-Archiv unter `~/.blun/conversation-history/`. Die Verdichtungszusammenfassung enthält den genauen `history_path`, sodass der Agent mit `Read` Einzelheiten wiederfinden kann, die nicht in der Zusammenfassung stehen.
|
|
246
|
+
|
|
247
|
+
Eingebettete Bild-, Audio- und Videodaten werden im Archiv nicht doppelt gespeichert. Der ursprüngliche Sitzungs-Wire bleibt maßgeblich. Kann das Archiv nicht geschrieben werden, protokolliert King `compaction_history_archive_failed` und lässt den normalen Verdichtungsweg verfügbar; ein Archivfehler löscht niemals den gespeicherten Sitzungsverlauf.
|
|
248
|
+
|
|
229
249
|
## Aktualisieren
|
|
230
250
|
|
|
231
251
|
`blun update`, `king update` und die jeweilige Variante `upgrade` verwenden
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { randomUUID } = require('node:crypto');
|
|
4
|
+
const { mkdir, writeFile } = require('node:fs/promises');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
const COMPACTION_HISTORY_DIR = 'conversation-history';
|
|
8
|
+
const INLINE_MEDIA_NOTICE = '[inline media payload omitted; original remains in session wire]';
|
|
9
|
+
|
|
10
|
+
async function archiveCompactionHistory(options = {}) {
|
|
11
|
+
const homedir = requiredString(options.homedir, 'homedir');
|
|
12
|
+
const messages = Array.isArray(options.messages) ? options.messages : [];
|
|
13
|
+
const now = finiteNumber(options.now, Date.now());
|
|
14
|
+
const id = safeFilePart(options.id || randomUUID());
|
|
15
|
+
const dir = path.join(homedir, COMPACTION_HISTORY_DIR);
|
|
16
|
+
const timestamp = new Date(now).toISOString().replace(/[:.]/g, '-');
|
|
17
|
+
const outputPath = path.join(dir, `compaction-${timestamp}-${id}.md`);
|
|
18
|
+
|
|
19
|
+
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
20
|
+
await writeFile(outputPath, serializeCompactionHistory(messages, { now }), {
|
|
21
|
+
encoding: 'utf8',
|
|
22
|
+
flag: 'wx',
|
|
23
|
+
mode: 0o600,
|
|
24
|
+
});
|
|
25
|
+
return outputPath;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function serializeCompactionHistory(messages, options = {}) {
|
|
29
|
+
const now = finiteNumber(options.now, Date.now());
|
|
30
|
+
const lines = [
|
|
31
|
+
'# BLUN conversation history archive',
|
|
32
|
+
'',
|
|
33
|
+
`Archived at: ${new Date(now).toISOString()}`,
|
|
34
|
+
`Messages: ${messages.length}`,
|
|
35
|
+
'',
|
|
36
|
+
'This file contains the messages displaced by a full context compaction.',
|
|
37
|
+
'Inline media payloads are omitted here; the original session wire remains authoritative.',
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
for (let index = 0; index < messages.length; index += 1) {
|
|
41
|
+
const message = sanitizeMessage(messages[index]);
|
|
42
|
+
lines.push(
|
|
43
|
+
'',
|
|
44
|
+
`## Message ${index + 1}: ${typeof message?.role === 'string' ? message.role : 'unknown'}`,
|
|
45
|
+
'',
|
|
46
|
+
'```json',
|
|
47
|
+
JSON.stringify(message, null, 2),
|
|
48
|
+
'```',
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
lines.push('');
|
|
52
|
+
return lines.join('\n');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function buildCompactionArchiveNotice(historyPath) {
|
|
56
|
+
return [
|
|
57
|
+
'<system-reminder>',
|
|
58
|
+
'The complete messages displaced by this compaction were archived locally.',
|
|
59
|
+
`history_path: ${historyPath}`,
|
|
60
|
+
'next_step: Use Read with history_path to recover exact details that the summary omitted.',
|
|
61
|
+
'</system-reminder>',
|
|
62
|
+
].join('\n');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function sanitizeMessage(message) {
|
|
66
|
+
if (message === null || typeof message !== 'object') return message;
|
|
67
|
+
if (!Array.isArray(message.content)) return message;
|
|
68
|
+
return {
|
|
69
|
+
...message,
|
|
70
|
+
content: message.content.map(sanitizeContentPart),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function sanitizeContentPart(part) {
|
|
75
|
+
if (part === null || typeof part !== 'object') return part;
|
|
76
|
+
if (part.type === 'image_url' && isInlineMediaUrl(part.imageUrl?.url)) {
|
|
77
|
+
return { type: 'text', text: INLINE_MEDIA_NOTICE };
|
|
78
|
+
}
|
|
79
|
+
if (part.type === 'audio_url' && isInlineMediaUrl(part.audioUrl?.url)) {
|
|
80
|
+
return { type: 'text', text: INLINE_MEDIA_NOTICE };
|
|
81
|
+
}
|
|
82
|
+
if (part.type === 'video_url' && isInlineMediaUrl(part.videoUrl?.url)) {
|
|
83
|
+
return { type: 'text', text: INLINE_MEDIA_NOTICE };
|
|
84
|
+
}
|
|
85
|
+
return part;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function isInlineMediaUrl(value) {
|
|
89
|
+
return typeof value === 'string' && /^data:(?:image|audio|video)\//i.test(value);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function requiredString(value, name) {
|
|
93
|
+
if (typeof value === 'string' && value.length > 0) return value;
|
|
94
|
+
throw new TypeError(`${name} must be a non-empty string`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function safeFilePart(value) {
|
|
98
|
+
const cleaned = String(value).replace(/[^a-zA-Z0-9._-]+/g, '_').replace(/^_+|_+$/g, '').slice(0, 96);
|
|
99
|
+
return cleaned || randomUUID();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function finiteNumber(value, fallback) {
|
|
103
|
+
const number = Number(value);
|
|
104
|
+
return Number.isFinite(number) ? number : fallback;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
module.exports = {
|
|
108
|
+
COMPACTION_HISTORY_DIR,
|
|
109
|
+
archiveCompactionHistory,
|
|
110
|
+
buildCompactionArchiveNotice,
|
|
111
|
+
serializeCompactionHistory,
|
|
112
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MICRO_COMPACTION_PRESSURE_RATIO = 0.75;
|
|
4
|
+
const MICRO_COMPACTION_MIN_ADVANCE_MESSAGES = 20;
|
|
5
|
+
|
|
6
|
+
function selectMicroCompactionCutoff(options = {}) {
|
|
7
|
+
const historyLength = nonNegativeInteger(options.historyLength);
|
|
8
|
+
const currentCutoff = nonNegativeInteger(options.currentCutoff);
|
|
9
|
+
const keepRecentMessages = nonNegativeInteger(options.keepRecentMessages);
|
|
10
|
+
const nextCutoff = Math.max(0, historyLength - keepRecentMessages);
|
|
11
|
+
if (nextCutoff <= currentCutoff) return null;
|
|
12
|
+
|
|
13
|
+
const maxContextTokens = positiveFinite(options.maxContextTokens);
|
|
14
|
+
const contextTokens = nonNegativeFinite(options.contextTokens);
|
|
15
|
+
const contextUsageRatio = maxContextTokens === null
|
|
16
|
+
? 1
|
|
17
|
+
: contextTokens / maxContextTokens;
|
|
18
|
+
const minContextUsageRatio = nonNegativeFinite(options.minContextUsageRatio);
|
|
19
|
+
if (contextUsageRatio < minContextUsageRatio) return null;
|
|
20
|
+
|
|
21
|
+
const now = finiteOr(options.now, Date.now());
|
|
22
|
+
const lastAssistantAt = finiteOrNull(options.lastAssistantAt);
|
|
23
|
+
const cacheAgeMs = lastAssistantAt === null ? null : Math.max(0, now - lastAssistantAt);
|
|
24
|
+
const cacheMissedThresholdMs = nonNegativeFinite(options.cacheMissedThresholdMs);
|
|
25
|
+
const cacheMissed = cacheAgeMs !== null && cacheAgeMs >= cacheMissedThresholdMs;
|
|
26
|
+
const underContextPressure = maxContextTokens !== null
|
|
27
|
+
&& contextUsageRatio >= MICRO_COMPACTION_PRESSURE_RATIO;
|
|
28
|
+
if (!cacheMissed && !underContextPressure) return null;
|
|
29
|
+
|
|
30
|
+
if (
|
|
31
|
+
!cacheMissed
|
|
32
|
+
&& currentCutoff > 0
|
|
33
|
+
&& nextCutoff - currentCutoff < MICRO_COMPACTION_MIN_ADVANCE_MESSAGES
|
|
34
|
+
) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
cacheAgeMs,
|
|
40
|
+
contextUsageRatio,
|
|
41
|
+
cutoff: nextCutoff,
|
|
42
|
+
trigger: cacheMissed ? 'cache_miss' : 'context_pressure',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function finiteOr(value, fallback) {
|
|
47
|
+
const number = Number(value);
|
|
48
|
+
return Number.isFinite(number) ? number : fallback;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function finiteOrNull(value) {
|
|
52
|
+
if (value === null || value === undefined) return null;
|
|
53
|
+
const number = Number(value);
|
|
54
|
+
return Number.isFinite(number) ? number : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function nonNegativeFinite(value) {
|
|
58
|
+
const number = Number(value);
|
|
59
|
+
return Number.isFinite(number) && number >= 0 ? number : 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function nonNegativeInteger(value) {
|
|
63
|
+
return Math.floor(nonNegativeFinite(value));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function positiveFinite(value) {
|
|
67
|
+
const number = Number(value);
|
|
68
|
+
return Number.isFinite(number) && number > 0 ? number : null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = {
|
|
72
|
+
MICRO_COMPACTION_MIN_ADVANCE_MESSAGES,
|
|
73
|
+
MICRO_COMPACTION_PRESSURE_RATIO,
|
|
74
|
+
selectMicroCompactionCutoff,
|
|
75
|
+
};
|
package/blun.mjs
CHANGED
|
@@ -75237,8 +75237,9 @@ function extractCompactionSummary(response) {
|
|
|
75237
75237
|
if (summary.trim().length === 0) throw new APIEmptyResponseError("The compaction response did not contain a non-empty summary.");
|
|
75238
75238
|
return summary;
|
|
75239
75239
|
}
|
|
75240
|
-
var DEFAULT_COMPACTION_MAX_COMPLETION_TOKENS, COMPACTION_THINKING_EFFORT, COMPACTION_SUMMARY_RESERVE_RATIO, MAX_HIERARCHICAL_COMPACTION_PASSES, HIERARCHICAL_COMPACTION_PREFIX, CompactionTruncatedError, CompactionStallError, COMPACTION_STALL_MEASUREMENT_MULTIPLIER, REBUILT_AFTER_COMPACTION_INJECTION_VARIANTS, FullCompaction, MAX_COMPACTION_OVERFLOW_SHRINK_ATTEMPTS, COMPACTION_OVERFLOW_SHRINK_RATIOS;
|
|
75240
|
+
var archiveCompactionHistory, buildCompactionArchiveNotice, DEFAULT_COMPACTION_MAX_COMPLETION_TOKENS, COMPACTION_THINKING_EFFORT, COMPACTION_SUMMARY_RESERVE_RATIO, MAX_HIERARCHICAL_COMPACTION_PASSES, HIERARCHICAL_COMPACTION_PREFIX, CompactionTruncatedError, CompactionStallError, COMPACTION_STALL_MEASUREMENT_MULTIPLIER, REBUILT_AFTER_COMPACTION_INJECTION_VARIANTS, FullCompaction, MAX_COMPACTION_OVERFLOW_SHRINK_ATTEMPTS, COMPACTION_OVERFLOW_SHRINK_RATIOS;
|
|
75241
75241
|
var init_full = __esmMin((() => {
|
|
75242
|
+
({ archiveCompactionHistory, buildCompactionArchiveNotice } = createRequire(import.meta.url)("./bin/compaction-history-archive.cjs"));
|
|
75242
75243
|
init_errors$8();
|
|
75243
75244
|
init_src$4();
|
|
75244
75245
|
init_errors$4();
|
|
@@ -75773,7 +75774,24 @@ var init_full = __esmMin((() => {
|
|
|
75773
75774
|
return;
|
|
75774
75775
|
}
|
|
75775
75776
|
const rawSummary = this.postProcessSummary(summary ?? "");
|
|
75776
|
-
|
|
75777
|
+
let contextSummary = buildCompactionSummaryText(rawSummary);
|
|
75778
|
+
let historyPath;
|
|
75779
|
+
try {
|
|
75780
|
+
historyPath = await archiveCompactionHistory({
|
|
75781
|
+
homedir: this.agent.blunHomeDir,
|
|
75782
|
+
messages: originalHistory
|
|
75783
|
+
});
|
|
75784
|
+
contextSummary = `${contextSummary}\n\n${buildCompactionArchiveNotice(historyPath)}`;
|
|
75785
|
+
this.agent.telemetry.track("compaction_history_archived", {
|
|
75786
|
+
history_path: historyPath,
|
|
75787
|
+
message_count: originalHistory.length
|
|
75788
|
+
});
|
|
75789
|
+
} catch (error) {
|
|
75790
|
+
this.agent.telemetry.track("compaction_history_archive_failed", {
|
|
75791
|
+
message_count: originalHistory.length,
|
|
75792
|
+
error_type: error instanceof Error ? error.name : "Unknown"
|
|
75793
|
+
});
|
|
75794
|
+
}
|
|
75777
75795
|
const result = this.agent.context.applyCompaction({
|
|
75778
75796
|
summary: rawSummary,
|
|
75779
75797
|
contextSummary,
|
|
@@ -75889,8 +75907,9 @@ var init_full = __esmMin((() => {
|
|
|
75889
75907
|
}));
|
|
75890
75908
|
//#endregion
|
|
75891
75909
|
//#region ../../packages/agent-core/src/agent/compaction/micro.ts
|
|
75892
|
-
var DEFAULT_CONFIG, MicroCompaction;
|
|
75910
|
+
var selectMicroCompactionCutoff, DEFAULT_CONFIG, MicroCompaction;
|
|
75893
75911
|
var init_micro = __esmMin((() => {
|
|
75912
|
+
({ selectMicroCompactionCutoff } = createRequire(import.meta.url)("./bin/micro-compaction-policy.cjs"));
|
|
75894
75913
|
init_tokens();
|
|
75895
75914
|
DEFAULT_CONFIG = {
|
|
75896
75915
|
keepRecentMessages: 20,
|
|
@@ -75920,9 +75939,67 @@ var init_micro = __esmMin((() => {
|
|
|
75920
75939
|
});
|
|
75921
75940
|
this.cutoff = cutoff;
|
|
75922
75941
|
}
|
|
75923
|
-
detect() {
|
|
75942
|
+
detect() {
|
|
75943
|
+
const config = this.config;
|
|
75944
|
+
const { history, lastAssistantAt } = this.agent.context;
|
|
75945
|
+
const maxContextTokens = this.agent.config.modelCapabilities.max_context_tokens;
|
|
75946
|
+
const contextTokens = this.agent.context.tokenCountWithPending;
|
|
75947
|
+
const selection = selectMicroCompactionCutoff({
|
|
75948
|
+
historyLength: history.length,
|
|
75949
|
+
currentCutoff: this.cutoff,
|
|
75950
|
+
keepRecentMessages: config.keepRecentMessages,
|
|
75951
|
+
contextTokens,
|
|
75952
|
+
maxContextTokens,
|
|
75953
|
+
lastAssistantAt,
|
|
75954
|
+
now: Date.now(),
|
|
75955
|
+
cacheMissedThresholdMs: config.cacheMissedThresholdMs,
|
|
75956
|
+
minContextUsageRatio: config.minContextUsageRatio
|
|
75957
|
+
});
|
|
75958
|
+
if (selection === null) return;
|
|
75959
|
+
const previousCutoff = this.cutoff;
|
|
75960
|
+
const effect = this.measureEffect(history, selection.cutoff);
|
|
75961
|
+
const previousEffect = this.measureEffect(history, previousCutoff);
|
|
75962
|
+
if (effect.truncatedToolResultCount <= previousEffect.truncatedToolResultCount) return;
|
|
75963
|
+
this.apply(selection.cutoff);
|
|
75964
|
+
const rawContextTokens = estimateTokensForMessages(history);
|
|
75965
|
+
const tokensBefore = rawContextTokens - previousEffect.truncatedToolResultTokensBefore + previousEffect.truncatedToolResultTokensAfter;
|
|
75966
|
+
const tokensAfter = rawContextTokens - effect.truncatedToolResultTokensBefore + effect.truncatedToolResultTokensAfter;
|
|
75967
|
+
this.agent.telemetry.track("micro_compaction_finished", {
|
|
75968
|
+
trigger: selection.trigger,
|
|
75969
|
+
keep_recent_messages: config.keepRecentMessages,
|
|
75970
|
+
min_content_tokens: config.minContentTokens,
|
|
75971
|
+
cache_missed_threshold_ms: config.cacheMissedThresholdMs,
|
|
75972
|
+
truncated_marker: config.truncatedMarker,
|
|
75973
|
+
min_context_usage_ratio: config.minContextUsageRatio,
|
|
75974
|
+
context_usage_ratio: selection.contextUsageRatio,
|
|
75975
|
+
truncated_tool_result_count: effect.truncatedToolResultCount,
|
|
75976
|
+
truncated_tool_result_tokens_before: effect.truncatedToolResultTokensBefore,
|
|
75977
|
+
truncated_tool_result_tokens_after: effect.truncatedToolResultTokensAfter,
|
|
75978
|
+
tokens_before: tokensBefore,
|
|
75979
|
+
tokens_after: tokensAfter,
|
|
75980
|
+
previous_cutoff: previousCutoff,
|
|
75981
|
+
cutoff: selection.cutoff,
|
|
75982
|
+
message_count: history.length,
|
|
75983
|
+
cache_age_ms: selection.cacheAgeMs,
|
|
75984
|
+
thinking_effort: this.agent.config.thinkingEffort
|
|
75985
|
+
});
|
|
75986
|
+
}
|
|
75924
75987
|
compact(messages) {
|
|
75925
|
-
|
|
75988
|
+
const config = this.config;
|
|
75989
|
+
const result = [];
|
|
75990
|
+
let i = 0;
|
|
75991
|
+
for (const msg of messages) {
|
|
75992
|
+
if (i < this.cutoff && msg.role === "tool" && msg.toolCallId !== void 0 && estimateTokensForContentParts(msg.content) >= config.minContentTokens) result.push({
|
|
75993
|
+
...msg,
|
|
75994
|
+
content: [{
|
|
75995
|
+
type: "text",
|
|
75996
|
+
text: config.truncatedMarker
|
|
75997
|
+
}]
|
|
75998
|
+
});
|
|
75999
|
+
else result.push(msg);
|
|
76000
|
+
i++;
|
|
76001
|
+
}
|
|
76002
|
+
return result;
|
|
75926
76003
|
}
|
|
75927
76004
|
measureEffect(messages, cutoff) {
|
|
75928
76005
|
let markerTokenCount;
|