blun-king-cli 9.1.610 → 9.1.612
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 +9 -0
- package/LIESMICH.txt +1 -1
- package/README.md +1 -1
- package/bin/profile-launch.cjs +42 -42
- package/blun.mjs +1771 -1063
- package/package.json +1 -1
- package/telegram-plugin/dist/bridge.mjs +3 -1
- package/telegram-plugin/dist/mcp-server.mjs +9 -0
- package/worker-host.mjs +293 -52
package/worker-host.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// BLUN_BUILD_INPUT_SHA256:
|
|
2
|
+
// BLUN_BUILD_INPUT_SHA256:f9f2527561c5e5ec1afc53eef27313667c4d323a444532439e73a66865340f69
|
|
3
3
|
import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
4
4
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
5
5
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = __cjsShimDirname(__filename);
|
|
7
7
|
import { createRequire } from "node:module";
|
|
8
|
-
import crypto$1, { createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
|
|
8
|
+
import crypto$1, { createHash, createHmac, randomBytes, randomInt, randomUUID } from "node:crypto";
|
|
9
9
|
import * as fs$12 from "node:fs";
|
|
10
10
|
import Kt, { appendFileSync, chmodSync, closeSync, constants, createReadStream, createWriteStream, existsSync, fstatSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, opendirSync, promises, readFileSync, readSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
11
11
|
import * as path$11 from "node:path";
|
|
@@ -1888,6 +1888,9 @@ var FetchTransport = class {
|
|
|
1888
1888
|
const maxRetries = normalizeMaxRetries(requestOptions?.maxRetries);
|
|
1889
1889
|
const requestBytes = exactBodyBytes(init.body);
|
|
1890
1890
|
const requestBreakdown = pathname === "/chat/completions" && requestOptions?.onTransportAttempt !== void 0 && typeof init.body === "string" && requestBytes !== void 0 ? measureSerializedRequest(init.body, requestBytes) : void 0;
|
|
1891
|
+
if (pathname === "/chat/completions" && typeof init.body === "string") try {
|
|
1892
|
+
requestOptions?.onSerializedRequest?.(init.body);
|
|
1893
|
+
} catch {}
|
|
1891
1894
|
let attempt = 0;
|
|
1892
1895
|
while (true) {
|
|
1893
1896
|
const headers = new Headers(init.headers);
|
|
@@ -1896,6 +1899,9 @@ var FetchTransport = class {
|
|
|
1896
1899
|
const startedAt = performance.now();
|
|
1897
1900
|
const startedAtMs = Date.now();
|
|
1898
1901
|
try {
|
|
1902
|
+
try {
|
|
1903
|
+
requestOptions?.onRequestSent?.();
|
|
1904
|
+
} catch {}
|
|
1899
1905
|
const response = await this.fetch(`${this.baseUrl}${pathname}`, {
|
|
1900
1906
|
...init,
|
|
1901
1907
|
headers
|
|
@@ -2648,6 +2654,13 @@ function collectBlunVisionAttachments(messages) {
|
|
|
2648
2654
|
}
|
|
2649
2655
|
return attachments;
|
|
2650
2656
|
}
|
|
2657
|
+
function estimateBlunRequestExtraBytes(tools, messages) {
|
|
2658
|
+
const attachments = collectBlunVisionAttachments(messages);
|
|
2659
|
+
return {
|
|
2660
|
+
toolsBytes: tools.length === 0 ? 0 : Buffer.byteLength(JSON.stringify({ tools: tools.map(convertTool) }), "utf8"),
|
|
2661
|
+
visionBytes: attachments.length === 0 ? 0 : Buffer.byteLength(JSON.stringify({ visionAttachments: attachments }), "utf8")
|
|
2662
|
+
};
|
|
2663
|
+
}
|
|
2651
2664
|
function convertMessage(message) {
|
|
2652
2665
|
let reasoningContent = "";
|
|
2653
2666
|
const nonThinkParts = [];
|
|
@@ -2957,12 +2970,13 @@ var BlunChatProvider = class {
|
|
|
2957
2970
|
if (this._stream) createParams["stream_options"] = { include_usage: true };
|
|
2958
2971
|
try {
|
|
2959
2972
|
const client = this._createClient(options?.auth);
|
|
2960
|
-
const requestOptions = options?.signal !== void 0 || options?.transportMaxRetries !== void 0 || options?.onTransportAttempt !== void 0 ? {
|
|
2973
|
+
const requestOptions = options?.signal !== void 0 || options?.transportMaxRetries !== void 0 || options?.onRequestSent !== void 0 || options?.onSerializedRequest !== void 0 || options?.onTransportAttempt !== void 0 ? {
|
|
2961
2974
|
...options.signal !== void 0 ? { signal: options.signal } : {},
|
|
2962
2975
|
...options.transportMaxRetries !== void 0 ? { maxRetries: options.transportMaxRetries } : {},
|
|
2976
|
+
...options.onRequestSent !== void 0 ? { onRequestSent: options.onRequestSent } : {},
|
|
2977
|
+
...options.onSerializedRequest !== void 0 ? { onSerializedRequest: options.onSerializedRequest } : {},
|
|
2963
2978
|
...options.onTransportAttempt !== void 0 ? { onTransportAttempt: options.onTransportAttempt } : {}
|
|
2964
2979
|
} : void 0;
|
|
2965
|
-
options?.onRequestSent?.();
|
|
2966
2980
|
let response;
|
|
2967
2981
|
try {
|
|
2968
2982
|
response = await client.chat.completions.create(createParams, requestOptions);
|
|
@@ -2971,7 +2985,6 @@ var BlunChatProvider = class {
|
|
|
2971
2985
|
const cap = rejection instanceof APIContextOverflowError ? contextOverflowOutputCap(rejection, createParams["max_completion_tokens"]) : void 0;
|
|
2972
2986
|
if (cap === void 0) throw rejection;
|
|
2973
2987
|
options?.signal?.throwIfAborted();
|
|
2974
|
-
options?.onRequestSent?.();
|
|
2975
2988
|
response = await client.chat.completions.create({
|
|
2976
2989
|
...createParams,
|
|
2977
2990
|
max_completion_tokens: cap
|
|
@@ -21757,10 +21770,15 @@ async function loadAgentsMdForRoots(kaos, brandHome, workDirs) {
|
|
|
21757
21770
|
const discovered = [];
|
|
21758
21771
|
const emptySources = /* @__PURE__ */ new Map();
|
|
21759
21772
|
const seen = /* @__PURE__ */ new Set();
|
|
21773
|
+
const notLoadedCandidates = /* @__PURE__ */ new Set();
|
|
21760
21774
|
const collect = async (path) => {
|
|
21761
21775
|
const file = await readAgentFile(kaos, path);
|
|
21762
|
-
if (file === void 0)
|
|
21776
|
+
if (file === void 0) {
|
|
21777
|
+
notLoadedCandidates.add(kaos.normpath(path));
|
|
21778
|
+
return false;
|
|
21779
|
+
}
|
|
21763
21780
|
const key = kaos.normpath(file.path);
|
|
21781
|
+
notLoadedCandidates.delete(key);
|
|
21764
21782
|
if (file.content.length === 0) {
|
|
21765
21783
|
emptySources.set(key, InstructionText.file(file.path, "", file.sourceTextBytes));
|
|
21766
21784
|
return false;
|
|
@@ -21796,7 +21814,10 @@ async function loadAgentsMdForRoots(kaos, brandHome, workDirs) {
|
|
|
21796
21814
|
return {
|
|
21797
21815
|
content,
|
|
21798
21816
|
warning: totalBytes > AGENTS_MD_RECOMMENDED_MAX_BYTES ? `AGENTS.md total ${formatKB(totalBytes)} KB exceeds the recommended ${formatKB(AGENTS_MD_RECOMMENDED_MAX_BYTES)} KB. Large instruction files increase cost and may impact performance; consider trimming.` : void 0,
|
|
21799
|
-
sources:
|
|
21817
|
+
sources: {
|
|
21818
|
+
...rendered.measure(),
|
|
21819
|
+
...notLoadedCandidates.size === 0 ? {} : { notLoadedCandidates: [...notLoadedCandidates] }
|
|
21820
|
+
}
|
|
21800
21821
|
};
|
|
21801
21822
|
}
|
|
21802
21823
|
async function loadAdditionalDirsInfo(kaos, additionalDirs) {
|
|
@@ -28778,17 +28799,20 @@ function createSystemPromptRenderer(merged) {
|
|
|
28778
28799
|
const counts = renderPromptContributions(merged.systemPromptTemplate, vars, rendered, true) ?? renderPromptContributions(merged.systemPromptTemplate, vars, rendered);
|
|
28779
28800
|
const sources = context.agentsMdSources;
|
|
28780
28801
|
const copies = counts?.instructionCopies ?? 0;
|
|
28781
|
-
const sourceMatches = sources !== void 0 && sources.version === 1 && Number.isSafeInteger(sources.generatedBytes) && sources.generatedBytes >= 0 && sources.files.every((file) => typeof file.path === "string" && Number.isSafeInteger(file.bytes) && file.bytes >= 0) && sources.totalBytes === Buffer.byteLength(vars["BLUN_AGENTS_MD"] ?? "", "utf8") && sources.generatedBytes + sources.files.reduce((sum, file) => sum + file.bytes, 0) === sources.totalBytes;
|
|
28802
|
+
const sourceMatches = sources !== void 0 && sources.version === 1 && Number.isSafeInteger(sources.generatedBytes) && sources.generatedBytes >= 0 && sources.files.every((file) => typeof file.path === "string" && Number.isSafeInteger(file.bytes) && file.bytes >= 0) && (sources.notLoadedCandidates?.every((path) => typeof path === "string") ?? true) && sources.totalBytes === Buffer.byteLength(vars["BLUN_AGENTS_MD"] ?? "", "utf8") && sources.generatedBytes + sources.files.reduce((sum, file) => sum + file.bytes, 0) === sources.totalBytes;
|
|
28803
|
+
const notLoadedCandidates = sourceMatches && sources.notLoadedCandidates !== void 0 ? { notLoadedCandidates: [...sources.notLoadedCandidates] } : {};
|
|
28782
28804
|
const instructionSources = copies === 0 ? {
|
|
28783
28805
|
version: 1,
|
|
28784
28806
|
totalBytes: 0,
|
|
28785
28807
|
generatedBytes: 0,
|
|
28786
|
-
files: sourceMatches ? sources.files.map((file) => copyInstructionFileBytes(file, 0)) : []
|
|
28808
|
+
files: sourceMatches ? sources.files.map((file) => copyInstructionFileBytes(file, 0)) : [],
|
|
28809
|
+
...notLoadedCandidates
|
|
28787
28810
|
} : !sourceMatches ? void 0 : {
|
|
28788
28811
|
version: 1,
|
|
28789
28812
|
totalBytes: sources.totalBytes * copies,
|
|
28790
28813
|
generatedBytes: sources.generatedBytes * copies,
|
|
28791
|
-
files: sources.files.map((file) => copyInstructionFileBytes(file, copies))
|
|
28814
|
+
files: sources.files.map((file) => copyInstructionFileBytes(file, copies)),
|
|
28815
|
+
...notLoadedCandidates
|
|
28792
28816
|
};
|
|
28793
28817
|
const skillListingSources = counts === void 0 ? void 0 : scaleSkillListingSources(skillSources, vars["BLUN_SKILLS"] ?? "", counts.skillListingBytes);
|
|
28794
28818
|
context.onContributions(counts === void 0 ? void 0 : {
|
|
@@ -230115,6 +230139,7 @@ function buildCompactionSummaryText(summary) {
|
|
|
230115
230139
|
const MAX_SESSION_COMPACTION_FAILURES = 2;
|
|
230116
230140
|
const DEFAULT_COMPACTION_MAX_COMPLETION_TOKENS = 128 * 1024;
|
|
230117
230141
|
const COMPACTION_SUMMARY_RESERVE_RATIO = .1;
|
|
230142
|
+
const BLUN_COMPACTION_REQUEST_BUDGET_BYTES = 75e4;
|
|
230118
230143
|
const MAX_HIERARCHICAL_COMPACTION_PASSES = 64;
|
|
230119
230144
|
const HIERARCHICAL_COMPACTION_PREFIX = "This is a complete summary of an earlier chronological segment. Preserve it as source material when merging it with the following conversation:";
|
|
230120
230145
|
var CompactionTruncatedError = class extends Error {
|
|
@@ -230234,16 +230259,19 @@ var FullCompaction = class {
|
|
|
230234
230259
|
const projected = context.additionalMessages === void 0 ? messages : [...messages, ...context.additionalMessages];
|
|
230235
230260
|
const historyBudget = this.requestHistoryByteBudget(projected);
|
|
230236
230261
|
const historyThresholdReached = historyBudget !== void 0 && historyBudget.usedHistoryBytes >= historyBudget.thresholdHistoryBytes;
|
|
230262
|
+
const requestBudget = this.requestBodyByteBudget(projected, context);
|
|
230263
|
+
const requestThresholdReached = requestBudget !== void 0 && requestBudget.usedRequestBytesEstimate >= requestBudget.thresholdRequestBytes;
|
|
230237
230264
|
if (this.sessionCompactionFailures >= MAX_SESSION_COMPACTION_FAILURES) reason = "session_stopped";
|
|
230238
230265
|
else if (this.isCompacting) reason = "already_compacting";
|
|
230239
|
-
else if (thresholdTokens === void 0 && historyBudget === void 0) reason = "no_budget";
|
|
230240
|
-
else if (!historyThresholdReached && (thresholdTokens === void 0 || !Number.isFinite(usedTokens) || usedTokens < thresholdTokens)) reason = "below_threshold";
|
|
230266
|
+
else if (thresholdTokens === void 0 && historyBudget === void 0 && requestBudget === void 0) reason = "no_budget";
|
|
230267
|
+
else if (!historyThresholdReached && !requestThresholdReached && (thresholdTokens === void 0 || !Number.isFinite(usedTokens) || usedTokens < thresholdTokens)) reason = "below_threshold";
|
|
230241
230268
|
else if (!this.hasShrinkableHistory(projected)) reason = "nothing_to_compact";
|
|
230242
230269
|
return {
|
|
230243
230270
|
eligible: reason === "eligible",
|
|
230244
230271
|
usedTokens,
|
|
230245
230272
|
thresholdTokens,
|
|
230246
230273
|
...historyBudget,
|
|
230274
|
+
...requestBudget,
|
|
230247
230275
|
reason
|
|
230248
230276
|
};
|
|
230249
230277
|
}
|
|
@@ -230265,6 +230293,35 @@ var FullCompaction = class {
|
|
|
230265
230293
|
thresholdHistoryBytes: limit
|
|
230266
230294
|
};
|
|
230267
230295
|
}
|
|
230296
|
+
requestBodyByteBudget(messages, context) {
|
|
230297
|
+
const limit = this.agent.blunConfig?.loopControl?.maxRequestHistoryBytes;
|
|
230298
|
+
if (!this.agent.config.hasProvider || this.strategy.compactionBudgetTokens === void 0 || limit === void 0 || !Number.isSafeInteger(limit) || limit <= 0) return void 0;
|
|
230299
|
+
const model = this.agent.activeResponderModel ?? this.agent.config.modelAlias;
|
|
230300
|
+
if (model === void 0 || this.agent.config.runtimeModel(model).provider.name !== "blun") return void 0;
|
|
230301
|
+
const systemPrompt = context.systemPrompt ?? this.agent.effectiveSystemPrompt;
|
|
230302
|
+
const tools = (context.tools ?? this.agent.tools.loopTools).map((tool) => ({
|
|
230303
|
+
name: tool.name,
|
|
230304
|
+
description: tool.description,
|
|
230305
|
+
parameters: tool.parameters
|
|
230306
|
+
}));
|
|
230307
|
+
let extraBytes;
|
|
230308
|
+
try {
|
|
230309
|
+
extraBytes = estimateBlunRequestExtraBytes(tools, messages);
|
|
230310
|
+
} catch {
|
|
230311
|
+
return;
|
|
230312
|
+
}
|
|
230313
|
+
if (Buffer.byteLength(JSON.stringify({
|
|
230314
|
+
systemPrompt,
|
|
230315
|
+
messages: []
|
|
230316
|
+
}), "utf8") + extraBytes.toolsBytes >= BLUN_COMPACTION_REQUEST_BUDGET_BYTES) return void 0;
|
|
230317
|
+
return {
|
|
230318
|
+
usedRequestBytesEstimate: Buffer.byteLength(JSON.stringify({
|
|
230319
|
+
systemPrompt,
|
|
230320
|
+
messages
|
|
230321
|
+
}), "utf8") + extraBytes.toolsBytes + extraBytes.visionBytes,
|
|
230322
|
+
thresholdRequestBytes: BLUN_COMPACTION_REQUEST_BUDGET_BYTES
|
|
230323
|
+
};
|
|
230324
|
+
}
|
|
230268
230325
|
requestProactiveCompaction(context = {}) {
|
|
230269
230326
|
const status = this.proactiveCompactionStatus(context);
|
|
230270
230327
|
if (status.eligible && !this.proactiveCompactionRequested) {
|
|
@@ -230273,7 +230330,9 @@ var FullCompaction = class {
|
|
|
230273
230330
|
used_tokens: status.usedTokens,
|
|
230274
230331
|
threshold_tokens: status.thresholdTokens,
|
|
230275
230332
|
used_history_bytes: status.usedHistoryBytes,
|
|
230276
|
-
threshold_history_bytes: status.thresholdHistoryBytes
|
|
230333
|
+
threshold_history_bytes: status.thresholdHistoryBytes,
|
|
230334
|
+
used_request_bytes_estimate: status.usedRequestBytesEstimate,
|
|
230335
|
+
threshold_request_bytes: status.thresholdRequestBytes
|
|
230277
230336
|
});
|
|
230278
230337
|
}
|
|
230279
230338
|
return status;
|
|
@@ -230402,7 +230461,9 @@ var FullCompaction = class {
|
|
|
230402
230461
|
const requestTokens = this.estimateCurrentRequestTokens(requestContext);
|
|
230403
230462
|
const budget = this.getCompactionBudgetTokens();
|
|
230404
230463
|
const historyBudget = this.requestHistoryByteBudget(projectedMessages);
|
|
230405
|
-
const
|
|
230464
|
+
const historyThresholdReached = historyBudget !== void 0 && historyBudget.usedHistoryBytes >= historyBudget.thresholdHistoryBytes;
|
|
230465
|
+
const requestBudget = this.requestBodyByteBudget(projectedMessages, requestContext);
|
|
230466
|
+
const proactive = (requestBudget !== void 0 && requestBudget.usedRequestBytesEstimate >= requestBudget.thresholdRequestBytes || historyThresholdReached || !this.isCompacting && budget !== void 0 && Number.isFinite(requestTokens) && requestTokens >= Math.max(1, Math.floor(budget * .9))) && this.hasShrinkableHistory(projectedMessages);
|
|
230406
230467
|
if (this.checkAutoCompaction(true, requestTokens, projectedMessages, proactive) && (proactive || this.strategy.shouldBlock(requestTokens))) await this.block(signal);
|
|
230407
230468
|
signal.throwIfAborted();
|
|
230408
230469
|
const compacted = this.agent.context.history !== historyBefore;
|
|
@@ -230604,6 +230665,7 @@ var FullCompaction = class {
|
|
|
230604
230665
|
let charsReceived = 0;
|
|
230605
230666
|
let lastProgressEmitAt = 0;
|
|
230606
230667
|
let initialCompactionRequestTokens;
|
|
230668
|
+
let initialCompactionRequestBytes;
|
|
230607
230669
|
const compactionTools = [];
|
|
230608
230670
|
const buildRequestMessages = (history, requestInstruction) => {
|
|
230609
230671
|
return stripMediaForCompaction(downgradeUnsupportedMedia([...this.agent.context.project(history, {
|
|
@@ -230611,6 +230673,7 @@ var FullCompaction = class {
|
|
|
230611
230673
|
dropOrphanResults: true
|
|
230612
230674
|
}), createUserMessage(requestInstruction)], capability));
|
|
230613
230675
|
};
|
|
230676
|
+
const estimateRequestBytes = (messages) => Buffer.byteLength(JSON.stringify(messages), "utf8") + Buffer.byteLength(this.agent.config.systemPrompt, "utf8");
|
|
230614
230677
|
while (true) {
|
|
230615
230678
|
signal.throwIfAborted();
|
|
230616
230679
|
if (hierarchicalPassCount >= MAX_HIERARCHICAL_COMPACTION_PASSES) throw new BlunError(ErrorCodes.COMPACTION_FAILED, `Compaction stopped after ${String(MAX_HIERARCHICAL_COMPACTION_PASSES)} staged requests without reaching a final summary. The conversation history was not changed.`, { details: {
|
|
@@ -230620,30 +230683,39 @@ var FullCompaction = class {
|
|
|
230620
230683
|
const compactionRequestLimit = this.getEffectiveMaxContextTokens(model);
|
|
230621
230684
|
const safeCompactionRequestLimit = compactionRequestLimit > 0 ? Math.max(1, Math.floor(compactionRequestLimit * (1 - COMPACTION_SUMMARY_RESERVE_RATIO))) : compactionRequestLimit;
|
|
230622
230685
|
let messages = buildRequestMessages(historyForModel, instruction);
|
|
230686
|
+
const requestByteBudget = provider.name === "blun" ? BLUN_COMPACTION_REQUEST_BUDGET_BYTES : void 0;
|
|
230623
230687
|
let estimatedCompactionRequestTokens = this.estimateRequestTokens(messages, this.agent.effectiveSystemPrompt, compactionTools);
|
|
230688
|
+
let estimatedCompactionRequestBytes = requestByteBudget === void 0 ? void 0 : estimateRequestBytes(messages);
|
|
230624
230689
|
initialCompactionRequestTokens ??= estimatedCompactionRequestTokens;
|
|
230690
|
+
initialCompactionRequestBytes ??= estimatedCompactionRequestBytes;
|
|
230625
230691
|
let hierarchicalChunkEnd;
|
|
230626
|
-
|
|
230692
|
+
const tokenBudgetExceeded = safeCompactionRequestLimit > 0 && estimatedCompactionRequestTokens >= safeCompactionRequestLimit;
|
|
230693
|
+
const byteBudgetExceeded = requestByteBudget !== void 0 && estimatedCompactionRequestBytes !== void 0 && estimatedCompactionRequestBytes >= requestByteBudget;
|
|
230694
|
+
if (tokenBudgetExceeded || byteBudgetExceeded) {
|
|
230627
230695
|
if (historyForModel.length > 1) {
|
|
230628
230696
|
const chunkInstruction = `${instruction}\n\nThis request contains only the oldest chronological segment. Summarize every fact needed by a later merge pass. Do not assume later messages are visible.`;
|
|
230629
|
-
const chunk = selectHierarchicalCompactionChunk(historyForModel, safeCompactionRequestLimit, safeCompactionRequestLimit, (candidate) => {
|
|
230697
|
+
const chunk = selectHierarchicalCompactionChunk(historyForModel, safeCompactionRequestLimit, safeCompactionRequestLimit, requestByteBudget, (candidate) => {
|
|
230630
230698
|
const candidateMessages = buildRequestMessages(candidate, chunkInstruction);
|
|
230631
230699
|
return {
|
|
230632
230700
|
messages: candidateMessages,
|
|
230633
|
-
estimatedTokens: this.estimateRequestTokens(candidateMessages, this.agent.effectiveSystemPrompt, compactionTools)
|
|
230701
|
+
estimatedTokens: this.estimateRequestTokens(candidateMessages, this.agent.effectiveSystemPrompt, compactionTools),
|
|
230702
|
+
estimatedBytes: requestByteBudget === void 0 ? void 0 : estimateRequestBytes(candidateMessages)
|
|
230634
230703
|
};
|
|
230635
230704
|
});
|
|
230636
230705
|
if (chunk !== void 0) {
|
|
230637
230706
|
hierarchicalChunkEnd = chunk.end;
|
|
230638
230707
|
messages = chunk.messages;
|
|
230639
230708
|
estimatedCompactionRequestTokens = chunk.estimatedTokens;
|
|
230709
|
+
estimatedCompactionRequestBytes = chunk.estimatedBytes;
|
|
230640
230710
|
}
|
|
230641
230711
|
}
|
|
230642
|
-
if (hierarchicalChunkEnd === void 0) throw new BlunError(ErrorCodes.CONTEXT_OVERFLOW, `Compaction stopped before upload: the conversation (${String(tokensBefore)} tokens) could not be divided into a request below the active model window (${String(compactionRequestLimit)} tokens).`, { details: {
|
|
230712
|
+
if (hierarchicalChunkEnd === void 0) throw new BlunError(ErrorCodes.CONTEXT_OVERFLOW, byteBudgetExceeded ? "Compaction stopped before upload: the conversation could not be divided into a request below the active byte limit." : `Compaction stopped before upload: the conversation (${String(tokensBefore)} tokens) could not be divided into a request below the active model window (${String(compactionRequestLimit)} tokens).`, { details: {
|
|
230643
230713
|
contextBrakeBlocked: true,
|
|
230644
230714
|
estimatedRequestTokens: estimatedCompactionRequestTokens,
|
|
230645
230715
|
maxContextTokens: compactionRequestLimit,
|
|
230646
230716
|
requestBudgetTokens: safeCompactionRequestLimit,
|
|
230717
|
+
estimatedRequestBytes: estimatedCompactionRequestBytes,
|
|
230718
|
+
requestBudgetBytes: requestByteBudget,
|
|
230647
230719
|
summaryReserveTokens: compactionRequestLimit - safeCompactionRequestLimit,
|
|
230648
230720
|
contextUnchanged: true
|
|
230649
230721
|
} });
|
|
@@ -230652,7 +230724,7 @@ var FullCompaction = class {
|
|
|
230652
230724
|
attemptCount += 1;
|
|
230653
230725
|
charsReceived = 0;
|
|
230654
230726
|
const stage = hierarchicalPassCount + 1;
|
|
230655
|
-
const estimatedStageCount = estimateCompactionStageCount(initialCompactionRequestTokens, safeCompactionRequestLimit, stage);
|
|
230727
|
+
const estimatedStageCount = estimateCompactionStageCount(initialCompactionRequestTokens, safeCompactionRequestLimit, stage, initialCompactionRequestBytes, requestByteBudget);
|
|
230656
230728
|
const estimatedProgressPercent = estimateCompactionProgressPercent(stage, estimatedStageCount);
|
|
230657
230729
|
const windowUsagePercent = estimateCompactionWindowUsagePercent(estimatedCompactionRequestTokens, compactionRequestLimit);
|
|
230658
230730
|
this.agent.log.info("compaction stage request", {
|
|
@@ -230661,6 +230733,8 @@ var FullCompaction = class {
|
|
|
230661
230733
|
estimatedStageCount,
|
|
230662
230734
|
activeContextTokens: this.estimateProjectedRequestTokens(),
|
|
230663
230735
|
estimatedInputTokens: estimatedCompactionRequestTokens,
|
|
230736
|
+
estimatedInputBytes: estimatedCompactionRequestBytes,
|
|
230737
|
+
requestBudgetBytes: requestByteBudget,
|
|
230664
230738
|
windowUsagePercent,
|
|
230665
230739
|
safeInputLimitTokens: safeCompactionRequestLimit,
|
|
230666
230740
|
maxContextTokens: compactionRequestLimit
|
|
@@ -230732,13 +230806,17 @@ var FullCompaction = class {
|
|
|
230732
230806
|
if (hierarchicalChunkEnd !== void 0) {
|
|
230733
230807
|
hierarchicalPassCount += 1;
|
|
230734
230808
|
const previousTokens = estimateTokensForMessages(historyForModel);
|
|
230809
|
+
const previousBytes = requestByteBudget === void 0 ? void 0 : Buffer.byteLength(JSON.stringify(historyForModel), "utf8");
|
|
230735
230810
|
const nextHistory = [createUserMessage(`${HIERARCHICAL_COMPACTION_PREFIX}\n${extractedSummary}`), ...historyForModel.slice(hierarchicalChunkEnd)];
|
|
230736
230811
|
const nextTokens = estimateTokensForMessages(nextHistory);
|
|
230737
|
-
|
|
230812
|
+
const nextBytes = requestByteBudget === void 0 ? void 0 : Buffer.byteLength(JSON.stringify(nextHistory), "utf8");
|
|
230813
|
+
if (nextTokens >= previousTokens || previousBytes !== void 0 && nextBytes !== void 0 && nextBytes >= previousBytes) throw new BlunError(ErrorCodes.COMPACTION_FAILED, "A staged compaction response did not reduce the pending history. The conversation history was not changed.", { details: {
|
|
230738
230814
|
contextUnchanged: true,
|
|
230739
230815
|
hierarchicalPassCount,
|
|
230740
230816
|
previousTokens,
|
|
230741
|
-
nextTokens
|
|
230817
|
+
nextTokens,
|
|
230818
|
+
previousBytes,
|
|
230819
|
+
nextBytes
|
|
230742
230820
|
} });
|
|
230743
230821
|
historyForModel = nextHistory;
|
|
230744
230822
|
retryCount = 0;
|
|
@@ -230934,9 +231012,10 @@ function isModelFallbackStatus(error) {
|
|
|
230934
231012
|
function compactionTimingKey(provider) {
|
|
230935
231013
|
return `${provider.name}\u0000${provider.modelName}`;
|
|
230936
231014
|
}
|
|
230937
|
-
function estimateCompactionStageCount(initialInputTokens, safeRequestLimitTokens, currentStage) {
|
|
230938
|
-
|
|
230939
|
-
|
|
231015
|
+
function estimateCompactionStageCount(initialInputTokens, safeRequestLimitTokens, currentStage, initialInputBytes, safeRequestLimitBytes) {
|
|
231016
|
+
const tokenStages = safeRequestLimitTokens > 0 ? Math.ceil(initialInputTokens / safeRequestLimitTokens) : 0;
|
|
231017
|
+
const byteStages = initialInputBytes !== void 0 && safeRequestLimitBytes !== void 0 && safeRequestLimitBytes > 0 ? Math.ceil(initialInputBytes / safeRequestLimitBytes) : 0;
|
|
231018
|
+
return Math.max(currentStage, tokenStages, byteStages);
|
|
230940
231019
|
}
|
|
230941
231020
|
function estimateCompactionProgressPercent(stage, estimatedStageCount) {
|
|
230942
231021
|
if (estimatedStageCount <= 0) return 0;
|
|
@@ -230952,7 +231031,7 @@ const COMPACTION_OVERFLOW_SHRINK_RATIOS = [
|
|
|
230952
231031
|
.5,
|
|
230953
231032
|
.35
|
|
230954
231033
|
];
|
|
230955
|
-
function selectHierarchicalCompactionChunk(history, targetRequestTokens, hardRequestLimit, build) {
|
|
231034
|
+
function selectHierarchicalCompactionChunk(history, targetRequestTokens, hardRequestLimit, requestByteBudget, build) {
|
|
230956
231035
|
const safeEnds = [];
|
|
230957
231036
|
for (let end = 1; end < history.length; end++) if (history[end]?.role !== "tool") safeEnds.push(end);
|
|
230958
231037
|
if (safeEnds.length === 0) return void 0;
|
|
@@ -230964,7 +231043,7 @@ function selectHierarchicalCompactionChunk(history, targetRequestTokens, hardReq
|
|
|
230964
231043
|
const middle = Math.floor((low + high) / 2);
|
|
230965
231044
|
const end = safeEnds[middle];
|
|
230966
231045
|
const request = build(history.slice(0, end));
|
|
230967
|
-
if (request.estimatedTokens < limit) {
|
|
231046
|
+
if (request.estimatedTokens < limit && (requestByteBudget === void 0 || request.estimatedBytes !== void 0 && request.estimatedBytes < requestByteBudget)) {
|
|
230968
231047
|
best = {
|
|
230969
231048
|
end,
|
|
230970
231049
|
...request
|
|
@@ -236771,8 +236850,14 @@ var PersonalMemoryRecallInjector = class {
|
|
|
236771
236850
|
* to read, write, list, or change any personal-memory state.
|
|
236772
236851
|
*/
|
|
236773
236852
|
filterToolsForTurn(turnId, input, origin, tools) {
|
|
236774
|
-
|
|
236775
|
-
|
|
236853
|
+
const brokerAllowed = this.toolsAllowedForTurn(turnId, input, origin);
|
|
236854
|
+
const localSearchAllowed = origin.kind === "user" && this.agent.type === "main" && !isTelegramGroupInput(input) && this.agent.localWorkHistorySearchEligibility?.() === true;
|
|
236855
|
+
return tools.filter((tool) => {
|
|
236856
|
+
if (!isPersonalMemoryToolName(tool.name)) return true;
|
|
236857
|
+
if (isPersonalMemoryRecallToolName(tool.name)) return false;
|
|
236858
|
+
if (tool.name === "mcp__personal-memory__memory_search" && localSearchAllowed) return true;
|
|
236859
|
+
return brokerAllowed && this.isTrustedHostTool(tool.name);
|
|
236860
|
+
});
|
|
236776
236861
|
}
|
|
236777
236862
|
isTrustedHostTool(name) {
|
|
236778
236863
|
const isHostTool = this.agent.isPersonalMemoryHostTool;
|
|
@@ -238951,6 +239036,32 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
238951
239036
|
"suchen"
|
|
238952
239037
|
]);
|
|
238953
239038
|
const TOOL_SEARCH_RELATED_TERM_GROUPS = Object.freeze([
|
|
239039
|
+
Object.freeze([
|
|
239040
|
+
"persist",
|
|
239041
|
+
"save",
|
|
239042
|
+
"speichere",
|
|
239043
|
+
"speichern",
|
|
239044
|
+
"store"
|
|
239045
|
+
]),
|
|
239046
|
+
Object.freeze([
|
|
239047
|
+
"erinnerung",
|
|
239048
|
+
"erinnerungen",
|
|
239049
|
+
"fact",
|
|
239050
|
+
"facts",
|
|
239051
|
+
"fakt",
|
|
239052
|
+
"fakten",
|
|
239053
|
+
"memory",
|
|
239054
|
+
"memories",
|
|
239055
|
+
"merk",
|
|
239056
|
+
"merken",
|
|
239057
|
+
"remember"
|
|
239058
|
+
]),
|
|
239059
|
+
Object.freeze([
|
|
239060
|
+
"note",
|
|
239061
|
+
"notes",
|
|
239062
|
+
"notiz",
|
|
239063
|
+
"notizen"
|
|
239064
|
+
]),
|
|
238954
239065
|
Object.freeze([
|
|
238955
239066
|
"checklist",
|
|
238956
239067
|
"list",
|
|
@@ -239209,7 +239320,7 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239209
239320
|
if (document.nameTokens.has(token)) exactNameMatches += 1;
|
|
239210
239321
|
else if (relatedSearchTerms(token).some((term) => document.nameTokens.has(term))) relatedNameMatches += 1;
|
|
239211
239322
|
}
|
|
239212
|
-
return matchedTokens >= 2 || exactNameMatches >= 1 && score >= 10 || relatedNameMatches >= 1 && score >= 5 ? {
|
|
239323
|
+
return matchedTokens >= 2 || exactNameMatches >= 1 && score >= 10 || queryTokens.length === 1 && relatedNameMatches >= 1 && score >= 5 ? {
|
|
239213
239324
|
name: document.name,
|
|
239214
239325
|
score,
|
|
239215
239326
|
matchedTokens,
|
|
@@ -239230,11 +239341,11 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239230
239341
|
function searchRelatedDeferredTools(tools, query, options = {}) {
|
|
239231
239342
|
const normalized = normalizeDeferredToolQuery(query).toLowerCase();
|
|
239232
239343
|
if (!normalized || normalized.startsWith("select:")) return [];
|
|
239233
|
-
const tokens = normalized.
|
|
239344
|
+
const tokens = normalized.match(/\+?[\p{L}\p{N}_-]+/gu) || [];
|
|
239234
239345
|
const requestedNameTokens = tokens.filter((token) => token.startsWith("+")).map((token) => token.slice(1)).filter(Boolean);
|
|
239235
239346
|
const relaxRequiredNameTokens = options.relaxRequiredNameTokens === true && requestedNameTokens.length > 0;
|
|
239236
239347
|
const requiredNameTokens = relaxRequiredNameTokens ? [] : requestedNameTokens;
|
|
239237
|
-
const searchTokens = [...tokens.filter((token) => !token.startsWith("+")), ...relaxRequiredNameTokens ? requestedNameTokens : []].filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token));
|
|
239348
|
+
const searchTokens = [...tokens.filter((token) => !token.startsWith("+")), ...relaxRequiredNameTokens ? requestedNameTokens : []].filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token) && !TOOL_RANK_STOP_WORDS.has(token));
|
|
239238
239349
|
if (searchTokens.length < 2 && !TOOL_SEARCH_SINGLE_TERM_RELATED_FALLBACKS.has(searchTokens[0])) return [];
|
|
239239
239350
|
const minimumMatchedTokens = searchTokens.length === 1 ? 1 : Math.max(2, Math.ceil(searchTokens.length * .75));
|
|
239240
239351
|
const ranked = tools.map((tool) => {
|
|
@@ -239295,9 +239406,12 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239295
239406
|
const name = String(tool?.name || "").trim();
|
|
239296
239407
|
if (name && !available.has(name)) available.set(name, tool);
|
|
239297
239408
|
}
|
|
239409
|
+
const usedNames = new Set([...selectedTools, ...available.values()].map((tool) => String(tool?.name ?? "")));
|
|
239410
|
+
let loaderName = DEFERRED_TOOL_LOADER_NAME;
|
|
239411
|
+
for (let suffix = 1; usedNames.has(loaderName); suffix += 1) loaderName = `${DEFERRED_TOOL_LOADER_NAME}_${suffix}`;
|
|
239298
239412
|
const deferredCount = available.size;
|
|
239299
239413
|
const loader = {
|
|
239300
|
-
name:
|
|
239414
|
+
name: loaderName,
|
|
239301
239415
|
description: [
|
|
239302
239416
|
`Search ${deferredCount} deferred ${deferredCount === 1 ? "tool schema" : "tool schemas"} without loading all definitions.`,
|
|
239303
239417
|
"Use select:leaf_name for one known tool, plain keywords to search, or +word to require that word in the tool name.",
|
|
@@ -239317,7 +239431,7 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239317
239431
|
const query = normalizeDeferredToolQuery(args?.query);
|
|
239318
239432
|
return {
|
|
239319
239433
|
description: query ? `Searching tool schemas for ${query}` : "Searching tool schemas",
|
|
239320
|
-
approvalRule:
|
|
239434
|
+
approvalRule: loaderName,
|
|
239321
239435
|
execute: async () => {
|
|
239322
239436
|
let matches = searchDeferredTools([...available.values()], query);
|
|
239323
239437
|
let relatedFallback = false;
|
|
@@ -239330,7 +239444,7 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239330
239444
|
relatedFallback = matches.length > 0;
|
|
239331
239445
|
}
|
|
239332
239446
|
if (matches.length === 0) {
|
|
239333
|
-
const alreadyLoaded = query.toLowerCase().startsWith("select:") ? searchDeferredTools(selectedTools.filter((tool) => tool?.name !==
|
|
239447
|
+
const alreadyLoaded = query.toLowerCase().startsWith("select:") ? searchDeferredTools(selectedTools.filter((tool) => tool?.name !== loaderName), query) : [];
|
|
239334
239448
|
if (alreadyLoaded.length === 1) return {
|
|
239335
239449
|
isError: false,
|
|
239336
239450
|
output: `Tool schema already loaded: ${alreadyLoaded[0].name}. Invoke it now.`
|
|
@@ -239340,7 +239454,7 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239340
239454
|
output: [
|
|
239341
239455
|
`No eligible deferred tool is available for: ${query || "[empty query]"}.`,
|
|
239342
239456
|
"Use a loaded alternative or report this integration as unavailable.",
|
|
239343
|
-
|
|
239457
|
+
`${loaderName} remains available for a different tool needed later.`
|
|
239344
239458
|
].join(" ")
|
|
239345
239459
|
};
|
|
239346
239460
|
}
|
|
@@ -250032,6 +250146,9 @@ function logStepTiming(log, turnId, step, response) {
|
|
|
250032
250146
|
streamDurationMs: timing.streamDurationMs,
|
|
250033
250147
|
...timing.serverDecodeMs !== void 0 ? { serverDecodeMs: timing.serverDecodeMs } : {},
|
|
250034
250148
|
...timing.clientConsumeMs !== void 0 ? { clientConsumeMs: timing.clientConsumeMs } : {},
|
|
250149
|
+
inputOtherTokens: response.usage.inputOther,
|
|
250150
|
+
cacheReadTokens: response.usage.inputCacheRead,
|
|
250151
|
+
cacheCreationTokens: response.usage.inputCacheCreation,
|
|
250035
250152
|
outputTokens: response.usage.output
|
|
250036
250153
|
});
|
|
250037
250154
|
}
|
|
@@ -266492,7 +266609,7 @@ var HistoricalToolProjection = class {
|
|
|
266492
266609
|
for (const { index, message, outputPath, text, reference, shellOutput } of candidates) try {
|
|
266493
266610
|
context.signal.throwIfAborted();
|
|
266494
266611
|
if (!await this.canRead(read, outputPath, context)) continue;
|
|
266495
|
-
const save = this.pending.then(() => this.persist(outputPath, text, context.signal));
|
|
266612
|
+
const save = this.pending.then(() => this.persist(outputPath, text, context.signal, true));
|
|
266496
266613
|
this.pending = save.catch(() => void 0);
|
|
266497
266614
|
await save;
|
|
266498
266615
|
const stat = await this.agent.kaos.stat(outputPath);
|
|
@@ -266584,7 +266701,7 @@ var HistoricalToolProjection = class {
|
|
|
266584
266701
|
revision: revision(after)
|
|
266585
266702
|
});
|
|
266586
266703
|
}
|
|
266587
|
-
async persist(path, text, signal) {
|
|
266704
|
+
async persist(path, text, signal, finalVerificationFollows = false) {
|
|
266588
266705
|
signal.throwIfAborted();
|
|
266589
266706
|
await checkedAncestors(dirname(dirname(dirname(path))));
|
|
266590
266707
|
signal.throwIfAborted();
|
|
@@ -266593,7 +266710,7 @@ var HistoricalToolProjection = class {
|
|
|
266593
266710
|
await this.ensureDirectory(dirname(path));
|
|
266594
266711
|
signal.throwIfAborted();
|
|
266595
266712
|
if (this.files.has(path)) {
|
|
266596
|
-
await this.verifyFile(path, text);
|
|
266713
|
+
if (!finalVerificationFollows) await this.verifyFile(path, text);
|
|
266597
266714
|
return;
|
|
266598
266715
|
}
|
|
266599
266716
|
try {
|
|
@@ -267062,7 +267179,7 @@ function blunToolsForOrigin(tools, origin) {
|
|
|
267062
267179
|
* the ordinary permission pipeline.
|
|
267063
267180
|
*/
|
|
267064
267181
|
function blunSelectTurnTools(tools, maxContextTokens, loadedToolNames = /* @__PURE__ */ new Set(), requiredToolNames = /* @__PURE__ */ new Set(), selected = []) {
|
|
267065
|
-
if (estimateTokensForTools(tools) <= (0, import_turn_tool_performance_policy.toolSchemaBudgetTokens)(maxContextTokens) || tools.some(
|
|
267182
|
+
if (estimateTokensForTools(tools) <= (0, import_turn_tool_performance_policy.toolSchemaBudgetTokens)(maxContextTokens) || tools.some(import_turn_tool_performance_policy.isDeferredToolLoader)) {
|
|
267066
267183
|
selected.splice(0, selected.length, ...tools);
|
|
267067
267184
|
return selected;
|
|
267068
267185
|
}
|
|
@@ -267559,6 +267676,7 @@ var TurnFlow = class {
|
|
|
267559
267676
|
const appendedMessage = this.agent.context.history.at(-1);
|
|
267560
267677
|
const turnAnchor = appendedMessage !== previousLastMessage && appendedMessage?.role === "user" && appendedMessage.origin === origin ? appendedMessage : void 0;
|
|
267561
267678
|
const startedAt = Date.now();
|
|
267679
|
+
const preRequestHookStartedAt = performance.now();
|
|
267562
267680
|
let ended;
|
|
267563
267681
|
let blockedByUserPromptHook = false;
|
|
267564
267682
|
let completedStopReason;
|
|
@@ -267584,6 +267702,13 @@ var TurnFlow = class {
|
|
|
267584
267702
|
this.agent.log.warn("Turn-start observation failed");
|
|
267585
267703
|
}
|
|
267586
267704
|
signal.throwIfAborted();
|
|
267705
|
+
if (this.agent.type === "main" && process.env["BLUN_DIAG_PRE_REQUEST_PHASES"] === "1") try {
|
|
267706
|
+
this.agent.log.info("turn pre-request phase", {
|
|
267707
|
+
turnId,
|
|
267708
|
+
phase: "turn-hooks",
|
|
267709
|
+
durationMs: Math.max(0, Math.round(performance.now() - preRequestHookStartedAt))
|
|
267710
|
+
});
|
|
267711
|
+
} catch {}
|
|
267587
267712
|
const stopReason = await this.runStepLoop(turnId, signal, input, origin, turnAnchor, (response) => {
|
|
267588
267713
|
completedResponse = response;
|
|
267589
267714
|
});
|
|
@@ -267753,9 +267878,26 @@ var TurnFlow = class {
|
|
|
267753
267878
|
let stopHookContinuationUsed = false;
|
|
267754
267879
|
let goalOutcomeMessageContinuationUsed = false;
|
|
267755
267880
|
const deduper = new ToolCallDeduplicator({ telemetry: this.agent.telemetry });
|
|
267881
|
+
const diagnosePreRequest = this.agent.type === "main" && process.env["BLUN_DIAG_PRE_REQUEST_PHASES"] === "1";
|
|
267882
|
+
const recordPreRequestPhase = (phase, startedAt) => {
|
|
267883
|
+
if (!diagnosePreRequest) return;
|
|
267884
|
+
try {
|
|
267885
|
+
this.agent.log.info("turn pre-request phase", {
|
|
267886
|
+
turnId,
|
|
267887
|
+
phase,
|
|
267888
|
+
durationMs: Math.max(0, Math.round(performance.now() - startedAt))
|
|
267889
|
+
});
|
|
267890
|
+
} catch {}
|
|
267891
|
+
};
|
|
267892
|
+
let phaseStartedAt = performance.now();
|
|
267756
267893
|
await this.agent.mcp?.waitForInitialLoad(signal);
|
|
267894
|
+
recordPreRequestPhase("mcp-initial-load", phaseStartedAt);
|
|
267895
|
+
phaseStartedAt = performance.now();
|
|
267757
267896
|
const personalMemoryRecall = await this.agent.injection.injectPersonalMemoryForTurn(turnId, input, origin, signal);
|
|
267897
|
+
recordPreRequestPhase("personal-memory-recall", phaseStartedAt);
|
|
267898
|
+
phaseStartedAt = performance.now();
|
|
267758
267899
|
await this.agent.injection.injectGoal();
|
|
267900
|
+
recordPreRequestPhase("goal-injection", phaseStartedAt);
|
|
267759
267901
|
this.setActiveSteerAcceptance(turnId, true);
|
|
267760
267902
|
const turnNeedsThinking = blunTurnNeedsTools(blunThinkingIntentInput(input), origin);
|
|
267761
267903
|
let toolInput = input;
|
|
@@ -267766,12 +267908,14 @@ var TurnFlow = class {
|
|
|
267766
267908
|
const raw = [...this.agent.context.history];
|
|
267767
267909
|
const history = personalMemoryRecall === void 0 ? raw : [...raw, personalMemoryRecall];
|
|
267768
267910
|
const selected = taskToolsNeeded ? history : greetingHistory(history, greetingAnchor);
|
|
267911
|
+
const projectionStartedAt = performance.now();
|
|
267769
267912
|
const projected = await this.historicalToolProjection.project(selected, turnAnchor, tools, {
|
|
267770
267913
|
turnId: String(turnId),
|
|
267771
267914
|
stepNumber: this.currentStep,
|
|
267772
267915
|
signal,
|
|
267773
267916
|
llm: turnLLM
|
|
267774
267917
|
});
|
|
267918
|
+
recordPreRequestPhase("historical-tool-projection", projectionStartedAt);
|
|
267775
267919
|
const current = this.agent.context.history;
|
|
267776
267920
|
if (current.length !== raw.length || current.some((message, index) => message !== raw[index])) {
|
|
267777
267921
|
const latest = personalMemoryRecall === void 0 ? current : [...current, personalMemoryRecall];
|
|
@@ -267782,7 +267926,7 @@ var TurnFlow = class {
|
|
|
267782
267926
|
partialContext = selected.length < history.length || projected.changed;
|
|
267783
267927
|
return projected.history;
|
|
267784
267928
|
};
|
|
267785
|
-
const turnLLM = this.agent.llmForTurn(turnNeedsThinking ? void 0 : "off");
|
|
267929
|
+
const turnLLM = this.agent.llmForTurn(turnNeedsThinking ? void 0 : "off", turnId);
|
|
267786
267930
|
const turnTools = this.agent.tools.captureTurnTools();
|
|
267787
267931
|
while (true) {
|
|
267788
267932
|
signal.throwIfAborted();
|
|
@@ -267792,6 +267936,7 @@ var TurnFlow = class {
|
|
|
267792
267936
|
try {
|
|
267793
267937
|
const selectedTools = [];
|
|
267794
267938
|
this.refreshSelectedTools = (snapshot) => {
|
|
267939
|
+
const selectionStartedAt = performance.now();
|
|
267795
267940
|
if (snapshot.messages.length > 0) toolInput = snapshot.messages.flatMap((message) => message.content);
|
|
267796
267941
|
const eligibleTools = blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, turnTools()), origin);
|
|
267797
267942
|
const intent = blunThinkingIntentInput(toolInput);
|
|
@@ -267804,6 +267949,7 @@ var TurnFlow = class {
|
|
|
267804
267949
|
if (tool !== void 0 && !selectedTools.some((candidate) => candidate.name === name) && estimateTokensForTools([...selectedTools, tool]) <= (0, import_turn_tool_performance_policy.toolSchemaBudgetTokens)(this.agent.config.modelCapabilities?.max_context_tokens)) selectedTools.push(tool);
|
|
267805
267950
|
}
|
|
267806
267951
|
} else selectedTools.splice(0, selectedTools.length, ...eligibleTools.filter((tool) => BLUN_LANGUAGE_REVIEW_TOOL_NAMES.has(tool.name) || BLUN_TELEGRAM_OUTBOUND_TOOL_RE.test(tool.name)));
|
|
267952
|
+
recordPreRequestPhase("tool-selection", selectionStartedAt);
|
|
267807
267953
|
return selectedTools;
|
|
267808
267954
|
};
|
|
267809
267955
|
return (await runTurn({
|
|
@@ -267816,14 +267962,24 @@ var TurnFlow = class {
|
|
|
267816
267962
|
}, completion);
|
|
267817
267963
|
},
|
|
267818
267964
|
llm: turnLLM,
|
|
267819
|
-
buildMessages: async () =>
|
|
267820
|
-
|
|
267821
|
-
|
|
267822
|
-
|
|
267823
|
-
|
|
267824
|
-
|
|
267825
|
-
|
|
267826
|
-
|
|
267965
|
+
buildMessages: async () => {
|
|
267966
|
+
const startedAt = performance.now();
|
|
267967
|
+
const messages = this.agent.context.project(await turnHistory(selectedTools), { dropOrphanResults: true });
|
|
267968
|
+
recordPreRequestPhase("message-build", startedAt);
|
|
267969
|
+
return messages;
|
|
267970
|
+
},
|
|
267971
|
+
buildMessagesStrict: async () => {
|
|
267972
|
+
const startedAt = performance.now();
|
|
267973
|
+
const messages = this.agent.context.project(await turnHistory(selectedTools), {
|
|
267974
|
+
synthesizeMissing: true,
|
|
267975
|
+
dropOrphanResults: true,
|
|
267976
|
+
dedupeDuplicateToolCalls: true,
|
|
267977
|
+
dropLeadingNonUser: true,
|
|
267978
|
+
mergeConsecutiveAssistants: true
|
|
267979
|
+
});
|
|
267980
|
+
recordPreRequestPhase("message-build-strict", startedAt);
|
|
267981
|
+
return messages;
|
|
267982
|
+
},
|
|
267827
267983
|
dispatchEvent: this.buildDispatchEvent(turnId, signal, onFinalResponse, () => partialContext),
|
|
267828
267984
|
tools: selectedTools,
|
|
267829
267985
|
log: this.agent.log,
|
|
@@ -267840,8 +267996,10 @@ var TurnFlow = class {
|
|
|
267840
267996
|
},
|
|
267841
267997
|
hooks: {
|
|
267842
267998
|
beforeStep: async ({ signal: stepSignal, llm }) => {
|
|
267999
|
+
const injectionStartedAt = performance.now();
|
|
267843
268000
|
this.agent.microCompaction.detect();
|
|
267844
268001
|
await this.agent.injection.inject();
|
|
268002
|
+
recordPreRequestPhase("step-injection", injectionStartedAt);
|
|
267845
268003
|
stepSignal.throwIfAborted();
|
|
267846
268004
|
deduper.beginStep();
|
|
267847
268005
|
},
|
|
@@ -271507,8 +271665,13 @@ var LlmRequestLogger = class {
|
|
|
271507
271665
|
toolsEstimatedTokens = 0;
|
|
271508
271666
|
requestSequence = 0;
|
|
271509
271667
|
lastTurnRequest;
|
|
271510
|
-
|
|
271668
|
+
serializedPrefixKey;
|
|
271669
|
+
requestSignatures = /* @__PURE__ */ new Map();
|
|
271670
|
+
prefixComparisons = /* @__PURE__ */ new Map();
|
|
271671
|
+
lastSerializedRequest;
|
|
271672
|
+
constructor(log, serializedPrefixDiagnostic = process.env["BLUN_DIAG_SERIALIZED_PREFIX"] === "1") {
|
|
271511
271673
|
this.log = log;
|
|
271674
|
+
this.serializedPrefixKey = serializedPrefixDiagnostic ? randomBytes(32) : void 0;
|
|
271512
271675
|
}
|
|
271513
271676
|
logRequest(input) {
|
|
271514
271677
|
const sequence = ++this.requestSequence;
|
|
@@ -271525,6 +271688,10 @@ var LlmRequestLogger = class {
|
|
|
271525
271688
|
toolsHash: fingerprint(JSON.stringify(toolSignature(tools)))
|
|
271526
271689
|
};
|
|
271527
271690
|
const signature = JSON.stringify(config);
|
|
271691
|
+
if (this.serializedPrefixKey !== void 0) {
|
|
271692
|
+
this.requestSignatures.set(sequence, signature);
|
|
271693
|
+
if (this.requestSignatures.size > 32) this.requestSignatures.delete(this.requestSignatures.keys().next().value);
|
|
271694
|
+
}
|
|
271528
271695
|
if (signature !== this.lastConfigLogSignature) {
|
|
271529
271696
|
this.lastConfigLogSignature = signature;
|
|
271530
271697
|
this.configRevision++;
|
|
@@ -271554,6 +271721,20 @@ var LlmRequestLogger = class {
|
|
|
271554
271721
|
}
|
|
271555
271722
|
};
|
|
271556
271723
|
if (partialMessageCount > 0) requestFields.partialMessageCount = partialMessageCount;
|
|
271724
|
+
const source = input.systemPromptContributions;
|
|
271725
|
+
if (source?.version === 1 && [
|
|
271726
|
+
source.totalBytes,
|
|
271727
|
+
source.instructionBytes,
|
|
271728
|
+
source.skillListingBytes,
|
|
271729
|
+
source.runtimeMemoryBytes,
|
|
271730
|
+
source.otherBytes
|
|
271731
|
+
].every((value) => Number.isSafeInteger(value) && value >= 0) && source.instructionBytes + source.skillListingBytes + source.runtimeMemoryBytes + source.otherBytes === source.totalBytes && source.totalBytes === Buffer.byteLength(systemPrompt, "utf8")) requestFields.systemPromptSourceBytes = {
|
|
271732
|
+
totalBytes: source.totalBytes,
|
|
271733
|
+
instructionBytes: source.instructionBytes,
|
|
271734
|
+
skillListingBytes: source.skillListingBytes,
|
|
271735
|
+
runtimeMemoryBytes: source.runtimeMemoryBytes,
|
|
271736
|
+
otherBytes: source.otherBytes
|
|
271737
|
+
};
|
|
271557
271738
|
this.log.info("llm request", requestFields);
|
|
271558
271739
|
if (fields?.turnStep !== void 0 && /^\d+\.\d+$/.test(fields.turnStep)) {
|
|
271559
271740
|
const historyTextOrigins = summarizeRequestTextOrigins(messages);
|
|
@@ -271579,10 +271760,51 @@ var LlmRequestLogger = class {
|
|
|
271579
271760
|
getLastTurnRequest() {
|
|
271580
271761
|
return this.lastTurnRequest === void 0 ? void 0 : structuredClone(this.lastTurnRequest);
|
|
271581
271762
|
}
|
|
271763
|
+
get serializedPrefixDiagnosticEnabled() {
|
|
271764
|
+
return this.serializedPrefixKey !== void 0;
|
|
271765
|
+
}
|
|
271766
|
+
observeSerializedRequest(body, fields, sequence) {
|
|
271767
|
+
const key = this.serializedPrefixKey;
|
|
271768
|
+
if (key === void 0 || !/^\d+\.\d+$/.test(fields?.turnStep ?? "")) return;
|
|
271769
|
+
const signature = this.requestSignatures.get(sequence);
|
|
271770
|
+
if (signature === void 0) return;
|
|
271771
|
+
try {
|
|
271772
|
+
const bytes = Buffer.from(body, "utf8");
|
|
271773
|
+
const granularityBytes = 1024;
|
|
271774
|
+
const chunks = [];
|
|
271775
|
+
for (let start = 0; start + granularityBytes <= bytes.length; start += granularityBytes) chunks.push(createHmac("sha256", key).update(bytes.subarray(start, start + granularityBytes)).digest("hex"));
|
|
271776
|
+
const previous = this.lastSerializedRequest;
|
|
271777
|
+
if (previous !== void 0 && previous.signature === signature) {
|
|
271778
|
+
let common = 0;
|
|
271779
|
+
while (common < previous.chunks.length && common < chunks.length && previous.chunks[common] === chunks[common]) common++;
|
|
271780
|
+
this.prefixComparisons.set(sequence, {
|
|
271781
|
+
version: 1,
|
|
271782
|
+
granularityBytes,
|
|
271783
|
+
previousBytes: previous.bytes,
|
|
271784
|
+
currentBytes: bytes.length,
|
|
271785
|
+
commonPrefixBytesLowerBound: common * granularityBytes,
|
|
271786
|
+
previousSequence: previous.sequence,
|
|
271787
|
+
currentSequence: sequence
|
|
271788
|
+
});
|
|
271789
|
+
if (this.prefixComparisons.size > 32) this.prefixComparisons.delete(this.prefixComparisons.keys().next().value);
|
|
271790
|
+
}
|
|
271791
|
+
this.lastSerializedRequest = {
|
|
271792
|
+
sequence,
|
|
271793
|
+
signature,
|
|
271794
|
+
bytes: bytes.length,
|
|
271795
|
+
chunks
|
|
271796
|
+
};
|
|
271797
|
+
} catch {
|
|
271798
|
+
this.lastSerializedRequest = void 0;
|
|
271799
|
+
}
|
|
271800
|
+
}
|
|
271582
271801
|
logTransportAttempt(stats, fields, sequence) {
|
|
271802
|
+
const serializedPrefix = sequence === void 0 ? void 0 : this.prefixComparisons.get(sequence);
|
|
271583
271803
|
this.log.info("llm transport attempt", {
|
|
271584
271804
|
...fields,
|
|
271585
|
-
...stats
|
|
271805
|
+
...stats,
|
|
271806
|
+
...this.serializedPrefixKey === void 0 || sequence === void 0 ? {} : { requestSequence: sequence },
|
|
271807
|
+
...serializedPrefix === void 0 ? {} : { serializedPrefix }
|
|
271586
271808
|
});
|
|
271587
271809
|
if (sequence === void 0 || this.lastTurnRequest?.sequence !== sequence) return;
|
|
271588
271810
|
const breakdown = stats.requestBreakdown;
|
|
@@ -271665,7 +271887,8 @@ function copyContributions(value) {
|
|
|
271665
271887
|
version: source.version,
|
|
271666
271888
|
totalBytes: source.totalBytes,
|
|
271667
271889
|
generatedBytes: source.generatedBytes,
|
|
271668
|
-
files: source.files.map((file) => copyInstructionFileBytes(file))
|
|
271890
|
+
files: source.files.map((file) => copyInstructionFileBytes(file)),
|
|
271891
|
+
...source.notLoadedCandidates === void 0 ? {} : { notLoadedCandidates: [...source.notLoadedCandidates] }
|
|
271669
271892
|
} }
|
|
271670
271893
|
};
|
|
271671
271894
|
}
|
|
@@ -271761,6 +271984,7 @@ var Agent$1 = class {
|
|
|
271761
271984
|
errorMemory;
|
|
271762
271985
|
replayBuilder;
|
|
271763
271986
|
additionalDirs;
|
|
271987
|
+
systemPromptStartedAt = /* @__PURE__ */ new Date();
|
|
271764
271988
|
activeProfile;
|
|
271765
271989
|
brandHome;
|
|
271766
271990
|
_activeResponderModel;
|
|
@@ -271831,6 +272055,7 @@ var Agent$1 = class {
|
|
|
271831
272055
|
}
|
|
271832
272056
|
personalMemoryRecallEligibility = () => this.type === "main" && this.personalMemoryHostCapabilityEnabled;
|
|
271833
272057
|
isPersonalMemoryHostTool = (name) => this.personalMemoryHostCapabilityEnabled && this.tools.hasUserTool(name);
|
|
272058
|
+
localWorkHistorySearchEligibility = () => this.type === "main" && this.tools.hasUserTool("mcp__personal-memory__memory_search");
|
|
271834
272059
|
setPersonalMemoryHostCapability(enabled) {
|
|
271835
272060
|
this.personalMemoryHostCapabilityEnabled = enabled === true;
|
|
271836
272061
|
}
|
|
@@ -271847,6 +272072,7 @@ var Agent$1 = class {
|
|
|
271847
272072
|
const retryScope = providerRetryScope(modelAlias, provider);
|
|
271848
272073
|
await this.providerRetryWait.wait(retryScope, generateOptions?.signal);
|
|
271849
272074
|
const callerTransportAttempt = generateOptions?.onTransportAttempt;
|
|
272075
|
+
const callerSerializedRequest = generateOptions?.onSerializedRequest;
|
|
271850
272076
|
const ownedGenerateOptions = {
|
|
271851
272077
|
...generateOptions,
|
|
271852
272078
|
transportMaxRetries: 0
|
|
@@ -271869,6 +272095,12 @@ var Agent$1 = class {
|
|
|
271869
272095
|
callerTransportAttempt?.(stats);
|
|
271870
272096
|
this.llmRequestLogger.logTransportAttempt(stats, requestLogFields, requestSequence);
|
|
271871
272097
|
},
|
|
272098
|
+
...callerSerializedRequest !== void 0 || this.llmRequestLogger.serializedPrefixDiagnosticEnabled ? { onSerializedRequest: (body) => {
|
|
272099
|
+
try {
|
|
272100
|
+
callerSerializedRequest?.(body);
|
|
272101
|
+
} catch {}
|
|
272102
|
+
this.llmRequestLogger.observeSerializedRequest(body, requestLogFields, requestSequence);
|
|
272103
|
+
} } : {},
|
|
271872
272104
|
onRequestStart: () => {
|
|
271873
272105
|
requestOptions?.onRequestStart?.();
|
|
271874
272106
|
requestStarted = true;
|
|
@@ -271894,7 +272126,7 @@ var Agent$1 = class {
|
|
|
271894
272126
|
get llm() {
|
|
271895
272127
|
return this.llmForTurn();
|
|
271896
272128
|
}
|
|
271897
|
-
llmForTurn(thinkingEffort) {
|
|
272129
|
+
llmForTurn(thinkingEffort, diagnosticTurnId) {
|
|
271898
272130
|
const selectedAlias = this.config.model;
|
|
271899
272131
|
const modelProvider = this.modelProvider;
|
|
271900
272132
|
if (modelProvider === void 0) throw new BlunError(ErrorCodes.MODEL_NOT_CONFIGURED, "Provider not set");
|
|
@@ -271909,6 +272141,7 @@ var Agent$1 = class {
|
|
|
271909
272141
|
messages: await rebuildMessages()
|
|
271910
272142
|
};
|
|
271911
272143
|
let systemPrompt = this.effectiveSystemPrompt;
|
|
272144
|
+
const preflightStartedAt = performance.now();
|
|
271912
272145
|
const compacted = await this.fullCompaction.beforeStep(params.signal, {
|
|
271913
272146
|
messages: params.messages,
|
|
271914
272147
|
additionalMessages: steers.messages,
|
|
@@ -271917,6 +272150,13 @@ var Agent$1 = class {
|
|
|
271917
272150
|
rebuildSystemPrompt: () => systemPrompt = this.effectiveSystemPrompt,
|
|
271918
272151
|
tools: params.tools
|
|
271919
272152
|
});
|
|
272153
|
+
if (this.type === "main" && diagnosticTurnId !== void 0 && process.env["BLUN_DIAG_PRE_REQUEST_PHASES"] === "1") try {
|
|
272154
|
+
this.log.info("turn pre-request phase", {
|
|
272155
|
+
turnId: diagnosticTurnId,
|
|
272156
|
+
phase: "compaction-preflight",
|
|
272157
|
+
durationMs: Math.max(0, Math.round(performance.now() - preflightStartedAt))
|
|
272158
|
+
});
|
|
272159
|
+
} catch {}
|
|
271920
272160
|
const tools = params.tools.some((tool) => tool.name === "CompactConversation") && !this.fullCompaction.proactiveCompactionStatus({
|
|
271921
272161
|
messages: compacted ? await rebuildMessages() : params.messages,
|
|
271922
272162
|
additionalMessages: steers.messages,
|
|
@@ -272021,6 +272261,7 @@ var Agent$1 = class {
|
|
|
272021
272261
|
let contributions;
|
|
272022
272262
|
const systemPrompt = profile.systemPrompt({
|
|
272023
272263
|
osEnv: this.kaos.osEnv,
|
|
272264
|
+
now: this.systemPromptStartedAt,
|
|
272024
272265
|
cwd: this.config.cwd,
|
|
272025
272266
|
skills: this.skills?.registry,
|
|
272026
272267
|
cwdListing: context?.cwdListing,
|