blun-king-cli 9.1.76 → 9.1.77

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 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.69
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
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
@@ -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
@@ -75889,8 +75889,9 @@ var init_full = __esmMin((() => {
75889
75889
  }));
75890
75890
  //#endregion
75891
75891
  //#region ../../packages/agent-core/src/agent/compaction/micro.ts
75892
- var DEFAULT_CONFIG, MicroCompaction;
75892
+ var selectMicroCompactionCutoff, DEFAULT_CONFIG, MicroCompaction;
75893
75893
  var init_micro = __esmMin((() => {
75894
+ ({ selectMicroCompactionCutoff } = createRequire(import.meta.url)("./bin/micro-compaction-policy.cjs"));
75894
75895
  init_tokens();
75895
75896
  DEFAULT_CONFIG = {
75896
75897
  keepRecentMessages: 20,
@@ -75920,9 +75921,67 @@ var init_micro = __esmMin((() => {
75920
75921
  });
75921
75922
  this.cutoff = cutoff;
75922
75923
  }
75923
- detect() {}
75924
+ detect() {
75925
+ const config = this.config;
75926
+ const { history, lastAssistantAt } = this.agent.context;
75927
+ const maxContextTokens = this.agent.config.modelCapabilities.max_context_tokens;
75928
+ const contextTokens = this.agent.context.tokenCountWithPending;
75929
+ const selection = selectMicroCompactionCutoff({
75930
+ historyLength: history.length,
75931
+ currentCutoff: this.cutoff,
75932
+ keepRecentMessages: config.keepRecentMessages,
75933
+ contextTokens,
75934
+ maxContextTokens,
75935
+ lastAssistantAt,
75936
+ now: Date.now(),
75937
+ cacheMissedThresholdMs: config.cacheMissedThresholdMs,
75938
+ minContextUsageRatio: config.minContextUsageRatio
75939
+ });
75940
+ if (selection === null) return;
75941
+ const previousCutoff = this.cutoff;
75942
+ const effect = this.measureEffect(history, selection.cutoff);
75943
+ const previousEffect = this.measureEffect(history, previousCutoff);
75944
+ if (effect.truncatedToolResultCount <= previousEffect.truncatedToolResultCount) return;
75945
+ this.apply(selection.cutoff);
75946
+ const rawContextTokens = estimateTokensForMessages(history);
75947
+ const tokensBefore = rawContextTokens - previousEffect.truncatedToolResultTokensBefore + previousEffect.truncatedToolResultTokensAfter;
75948
+ const tokensAfter = rawContextTokens - effect.truncatedToolResultTokensBefore + effect.truncatedToolResultTokensAfter;
75949
+ this.agent.telemetry.track("micro_compaction_finished", {
75950
+ trigger: selection.trigger,
75951
+ keep_recent_messages: config.keepRecentMessages,
75952
+ min_content_tokens: config.minContentTokens,
75953
+ cache_missed_threshold_ms: config.cacheMissedThresholdMs,
75954
+ truncated_marker: config.truncatedMarker,
75955
+ min_context_usage_ratio: config.minContextUsageRatio,
75956
+ context_usage_ratio: selection.contextUsageRatio,
75957
+ truncated_tool_result_count: effect.truncatedToolResultCount,
75958
+ truncated_tool_result_tokens_before: effect.truncatedToolResultTokensBefore,
75959
+ truncated_tool_result_tokens_after: effect.truncatedToolResultTokensAfter,
75960
+ tokens_before: tokensBefore,
75961
+ tokens_after: tokensAfter,
75962
+ previous_cutoff: previousCutoff,
75963
+ cutoff: selection.cutoff,
75964
+ message_count: history.length,
75965
+ cache_age_ms: selection.cacheAgeMs,
75966
+ thinking_effort: this.agent.config.thinkingEffort
75967
+ });
75968
+ }
75924
75969
  compact(messages) {
75925
- return messages;
75970
+ const config = this.config;
75971
+ const result = [];
75972
+ let i = 0;
75973
+ for (const msg of messages) {
75974
+ if (i < this.cutoff && msg.role === "tool" && msg.toolCallId !== void 0 && estimateTokensForContentParts(msg.content) >= config.minContentTokens) result.push({
75975
+ ...msg,
75976
+ content: [{
75977
+ type: "text",
75978
+ text: config.truncatedMarker
75979
+ }]
75980
+ });
75981
+ else result.push(msg);
75982
+ i++;
75983
+ }
75984
+ return result;
75926
75985
  }
75927
75986
  measureEffect(messages, cutoff) {
75928
75987
  let markerTokenCount;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.76",
3
+ "version": "9.1.77",
4
4
  "description": "BLUN CLI - your own AI agent with a Telegram channel. Get it done. With BLUN.",
5
5
  "license": "MIT",
6
6
  "bin": {