blun-king-cli 9.1.110 → 9.1.112

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.
@@ -1,6 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  const USER_MESSAGE_MAX_CHARS = 200_000;
4
+ const HISTORICAL_USER_MESSAGE_MAX_CHARS = 4_000;
5
+ const USER_MESSAGE_KEEP_RECENT_MESSAGES = 20;
4
6
  const USER_MESSAGE_PREVIEW_LINES = 5;
5
7
  const USER_MESSAGE_PREVIEW_LINE_CHARS = 1_000;
6
8
  const USER_MESSAGE_OFFLOAD_MARKER = '[User message offloaded]';
@@ -9,6 +11,22 @@ function shouldOffloadUserMessage(textChars) {
9
11
  return Number.isSafeInteger(textChars) && textChars > USER_MESSAGE_MAX_CHARS;
10
12
  }
11
13
 
14
+ function shouldOffloadHistoricalUserMessage(options = {}) {
15
+ const historyIndex = Number(options.historyIndex);
16
+ const historyLength = Number(options.historyLength);
17
+ const textChars = Number(options.textChars);
18
+ if (
19
+ !Number.isSafeInteger(historyIndex)
20
+ || !Number.isSafeInteger(historyLength)
21
+ || !Number.isSafeInteger(textChars)
22
+ || historyIndex < 0
23
+ || historyLength < 0
24
+ || historyIndex >= historyLength
25
+ ) return false;
26
+ const cutoff = Math.max(0, historyLength - USER_MESSAGE_KEEP_RECENT_MESSAGES);
27
+ return historyIndex < cutoff && textChars > HISTORICAL_USER_MESSAGE_MAX_CHARS;
28
+ }
29
+
12
30
  function createUserMessagePreview(text) {
13
31
  const lines = String(text).split(/\r?\n/u);
14
32
  const render = (line, index) => `${index}: ${line.slice(0, USER_MESSAGE_PREVIEW_LINE_CHARS)}`;
@@ -28,10 +46,13 @@ function createUserMessagePreview(text) {
28
46
  }
29
47
 
30
48
  module.exports = {
49
+ HISTORICAL_USER_MESSAGE_MAX_CHARS,
31
50
  USER_MESSAGE_MAX_CHARS,
51
+ USER_MESSAGE_KEEP_RECENT_MESSAGES,
32
52
  USER_MESSAGE_OFFLOAD_MARKER,
33
53
  USER_MESSAGE_PREVIEW_LINES,
34
54
  USER_MESSAGE_PREVIEW_LINE_CHARS,
35
55
  createUserMessagePreview,
56
+ shouldOffloadHistoricalUserMessage,
36
57
  shouldOffloadUserMessage,
37
58
  };
package/blun.mjs CHANGED
@@ -260422,7 +260422,7 @@ async function saveUserMessage(homedir, text) {
260422
260422
  function renderPersistedUserMessage(text, outputPath) {
260423
260423
  return [
260424
260424
  USER_MESSAGE_OFFLOAD_MARKER,
260425
- `Message text exceeded ${String(USER_MESSAGE_MAX_CHARS)} characters; the complete original remains in conversation history.`,
260425
+ "The complete original was archived to keep the active context fast and remains available on disk.",
260426
260426
  `message_size_chars: ${String(text.length)}`,
260427
260427
  `message_size_bytes: ${String(Buffer.byteLength(text, "utf8"))}`,
260428
260428
  `output_path: ${outputPath}`,
@@ -260432,12 +260432,13 @@ function renderPersistedUserMessage(text, outputPath) {
260432
260432
  createUserMessagePreview(text)
260433
260433
  ].join("\n");
260434
260434
  }
260435
- var USER_MESSAGE_MAX_CHARS, USER_MESSAGE_OFFLOAD_MARKER, shouldOffloadUserMessage, createUserMessagePreview;
260435
+ var USER_MESSAGE_MAX_CHARS, USER_MESSAGE_OFFLOAD_MARKER, shouldOffloadUserMessage, shouldOffloadHistoricalUserMessage, createUserMessagePreview;
260436
260436
  var init_user_message_offload = __esmMin((() => {
260437
260437
  const policy = createRequire(import.meta.url)("./bin/user-message-offload-policy.cjs");
260438
260438
  USER_MESSAGE_MAX_CHARS = policy.USER_MESSAGE_MAX_CHARS;
260439
260439
  USER_MESSAGE_OFFLOAD_MARKER = policy.USER_MESSAGE_OFFLOAD_MARKER;
260440
260440
  shouldOffloadUserMessage = policy.shouldOffloadUserMessage;
260441
+ shouldOffloadHistoricalUserMessage = policy.shouldOffloadHistoricalUserMessage;
260441
260442
  createUserMessagePreview = policy.createUserMessagePreview;
260442
260443
  }));
260443
260444
  var UserMessageOffload = class {
@@ -260447,30 +260448,44 @@ var UserMessageOffload = class {
260447
260448
  this.agent = agent;
260448
260449
  }
260449
260450
  async detect() {
260450
- const message = this.agent.context.history.at(-1);
260451
- const text = persistableUserMessageText(message);
260452
- if (text === void 0 || !shouldOffloadUserMessage(text.length)) return 0;
260453
- const messageHash = userMessageOffloadHash(message, text);
260454
- if (this.replacements.has(messageHash) || this.agent.homedir === void 0) return 0;
260455
- const outputPath = await saveUserMessage(this.agent.homedir, text);
260456
- if (outputPath === void 0) return 0;
260457
- const replacementText = renderPersistedUserMessage(text, outputPath);
260458
- const content = [{
260459
- type: "text",
260460
- text: replacementText
260461
- }, ...message.content.filter((part) => part.type !== "text")];
260462
- this.apply({
260463
- messageHash,
260464
- content,
260465
- outputPath
260466
- });
260467
- this.agent.telemetry.track("user_message_offloaded", {
260468
- chars_before: text.length,
260469
- chars_after: replacementText.length,
260470
- chars_saved: text.length - replacementText.length,
260471
- media_part_count: content.length - 1
260472
- });
260473
- return 1;
260451
+ const history = this.agent.context.history;
260452
+ if (this.agent.homedir === void 0) return 0;
260453
+ let offloaded = 0;
260454
+ for (let historyIndex = 0; historyIndex < history.length; historyIndex++) {
260455
+ const message = history[historyIndex];
260456
+ const text = persistableUserMessageText(message);
260457
+ if (text === void 0) continue;
260458
+ const immediateOversize = historyIndex === history.length - 1 && shouldOffloadUserMessage(text.length);
260459
+ const historicalOversize = shouldOffloadHistoricalUserMessage({
260460
+ historyIndex,
260461
+ historyLength: history.length,
260462
+ textChars: text.length
260463
+ });
260464
+ if (!immediateOversize && !historicalOversize) continue;
260465
+ const messageHash = userMessageOffloadHash(message, text);
260466
+ if (this.replacements.has(messageHash)) continue;
260467
+ const outputPath = await saveUserMessage(this.agent.homedir, text);
260468
+ if (outputPath === void 0) continue;
260469
+ const replacementText = renderPersistedUserMessage(text, outputPath);
260470
+ const content = [{
260471
+ type: "text",
260472
+ text: replacementText
260473
+ }, ...message.content.filter((part) => part.type !== "text")];
260474
+ this.apply({
260475
+ messageHash,
260476
+ content,
260477
+ outputPath
260478
+ });
260479
+ this.agent.telemetry.track("user_message_offloaded", {
260480
+ chars_before: text.length,
260481
+ chars_after: replacementText.length,
260482
+ chars_saved: text.length - replacementText.length,
260483
+ media_part_count: content.length - 1,
260484
+ reason: immediateOversize ? "immediate_oversize" : "historical_oversize"
260485
+ });
260486
+ offloaded++;
260487
+ }
260488
+ return offloaded;
260474
260489
  }
260475
260490
  apply(replacement) {
260476
260491
  this.replacements.set(replacement.messageHash, replacement);
@@ -260584,12 +260599,12 @@ function blunFastConversationTools(tools, input, pendingMediaJobIds = []) {
260584
260599
  * name through ToolSearch. The absolute cap prevents large context windows
260585
260600
  * from turning every deferred schema into permanent request overhead.
260586
260601
  */
260587
- function blunSelectTurnTools(tools, maxContextTokens, loadedToolNames) {
260602
+ function blunSelectTurnTools(tools, maxContextTokens, loadedToolNames, requiredToolNames = /* @__PURE__ */ new Set()) {
260588
260603
  if (estimateTokensForTools(tools) <= toolSchemaBudgetTokens(maxContextTokens)) return {
260589
260604
  tools,
260590
260605
  deferredToolCount: 0
260591
260606
  };
260592
- const selected = tools.filter((tool) => BLUN_LEAN_TOOL_NAMES.has(tool.name) || loadedToolNames.has(tool.name));
260607
+ const selected = tools.filter((tool) => BLUN_LEAN_TOOL_NAMES.has(tool.name) || loadedToolNames.has(tool.name) || requiredToolNames.has(tool.name));
260593
260608
  const selectedNames = new Set(selected.map((tool) => tool.name));
260594
260609
  const deferred = tools.filter((tool) => !selectedNames.has(tool.name));
260595
260610
  if (deferred.length > 0) selected.push(createDeferredToolLoader(selected, deferred, loadedToolNames));
@@ -261430,7 +261445,7 @@ var init_turn = __esmMin((() => {
261430
261445
  const toolSelection = fastConversation ? {
261431
261446
  tools: [...blunFastConversationTools(eligibleTools, input, pendingMediaJobIds)],
261432
261447
  deferredToolCount: 0
261433
- } : turnNeedsTools ? blunSelectTurnTools(eligibleTools, this.agent.config.modelCapabilities?.max_context_tokens, this.loadedToolNames) : {
261448
+ } : turnNeedsTools ? blunSelectTurnTools(eligibleTools, this.agent.config.modelCapabilities?.max_context_tokens, this.loadedToolNames, turnHasAttachment ? new Set(["mcp__plugin-telegram_telegram__download_attachment"]) : void 0) : {
261434
261449
  tools: [],
261435
261450
  deferredToolCount: 0
261436
261451
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.110",
3
+ "version": "9.1.112",
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": {