blun-king-cli 9.1.550 → 9.1.561

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
@@ -1,7 +1,7 @@
1
- BLUN Code 9.1.550
1
+ BLUN Code 9.1.561
2
2
 
3
3
  Installation:
4
- npm install -g blun-king-cli@9.1.550
4
+ npm install -g blun-king-cli@9.1.561
5
5
 
6
6
  Start:
7
7
  blun
package/README.md CHANGED
@@ -11,7 +11,7 @@ web tools, MCP servers, and an optional Telegram channel.
11
11
  ## Install
12
12
 
13
13
  ```sh
14
- npm install -g blun-king-cli@9.1.550
14
+ npm install -g blun-king-cli@9.1.561
15
15
  ```
16
16
 
17
17
  Start the local console with:
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ const { randomUUID } = require('node:crypto');
4
+
5
+ function positiveInteger(value, label) {
6
+ if (!Number.isSafeInteger(value) || value < 0) {
7
+ throw new TypeError(`${label} must be a non-negative safe integer`);
8
+ }
9
+ return value;
10
+ }
11
+
12
+ function toolCallId(call) {
13
+ return typeof call?.id === 'string' && call.id.length > 0 ? call.id : undefined;
14
+ }
15
+
16
+ function assertBalancedToolPairs(messages, label = 'compaction history') {
17
+ const pending = new Set();
18
+ for (const message of messages) {
19
+ if (message?.role === 'assistant') {
20
+ for (const call of message.toolCalls ?? []) {
21
+ const id = toolCallId(call);
22
+ if (id === undefined) throw new Error(`${label} contains a tool call without an id`);
23
+ if (pending.has(id)) throw new Error(`${label} contains duplicate tool call id ${id}`);
24
+ pending.add(id);
25
+ }
26
+ continue;
27
+ }
28
+ if (message?.role !== 'tool') continue;
29
+ const id = typeof message.toolCallId === 'string' ? message.toolCallId : undefined;
30
+ if (id === undefined || !pending.delete(id)) {
31
+ throw new Error(`${label} contains an orphan tool result${id ? ` ${id}` : ''}`);
32
+ }
33
+ }
34
+ if (pending.size > 0) {
35
+ throw new Error(`${label} contains ${pending.size} tool call(s) without results`);
36
+ }
37
+ return true;
38
+ }
39
+
40
+ function createCompactionTransaction({ source, turnId, tokensBefore, messageCountBefore }) {
41
+ const transaction = {
42
+ id: randomUUID(),
43
+ source,
44
+ turnId: turnId ?? null,
45
+ tokensBefore: positiveInteger(tokensBefore, 'tokensBefore'),
46
+ messageCountBefore: positiveInteger(messageCountBefore, 'messageCountBefore'),
47
+ state: 'started',
48
+ };
49
+ return {
50
+ transaction,
51
+ record: {
52
+ type: 'compaction/start',
53
+ compaction_id: transaction.id,
54
+ source: transaction.source,
55
+ turn_id: transaction.turnId,
56
+ size_before: transaction.tokensBefore,
57
+ message_count_before: transaction.messageCountBefore,
58
+ unit: 'tokens',
59
+ },
60
+ };
61
+ }
62
+
63
+ function summarizeCompactionTransaction(transaction, input) {
64
+ if (transaction?.state !== 'started') {
65
+ throw new Error('compaction/summary requires exactly one open compaction/start');
66
+ }
67
+ if (typeof input.summary !== 'string' || input.summary.trim().length === 0) {
68
+ throw new Error('compaction/summary requires non-empty model-visible summary text');
69
+ }
70
+ assertBalancedToolPairs(input.historyBefore, 'history before compaction');
71
+ assertBalancedToolPairs(input.historyAfter, 'history after compaction');
72
+ transaction.state = 'summarized';
73
+ transaction.tokensAfter = positiveInteger(input.tokensAfter, 'tokensAfter');
74
+ transaction.messageCountAfter = positiveInteger(input.messageCountAfter, 'messageCountAfter');
75
+ return {
76
+ type: 'compaction/summary',
77
+ compaction_id: transaction.id,
78
+ source: transaction.source,
79
+ turn_id: transaction.turnId,
80
+ summary: input.summary,
81
+ shadowed_token_count: transaction.tokensBefore,
82
+ size_before: transaction.tokensBefore,
83
+ size_after: transaction.tokensAfter,
84
+ message_count_before: transaction.messageCountBefore,
85
+ message_count_after: transaction.messageCountAfter,
86
+ tool_pairing_balanced_before: true,
87
+ tool_pairing_balanced_after: true,
88
+ unit: 'tokens',
89
+ };
90
+ }
91
+
92
+ function endCompactionTransaction(transaction, { status, error } = {}) {
93
+ if (transaction?.state === 'ended') return undefined;
94
+ if (transaction?.state !== 'started' && transaction?.state !== 'summarized') {
95
+ throw new Error('compaction/end requires an open compaction/start');
96
+ }
97
+ const normalizedStatus = status ?? 'success';
98
+ if (normalizedStatus === 'success' && transaction.state !== 'summarized') {
99
+ throw new Error('successful compaction/end requires one compaction/summary');
100
+ }
101
+ if (!['success', 'cancelled', 'failed'].includes(normalizedStatus)) {
102
+ throw new Error(`unsupported compaction status ${normalizedStatus}`);
103
+ }
104
+ transaction.state = 'ended';
105
+ return {
106
+ type: 'compaction/end',
107
+ compaction_id: transaction.id,
108
+ source: transaction.source,
109
+ turn_id: transaction.turnId,
110
+ status: normalizedStatus,
111
+ ...(transaction.tokensAfter === undefined ? {} : { size_after: transaction.tokensAfter }),
112
+ ...(typeof error === 'string' && error.length > 0 ? { error } : {}),
113
+ unit: 'tokens',
114
+ };
115
+ }
116
+
117
+ module.exports = {
118
+ assertBalancedToolPairs,
119
+ createCompactionTransaction,
120
+ endCompactionTransaction,
121
+ summarizeCompactionTransaction,
122
+ };
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ const DEFAULT_MODEL_ALIAS = 'blun/king';
4
+ const DEFAULT_MAX_OUTPUT_SIZE = 128000;
5
+
6
+ function applyDefaultModelOutputBudget(config) {
7
+ const models = config?.models;
8
+ const model = models?.[DEFAULT_MODEL_ALIAS];
9
+
10
+ if (!model || model.maxOutputSize !== undefined) return config;
11
+
12
+ return {
13
+ ...config,
14
+ models: {
15
+ ...models,
16
+ [DEFAULT_MODEL_ALIAS]: {
17
+ ...model,
18
+ maxOutputSize: DEFAULT_MAX_OUTPUT_SIZE,
19
+ },
20
+ },
21
+ };
22
+ }
23
+
24
+ module.exports = {
25
+ DEFAULT_MAX_OUTPUT_SIZE,
26
+ DEFAULT_MODEL_ALIAS,
27
+ applyDefaultModelOutputBudget,
28
+ };
@@ -0,0 +1,133 @@
1
+ 'use strict';
2
+
3
+ function versionFromStat(stat) {
4
+ if (!stat || typeof stat !== 'object') return null;
5
+ return [
6
+ stat.stDev ?? null,
7
+ stat.stIno ?? null,
8
+ stat.stSize ?? null,
9
+ stat.stMtime ?? null,
10
+ ].join(':');
11
+ }
12
+
13
+ function isNotFoundError(error) {
14
+ return error?.code === 'ENOENT' || error?.code === 'ENOTDIR';
15
+ }
16
+
17
+ function createFileObservationPolicy(options = {}) {
18
+ const caseInsensitive = options.pathClass === 'win32';
19
+ const observations = new Map();
20
+
21
+ function key(filePath) {
22
+ const normalized = String(filePath).replaceAll('\\', '/');
23
+ return caseInsensitive ? normalized.toLowerCase() : normalized;
24
+ }
25
+
26
+ function recordPresent(filePath, stat) {
27
+ const version = versionFromStat(stat);
28
+ if (version === null) throw new TypeError('recordPresent requires a file stat');
29
+ observations.set(key(filePath), { kind: 'present', version });
30
+ }
31
+
32
+ function recordAbsent(filePath) {
33
+ observations.set(key(filePath), { kind: 'absent' });
34
+ }
35
+
36
+ function verifyStableRead(filePath, before, after) {
37
+ const beforeVersion = versionFromStat(before);
38
+ const afterVersion = versionFromStat(after);
39
+ if (beforeVersion === null || afterVersion === null || beforeVersion !== afterVersion) {
40
+ return {
41
+ allowed: false,
42
+ code: 'FS_STALE_VERSION',
43
+ error: `File changed while reading "${filePath}". Read it again before editing or overwriting it.`,
44
+ };
45
+ }
46
+ recordPresent(filePath, after);
47
+ return { allowed: true, version: afterVersion };
48
+ }
49
+
50
+ function authorizeEdit(filePath, currentStat) {
51
+ const prior = observations.get(key(filePath));
52
+ if (currentStat === null) {
53
+ return {
54
+ allowed: false,
55
+ code: prior?.kind === 'absent' ? 'FS_NOT_FOUND' : 'FS_NOT_OBSERVED',
56
+ error: prior?.kind === 'absent'
57
+ ? `Cannot edit "${filePath}": the last Read confirmed that it does not exist.`
58
+ : `Edit requires reading "${filePath}" first. Read the exact target path, then retry.`,
59
+ };
60
+ }
61
+ if (prior === undefined) {
62
+ return {
63
+ allowed: false,
64
+ code: 'FS_NOT_OBSERVED',
65
+ error: `Edit requires reading "${filePath}" first. Read the exact target path, then retry.`,
66
+ };
67
+ }
68
+ if (prior.kind !== 'present' || prior.version !== versionFromStat(currentStat)) {
69
+ return {
70
+ allowed: false,
71
+ code: 'FS_STALE_VERSION',
72
+ error: `"${filePath}" changed since the last Read. Read it again, then retry the Edit.`,
73
+ };
74
+ }
75
+ return { allowed: true, version: prior.version };
76
+ }
77
+
78
+ function authorizeWrite(filePath, currentStat) {
79
+ const prior = observations.get(key(filePath));
80
+ if (currentStat === null) {
81
+ if (prior?.kind === 'present') {
82
+ return {
83
+ allowed: false,
84
+ code: 'FS_STALE_VERSION',
85
+ error: `"${filePath}" disappeared since the last Read. Read it again before recreating it.`,
86
+ };
87
+ }
88
+ return { allowed: true, version: null, create: true };
89
+ }
90
+ if (prior === undefined) {
91
+ return {
92
+ allowed: false,
93
+ code: 'FS_NOT_OBSERVED',
94
+ error: `Write would replace or append to existing file "${filePath}" without a prior Read. Read it first, then retry.`,
95
+ };
96
+ }
97
+ if (prior.kind !== 'present' || prior.version !== versionFromStat(currentStat)) {
98
+ return {
99
+ allowed: false,
100
+ code: 'FS_STALE_VERSION',
101
+ error: `"${filePath}" changed since the last Read. Read it again, then retry the Write.`,
102
+ };
103
+ }
104
+ return { allowed: true, version: prior.version, create: false };
105
+ }
106
+
107
+ function verifyUnchanged(filePath, expectedVersion, currentStat) {
108
+ const currentVersion = versionFromStat(currentStat);
109
+ if (expectedVersion === currentVersion) return { allowed: true };
110
+ return {
111
+ allowed: false,
112
+ code: 'FS_STALE_VERSION',
113
+ error: expectedVersion === null
114
+ ? `"${filePath}" appeared before the new file could be created. Read it before deciding whether to overwrite it.`
115
+ : `"${filePath}" changed before the mutation was written. Read it again, then retry.`,
116
+ };
117
+ }
118
+
119
+ return {
120
+ authorizeEdit,
121
+ authorizeWrite,
122
+ recordAbsent,
123
+ recordPresent,
124
+ verifyStableRead,
125
+ verifyUnchanged,
126
+ };
127
+ }
128
+
129
+ module.exports = {
130
+ createFileObservationPolicy,
131
+ isNotFoundError,
132
+ versionFromStat,
133
+ };
@@ -539,7 +539,6 @@ async function runLauncher(options = {}) {
539
539
  env.BLUN_SHARED_HOME = privatePaths.sharedHome;
540
540
  env.BLUN_LOG_HOME = privatePaths.sharedHome;
541
541
  env.BLUN_PROFILE = PROFILE.profileName;
542
- env.BLUN_MODEL_MAX_COMPLETION_TOKENS = env.BLUN_MODEL_MAX_COMPLETION_TOKENS || '32768';
543
542
  const mnemoConnect = startMnemoConnectHeartbeat({
544
543
  env,
545
544
  profileName: PROFILE.profileName,
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const { createHash } = require('node:crypto');
4
+
3
5
  const MICRO_COMPACTION_PRESSURE_RATIO = 0.75;
4
6
  const MICRO_COMPACTION_MIN_ADVANCE_MESSAGES = 20;
5
7
  const MICRO_COMPACTION_RECENT_MESSAGES = 4;
@@ -46,6 +48,66 @@ function selectMicroCompactionCutoff(options = {}) {
46
48
  };
47
49
  }
48
50
 
51
+ function redundantHistoricalToolResultIds(messages, cutoff) {
52
+ return new Set(redundantHistoricalToolResultReferences(messages, cutoff).keys());
53
+ }
54
+
55
+ function redundantHistoricalToolResultReferences(messages, cutoff) {
56
+ if (!Array.isArray(messages)) return new Map();
57
+
58
+ const historicalCutoff = Math.min(messages.length, nonNegativeInteger(cutoff));
59
+ const callSignatures = new Map();
60
+ for (const message of messages) {
61
+ if (message?.role !== 'assistant' || !Array.isArray(message.toolCalls)) continue;
62
+ for (const call of message.toolCalls) {
63
+ if (
64
+ typeof call?.id !== 'string'
65
+ || typeof call.name !== 'string'
66
+ || typeof call.arguments !== 'string'
67
+ ) {
68
+ continue;
69
+ }
70
+ callSignatures.set(call.id, JSON.stringify([call.name, call.arguments]));
71
+ }
72
+ }
73
+
74
+ const resultsBySignature = new Map();
75
+ for (let index = 0; index < messages.length; index++) {
76
+ const message = messages[index];
77
+ if (message?.role !== 'tool' || typeof message.toolCallId !== 'string') continue;
78
+ const callSignature = callSignatures.get(message.toolCallId);
79
+ if (callSignature === undefined || !Array.isArray(message.content)) continue;
80
+
81
+ let resultSignature;
82
+ try {
83
+ resultSignature = createHash('sha256')
84
+ .update(callSignature)
85
+ .update('\0')
86
+ .update(JSON.stringify(message.content))
87
+ .digest('hex');
88
+ } catch {
89
+ continue;
90
+ }
91
+
92
+ const entries = resultsBySignature.get(resultSignature) ?? [];
93
+ entries.push({ index, toolCallId: message.toolCallId });
94
+ resultsBySignature.set(resultSignature, entries);
95
+ }
96
+
97
+ const redundantIds = new Map();
98
+ for (const entries of resultsBySignature.values()) {
99
+ if (entries.length < 2) continue;
100
+ const newestToolCallId = entries.at(-1)?.toolCallId;
101
+ if (newestToolCallId === undefined) continue;
102
+ for (const entry of entries.slice(0, -1)) {
103
+ if (entry.index < historicalCutoff) {
104
+ redundantIds.set(entry.toolCallId, newestToolCallId);
105
+ }
106
+ }
107
+ }
108
+ return redundantIds;
109
+ }
110
+
49
111
  function finiteOr(value, fallback) {
50
112
  const number = Number(value);
51
113
  return Number.isFinite(number) ? number : fallback;
@@ -77,5 +139,7 @@ module.exports = {
77
139
  MICRO_COMPACTION_RECENT_MESSAGES,
78
140
  MICRO_COMPACTION_TOOL_ARGUMENTS_ENABLED,
79
141
  MICRO_COMPACTION_TOOL_ARGUMENT_MIN_TOKENS,
142
+ redundantHistoricalToolResultIds,
143
+ redundantHistoricalToolResultReferences,
80
144
  selectMicroCompactionCutoff,
81
145
  };
@@ -5,7 +5,6 @@ const os = require('node:os');
5
5
 
6
6
  const DEFAULT_HEARTBEAT_MS = 60_000;
7
7
  const DEFAULT_TIMEOUT_MS = 5_000;
8
- const DEFAULT_INTERNAL_HUB_URL = 'http://100.85.21.103:7117';
9
8
 
10
9
  function resolveMnemoHubUrl(env = process.env) {
11
10
  const raw = [
@@ -51,7 +50,7 @@ function resolveMnemoProfileConnectConfig(configPath) {
51
50
  ].some((value) => typeof value === 'string' && value.trim().length > 0);
52
51
  const baseUrl = resolveMnemoHubUrl(server.env);
53
52
  if (configuredUrl && !baseUrl) return null;
54
- return { agentName, baseUrl: baseUrl || DEFAULT_INTERNAL_HUB_URL };
53
+ return baseUrl ? { agentName, baseUrl } : null;
55
54
  } catch {
56
55
  return null;
57
56
  }
@@ -196,7 +195,6 @@ function startMnemoConnectHeartbeat(options = {}) {
196
195
 
197
196
  module.exports = {
198
197
  DEFAULT_HEARTBEAT_MS,
199
- DEFAULT_INTERNAL_HUB_URL,
200
198
  DEFAULT_TIMEOUT_MS,
201
199
  postMnemoTool,
202
200
  resolveMnemoAgentName,
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ async function persistRetrySchedule(input = {}) {
4
+ const { dispatchRetrying, flush, event, signal } = input;
5
+ if (typeof dispatchRetrying !== 'function') throw new TypeError('persistRetrySchedule requires dispatchRetrying');
6
+ if (typeof flush !== 'function') throw new TypeError('persistRetrySchedule requires flush');
7
+ signal?.throwIfAborted?.();
8
+ await dispatchRetrying(event);
9
+ await flush();
10
+ signal?.throwIfAborted?.();
11
+ }
12
+
13
+ module.exports = { persistRetrySchedule };
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ const TOOL_ABORTED_BEFORE_DISPATCH = 'TOOL_ABORTED_BEFORE_DISPATCH';
4
+
5
+ async function checkpointBeforeExternalSideEffect(options = {}) {
6
+ const flush = options.flush;
7
+ const signal = options.signal;
8
+ if (typeof flush !== 'function') {
9
+ throw new TypeError('checkpointBeforeExternalSideEffect requires flush');
10
+ }
11
+ await flush();
12
+ if (signal?.aborted === true) {
13
+ return {
14
+ allowed: false,
15
+ code: TOOL_ABORTED_BEFORE_DISPATCH,
16
+ error: 'Tool call aborted before dispatch while its durable checkpoint was being written.',
17
+ };
18
+ }
19
+ return { allowed: true };
20
+ }
21
+
22
+ module.exports = {
23
+ TOOL_ABORTED_BEFORE_DISPATCH,
24
+ checkpointBeforeExternalSideEffect,
25
+ };
@@ -125,6 +125,7 @@ function migrateLegacyStartupPreferences(profileHome, fsImpl = fs) {
125
125
 
126
126
  module.exports = {
127
127
  migrateLegacyStartupPreferences,
128
+ parseStartupPreferences,
128
129
  readStartupPreferences,
129
130
  resolveStartupUiLocale,
130
131
  };
@@ -0,0 +1,141 @@
1
+ 'use strict';
2
+
3
+ const { randomBytes } = require('node:crypto');
4
+ const fs = require('node:fs/promises');
5
+ const path = require('node:path');
6
+
7
+ const WINDOWS_RENAME_RETRY_CODES = new Set(['EACCES', 'EBUSY', 'EPERM']);
8
+ const DEFAULT_WINDOWS_RENAME_DELAYS_MS = Object.freeze([10, 25, 50, 100]);
9
+
10
+ function isAbortError(error) {
11
+ return error instanceof Error && error.name === 'AbortError';
12
+ }
13
+
14
+ function throwIfAborted(signal) {
15
+ if (!signal?.aborted) return;
16
+ const error = new Error('Atomic tool write aborted before publication.');
17
+ error.name = 'AbortError';
18
+ throw error;
19
+ }
20
+
21
+ function isMissing(error) {
22
+ return error?.code === 'ENOENT' || error?.code === 'ENOTDIR';
23
+ }
24
+
25
+ async function existingFileMode(filePath, statFile) {
26
+ try {
27
+ const info = await statFile(filePath);
28
+ if (!info.isFile()) throw Object.assign(new Error(`Cannot replace non-file target: ${filePath}`), { code: 'EISDIR' });
29
+ return typeof info.mode === 'number' ? info.mode & 0o777 : undefined;
30
+ } catch (error) {
31
+ if (isMissing(error)) return undefined;
32
+ throw error;
33
+ }
34
+ }
35
+
36
+ async function resolvePublicationPath(filePath, operations) {
37
+ try {
38
+ return await operations.realpathFile(filePath);
39
+ } catch (error) {
40
+ if (!isMissing(error)) throw error;
41
+ }
42
+
43
+ try {
44
+ const linkInfo = await operations.lstatFile(filePath);
45
+ if (linkInfo.isSymbolicLink()) {
46
+ throw Object.assign(new Error(`Refused atomic replacement through dangling symbolic link: ${filePath}`), { code: 'ELOOP' });
47
+ }
48
+ } catch (error) {
49
+ if (!isMissing(error)) throw error;
50
+ }
51
+
52
+ const realParent = await operations.realpathFile(path.dirname(filePath));
53
+ return path.join(realParent, path.basename(filePath));
54
+ }
55
+
56
+ async function renameWithWindowsRetry(source, target, options) {
57
+ const delays = options.platform === 'win32'
58
+ ? options.windowsRenameDelaysMs
59
+ : [];
60
+ let attempt = 0;
61
+ while (true) {
62
+ try {
63
+ await options.renameFile(source, target);
64
+ return;
65
+ } catch (error) {
66
+ const delayMs = delays[attempt];
67
+ if (delayMs === undefined || !WINDOWS_RENAME_RETRY_CODES.has(error?.code)) throw error;
68
+ attempt += 1;
69
+ throwIfAborted(options.signal);
70
+ await options.sleep(delayMs);
71
+ }
72
+ }
73
+ }
74
+
75
+ async function writeToolTextAtomic(filePath, content, options = {}) {
76
+ if (typeof filePath !== 'string' || filePath.length === 0) throw new TypeError('filePath must be a non-empty string');
77
+ if (typeof content !== 'string' && !Buffer.isBuffer(content)) throw new TypeError('content must be a string or Buffer');
78
+
79
+ const openFile = options.openFile || fs.open;
80
+ const renameFile = options.renameFile || fs.rename;
81
+ const unlinkFile = options.unlinkFile || fs.unlink;
82
+ const statFile = options.statFile || fs.stat;
83
+ const lstatFile = options.lstatFile || fs.lstat;
84
+ const realpathFile = options.realpathFile || fs.realpath;
85
+ const syncHandle = options.syncHandle || ((handle) => handle.sync());
86
+ const sleep = options.sleep || ((delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs)));
87
+ const signal = options.signal;
88
+ const platform = options.platform || process.platform;
89
+ const windowsRenameDelaysMs = options.windowsRenameDelaysMs || DEFAULT_WINDOWS_RENAME_DELAYS_MS;
90
+
91
+ throwIfAborted(signal);
92
+ const publicationPath = await resolvePublicationPath(filePath, { lstatFile, realpathFile });
93
+ const mode = await existingFileMode(publicationPath, statFile);
94
+ const suffix = `${process.pid}.${randomBytes(6).toString('hex')}`;
95
+ const temporaryPath = path.join(path.dirname(publicationPath), `.${path.basename(publicationPath)}.${suffix}.tmp`);
96
+ let handle;
97
+ let published = false;
98
+
99
+ try {
100
+ handle = await openFile(temporaryPath, 'wx', mode ?? 0o666);
101
+ await handle.writeFile(content, typeof content === 'string' ? { encoding: 'utf8', signal } : { signal });
102
+ await syncHandle(handle);
103
+ if (mode !== undefined && platform !== 'win32') await handle.chmod(mode);
104
+ await handle.close();
105
+ handle = undefined;
106
+
107
+ throwIfAborted(signal);
108
+ await renameWithWindowsRetry(temporaryPath, publicationPath, {
109
+ platform,
110
+ renameFile,
111
+ signal,
112
+ sleep,
113
+ windowsRenameDelaysMs,
114
+ });
115
+ published = true;
116
+ return { bytesWritten: Buffer.byteLength(content) };
117
+ } finally {
118
+ if (handle !== undefined) {
119
+ try {
120
+ await handle.close();
121
+ } catch {}
122
+ }
123
+ if (!published) {
124
+ try {
125
+ await unlinkFile(temporaryPath);
126
+ } catch (error) {
127
+ if (!isMissing(error)) {
128
+ // The primary write error remains authoritative; stale temp names are unique and never read.
129
+ }
130
+ }
131
+ }
132
+ }
133
+ }
134
+
135
+ module.exports = {
136
+ DEFAULT_WINDOWS_RENAME_DELAYS_MS,
137
+ WINDOWS_RENAME_RETRY_CODES,
138
+ renameWithWindowsRetry,
139
+ resolvePublicationPath,
140
+ writeToolTextAtomic,
141
+ };
@@ -28,8 +28,10 @@ function hasToolResultOffloadPressure(options = {}) {
28
28
  return hasContextPressure(options);
29
29
  }
30
30
 
31
- function shouldOffloadToolResult(textLength) {
32
- return Number.isFinite(textLength) && textLength > TOOL_RESULT_MAX_CHARS;
31
+ function shouldOffloadToolResult(textLength, options = {}) {
32
+ return Number.isFinite(textLength)
33
+ && textLength > TOOL_RESULT_MAX_CHARS
34
+ && hasToolResultOffloadPressure(options);
33
35
  }
34
36
 
35
37
  function shouldKeepFreshToolResult(toolName) {
@@ -165,33 +167,8 @@ function compactPersistedToolResultReference(content) {
165
167
  }
166
168
 
167
169
  function compactHistoricalSuccessfulToolResults(messages, options = {}) {
168
- if (!Array.isArray(messages) || messages.length === 0) return messages;
169
- if (!hasToolResultOffloadPressure(options)) return messages;
170
-
171
- const recentStart = Math.max(0, messages.length - TOOL_RESULT_SUCCESS_KEEP_RECENT_MESSAGES);
172
- const freshIds = freshToolResultIds(messages);
173
- let changed = false;
174
- const projected = messages.map((message, index) => {
175
- if (
176
- index >= recentStart
177
- || message?.role !== 'tool'
178
- || freshIds.has(message.toolCallId)
179
- || message.isError === true
180
- || !Array.isArray(message.content)
181
- || isPersistedToolResultReference(message.content)
182
- || !message.content.every((part) => part?.type === 'text' && typeof part.text === 'string')
183
- ) return message;
184
-
185
- const textChars = message.content.reduce((total, part) => total + part.text.length, 0);
186
- if (textChars <= TOOL_RESULT_HISTORICAL_SUCCESS_MARKER.length) return message;
187
- changed = true;
188
- return {
189
- ...message,
190
- content: [{ type: 'text', text: TOOL_RESULT_HISTORICAL_SUCCESS_MARKER }],
191
- };
192
- });
193
-
194
- return changed ? projected : messages;
170
+ void options;
171
+ return messages;
195
172
  }
196
173
 
197
174
  function toolCallSignaturesById(messages) {
@@ -280,10 +257,12 @@ function dedupeRepeatedSuccessfulToolResults(sourceMessages, projectedMessages =
280
257
  ...projectedMessage,
281
258
  content: [{ type: 'text', text: reference }],
282
259
  };
283
- projected[newest.index] = {
284
- ...projected[newest.index],
285
- content: sourceMessages[newest.index].content,
286
- };
260
+ if (projected[newest.index] !== sourceMessages[newest.index]) {
261
+ projected[newest.index] = {
262
+ ...projected[newest.index],
263
+ content: sourceMessages[newest.index].content,
264
+ };
265
+ }
287
266
  changed = true;
288
267
  }
289
268