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.
- package/bin/user-message-offload-policy.cjs +37 -0
- package/blun.mjs +126 -1
- package/package.json +1 -1
|
@@ -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);
|