blun-king-cli 9.1.77 → 9.1.79

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
@@ -213,6 +213,28 @@ sodass auch kurze Schritte wie Rendern und Speichern in der Produktionskette
213
213
  sichtbar sind. Aktualisierte Vorschaubilder werden erneuert; Medienpfade und
214
214
  Webadressen sind als Terminalverweise anklickbar.
215
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
+
231
+ Dauerhafte Checkpoints zwischen Arbeitsschritten
232
+ -------------------------------------------------
233
+
234
+ Bevor King den nächsten Modellschritt beginnt, schreibt er alle vorangegangenen Wire-Einträge dauerhaft auf den Datenträger. Nach dem Ende eines Zuges erfolgt eine weitere vollständige Sicherung, bevor der zugehörige Worker abgeschlossen wird. Das schließt beendete Modell- und Werkzeugschritte ein. Eine fortgesetzte Sitzung beginnt dadurch beim letzten abgeschlossenen Schritt und ist nicht auf noch ungesicherte Einträge im Arbeitsspeicher angewiesen.
235
+
236
+ Beispiel: Wenn der Anbieter oder das Terminal nach einem abgeschlossenen Werkzeugaufruf, aber vor der nächsten Modellantwort ausfällt, kann die Sitzung neu gestartet oder fortgesetzt werden. Der vorangegangene Werkzeugeintrag wurde vor der nächsten Anfrage an den Anbieter in wire.jsonl synchronisiert und wird beim Fortsetzen wieder eingelesen. Der Checkpoint verkürzt keine Prompts und ersetzt nicht die wiederauffindbaren Verdichtungsarchive; er schützt die Übergabe zwischen zwei Arbeitsschritten.
237
+
216
238
  Aktualisieren
217
239
  -------------
218
240
 
package/README.md CHANGED
@@ -240,6 +240,18 @@ sodass auch kurze Schritte wie Rendern und Speichern in der Produktionskette
240
240
  sichtbar sind. Aktualisierte Vorschaubilder werden erneuert; Medienpfade und
241
241
  Webadressen sind als Terminalverweise anklickbar.
242
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
+
249
+ ## Dauerhafte Checkpoints zwischen Arbeitsschritten
250
+
251
+ Bevor King den nächsten Modellschritt beginnt, schreibt er alle vorangegangenen Wire-Einträge dauerhaft auf den Datenträger. Nach dem Ende eines Zuges erfolgt eine weitere vollständige Sicherung, bevor der zugehörige Worker abgeschlossen wird. Das schließt beendete Modell- und Werkzeugschritte ein. Eine fortgesetzte Sitzung beginnt dadurch beim letzten abgeschlossenen Schritt und ist nicht auf noch ungesicherte Einträge im Arbeitsspeicher angewiesen.
252
+
253
+ Beispiel: Wenn der Anbieter oder das Terminal nach einem abgeschlossenen Werkzeugaufruf, aber vor der nächsten Modellantwort ausfällt, kann die Sitzung neu gestartet oder fortgesetzt werden. Der vorangegangene Werkzeugeintrag wurde vor der nächsten Anfrage an den Anbieter in `wire.jsonl` synchronisiert und wird beim Fortsetzen wieder eingelesen. Der Checkpoint verkürzt keine Prompts und ersetzt nicht die wiederauffindbaren Verdichtungsarchive; er schützt die Übergabe zwischen zwei Arbeitsschritten.
254
+
243
255
  ## Aktualisieren
244
256
 
245
257
  `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
+ };
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
- const contextSummary = buildCompactionSummaryText(rawSummary);
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,
@@ -260766,6 +260784,7 @@ var init_turn = __esmMin((() => {
260766
260784
  this.currentStepByTurn.delete(turnId);
260767
260785
  this.interruptedTelemetryTurnIds.delete(turnId);
260768
260786
  this.stepFailureByTurn.delete(turnId);
260787
+ await this.agent.records.flush();
260769
260788
  return {
260770
260789
  event: ended,
260771
260790
  stopReason: completedStopReason,
@@ -260898,6 +260917,7 @@ var init_turn = __esmMin((() => {
260898
260917
  },
260899
260918
  hooks: {
260900
260919
  beforeStep: async ({ signal: stepSignal, stepNumber }) => {
260920
+ await this.agent.records.flush();
260901
260921
  this.agent.microCompaction.detect();
260902
260922
  await this.agent.injection.inject();
260903
260923
  stepSignal.throwIfAborted();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.77",
3
+ "version": "9.1.79",
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": {