blun-king-cli 9.1.498 → 9.1.499

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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 9.1.499 - 2026-08-30
4
+
5
+ - Replaces image, audio, and video payloads older than the newest twelve conversation messages with short model-facing references while preserving the complete original session wire and every recent media attachment.
6
+ - Reduces Fredrik's measured repeated model input by 85,748 characters, approximately 21,437 estimated tokens per subsequent work step, without changing the current image, message text, or persisted history.
7
+ - Runs overdue TodoList maintenance as its own low-effort model step before the ninth work batch and exposes only TodoList during that step, preventing the normal workflow from hitting a visible red policy error first.
8
+ - Keeps fresh user steers ahead of TodoList housekeeping while preserving the hard policy gate as a fallback for an actually invalid update.
9
+
3
10
  ## 9.1.498 - 2026-08-30
4
11
 
5
12
  - Shows prompt-cache hit rate plus cache-read and cache-write tokens per model in `/usage`.
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.498
12
+ npm install -g blun-king-cli@9.1.499
13
13
 
14
14
  Start
15
15
  -----
@@ -65,6 +65,19 @@ geschriebenen Entwurf zu löschen. Das gilt auch bei
65
65
  Autovervollständigung, Geistervorschlägen, Bash-Eingabe und einer offenen
66
66
  Mehrzeileneingabe.
67
67
 
68
+ Version 9.1.499 ersetzt Bild-, Audio- und Videodaten ausserhalb der neuesten zwoelf
69
+ Gespraechsnachrichten ausschliesslich in der wiederholten Modellprojektion durch
70
+ kurze Verweise. Aktuelle Medien, Nachrichtentext und vollstaendiger Sitzungsrohverlauf
71
+ bleiben unveraendert. In Fredriks gemessenem Wiederaufnahme-Checkpoint spart der
72
+ Schnitt 85.748 Zeichen beziehungsweise rund 21.437 geschaetzte Eingabetoken je
73
+ weiterem Werkzeugschritt.
74
+
75
+ Faellige Todo-Pflege laeuft in 9.1.499 vor dem naechsten Sachwerkzeug als eigener
76
+ kleiner Modellschritt. In diesem Schritt bietet die Laufzeit ausschliesslich
77
+ TodoList an; erst nach einer gueltigen Aktualisierung werden Datei-, Such- und
78
+ Shell-Werkzeuge wieder freigegeben. Dadurch entsteht im normalen Ablauf kein
79
+ roter Zwischenfehler. Frische Benutzernachrichten behalten Vorrang.
80
+
68
81
  Version 9.1.498 zeigt in /usage die gemessene Prompt-Cache-Trefferquote sowie
69
82
  gelesene und geschriebene Cache-Token je Modell. /tokens ist ein kurzer Alias
70
83
  fuer die bereits vorhandene detaillierte Kontextdiagnose; /offload ruft die
package/README.md CHANGED
@@ -9,7 +9,7 @@ Voraussetzung ist Node.js 24.15 oder neuer. Die geprüfte Version wird exakt
9
9
  installiert:
10
10
 
11
11
  ```powershell
12
- npm install -g blun-king-cli@9.1.498
12
+ npm install -g blun-king-cli@9.1.499
13
13
  ```
14
14
 
15
15
  ## Reproduzierbares Staging und Packen
@@ -81,6 +81,19 @@ konkurrierenden Start zurückgewiesen und bleiben an der Spitze der
81
81
  FIFO-Warteschlange. Für diesen normalen Wartestatus erscheint kein
82
82
  `turn.agent_busy`-Fehler.
83
83
 
84
+ Version 9.1.499 ersetzt Bild-, Audio- und Videodaten außerhalb der neuesten zwölf
85
+ Gesprächsnachrichten ausschließlich in der wiederholten Modellprojektion durch
86
+ kurze Verweise. Aktuelle Medien, Nachrichtentext und vollständiger Sitzungsrohverlauf
87
+ bleiben unverändert. In Fredriks gemessenem Wiederaufnahme-Checkpoint spart der
88
+ Schnitt 85.748 Zeichen beziehungsweise rund 21.437 geschätzte Eingabetoken je
89
+ weiterem Werkzeugschritt.
90
+
91
+ Faellige Todo-Pflege laeuft in 9.1.499 vor dem naechsten Sachwerkzeug als eigener
92
+ kleiner Modellschritt. In diesem Schritt bietet die Laufzeit ausschliesslich
93
+ `TodoList` an; erst nach einer gueltigen Aktualisierung werden Datei-, Such- und
94
+ Shell-Werkzeuge wieder freigegeben. Dadurch entsteht im normalen Ablauf kein
95
+ roter Zwischenfehler. Frische Benutzernachrichten behalten Vorrang.
96
+
84
97
  Version 9.1.498 zeigt in `/usage` die gemessene Prompt-Cache-Trefferquote sowie
85
98
  gelesene und geschriebene Cache-Token je Modell. `/tokens` ist ein kurzer Alias
86
99
  fuer die bereits vorhandene detaillierte Kontextdiagnose; `/offload` ruft die
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ const HISTORICAL_MEDIA_KEEP_RECENT_MESSAGES = 12;
4
+ const HISTORICAL_MEDIA_PLACEHOLDERS = Object.freeze({
5
+ image_url: '[historical image omitted from active model context; original remains in session wire]',
6
+ audio_url: '[historical audio omitted from active model context; original remains in session wire]',
7
+ video_url: '[historical video omitted from active model context; original remains in session wire]',
8
+ });
9
+
10
+ function projectHistoricalMediaParts(messages, options = {}) {
11
+ if (!Array.isArray(messages) || messages.length === 0) return messages;
12
+ const keepRecentMessages = nonNegativeInteger(
13
+ options.keepRecentMessages,
14
+ HISTORICAL_MEDIA_KEEP_RECENT_MESSAGES,
15
+ );
16
+ const historicalEnd = Math.max(0, messages.length - keepRecentMessages);
17
+ let changed = false;
18
+
19
+ const projected = messages.map((message, messageIndex) => {
20
+ if (messageIndex >= historicalEnd || !Array.isArray(message?.content)) return message;
21
+ let nextContent;
22
+ for (let partIndex = 0; partIndex < message.content.length; partIndex += 1) {
23
+ const part = message.content[partIndex];
24
+ const placeholder = HISTORICAL_MEDIA_PLACEHOLDERS[part?.type];
25
+ if (placeholder === undefined) {
26
+ nextContent?.push(part);
27
+ continue;
28
+ }
29
+ nextContent ??= message.content.slice(0, partIndex);
30
+ nextContent.push({ type: 'text', text: placeholder });
31
+ changed = true;
32
+ }
33
+ return nextContent === undefined ? message : { ...message, content: nextContent };
34
+ });
35
+
36
+ return changed ? projected : messages;
37
+ }
38
+
39
+ function nonNegativeInteger(value, fallback) {
40
+ const number = Number(value);
41
+ return Number.isInteger(number) && number >= 0 ? number : fallback;
42
+ }
43
+
44
+ module.exports = {
45
+ HISTORICAL_MEDIA_KEEP_RECENT_MESSAGES,
46
+ HISTORICAL_MEDIA_PLACEHOLDERS,
47
+ projectHistoricalMediaParts,
48
+ };
package/blun.mjs CHANGED
@@ -79049,7 +79049,8 @@ var init_context$2 = __esmMin((() => {
79049
79049
  project(messages, options) {
79050
79050
  const anomalies = [];
79051
79051
  const userOffloaded = this.agent.userMessageOffload.compact(messages);
79052
- const historicalUserReferencesProjected = compactHistoricalPersistedUserMessageReferences(userOffloaded);
79052
+ const historicalMediaProjected = projectHistoricalMediaParts(userOffloaded);
79053
+ const historicalUserReferencesProjected = compactHistoricalPersistedUserMessageReferences(historicalMediaProjected);
79053
79054
  const duplicateUserMessagesProjected = dedupeRepeatedUserMessages(historicalUserReferencesProjected);
79054
79055
  const historicalTelegramProjected = projectHistoricalUnaddressedTelegramMessages(duplicateUserMessagesProjected);
79055
79056
  const assistantOffloaded = this.agent.assistantMessageOffload.compact(historicalTelegramProjected);
@@ -261279,7 +261280,7 @@ function renderPersistedUserMessage(text, outputPath) {
261279
261280
  createUserMessagePreview(text)
261280
261281
  ].join("\n");
261281
261282
  }
261282
- var USER_MESSAGE_MAX_CHARS, USER_MESSAGE_OFFLOAD_MARKER, shouldOffloadUserMessage, shouldOffloadHistoricalUserMessage, createUserMessagePreview, compactHistoricalPersistedUserMessageReferences;
261283
+ var USER_MESSAGE_MAX_CHARS, USER_MESSAGE_OFFLOAD_MARKER, shouldOffloadUserMessage, shouldOffloadHistoricalUserMessage, createUserMessagePreview, compactHistoricalPersistedUserMessageReferences, projectHistoricalMediaParts;
261283
261284
  var init_user_message_offload = __esmMin((() => {
261284
261285
  const policy = createRequire(import.meta.url)("./bin/user-message-offload-policy.cjs");
261285
261286
  USER_MESSAGE_MAX_CHARS = policy.USER_MESSAGE_MAX_CHARS;
@@ -261287,8 +261288,9 @@ var init_user_message_offload = __esmMin((() => {
261287
261288
  shouldOffloadUserMessage = policy.shouldOffloadUserMessage;
261288
261289
  shouldOffloadHistoricalUserMessage = policy.shouldOffloadHistoricalUserMessage;
261289
261290
  createUserMessagePreview = policy.createUserMessagePreview;
261290
- compactHistoricalPersistedUserMessageReferences = policy.compactHistoricalPersistedUserMessageReferences;
261291
- }));
261291
+ compactHistoricalPersistedUserMessageReferences = policy.compactHistoricalPersistedUserMessageReferences;
261292
+ ({ projectHistoricalMediaParts } = createRequire(import.meta.url)("./bin/historical-media-projection-policy.cjs"));
261293
+ }));
261292
261294
  var UserMessageOffload = class {
261293
261295
  agent;
261294
261296
  replacements = /* @__PURE__ */ new Map();
@@ -262784,6 +262786,24 @@ var init_turn = __esmMin((() => {
262784
262786
  currentStepHadFailure = false;
262785
262787
  const pendingSteers = this.matchingSteers(turnId);
262786
262788
  if (pendingSteers.length === 0) {
262789
+ const todoMaintenanceMode = goalTodoMaintenanceMode(this.agent);
262790
+ if (todoMaintenanceMode !== null) {
262791
+ const todoTool = eligibleTools.find((tool) => tool.name === "TodoList");
262792
+ if (todoTool === void 0) return {
262793
+ block: true,
262794
+ reason: "TodoList maintenance is due, but the TodoList tool is unavailable."
262795
+ };
262796
+ this.agent.log.info("proactive TodoList maintenance step", {
262797
+ stepNumber,
262798
+ mode: todoMaintenanceMode,
262799
+ workCallsSinceRefresh: this.agent.goalTodoPolicyState?.workCallsSinceRefresh ?? 0
262800
+ });
262801
+ const todoSystemPrompt = buildGoalTodoMaintenanceSystemPrompt(this.agent, turnSystemPrompt ?? this.agent.effectiveSystemPrompt, todoMaintenanceMode);
262802
+ return {
262803
+ llm: this.agent.llmForTurn("low", todoSystemPrompt),
262804
+ tools: [todoTool]
262805
+ };
262806
+ }
262787
262807
  if (workStepThinkingEffort === void 0) return;
262788
262808
  this.agent.log.info("work step thinking effort", {
262789
262809
  stepNumber,
@@ -423194,6 +423214,7 @@ async function handleGoalCommand(host, args) {
423194
423214
  }
423195
423215
  const IDEA_CONTRACT_MARKER = "Work as a self-directing employee:";
423196
423216
  const IDEA_ALLOWED_CHANNELS = Object.freeze([]);
423217
+ const GOAL_TODO_REFRESH_WORK_CALL_LIMIT = 8;
423197
423218
  const IDEA_TERMINAL_TODO_STATUSES = Object.freeze([
423198
423219
  "done",
423199
423220
  "blocked",
@@ -423221,6 +423242,30 @@ function validInitialIdeaPlan(value) {
423221
423242
  }
423222
423243
  return active === 1;
423223
423244
  }
423245
+ function goalTodoMaintenanceMode(agent) {
423246
+ if (isIdeaGoal(agent)) return null;
423247
+ const todos = ideaTodos(agent);
423248
+ if (todos.length === 0) return agent.goal.getActiveGoal() === null ? null : "initial";
423249
+ const progress = agent.goalTodoPolicyState ??= {
423250
+ workCallsSinceRefresh: 0,
423251
+ refreshRequired: false
423252
+ };
423253
+ return progress.refreshRequired || progress.workCallsSinceRefresh >= GOAL_TODO_REFRESH_WORK_CALL_LIMIT ? "refresh" : null;
423254
+ }
423255
+ function buildGoalTodoMaintenanceSystemPrompt(agent, basePrompt, mode) {
423256
+ const todos = ideaTodos(agent);
423257
+ const visibleTodoList = todos.length === 0 ? "The visible TodoList is empty." : ["Current visible TodoList:", ...todos.map((todo) => `- [${String(todo?.status ?? "pending")}] ${String(todo?.title ?? "").trim()}`)].join("\n");
423258
+ const action = mode === "initial" ? "Create the visible task-specific TodoList now. Keep exactly one item in_progress and every later item pending." : "Update the visible TodoList now, before any more task work. Mark only evidenced steps done, keep the actual current step in_progress, and leave later steps pending. If the current title is stale, refine it to the concrete verified substep.";
423259
+ return `<todo-maintenance>
423260
+ TODO MAINTENANCE IS THE ONLY ACTION FOR THIS STEP.
423261
+ ${action}
423262
+ Call TodoList as the first and only tool. Do not call a work, search, file, shell, web, messaging, or goal tool in this step. Do not merely describe the update.
423263
+
423264
+ ${visibleTodoList}
423265
+ </todo-maintenance>
423266
+
423267
+ ${basePrompt}`;
423268
+ }
423224
423269
  function enforceGoalTodoPolicy(agent, context) {
423225
423270
  if (isIdeaGoal(agent)) return;
423226
423271
  if (TELEGRAM_DELIVERY_TOOL_RE.test(String(context.toolCall.name ?? ""))) return;
@@ -423295,7 +423340,7 @@ function enforceGoalTodoPolicy(agent, context) {
423295
423340
  }
423296
423341
  if (context.toolCall.id === context.toolCalls[0]?.id) {
423297
423342
  progress.workCallsSinceRefresh += 1;
423298
- if (progress.workCallsSinceRefresh > 8) progress.refreshRequired = true;
423343
+ if (progress.workCallsSinceRefresh > GOAL_TODO_REFRESH_WORK_CALL_LIMIT) progress.refreshRequired = true;
423299
423344
  }
423300
423345
  if (!progress.refreshRequired) return;
423301
423346
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.498",
3
+ "version": "9.1.499",
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": {