blun-king-cli 9.1.100 → 9.1.101

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.
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ const USER_MESSAGE_MAX_CHARS = 200_000;
4
+ const USER_MESSAGE_PREVIEW_LINES = 5;
5
+ const USER_MESSAGE_PREVIEW_LINE_CHARS = 1_000;
6
+ const USER_MESSAGE_OFFLOAD_MARKER = '[User message offloaded]';
7
+
8
+ function shouldOffloadUserMessage(textChars) {
9
+ return Number.isSafeInteger(textChars) && textChars > USER_MESSAGE_MAX_CHARS;
10
+ }
11
+
12
+ function createUserMessagePreview(text) {
13
+ const lines = String(text).split(/\r?\n/u);
14
+ const render = (line, index) => `${index}: ${line.slice(0, USER_MESSAGE_PREVIEW_LINE_CHARS)}`;
15
+ if (lines.length <= USER_MESSAGE_PREVIEW_LINES * 2) {
16
+ return lines.map((line, index) => render(line, index + 1)).join('\n');
17
+ }
18
+ const head = lines.slice(0, USER_MESSAGE_PREVIEW_LINES)
19
+ .map((line, index) => render(line, index + 1));
20
+ const tailStart = lines.length - USER_MESSAGE_PREVIEW_LINES;
21
+ const tail = lines.slice(tailStart)
22
+ .map((line, index) => render(line, tailStart + index + 1));
23
+ return [
24
+ ...head,
25
+ `... [${lines.length - USER_MESSAGE_PREVIEW_LINES * 2} lines omitted] ...`,
26
+ ...tail,
27
+ ].join('\n');
28
+ }
29
+
30
+ module.exports = {
31
+ USER_MESSAGE_MAX_CHARS,
32
+ USER_MESSAGE_OFFLOAD_MARKER,
33
+ USER_MESSAGE_PREVIEW_LINES,
34
+ USER_MESSAGE_PREVIEW_LINE_CHARS,
35
+ createUserMessagePreview,
36
+ shouldOffloadUserMessage,
37
+ };
package/blun.mjs CHANGED
@@ -78758,6 +78758,7 @@ var init_context$2 = __esmMin((() => {
78758
78758
  this.agent.replayBuilder.removeLastMessages(removedMessages);
78759
78759
  this.agent.microCompaction.reset(this._history.length);
78760
78760
  this.agent.toolResultBatchOffload.reset(this._history);
78761
+ this.agent.userMessageOffload.reset(this._history);
78761
78762
  this.agent.emitStatusUpdated();
78762
78763
  return removedMessages.size;
78763
78764
  }
@@ -78772,6 +78773,7 @@ var init_context$2 = __esmMin((() => {
78772
78773
  this._lastAssistantAt = null;
78773
78774
  this.agent.microCompaction.reset();
78774
78775
  this.agent.toolResultBatchOffload.clear();
78776
+ this.agent.userMessageOffload.clear();
78775
78777
  this.agent.injection.onContextClear();
78776
78778
  this.agent.emitStatusUpdated();
78777
78779
  }
@@ -78811,6 +78813,7 @@ var init_context$2 = __esmMin((() => {
78811
78813
  this.deferredMessages = [];
78812
78814
  this.agent.microCompaction.reset(this._history.length);
78813
78815
  this.agent.toolResultBatchOffload.reset(this._history);
78816
+ this.agent.userMessageOffload.reset(this._history);
78814
78817
  this.agent.emitStatusUpdated();
78815
78818
  if (!this.agent.records.restoring && (stoppedAtBoundary || removedUserCount < count)) throw new BlunError(ErrorCodes.REQUEST_INVALID, formatUndoUnavailableMessage(count, removedUserCount, stoppedAtBoundary), { details: {
78816
78819
  reason: "undo_limit",
@@ -78890,6 +78893,7 @@ var init_context$2 = __esmMin((() => {
78890
78893
  this.tokenCountCoveredMessageCount = this._history.length;
78891
78894
  this.agent.microCompaction.reset();
78892
78895
  this.agent.toolResultBatchOffload.reset(this._history);
78896
+ this.agent.userMessageOffload.reset(this._history);
78893
78897
  this.agent.injection.onContextCompacted();
78894
78898
  this.agent.emitStatusUpdated();
78895
78899
  return result;
@@ -78912,7 +78916,7 @@ var init_context$2 = __esmMin((() => {
78912
78916
  }
78913
78917
  project(messages, options) {
78914
78918
  const anomalies = [];
78915
- const result = project(this.agent.microCompaction.compact(this.agent.toolResultBatchOffload.compact(messages)), {
78919
+ const result = project(this.agent.userMessageOffload.compact(this.agent.microCompaction.compact(this.agent.toolResultBatchOffload.compact(messages))), {
78916
78920
  ...options,
78917
78921
  onAnomaly: (anomaly) => {
78918
78922
  anomalies.push(anomaly);
@@ -234835,6 +234839,9 @@ function restoreAgentRecord(agent, input) {
234835
234839
  case "tool_result_batch_offload.apply":
234836
234840
  agent.toolResultBatchOffload.apply(input.replacements);
234837
234841
  return;
234842
+ case "user_message_offload.apply":
234843
+ agent.userMessageOffload.apply(input.replacement);
234844
+ return;
234838
234845
  case "plan_mode.enter":
234839
234846
  agent.planMode.restoreEnter(input);
234840
234847
  return;
@@ -260237,6 +260244,121 @@ var ToolResultBatchOffload = class {
260237
260244
  }
260238
260245
  };
260239
260246
  //#endregion
260247
+ //#region ../../packages/agent-core/src/agent/turn/user-message-offload.ts
260248
+ function persistableUserMessageText(message) {
260249
+ if (message?.role !== "user" || message.origin?.kind !== "user") return;
260250
+ const textParts = message.content.filter((part) => part.type === "text");
260251
+ if (textParts.length === 0) return;
260252
+ return textParts.map((part) => part.text).join("\n");
260253
+ }
260254
+ function userMessageOffloadHash(message, text) {
260255
+ return createHash("sha256").update(JSON.stringify({
260256
+ origin: message.origin,
260257
+ text
260258
+ })).digest("hex");
260259
+ }
260260
+ async function saveUserMessage(homedir, text) {
260261
+ try {
260262
+ const dir = join$4(homedir, "conversation-history");
260263
+ await mkdir(dir, {
260264
+ recursive: true,
260265
+ mode: 448
260266
+ });
260267
+ const outputPath = join$4(dir, `user-message-${randomUUID()}.txt`);
260268
+ await writeFile(outputPath, text, {
260269
+ encoding: "utf8",
260270
+ flag: "wx",
260271
+ mode: 384
260272
+ });
260273
+ return outputPath;
260274
+ } catch {
260275
+ return;
260276
+ }
260277
+ }
260278
+ function renderPersistedUserMessage(text, outputPath) {
260279
+ return [
260280
+ USER_MESSAGE_OFFLOAD_MARKER,
260281
+ `Message text exceeded ${String(USER_MESSAGE_MAX_CHARS)} characters; the complete original remains in conversation history.`,
260282
+ `message_size_chars: ${String(text.length)}`,
260283
+ `message_size_bytes: ${String(Buffer.byteLength(text, "utf8"))}`,
260284
+ `output_path: ${outputPath}`,
260285
+ "next_step: Use Read with output_path to inspect the complete message in pages.",
260286
+ "",
260287
+ "[preview: head and tail]",
260288
+ createUserMessagePreview(text)
260289
+ ].join("\n");
260290
+ }
260291
+ var USER_MESSAGE_MAX_CHARS, USER_MESSAGE_OFFLOAD_MARKER, shouldOffloadUserMessage, createUserMessagePreview;
260292
+ var init_user_message_offload = __esmMin((() => {
260293
+ const policy = createRequire(import.meta.url)("./bin/user-message-offload-policy.cjs");
260294
+ USER_MESSAGE_MAX_CHARS = policy.USER_MESSAGE_MAX_CHARS;
260295
+ USER_MESSAGE_OFFLOAD_MARKER = policy.USER_MESSAGE_OFFLOAD_MARKER;
260296
+ shouldOffloadUserMessage = policy.shouldOffloadUserMessage;
260297
+ createUserMessagePreview = policy.createUserMessagePreview;
260298
+ }));
260299
+ var UserMessageOffload = class {
260300
+ agent;
260301
+ replacements = /* @__PURE__ */ new Map();
260302
+ constructor(agent) {
260303
+ this.agent = agent;
260304
+ }
260305
+ async detect() {
260306
+ const message = this.agent.context.history.at(-1);
260307
+ const text = persistableUserMessageText(message);
260308
+ if (text === void 0 || !shouldOffloadUserMessage(text.length)) return 0;
260309
+ const messageHash = userMessageOffloadHash(message, text);
260310
+ if (this.replacements.has(messageHash) || this.agent.homedir === void 0) return 0;
260311
+ const outputPath = await saveUserMessage(this.agent.homedir, text);
260312
+ if (outputPath === void 0) return 0;
260313
+ const replacementText = renderPersistedUserMessage(text, outputPath);
260314
+ const content = [{
260315
+ type: "text",
260316
+ text: replacementText
260317
+ }, ...message.content.filter((part) => part.type !== "text")];
260318
+ this.apply({
260319
+ messageHash,
260320
+ content,
260321
+ outputPath
260322
+ });
260323
+ this.agent.telemetry.track("user_message_offloaded", {
260324
+ chars_before: text.length,
260325
+ chars_after: replacementText.length,
260326
+ chars_saved: text.length - replacementText.length,
260327
+ media_part_count: content.length - 1
260328
+ });
260329
+ return 1;
260330
+ }
260331
+ apply(replacement) {
260332
+ this.replacements.set(replacement.messageHash, replacement);
260333
+ this.agent.records.logRecord({
260334
+ type: "user_message_offload.apply",
260335
+ replacement
260336
+ });
260337
+ }
260338
+ compact(messages) {
260339
+ if (this.replacements.size === 0) return messages;
260340
+ return messages.map((message) => {
260341
+ const text = persistableUserMessageText(message);
260342
+ if (text === void 0) return message;
260343
+ const replacement = this.replacements.get(userMessageOffloadHash(message, text));
260344
+ return replacement === void 0 ? message : {
260345
+ ...message,
260346
+ content: replacement.content
260347
+ };
260348
+ });
260349
+ }
260350
+ reset(history = this.agent.context?.history ?? []) {
260351
+ const activeHashes = new Set(history.map((message) => {
260352
+ const text = persistableUserMessageText(message);
260353
+ return text === void 0 ? void 0 : userMessageOffloadHash(message, text);
260354
+ }).filter((hash) => hash !== void 0));
260355
+ for (const messageHash of this.replacements.keys()) if (!activeHashes.has(messageHash)) this.replacements.delete(messageHash);
260356
+ }
260357
+ clear() {
260358
+ this.replacements.clear();
260359
+ }
260360
+ };
260361
+ //#endregion
260240
260362
  //#region ../../packages/agent-core/src/agent/turn/index.ts
260241
260363
  function blunExtractText(content) {
260242
260364
  if (typeof content === "string") return content;
@@ -260572,6 +260694,7 @@ var init_turn = __esmMin((() => {
260572
260694
  init_canonical_args();
260573
260695
  init_tool_dedup();
260574
260696
  init_tool_result_budget();
260697
+ init_user_message_offload();
260575
260698
  ({ CORE_TOOL_NAMES: BLUN_CORE_TOOL_NAMES, createDeferredToolLoader, toolSchemaBudgetTokens } = createRequire(import.meta.url)("./bin/turn-tool-performance-policy.cjs"));
260576
260699
  BLUN_LEAN_TOOL_NAMES = new Set(BLUN_CORE_TOOL_NAMES);
260577
260700
  BLUN_ATTACHMENT_MARKER_RE = /\b(?:attachment_file_id|telegram-anhang|telegram attachment)\b/i;
@@ -261206,6 +261329,7 @@ var init_turn = __esmMin((() => {
261206
261329
  beforeStep: async ({ signal: stepSignal, stepNumber }) => {
261207
261330
  await this.agent.records.flush();
261208
261331
  this.agent.microCompaction.detect();
261332
+ await this.agent.userMessageOffload.detect();
261209
261333
  await this.agent.injection.inject();
261210
261334
  stepSignal.throwIfAborted();
261211
261335
  deduper.beginStep();
@@ -264014,6 +264138,7 @@ var init_agent = __esmMin((() => {
264014
264138
  this.fullCompaction = new FullCompaction(this, options.compactionStrategy);
264015
264139
  this.microCompaction = new MicroCompaction(this, options.microCompaction);
264016
264140
  this.toolResultBatchOffload = new ToolResultBatchOffload(this);
264141
+ this.userMessageOffload = new UserMessageOffload(this);
264017
264142
  this.context = new ContextMemory(this);
264018
264143
  this.config = new ConfigState(this);
264019
264144
  this.turn = new TurnFlow(this);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.100",
3
+ "version": "9.1.101",
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": {