blun-king-cli 9.1.614 → 9.1.616
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 +15 -0
- package/LIESMICH.txt +1 -1
- package/README.md +1 -1
- package/bin/managed-plugin-selection.cjs +15 -8
- package/bin/plugin-bootstrap.js +40 -17
- package/bin/private-paths.js +10 -2
- package/bin/profile-launch.cjs +84 -6
- package/blun.mjs +2602 -1338
- package/codebase-index/codebase_index.py +25 -17
- package/package.json +1 -1
- package/telegram-plugin/dist/bridge.mjs +54 -213
- package/telegram-plugin/dist/mcp-server.mjs +62 -14
- package/telegram-plugin/dist/noise.mjs +9 -1
- package/worker-host.mjs +1883 -695
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:8034cba54fd011bf9ce255483d60f6d12f8cdb9862b405ccf424ae40ac14b7c5
|
|
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";
|
|
@@ -14,13 +14,14 @@ import { Blob as Blob$1, File as File$1 } from "node:buffer";
|
|
|
14
14
|
import fs, { access, appendFile, chmod, copyFile, cp, link, lstat, mkdir, mkdtemp, open, readFile, readdir, readlink, realpath, rename, rm, rmdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
15
15
|
import * as nodeOs from "node:os";
|
|
16
16
|
import os, { arch, homedir, hostname, release, tmpdir, type, userInfo } from "node:os";
|
|
17
|
-
import { execFile, execFileSync, spawn
|
|
17
|
+
import { execFile, execFileSync, spawn } from "node:child_process";
|
|
18
18
|
import { Worker } from "node:worker_threads";
|
|
19
19
|
import * as sysPath from "path";
|
|
20
20
|
import path$1, { dirname as dirname$1, parse as parse$1 } from "path";
|
|
21
21
|
import I, { existsSync as existsSync$1, promises as promises$1, stat as stat$1, unwatchFile, watch, watchFile } from "fs";
|
|
22
22
|
import zi from "assert";
|
|
23
23
|
import Qr, { EventEmitter } from "events";
|
|
24
|
+
import { StringDecoder } from "node:string_decoder";
|
|
24
25
|
import { lstat as lstat$1, open as open$1, readdir as readdir$1, realpath as realpath$1, stat as stat$2 } from "fs/promises";
|
|
25
26
|
import Cs, { PassThrough, Readable, pipeline } from "node:stream";
|
|
26
27
|
import { type as type$1 } from "os";
|
|
@@ -35,7 +36,6 @@ import * as win32Path from "node:path/win32";
|
|
|
35
36
|
import { createServer } from "node:http";
|
|
36
37
|
import { pipeline as pipeline$1 } from "node:stream/promises";
|
|
37
38
|
import { EventEmitter as EventEmitter$1 } from "node:events";
|
|
38
|
-
import { StringDecoder } from "node:string_decoder";
|
|
39
39
|
import co from "node:assert";
|
|
40
40
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
41
41
|
import { QuickJSAsyncWASMModule, RELEASE_ASYNC, newQuickJSAsyncWASMModule, shouldInterruptAfterDeadline } from "quickjs-emscripten";
|
|
@@ -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
|
|
@@ -1953,16 +1959,6 @@ function measureSerializedRequest(body, requestBytes) {
|
|
|
1953
1959
|
const payload = parsed;
|
|
1954
1960
|
const messages = Array.isArray(payload["messages"]) ? payload["messages"] : [];
|
|
1955
1961
|
const tools = Array.isArray(payload["tools"]) ? payload["tools"] : void 0;
|
|
1956
|
-
let systemMessageBytes = 0;
|
|
1957
|
-
let conversationMessageBytes = 0;
|
|
1958
|
-
let toolResultMessageBytes = 0;
|
|
1959
|
-
for (const message of messages) {
|
|
1960
|
-
const size = Buffer.byteLength(JSON.stringify(message), "utf8");
|
|
1961
|
-
const role = message !== null && typeof message === "object" ? message["role"] : void 0;
|
|
1962
|
-
if (role === "system" || role === "developer") systemMessageBytes += size;
|
|
1963
|
-
else if (role === "tool") toolResultMessageBytes += size;
|
|
1964
|
-
else conversationMessageBytes += size;
|
|
1965
|
-
}
|
|
1966
1962
|
const toolDefinitions = Object.freeze((tools ?? []).map((tool, index) => {
|
|
1967
1963
|
const entry = tool !== null && typeof tool === "object" ? tool : void 0;
|
|
1968
1964
|
const fn = entry?.["function"];
|
|
@@ -1973,6 +1969,44 @@ function measureSerializedRequest(body, requestBytes) {
|
|
|
1973
1969
|
...typeof name === "string" && name.length > 0 && name.length <= 128 ? { name } : {}
|
|
1974
1970
|
});
|
|
1975
1971
|
}));
|
|
1972
|
+
const declaredNames = new Set(toolDefinitions.flatMap((tool) => tool.name === void 0 ? [] : [tool.name]));
|
|
1973
|
+
const callNames = /* @__PURE__ */ new Map();
|
|
1974
|
+
for (const message of messages) {
|
|
1975
|
+
if (message === null || typeof message !== "object" || message["role"] !== "assistant") continue;
|
|
1976
|
+
const calls = message["tool_calls"];
|
|
1977
|
+
if (!Array.isArray(calls)) continue;
|
|
1978
|
+
for (const call of calls) {
|
|
1979
|
+
if (call === null || typeof call !== "object") continue;
|
|
1980
|
+
const entry = call;
|
|
1981
|
+
const fn = entry["function"];
|
|
1982
|
+
const name = fn !== null && typeof fn === "object" ? fn["name"] : void 0;
|
|
1983
|
+
const id = entry["id"];
|
|
1984
|
+
if (typeof id !== "string" || id.length === 0) continue;
|
|
1985
|
+
callNames.set(id, callNames.has(id) ? void 0 : typeof name === "string" && declaredNames.has(name) ? name : void 0);
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
let systemMessageBytes = 0;
|
|
1989
|
+
let conversationMessageBytes = 0;
|
|
1990
|
+
let toolResultMessageBytes = 0;
|
|
1991
|
+
const results = /* @__PURE__ */ new Map();
|
|
1992
|
+
for (const message of messages) {
|
|
1993
|
+
const size = Buffer.byteLength(JSON.stringify(message), "utf8");
|
|
1994
|
+
const role = message !== null && typeof message === "object" ? message["role"] : void 0;
|
|
1995
|
+
if (role === "system" || role === "developer") systemMessageBytes += size;
|
|
1996
|
+
else if (role === "tool") {
|
|
1997
|
+
toolResultMessageBytes += size;
|
|
1998
|
+
const id = message["tool_call_id"];
|
|
1999
|
+
const name = typeof id === "string" ? callNames.get(id) : void 0;
|
|
2000
|
+
const key = name ?? "";
|
|
2001
|
+
const previous = results.get(key);
|
|
2002
|
+
results.set(key, {
|
|
2003
|
+
...name === void 0 ? {} : { name },
|
|
2004
|
+
count: (previous?.count ?? 0) + 1,
|
|
2005
|
+
bytes: (previous?.bytes ?? 0) + size
|
|
2006
|
+
});
|
|
2007
|
+
} else conversationMessageBytes += size;
|
|
2008
|
+
}
|
|
2009
|
+
const toolResultByTool = Object.freeze(Array.from(results.values(), (entry) => Object.freeze(entry)));
|
|
1976
2010
|
const toolArrayOverheadBytes = tools === void 0 ? 0 : 2 + Math.max(0, tools.length - 1);
|
|
1977
2011
|
const toolSchemaBytes = toolDefinitions.reduce((sum, tool) => sum + tool.bytes, toolArrayOverheadBytes);
|
|
1978
2012
|
return Object.freeze({
|
|
@@ -1982,6 +2016,7 @@ function measureSerializedRequest(body, requestBytes) {
|
|
|
1982
2016
|
systemMessageBytes,
|
|
1983
2017
|
conversationMessageBytes,
|
|
1984
2018
|
toolResultMessageBytes,
|
|
2019
|
+
...toolResultByTool.length === 0 ? {} : { toolResultByTool },
|
|
1985
2020
|
toolSchemaBytes,
|
|
1986
2021
|
toolDefinitions,
|
|
1987
2022
|
toolArrayOverheadBytes,
|
|
@@ -2366,6 +2401,9 @@ function extractChatCompletionUsage(usage) {
|
|
|
2366
2401
|
const value = usage;
|
|
2367
2402
|
const promptTokens = typeof value["prompt_tokens"] === "number" ? value["prompt_tokens"] : 0;
|
|
2368
2403
|
const completionTokens = typeof value["completion_tokens"] === "number" ? value["completion_tokens"] : 0;
|
|
2404
|
+
const completionDetails = value["completion_tokens_details"];
|
|
2405
|
+
const reportedReasoning = completionDetails !== null && typeof completionDetails === "object" ? completionDetails["reasoning_tokens"] : void 0;
|
|
2406
|
+
const outputReasoning = typeof reportedReasoning === "number" && Number.isSafeInteger(reportedReasoning) && reportedReasoning >= 0 && reportedReasoning <= completionTokens ? reportedReasoning : void 0;
|
|
2369
2407
|
let cachedTokens = 0;
|
|
2370
2408
|
if (typeof value["cached_tokens"] === "number") cachedTokens = value["cached_tokens"];
|
|
2371
2409
|
else if (value["prompt_tokens_details"] !== null && typeof value["prompt_tokens_details"] === "object") {
|
|
@@ -2375,6 +2413,7 @@ function extractChatCompletionUsage(usage) {
|
|
|
2375
2413
|
return {
|
|
2376
2414
|
inputOther: promptTokens - cachedTokens,
|
|
2377
2415
|
output: completionTokens,
|
|
2416
|
+
...outputReasoning === void 0 ? {} : { outputReasoning },
|
|
2378
2417
|
inputCacheRead: cachedTokens,
|
|
2379
2418
|
inputCacheCreation: 0
|
|
2380
2419
|
};
|
|
@@ -2648,6 +2687,23 @@ function collectBlunVisionAttachments(messages) {
|
|
|
2648
2687
|
}
|
|
2649
2688
|
return attachments;
|
|
2650
2689
|
}
|
|
2690
|
+
function estimateBlunSerializedBodyBytes(systemPrompt, tools, history) {
|
|
2691
|
+
const normalizedHistory = normalizeToolCallIdsForProvider([...history], BLUN_TOOL_CALL_ID_POLICY);
|
|
2692
|
+
const messages = systemPrompt ? [{
|
|
2693
|
+
role: "system",
|
|
2694
|
+
content: systemPrompt
|
|
2695
|
+
}] : [];
|
|
2696
|
+
for (const message of normalizedHistory) if (!isEmptyAssistantHistoryMessage(message)) messages.push(convertMessage(message));
|
|
2697
|
+
const attachments = collectBlunVisionAttachments(normalizedHistory);
|
|
2698
|
+
return Buffer.byteLength(JSON.stringify({
|
|
2699
|
+
model: "king",
|
|
2700
|
+
messages,
|
|
2701
|
+
stream: true,
|
|
2702
|
+
...tools.length > 0 ? { tools: tools.map(convertTool) } : {},
|
|
2703
|
+
...attachments.length > 0 ? { visionAttachments: attachments } : {},
|
|
2704
|
+
stream_options: { include_usage: true }
|
|
2705
|
+
}), "utf8");
|
|
2706
|
+
}
|
|
2651
2707
|
function convertMessage(message) {
|
|
2652
2708
|
let reasoningContent = "";
|
|
2653
2709
|
const nonThinkParts = [];
|
|
@@ -2957,12 +3013,13 @@ var BlunChatProvider = class {
|
|
|
2957
3013
|
if (this._stream) createParams["stream_options"] = { include_usage: true };
|
|
2958
3014
|
try {
|
|
2959
3015
|
const client = this._createClient(options?.auth);
|
|
2960
|
-
const requestOptions = options?.signal !== void 0 || options?.transportMaxRetries !== void 0 || options?.onTransportAttempt !== void 0 ? {
|
|
3016
|
+
const requestOptions = options?.signal !== void 0 || options?.transportMaxRetries !== void 0 || options?.onRequestSent !== void 0 || options?.onSerializedRequest !== void 0 || options?.onTransportAttempt !== void 0 ? {
|
|
2961
3017
|
...options.signal !== void 0 ? { signal: options.signal } : {},
|
|
2962
3018
|
...options.transportMaxRetries !== void 0 ? { maxRetries: options.transportMaxRetries } : {},
|
|
3019
|
+
...options.onRequestSent !== void 0 ? { onRequestSent: options.onRequestSent } : {},
|
|
3020
|
+
...options.onSerializedRequest !== void 0 ? { onSerializedRequest: options.onSerializedRequest } : {},
|
|
2963
3021
|
...options.onTransportAttempt !== void 0 ? { onTransportAttempt: options.onTransportAttempt } : {}
|
|
2964
3022
|
} : void 0;
|
|
2965
|
-
options?.onRequestSent?.();
|
|
2966
3023
|
let response;
|
|
2967
3024
|
try {
|
|
2968
3025
|
response = await client.chat.completions.create(createParams, requestOptions);
|
|
@@ -2971,7 +3028,6 @@ var BlunChatProvider = class {
|
|
|
2971
3028
|
const cap = rejection instanceof APIContextOverflowError ? contextOverflowOutputCap(rejection, createParams["max_completion_tokens"]) : void 0;
|
|
2972
3029
|
if (cap === void 0) throw rejection;
|
|
2973
3030
|
options?.signal?.throwIfAborted();
|
|
2974
|
-
options?.onRequestSent?.();
|
|
2975
3031
|
response = await client.chat.completions.create({
|
|
2976
3032
|
...createParams,
|
|
2977
3033
|
max_completion_tokens: cap
|
|
@@ -3358,9 +3414,11 @@ function emptyUsage() {
|
|
|
3358
3414
|
* Sum two TokenUsage values.
|
|
3359
3415
|
*/
|
|
3360
3416
|
function addUsage(a, b) {
|
|
3417
|
+
const outputReasoning = a.outputReasoning !== void 0 && b.outputReasoning !== void 0 ? a.outputReasoning + b.outputReasoning : a.output === 0 ? b.outputReasoning : b.output === 0 ? a.outputReasoning : void 0;
|
|
3361
3418
|
return {
|
|
3362
3419
|
inputOther: a.inputOther + b.inputOther,
|
|
3363
3420
|
output: a.output + b.output,
|
|
3421
|
+
...outputReasoning === void 0 ? {} : { outputReasoning },
|
|
3364
3422
|
inputCacheRead: a.inputCacheRead + b.inputCacheRead,
|
|
3365
3423
|
inputCacheCreation: a.inputCacheCreation + b.inputCacheCreation
|
|
3366
3424
|
};
|
|
@@ -9770,6 +9828,8 @@ const StringRecordSchema = record$2(string(), string());
|
|
|
9770
9828
|
const ProviderConfigSchema = object({
|
|
9771
9829
|
type: ProviderTypeSchema,
|
|
9772
9830
|
apiKey: string().optional(),
|
|
9831
|
+
memoryWorkspaceId: string().regex(/^blun-[0-9a-f]{64}$/u).optional(),
|
|
9832
|
+
memoryApiKeyHash: string().regex(/^[0-9a-f]{64}$/u).optional(),
|
|
9773
9833
|
baseUrl: string().optional(),
|
|
9774
9834
|
defaultModel: string().optional(),
|
|
9775
9835
|
oauth: OAuthRefSchema.optional(),
|
|
@@ -10121,7 +10181,17 @@ async function canonicalWriterPath(target) {
|
|
|
10121
10181
|
async function readOwner(lockDirectory) {
|
|
10122
10182
|
const directory = await lstat(lockDirectory);
|
|
10123
10183
|
if (!directory.isDirectory() || directory.isSymbolicLink()) throw unavailable();
|
|
10124
|
-
|
|
10184
|
+
let names;
|
|
10185
|
+
try {
|
|
10186
|
+
names = await readdir(lockDirectory);
|
|
10187
|
+
} catch (error) {
|
|
10188
|
+
if (process.platform === "win32" && codeOf(error) === "EPERM") try {
|
|
10189
|
+
await lstat(lockDirectory);
|
|
10190
|
+
} catch (inspectionError) {
|
|
10191
|
+
if (codeOf(inspectionError) === "ENOENT") throw inspectionError;
|
|
10192
|
+
}
|
|
10193
|
+
throw error;
|
|
10194
|
+
}
|
|
10125
10195
|
if (names.length === 0) return void 0;
|
|
10126
10196
|
const name = names[0];
|
|
10127
10197
|
const match = markerPattern.exec(name);
|
|
@@ -10196,7 +10266,10 @@ async function reclaimDeadOwner(lockDirectory) {
|
|
|
10196
10266
|
}
|
|
10197
10267
|
}
|
|
10198
10268
|
/** A local-host writer claim. It never expires based on age or missed heartbeats. */
|
|
10199
|
-
async function acquireSessionWriter(sessionDirectory) {
|
|
10269
|
+
async function acquireSessionWriter(sessionDirectory, options = {}) {
|
|
10270
|
+
const waitForBusyMs = options.waitForBusyMs ?? 0;
|
|
10271
|
+
if (!Number.isFinite(waitForBusyMs) || waitForBusyMs < 0 || waitForBusyMs > 5e3) throw new RangeError("Writer contention budget must be between 0 and 5000 milliseconds");
|
|
10272
|
+
const deadline = performance.now() + waitForBusyMs;
|
|
10200
10273
|
let staged;
|
|
10201
10274
|
let name;
|
|
10202
10275
|
try {
|
|
@@ -10215,7 +10288,8 @@ async function acquireSessionWriter(sessionDirectory) {
|
|
|
10215
10288
|
flag: "wx",
|
|
10216
10289
|
mode: 384
|
|
10217
10290
|
});
|
|
10218
|
-
|
|
10291
|
+
let unownedCollisions = 0;
|
|
10292
|
+
for (;;) {
|
|
10219
10293
|
try {
|
|
10220
10294
|
await rename(staged, lockDirectory);
|
|
10221
10295
|
} catch (error) {
|
|
@@ -10225,7 +10299,19 @@ async function acquireSessionWriter(sessionDirectory) {
|
|
|
10225
10299
|
"EPERM",
|
|
10226
10300
|
"EACCES"
|
|
10227
10301
|
].includes(codeOf(error) ?? "")) throw error;
|
|
10228
|
-
|
|
10302
|
+
try {
|
|
10303
|
+
await reclaimDeadOwner(lockDirectory);
|
|
10304
|
+
} catch (ownershipError) {
|
|
10305
|
+
if (!(ownershipError instanceof BlunError) || ownershipError.code !== ErrorCodes.SESSION_WRITER_BUSY) throw ownershipError;
|
|
10306
|
+
const remaining = deadline - performance.now();
|
|
10307
|
+
if (waitForBusyMs === 0 || remaining <= 0) throw ownershipError;
|
|
10308
|
+
await new Promise((resolve) => {
|
|
10309
|
+
setTimeout(resolve, Math.min(25, remaining));
|
|
10310
|
+
});
|
|
10311
|
+
unownedCollisions = 0;
|
|
10312
|
+
continue;
|
|
10313
|
+
}
|
|
10314
|
+
if (++unownedCollisions >= 8) throw unavailable();
|
|
10229
10315
|
continue;
|
|
10230
10316
|
}
|
|
10231
10317
|
let released = false;
|
|
@@ -10248,7 +10334,6 @@ async function acquireSessionWriter(sessionDirectory) {
|
|
|
10248
10334
|
}
|
|
10249
10335
|
};
|
|
10250
10336
|
}
|
|
10251
|
-
throw unavailable();
|
|
10252
10337
|
} catch (error) {
|
|
10253
10338
|
if (error instanceof BlunError) throw error;
|
|
10254
10339
|
throw unavailable(error);
|
|
@@ -10318,7 +10403,8 @@ function tokenToWire(token) {
|
|
|
10318
10403
|
expires_at: token.expiresAt,
|
|
10319
10404
|
scope: token.scope,
|
|
10320
10405
|
token_type: token.tokenType,
|
|
10321
|
-
expires_in: token.expiresIn
|
|
10406
|
+
expires_in: token.expiresIn,
|
|
10407
|
+
...token.memoryWorkspaceId === void 0 ? {} : { memory_workspace_id: token.memoryWorkspaceId }
|
|
10322
10408
|
};
|
|
10323
10409
|
}
|
|
10324
10410
|
function tokenFromWire(wire) {
|
|
@@ -10328,7 +10414,8 @@ function tokenFromWire(wire) {
|
|
|
10328
10414
|
expiresAt: typeof wire.expires_at === "number" ? wire.expires_at : 0,
|
|
10329
10415
|
scope: wire.scope ?? "",
|
|
10330
10416
|
tokenType: wire.token_type ?? "",
|
|
10331
|
-
expiresIn: typeof wire.expires_in === "number" ? wire.expires_in : 0
|
|
10417
|
+
expiresIn: typeof wire.expires_in === "number" ? wire.expires_in : 0,
|
|
10418
|
+
...typeof wire.memory_workspace_id === "string" && wire.memory_workspace_id.length > 0 ? { memoryWorkspaceId: wire.memory_workspace_id } : {}
|
|
10332
10419
|
};
|
|
10333
10420
|
}
|
|
10334
10421
|
//#endregion
|
|
@@ -12719,6 +12806,27 @@ var OAuthManager = class {
|
|
|
12719
12806
|
const state = await this.loadState();
|
|
12720
12807
|
return state.kind === "valid" ? state.token.accessToken : void 0;
|
|
12721
12808
|
}
|
|
12809
|
+
async getCachedMemoryWorkspaceId() {
|
|
12810
|
+
const state = await this.loadState();
|
|
12811
|
+
return state.kind === "valid" && state.token.expiresAt > this.now() ? state.token.memoryWorkspaceId : void 0;
|
|
12812
|
+
}
|
|
12813
|
+
async cacheMemoryWorkspaceId(workspaceId) {
|
|
12814
|
+
if (workspaceId.length === 0) return false;
|
|
12815
|
+
const release = await this.acquireRefreshLock();
|
|
12816
|
+
try {
|
|
12817
|
+
const state = await this.loadState();
|
|
12818
|
+
if (state.kind !== "valid" || state.token.expiresAt <= this.now()) return false;
|
|
12819
|
+
if (state.token.memoryWorkspaceId === workspaceId) return true;
|
|
12820
|
+
if (state.token.memoryWorkspaceId !== void 0) return false;
|
|
12821
|
+
await this.storage.save(this.config.name, {
|
|
12822
|
+
...state.token,
|
|
12823
|
+
memoryWorkspaceId: workspaceId
|
|
12824
|
+
});
|
|
12825
|
+
return true;
|
|
12826
|
+
} finally {
|
|
12827
|
+
await release();
|
|
12828
|
+
}
|
|
12829
|
+
}
|
|
12722
12830
|
async logout() {
|
|
12723
12831
|
await this.inFlightRefresh?.promise.catch(() => void 0);
|
|
12724
12832
|
const release = await this.acquireRefreshLock();
|
|
@@ -12786,7 +12894,10 @@ var OAuthManager = class {
|
|
|
12786
12894
|
if (activeToken.refreshToken.length === 0) throw new OAuthUnauthorizedError(`Token for "${this.config.name}" has no refresh_token; re-login required.`);
|
|
12787
12895
|
try {
|
|
12788
12896
|
const refreshed = await this.refreshImpl(this.config, activeToken.refreshToken);
|
|
12789
|
-
await this.storage.save(this.config.name,
|
|
12897
|
+
await this.storage.save(this.config.name, {
|
|
12898
|
+
...refreshed,
|
|
12899
|
+
memoryWorkspaceId: activeToken.memoryWorkspaceId
|
|
12900
|
+
});
|
|
12790
12901
|
this.notifyRefresh({ success: true });
|
|
12791
12902
|
return refreshed.accessToken;
|
|
12792
12903
|
} catch (error) {
|
|
@@ -14163,6 +14274,16 @@ var BlunOAuthToolkit = class {
|
|
|
14163
14274
|
hasToken: await this.managerFor(name, oauthKey, oauthHost).hasToken()
|
|
14164
14275
|
}] };
|
|
14165
14276
|
}
|
|
14277
|
+
async getCachedMemoryWorkspaceId(oauthRef) {
|
|
14278
|
+
const oauthHost = this.oauthHostFor(oauthRef);
|
|
14279
|
+
const oauthKey = oauthRef?.key ?? this.defaultOAuthKey(void 0, oauthHost);
|
|
14280
|
+
return this.managerFor(BLUN_PROVIDER_NAME$1, oauthKey, oauthHost).getCachedMemoryWorkspaceId();
|
|
14281
|
+
}
|
|
14282
|
+
async cacheMemoryWorkspaceId(workspaceId, oauthRef) {
|
|
14283
|
+
const oauthHost = this.oauthHostFor(oauthRef);
|
|
14284
|
+
const oauthKey = oauthRef?.key ?? this.defaultOAuthKey(void 0, oauthHost);
|
|
14285
|
+
return this.managerFor(BLUN_PROVIDER_NAME$1, oauthKey, oauthHost).cacheMemoryWorkspaceId(workspaceId);
|
|
14286
|
+
}
|
|
14166
14287
|
async login(providerName, options = {}) {
|
|
14167
14288
|
const name = providerName ?? "managed:blun";
|
|
14168
14289
|
const oauthHost = this.oauthHostFor(options.oauthRef, options.oauthHost);
|
|
@@ -16230,6 +16351,8 @@ function providerToToml(provider, rawProvider) {
|
|
|
16230
16351
|
for (const key of [
|
|
16231
16352
|
"type",
|
|
16232
16353
|
"apiKey",
|
|
16354
|
+
"memoryWorkspaceId",
|
|
16355
|
+
"memoryApiKeyHash",
|
|
16233
16356
|
"baseUrl",
|
|
16234
16357
|
"defaultModel",
|
|
16235
16358
|
"oauth",
|
|
@@ -16375,16 +16498,11 @@ function configWriterError(error) {
|
|
|
16375
16498
|
return error;
|
|
16376
16499
|
}
|
|
16377
16500
|
async function acquireConfigWriter(filePath) {
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
return await acquireSessionWriter(filePath);
|
|
16501
|
+
try {
|
|
16502
|
+
return await acquireSessionWriter(filePath, { waitForBusyMs: 5e3 });
|
|
16381
16503
|
} catch (error) {
|
|
16382
16504
|
if (!(error instanceof BlunError) || error.code !== ErrorCodes.SESSION_WRITER_BUSY) throw error;
|
|
16383
|
-
|
|
16384
|
-
if (remaining <= 0) throw new BlunError(ErrorCodes.CONFIG_WRITE_BUSY, "Another configuration change is still being saved", { cause: error });
|
|
16385
|
-
await new Promise((resolve) => {
|
|
16386
|
-
setTimeout(resolve, Math.min(25, remaining));
|
|
16387
|
-
});
|
|
16505
|
+
throw new BlunError(ErrorCodes.CONFIG_WRITE_BUSY, "Another configuration change is still being saved", { cause: error });
|
|
16388
16506
|
}
|
|
16389
16507
|
}
|
|
16390
16508
|
/** Keep transforms synchronous; credential validation and discovery belong before this boundary. */
|
|
@@ -21678,6 +21796,31 @@ var InstructionText = class InstructionText {
|
|
|
21678
21796
|
get content() {
|
|
21679
21797
|
return this.pieces.map((piece) => piece.text).join("");
|
|
21680
21798
|
}
|
|
21799
|
+
prefixUtf8(maxBytes) {
|
|
21800
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) throw new RangeError("Invalid instruction byte budget");
|
|
21801
|
+
const kept = [];
|
|
21802
|
+
let remaining = maxBytes;
|
|
21803
|
+
let totalBytes = 0;
|
|
21804
|
+
let readBytes = 0;
|
|
21805
|
+
for (const piece of this.pieces) {
|
|
21806
|
+
const encoded = Buffer.from(piece.text, "utf8");
|
|
21807
|
+
totalBytes += encoded.length;
|
|
21808
|
+
if (remaining <= 0) continue;
|
|
21809
|
+
const content = encoded.length <= remaining ? piece.text : new StringDecoder("utf8").write(encoded.subarray(0, remaining));
|
|
21810
|
+
const bytes = Buffer.byteLength(content, "utf8");
|
|
21811
|
+
if (content.length > 0) kept.push({
|
|
21812
|
+
...piece,
|
|
21813
|
+
text: content
|
|
21814
|
+
});
|
|
21815
|
+
readBytes += bytes;
|
|
21816
|
+
remaining -= bytes;
|
|
21817
|
+
if (bytes < encoded.length) remaining = 0;
|
|
21818
|
+
}
|
|
21819
|
+
return {
|
|
21820
|
+
text: new InstructionText(kept, new Map(this.sources)),
|
|
21821
|
+
omittedBytes: totalBytes - readBytes
|
|
21822
|
+
};
|
|
21823
|
+
}
|
|
21681
21824
|
replaceFirst(needle, replacement) {
|
|
21682
21825
|
const start = this.content.indexOf(needle);
|
|
21683
21826
|
if (start >= 0) this.replaceRange(start, start + needle.length, replacement);
|
|
@@ -21735,6 +21878,64 @@ const IMPORT_MAX_DEPTH = 4;
|
|
|
21735
21878
|
const IMPORT_LINE_RE = /^@import\s+(.+)$/gm;
|
|
21736
21879
|
const S_IFMT$4 = 61440;
|
|
21737
21880
|
const S_IFREG$2 = 32768;
|
|
21881
|
+
function fitAgentsMdContext(context, maxFixedRequestBytes, measureFixedRequestBytes) {
|
|
21882
|
+
if (!Number.isSafeInteger(maxFixedRequestBytes) || maxFixedRequestBytes <= 0) throw new RangeError("Invalid fixed request byte budget");
|
|
21883
|
+
const originalBytes = measureFixedRequestBytes(context);
|
|
21884
|
+
if (originalBytes <= maxFixedRequestBytes) return {
|
|
21885
|
+
context,
|
|
21886
|
+
fixedRequestBytes: originalBytes,
|
|
21887
|
+
omittedBytes: 0,
|
|
21888
|
+
fits: true
|
|
21889
|
+
};
|
|
21890
|
+
const source = context.agentsMdText;
|
|
21891
|
+
if (source === void 0) return {
|
|
21892
|
+
context,
|
|
21893
|
+
fixedRequestBytes: originalBytes,
|
|
21894
|
+
omittedBytes: 0,
|
|
21895
|
+
fits: false
|
|
21896
|
+
};
|
|
21897
|
+
const totalBytes = source.measure().totalBytes;
|
|
21898
|
+
const candidateAt = (maxBytes) => {
|
|
21899
|
+
const { text } = source.prefixUtf8(maxBytes);
|
|
21900
|
+
return {
|
|
21901
|
+
...context,
|
|
21902
|
+
agentsMd: text.content,
|
|
21903
|
+
agentsMdSources: text.measure(),
|
|
21904
|
+
agentsMdText: text
|
|
21905
|
+
};
|
|
21906
|
+
};
|
|
21907
|
+
let low = 0;
|
|
21908
|
+
let high = totalBytes;
|
|
21909
|
+
let fitted = candidateAt(0);
|
|
21910
|
+
let fittedBytes = measureFixedRequestBytes(fitted);
|
|
21911
|
+
if (fittedBytes > maxFixedRequestBytes) {
|
|
21912
|
+
const omittedBytes = context.agentsMdSources?.files.reduce((sum, file) => sum + file.bytes, 0) ?? totalBytes;
|
|
21913
|
+
return {
|
|
21914
|
+
context: fitted,
|
|
21915
|
+
fixedRequestBytes: fittedBytes,
|
|
21916
|
+
omittedBytes,
|
|
21917
|
+
fits: false
|
|
21918
|
+
};
|
|
21919
|
+
}
|
|
21920
|
+
while (low < high) {
|
|
21921
|
+
const middle = Math.ceil((low + high) / 2);
|
|
21922
|
+
const candidate = candidateAt(middle);
|
|
21923
|
+
const bytes = measureFixedRequestBytes(candidate);
|
|
21924
|
+
if (bytes <= maxFixedRequestBytes) {
|
|
21925
|
+
low = middle;
|
|
21926
|
+
fitted = candidate;
|
|
21927
|
+
fittedBytes = bytes;
|
|
21928
|
+
} else high = middle - 1;
|
|
21929
|
+
}
|
|
21930
|
+
const omittedBytes = context.agentsMdSources?.files.reduce((sum, file) => sum + file.bytes, 0) ?? totalBytes;
|
|
21931
|
+
const retainedBytes = fitted.agentsMdSources?.files.reduce((sum, file) => sum + file.bytes, 0) ?? 0;
|
|
21932
|
+
return {
|
|
21933
|
+
context: fitted,
|
|
21934
|
+
fixedRequestBytes: fittedBytes,
|
|
21935
|
+
omittedBytes: omittedBytes - retainedBytes,
|
|
21936
|
+
fits: true
|
|
21937
|
+
};
|
|
21938
|
+
}
|
|
21738
21939
|
async function prepareSystemPromptContext(kaos, brandHome, options) {
|
|
21739
21940
|
const additionalDirs = normalizeAdditionalDirs(options?.additionalDirs ?? []);
|
|
21740
21941
|
const [cwdListing, agentsMdResult, additionalDirsInfo] = await Promise.all([
|
|
@@ -21747,7 +21948,8 @@ async function prepareSystemPromptContext(kaos, brandHome, options) {
|
|
|
21747
21948
|
agentsMd: agentsMdResult.content,
|
|
21748
21949
|
additionalDirsInfo,
|
|
21749
21950
|
agentsMdWarning: agentsMdResult.warning,
|
|
21750
|
-
agentsMdSources: agentsMdResult.sources
|
|
21951
|
+
agentsMdSources: agentsMdResult.sources,
|
|
21952
|
+
agentsMdText: agentsMdResult.text
|
|
21751
21953
|
};
|
|
21752
21954
|
}
|
|
21753
21955
|
async function loadAgentsMd(kaos, brandHome) {
|
|
@@ -21757,10 +21959,15 @@ async function loadAgentsMdForRoots(kaos, brandHome, workDirs) {
|
|
|
21757
21959
|
const discovered = [];
|
|
21758
21960
|
const emptySources = /* @__PURE__ */ new Map();
|
|
21759
21961
|
const seen = /* @__PURE__ */ new Set();
|
|
21962
|
+
const notLoadedCandidates = /* @__PURE__ */ new Set();
|
|
21760
21963
|
const collect = async (path) => {
|
|
21761
21964
|
const file = await readAgentFile(kaos, path);
|
|
21762
|
-
if (file === void 0)
|
|
21965
|
+
if (file === void 0) {
|
|
21966
|
+
notLoadedCandidates.add(kaos.normpath(path));
|
|
21967
|
+
return false;
|
|
21968
|
+
}
|
|
21763
21969
|
const key = kaos.normpath(file.path);
|
|
21970
|
+
notLoadedCandidates.delete(key);
|
|
21764
21971
|
if (file.content.length === 0) {
|
|
21765
21972
|
emptySources.set(key, InstructionText.file(file.path, "", file.sourceTextBytes));
|
|
21766
21973
|
return false;
|
|
@@ -21796,7 +22003,11 @@ async function loadAgentsMdForRoots(kaos, brandHome, workDirs) {
|
|
|
21796
22003
|
return {
|
|
21797
22004
|
content,
|
|
21798
22005
|
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
|
-
|
|
22006
|
+
text: rendered,
|
|
22007
|
+
sources: {
|
|
22008
|
+
...rendered.measure(),
|
|
22009
|
+
...notLoadedCandidates.size === 0 ? {} : { notLoadedCandidates: [...notLoadedCandidates] }
|
|
22010
|
+
}
|
|
21800
22011
|
};
|
|
21801
22012
|
}
|
|
21802
22013
|
async function loadAdditionalDirsInfo(kaos, additionalDirs) {
|
|
@@ -28778,17 +28989,20 @@ function createSystemPromptRenderer(merged) {
|
|
|
28778
28989
|
const counts = renderPromptContributions(merged.systemPromptTemplate, vars, rendered, true) ?? renderPromptContributions(merged.systemPromptTemplate, vars, rendered);
|
|
28779
28990
|
const sources = context.agentsMdSources;
|
|
28780
28991
|
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;
|
|
28992
|
+
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;
|
|
28993
|
+
const notLoadedCandidates = sourceMatches && sources.notLoadedCandidates !== void 0 ? { notLoadedCandidates: [...sources.notLoadedCandidates] } : {};
|
|
28782
28994
|
const instructionSources = copies === 0 ? {
|
|
28783
28995
|
version: 1,
|
|
28784
28996
|
totalBytes: 0,
|
|
28785
28997
|
generatedBytes: 0,
|
|
28786
|
-
files: sourceMatches ? sources.files.map((file) => copyInstructionFileBytes(file, 0)) : []
|
|
28998
|
+
files: sourceMatches ? sources.files.map((file) => copyInstructionFileBytes(file, 0)) : [],
|
|
28999
|
+
...notLoadedCandidates
|
|
28787
29000
|
} : !sourceMatches ? void 0 : {
|
|
28788
29001
|
version: 1,
|
|
28789
29002
|
totalBytes: sources.totalBytes * copies,
|
|
28790
29003
|
generatedBytes: sources.generatedBytes * copies,
|
|
28791
|
-
files: sources.files.map((file) => copyInstructionFileBytes(file, copies))
|
|
29004
|
+
files: sources.files.map((file) => copyInstructionFileBytes(file, copies)),
|
|
29005
|
+
...notLoadedCandidates
|
|
28792
29006
|
};
|
|
28793
29007
|
const skillListingSources = counts === void 0 ? void 0 : scaleSkillListingSources(skillSources, vars["BLUN_SKILLS"] ?? "", counts.skillListingBytes);
|
|
28794
29008
|
context.onContributions(counts === void 0 ? void 0 : {
|
|
@@ -29811,7 +30025,7 @@ var FileSystemAgentRecordPersistence = class {
|
|
|
29811
30025
|
async *readFrom(offset, recordCount) {
|
|
29812
30026
|
if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(recordCount) || recordCount < 0) throw new Error("Invalid Wire replay offset");
|
|
29813
30027
|
await this.flush();
|
|
29814
|
-
|
|
30028
|
+
const fragments = [];
|
|
29815
30029
|
let lineNumber = recordCount;
|
|
29816
30030
|
let byteLength = offset;
|
|
29817
30031
|
const stream = createReadStream(this.filePath, {
|
|
@@ -29820,29 +30034,36 @@ var FileSystemAgentRecordPersistence = class {
|
|
|
29820
30034
|
});
|
|
29821
30035
|
try {
|
|
29822
30036
|
for await (const chunk of stream) {
|
|
29823
|
-
|
|
29824
|
-
let newlineIndex =
|
|
30037
|
+
let start = 0;
|
|
30038
|
+
let newlineIndex = chunk.indexOf("\n", start);
|
|
29825
30039
|
while (newlineIndex !== -1) {
|
|
29826
|
-
const
|
|
29827
|
-
|
|
30040
|
+
const part = chunk.slice(start, newlineIndex);
|
|
30041
|
+
let rawLine = part;
|
|
30042
|
+
if (fragments.length > 0) {
|
|
30043
|
+
fragments.push(part);
|
|
30044
|
+
rawLine = fragments.join("");
|
|
30045
|
+
fragments.length = 0;
|
|
30046
|
+
}
|
|
29828
30047
|
lineNumber++;
|
|
29829
30048
|
byteLength += Buffer.byteLength(rawLine, "utf8") + 1;
|
|
29830
30049
|
const record = parseRecordLine(rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine, lineNumber, this.filePath, false);
|
|
29831
30050
|
if (record !== void 0) yield record;
|
|
29832
|
-
|
|
30051
|
+
start = newlineIndex + 1;
|
|
30052
|
+
newlineIndex = chunk.indexOf("\n", start);
|
|
29833
30053
|
}
|
|
30054
|
+
if (start < chunk.length) fragments.push(chunk.slice(start));
|
|
29834
30055
|
}
|
|
29835
30056
|
} catch (error) {
|
|
29836
30057
|
if (error.code === "ENOENT") return;
|
|
29837
30058
|
throw error;
|
|
29838
30059
|
}
|
|
29839
|
-
if (
|
|
30060
|
+
if (fragments.length > 0) {
|
|
29840
30061
|
lineNumber++;
|
|
29841
|
-
const record = parseRecordLine(
|
|
30062
|
+
const record = parseRecordLine(fragments.join(""), lineNumber, this.filePath, true);
|
|
29842
30063
|
if (record !== void 0) yield record;
|
|
29843
30064
|
}
|
|
29844
30065
|
this.persistedRecordCount = lineNumber;
|
|
29845
|
-
this.persistedByteLength =
|
|
30066
|
+
this.persistedByteLength = fragments.length === 0 ? byteLength : void 0;
|
|
29846
30067
|
}
|
|
29847
30068
|
append(input) {
|
|
29848
30069
|
this.throwIfError();
|
|
@@ -180665,6 +180886,10 @@ var GoalMode = class {
|
|
|
180665
180886
|
restoreUpdate(record) {
|
|
180666
180887
|
const state = this.state;
|
|
180667
180888
|
if (state === void 0) return;
|
|
180889
|
+
if (record.objective !== void 0) {
|
|
180890
|
+
state.objective = record.objective;
|
|
180891
|
+
this.lifecycleRevision += 1;
|
|
180892
|
+
}
|
|
180668
180893
|
const status = record.status;
|
|
180669
180894
|
if (status !== void 0) {
|
|
180670
180895
|
this.lifecycleRevision += 1;
|
|
@@ -180679,7 +180904,17 @@ var GoalMode = class {
|
|
|
180679
180904
|
state.wallClockResumedAt = void 0;
|
|
180680
180905
|
}
|
|
180681
180906
|
if (record.budgetLimits !== void 0) state.budgetLimits = record.budgetLimits;
|
|
180682
|
-
if (status === void 0)
|
|
180907
|
+
if (status === void 0) {
|
|
180908
|
+
if (record.objective !== void 0) this.agent.replayBuilder.push({
|
|
180909
|
+
type: "goal_updated",
|
|
180910
|
+
snapshot: this.toSnapshot(state),
|
|
180911
|
+
change: {
|
|
180912
|
+
kind: "edited",
|
|
180913
|
+
actor: record.actor
|
|
180914
|
+
}
|
|
180915
|
+
});
|
|
180916
|
+
return;
|
|
180917
|
+
}
|
|
180683
180918
|
this.agent.replayBuilder.push({
|
|
180684
180919
|
type: "goal_updated",
|
|
180685
180920
|
snapshot: this.toSnapshot(state),
|
|
@@ -180723,11 +180958,11 @@ var GoalMode = class {
|
|
|
180723
180958
|
if (objective.length === 0) throw new BlunError(ErrorCodes.GOAL_OBJECTIVE_EMPTY, "Goal objective cannot be empty");
|
|
180724
180959
|
if (objective.length > MAX_GOAL_OBJECTIVE_LENGTH) throw new BlunError(ErrorCodes.GOAL_OBJECTIVE_TOO_LONG, `Goal objective cannot exceed ${MAX_GOAL_OBJECTIVE_LENGTH} characters`);
|
|
180725
180960
|
const verificationScope = normalizeVerificationScope(input.verificationScope);
|
|
180961
|
+
const completionCriterion = normalizeCompletionCriterion(input.completionCriterion);
|
|
180726
180962
|
if (this.state !== void 0) {
|
|
180727
180963
|
if (input.replace !== true) throw new BlunError(ErrorCodes.GOAL_ALREADY_EXISTS, "A goal already exists; use replace to start a new one");
|
|
180728
180964
|
this.clearInternal("system");
|
|
180729
180965
|
}
|
|
180730
|
-
const completionCriterion = normalizeCompletionCriterion(input.completionCriterion);
|
|
180731
180966
|
const state = {
|
|
180732
180967
|
goalId: randomUUID(),
|
|
180733
180968
|
objective,
|
|
@@ -180751,6 +180986,35 @@ var GoalMode = class {
|
|
|
180751
180986
|
this.trackGoalCreated(actor, input.replace === true);
|
|
180752
180987
|
return this.toSnapshot(state);
|
|
180753
180988
|
}
|
|
180989
|
+
async completeGoal() {
|
|
180990
|
+
const state = this.requireState();
|
|
180991
|
+
if (state.status !== "active") throw new BlunError(ErrorCodes.GOAL_STATUS_INVALID, `Cannot complete a goal in status "${state.status}"`);
|
|
180992
|
+
return this.markComplete({}, "user");
|
|
180993
|
+
}
|
|
180994
|
+
async blockGoal(input = {}) {
|
|
180995
|
+
const state = this.requireState();
|
|
180996
|
+
if (state.status === "blocked") return this.toSnapshot(state);
|
|
180997
|
+
if (state.status !== "active") throw new BlunError(ErrorCodes.GOAL_STATUS_INVALID, `Cannot block a goal in status "${state.status}"`);
|
|
180998
|
+
return await this.markBlocked(input, "user");
|
|
180999
|
+
}
|
|
181000
|
+
async editGoal(input, actor = "user") {
|
|
181001
|
+
const state = this.requireState();
|
|
181002
|
+
const objective = input.objective.trim();
|
|
181003
|
+
if (objective.length === 0) throw new BlunError(ErrorCodes.GOAL_OBJECTIVE_EMPTY, "Goal objective cannot be empty");
|
|
181004
|
+
if (objective.length > MAX_GOAL_OBJECTIVE_LENGTH) throw new BlunError(ErrorCodes.GOAL_OBJECTIVE_TOO_LONG, `Goal objective cannot exceed ${MAX_GOAL_OBJECTIVE_LENGTH} characters`);
|
|
181005
|
+
if (objective === state.objective) return this.toSnapshot(state);
|
|
181006
|
+
state.objective = objective;
|
|
181007
|
+
this.lifecycleRevision += 1;
|
|
181008
|
+
this.appendGoalUpdate({
|
|
181009
|
+
objective,
|
|
181010
|
+
actor
|
|
181011
|
+
});
|
|
181012
|
+
this.persistState(state, { change: {
|
|
181013
|
+
kind: "edited",
|
|
181014
|
+
actor
|
|
181015
|
+
} });
|
|
181016
|
+
return this.toSnapshot(state);
|
|
181017
|
+
}
|
|
180754
181018
|
async pauseGoal(input = {}, actor = "user") {
|
|
180755
181019
|
const state = this.requireState();
|
|
180756
181020
|
if (state.status === "paused") return this.toSnapshot(state);
|
|
@@ -181520,6 +181784,613 @@ var ProviderRetryWait = class {
|
|
|
181520
181784
|
}
|
|
181521
181785
|
}
|
|
181522
181786
|
};
|
|
181787
|
+
const IMAGE_MIME_BY_SUFFIX = Object.freeze({
|
|
181788
|
+
".png": "image/png",
|
|
181789
|
+
".jpg": "image/jpeg",
|
|
181790
|
+
".jpeg": "image/jpeg",
|
|
181791
|
+
".gif": "image/gif",
|
|
181792
|
+
".bmp": "image/bmp",
|
|
181793
|
+
".tif": "image/tiff",
|
|
181794
|
+
".tiff": "image/tiff",
|
|
181795
|
+
".webp": "image/webp",
|
|
181796
|
+
".ico": "image/x-icon",
|
|
181797
|
+
".heic": "image/heic",
|
|
181798
|
+
".heif": "image/heif",
|
|
181799
|
+
".avif": "image/avif",
|
|
181800
|
+
".svgz": "image/svg+xml"
|
|
181801
|
+
});
|
|
181802
|
+
const VIDEO_MIME_BY_SUFFIX = Object.freeze({
|
|
181803
|
+
".mp4": "video/mp4",
|
|
181804
|
+
".mpg": "video/mpeg",
|
|
181805
|
+
".mpeg": "video/mpeg",
|
|
181806
|
+
".mkv": "video/x-matroska",
|
|
181807
|
+
".avi": "video/x-msvideo",
|
|
181808
|
+
".mov": "video/quicktime",
|
|
181809
|
+
".ogv": "video/ogg",
|
|
181810
|
+
".wmv": "video/x-ms-wmv",
|
|
181811
|
+
".webm": "video/webm",
|
|
181812
|
+
".m4v": "video/x-m4v",
|
|
181813
|
+
".flv": "video/x-flv",
|
|
181814
|
+
".3gp": "video/3gpp",
|
|
181815
|
+
".3g2": "video/3gpp2"
|
|
181816
|
+
});
|
|
181817
|
+
const TEXT_MIME_BY_SUFFIX = Object.freeze({ ".svg": "image/svg+xml" });
|
|
181818
|
+
const NON_TEXT_SUFFIXES = new Set([
|
|
181819
|
+
".icns",
|
|
181820
|
+
".psd",
|
|
181821
|
+
".ai",
|
|
181822
|
+
".eps",
|
|
181823
|
+
".pdf",
|
|
181824
|
+
".doc",
|
|
181825
|
+
".docx",
|
|
181826
|
+
".dot",
|
|
181827
|
+
".dotx",
|
|
181828
|
+
".rtf",
|
|
181829
|
+
".odt",
|
|
181830
|
+
".xls",
|
|
181831
|
+
".xlsx",
|
|
181832
|
+
".xlsm",
|
|
181833
|
+
".xlt",
|
|
181834
|
+
".xltx",
|
|
181835
|
+
".xltm",
|
|
181836
|
+
".ods",
|
|
181837
|
+
".ppt",
|
|
181838
|
+
".pptx",
|
|
181839
|
+
".pptm",
|
|
181840
|
+
".pps",
|
|
181841
|
+
".ppsx",
|
|
181842
|
+
".odp",
|
|
181843
|
+
".pages",
|
|
181844
|
+
".numbers",
|
|
181845
|
+
".key",
|
|
181846
|
+
".zip",
|
|
181847
|
+
".rar",
|
|
181848
|
+
".7z",
|
|
181849
|
+
".tar",
|
|
181850
|
+
".gz",
|
|
181851
|
+
".tgz",
|
|
181852
|
+
".bz2",
|
|
181853
|
+
".xz",
|
|
181854
|
+
".zst",
|
|
181855
|
+
".lz",
|
|
181856
|
+
".lz4",
|
|
181857
|
+
".br",
|
|
181858
|
+
".cab",
|
|
181859
|
+
".ar",
|
|
181860
|
+
".deb",
|
|
181861
|
+
".rpm",
|
|
181862
|
+
".mp3",
|
|
181863
|
+
".wav",
|
|
181864
|
+
".flac",
|
|
181865
|
+
".ogg",
|
|
181866
|
+
".oga",
|
|
181867
|
+
".opus",
|
|
181868
|
+
".aac",
|
|
181869
|
+
".m4a",
|
|
181870
|
+
".wma",
|
|
181871
|
+
".ttf",
|
|
181872
|
+
".otf",
|
|
181873
|
+
".woff",
|
|
181874
|
+
".woff2",
|
|
181875
|
+
".exe",
|
|
181876
|
+
".dll",
|
|
181877
|
+
".so",
|
|
181878
|
+
".dylib",
|
|
181879
|
+
".bin",
|
|
181880
|
+
".apk",
|
|
181881
|
+
".ipa",
|
|
181882
|
+
".jar",
|
|
181883
|
+
".class",
|
|
181884
|
+
".pyc",
|
|
181885
|
+
".pyo",
|
|
181886
|
+
".wasm",
|
|
181887
|
+
".dmg",
|
|
181888
|
+
".iso",
|
|
181889
|
+
".img",
|
|
181890
|
+
".sqlite",
|
|
181891
|
+
".sqlite3",
|
|
181892
|
+
".db",
|
|
181893
|
+
".db3"
|
|
181894
|
+
]);
|
|
181895
|
+
const ASF_HEADER = Buffer.from([
|
|
181896
|
+
48,
|
|
181897
|
+
38,
|
|
181898
|
+
178,
|
|
181899
|
+
117,
|
|
181900
|
+
142,
|
|
181901
|
+
102,
|
|
181902
|
+
207,
|
|
181903
|
+
17,
|
|
181904
|
+
166,
|
|
181905
|
+
217,
|
|
181906
|
+
0,
|
|
181907
|
+
170,
|
|
181908
|
+
0,
|
|
181909
|
+
98,
|
|
181910
|
+
206,
|
|
181911
|
+
108
|
|
181912
|
+
]);
|
|
181913
|
+
const FTYP_IMAGE_BRANDS = Object.freeze({
|
|
181914
|
+
avif: "image/avif",
|
|
181915
|
+
avis: "image/avif",
|
|
181916
|
+
heic: "image/heic",
|
|
181917
|
+
heif: "image/heif",
|
|
181918
|
+
heix: "image/heif",
|
|
181919
|
+
hevc: "image/heic",
|
|
181920
|
+
mif1: "image/heif",
|
|
181921
|
+
msf1: "image/heif"
|
|
181922
|
+
});
|
|
181923
|
+
const FTYP_VIDEO_BRANDS = Object.freeze({
|
|
181924
|
+
isom: "video/mp4",
|
|
181925
|
+
iso2: "video/mp4",
|
|
181926
|
+
iso5: "video/mp4",
|
|
181927
|
+
mp41: "video/mp4",
|
|
181928
|
+
mp42: "video/mp4",
|
|
181929
|
+
avc1: "video/mp4",
|
|
181930
|
+
mp4v: "video/mp4",
|
|
181931
|
+
m4v: "video/x-m4v",
|
|
181932
|
+
qt: "video/quicktime",
|
|
181933
|
+
"3gp4": "video/3gpp",
|
|
181934
|
+
"3gp5": "video/3gpp",
|
|
181935
|
+
"3gp6": "video/3gpp",
|
|
181936
|
+
"3gp7": "video/3gpp",
|
|
181937
|
+
"3g2": "video/3gpp2"
|
|
181938
|
+
});
|
|
181939
|
+
function toBuffer(data) {
|
|
181940
|
+
return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
181941
|
+
}
|
|
181942
|
+
function startsWith(buf, prefix) {
|
|
181943
|
+
const needle = Buffer.isBuffer(prefix) ? prefix : Buffer.from(prefix);
|
|
181944
|
+
if (buf.length < needle.length) return false;
|
|
181945
|
+
for (let i = 0; i < needle.length; i += 1) if (buf[i] !== needle[i]) return false;
|
|
181946
|
+
return true;
|
|
181947
|
+
}
|
|
181948
|
+
function sniffFtypBrand(header) {
|
|
181949
|
+
if (header.length < 12) return null;
|
|
181950
|
+
if (header.subarray(4, 8).toString("latin1") !== "ftyp") return null;
|
|
181951
|
+
return header.subarray(8, 12).toString("latin1").toLowerCase().replaceAll(/[\s\u0000]+$/g, "").trim();
|
|
181952
|
+
}
|
|
181953
|
+
function sniffMediaFromMagic(data) {
|
|
181954
|
+
const buf = toBuffer(data);
|
|
181955
|
+
const header = buf.length > 512 ? buf.subarray(0, 512) : buf;
|
|
181956
|
+
if (startsWith(header, [
|
|
181957
|
+
137,
|
|
181958
|
+
80,
|
|
181959
|
+
78,
|
|
181960
|
+
71,
|
|
181961
|
+
13,
|
|
181962
|
+
10,
|
|
181963
|
+
26,
|
|
181964
|
+
10
|
|
181965
|
+
])) return {
|
|
181966
|
+
kind: "image",
|
|
181967
|
+
mimeType: "image/png"
|
|
181968
|
+
};
|
|
181969
|
+
if (startsWith(header, [
|
|
181970
|
+
255,
|
|
181971
|
+
216,
|
|
181972
|
+
255
|
|
181973
|
+
])) return {
|
|
181974
|
+
kind: "image",
|
|
181975
|
+
mimeType: "image/jpeg"
|
|
181976
|
+
};
|
|
181977
|
+
if (startsWith(header, Buffer.from("GIF87a")) || startsWith(header, Buffer.from("GIF89a"))) return {
|
|
181978
|
+
kind: "image",
|
|
181979
|
+
mimeType: "image/gif"
|
|
181980
|
+
};
|
|
181981
|
+
if (startsWith(header, Buffer.from("BM"))) return {
|
|
181982
|
+
kind: "image",
|
|
181983
|
+
mimeType: "image/bmp"
|
|
181984
|
+
};
|
|
181985
|
+
if (startsWith(header, [
|
|
181986
|
+
73,
|
|
181987
|
+
73,
|
|
181988
|
+
42,
|
|
181989
|
+
0
|
|
181990
|
+
]) || startsWith(header, [
|
|
181991
|
+
77,
|
|
181992
|
+
77,
|
|
181993
|
+
0,
|
|
181994
|
+
42
|
|
181995
|
+
])) return {
|
|
181996
|
+
kind: "image",
|
|
181997
|
+
mimeType: "image/tiff"
|
|
181998
|
+
};
|
|
181999
|
+
if (startsWith(header, [
|
|
182000
|
+
0,
|
|
182001
|
+
0,
|
|
182002
|
+
1,
|
|
182003
|
+
0
|
|
182004
|
+
])) return {
|
|
182005
|
+
kind: "image",
|
|
182006
|
+
mimeType: "image/x-icon"
|
|
182007
|
+
};
|
|
182008
|
+
if (startsWith(header, Buffer.from("RIFF")) && header.length >= 12) {
|
|
182009
|
+
const chunk = header.subarray(8, 12).toString("latin1");
|
|
182010
|
+
if (chunk === "WEBP") return {
|
|
182011
|
+
kind: "image",
|
|
182012
|
+
mimeType: "image/webp"
|
|
182013
|
+
};
|
|
182014
|
+
if (chunk === "AVI ") return {
|
|
182015
|
+
kind: "video",
|
|
182016
|
+
mimeType: "video/x-msvideo"
|
|
182017
|
+
};
|
|
182018
|
+
}
|
|
182019
|
+
if (startsWith(header, Buffer.from("FLV"))) return {
|
|
182020
|
+
kind: "video",
|
|
182021
|
+
mimeType: "video/x-flv"
|
|
182022
|
+
};
|
|
182023
|
+
if (startsWith(header, ASF_HEADER)) return {
|
|
182024
|
+
kind: "video",
|
|
182025
|
+
mimeType: "video/x-ms-wmv"
|
|
182026
|
+
};
|
|
182027
|
+
if (startsWith(header, [
|
|
182028
|
+
26,
|
|
182029
|
+
69,
|
|
182030
|
+
223,
|
|
182031
|
+
163
|
|
182032
|
+
])) {
|
|
182033
|
+
const lowered = header.toString("latin1").toLowerCase();
|
|
182034
|
+
if (lowered.includes("webm")) return {
|
|
182035
|
+
kind: "video",
|
|
182036
|
+
mimeType: "video/webm"
|
|
182037
|
+
};
|
|
182038
|
+
if (lowered.includes("matroska")) return {
|
|
182039
|
+
kind: "video",
|
|
182040
|
+
mimeType: "video/x-matroska"
|
|
182041
|
+
};
|
|
182042
|
+
}
|
|
182043
|
+
const brand = sniffFtypBrand(header);
|
|
182044
|
+
if (brand !== null && brand !== "") {
|
|
182045
|
+
if (brand in FTYP_IMAGE_BRANDS) return {
|
|
182046
|
+
kind: "image",
|
|
182047
|
+
mimeType: FTYP_IMAGE_BRANDS[brand]
|
|
182048
|
+
};
|
|
182049
|
+
if (brand in FTYP_VIDEO_BRANDS) return {
|
|
182050
|
+
kind: "video",
|
|
182051
|
+
mimeType: FTYP_VIDEO_BRANDS[brand]
|
|
182052
|
+
};
|
|
182053
|
+
}
|
|
182054
|
+
return null;
|
|
182055
|
+
}
|
|
182056
|
+
/**
|
|
182057
|
+
* Best-effort pixel-dimension reader for common raster formats.
|
|
182058
|
+
*
|
|
182059
|
+
* Inspects only the fixed region near the start of the file where each
|
|
182060
|
+
* format records its dimensions (the IHDR/DIB header, the RIFF chunk
|
|
182061
|
+
* after the `WEBP` tag, or the first JPEG SOFn segment). Returns `null`
|
|
182062
|
+
* for formats whose dimensions are not locatable from that region, or
|
|
182063
|
+
* when the supplied buffer is too short to cover it.
|
|
182064
|
+
*/
|
|
182065
|
+
function sniffImageDimensions(data) {
|
|
182066
|
+
const buf = toBuffer(data);
|
|
182067
|
+
if (startsWith(buf, [
|
|
182068
|
+
137,
|
|
182069
|
+
80,
|
|
182070
|
+
78,
|
|
182071
|
+
71,
|
|
182072
|
+
13,
|
|
182073
|
+
10,
|
|
182074
|
+
26,
|
|
182075
|
+
10
|
|
182076
|
+
]) && buf.length >= 24) return {
|
|
182077
|
+
width: buf.readUInt32BE(16),
|
|
182078
|
+
height: buf.readUInt32BE(20)
|
|
182079
|
+
};
|
|
182080
|
+
if ((startsWith(buf, Buffer.from("GIF87a")) || startsWith(buf, Buffer.from("GIF89a"))) && buf.length >= 10) return {
|
|
182081
|
+
width: buf.readUInt16LE(6),
|
|
182082
|
+
height: buf.readUInt16LE(8)
|
|
182083
|
+
};
|
|
182084
|
+
if (startsWith(buf, Buffer.from("BM")) && buf.length >= 26) return {
|
|
182085
|
+
width: buf.readInt32LE(18),
|
|
182086
|
+
height: Math.abs(buf.readInt32LE(22))
|
|
182087
|
+
};
|
|
182088
|
+
if (startsWith(buf, Buffer.from("RIFF")) && buf.length >= 30) {
|
|
182089
|
+
const fourCc = buf.subarray(12, 16).toString("latin1");
|
|
182090
|
+
if (fourCc === "VP8 ") return {
|
|
182091
|
+
width: buf.readUInt16LE(26) & 16383,
|
|
182092
|
+
height: buf.readUInt16LE(28) & 16383
|
|
182093
|
+
};
|
|
182094
|
+
if (fourCc === "VP8L" && buf.length >= 25) {
|
|
182095
|
+
const bits = buf.readUInt32LE(21);
|
|
182096
|
+
return {
|
|
182097
|
+
width: (bits & 16383) + 1,
|
|
182098
|
+
height: (bits >> 14 & 16383) + 1
|
|
182099
|
+
};
|
|
182100
|
+
}
|
|
182101
|
+
if (fourCc === "VP8X") return {
|
|
182102
|
+
width: 1 + (buf[24] | buf[25] << 8 | buf[26] << 16),
|
|
182103
|
+
height: 1 + (buf[27] | buf[28] << 8 | buf[29] << 16)
|
|
182104
|
+
};
|
|
182105
|
+
}
|
|
182106
|
+
if (startsWith(buf, [255, 216])) {
|
|
182107
|
+
let offset = 2;
|
|
182108
|
+
while (offset + 9 < buf.length) {
|
|
182109
|
+
if (buf[offset] !== 255) {
|
|
182110
|
+
offset += 1;
|
|
182111
|
+
continue;
|
|
182112
|
+
}
|
|
182113
|
+
const marker = buf[offset + 1];
|
|
182114
|
+
if (marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204) return {
|
|
182115
|
+
height: buf.readUInt16BE(offset + 5),
|
|
182116
|
+
width: buf.readUInt16BE(offset + 7)
|
|
182117
|
+
};
|
|
182118
|
+
if (marker === 216 || marker === 217 || marker >= 208 && marker <= 215) {
|
|
182119
|
+
offset += 2;
|
|
182120
|
+
continue;
|
|
182121
|
+
}
|
|
182122
|
+
const segmentLength = buf.readUInt16BE(offset + 2);
|
|
182123
|
+
if (segmentLength < 2) break;
|
|
182124
|
+
offset += 2 + segmentLength;
|
|
182125
|
+
}
|
|
182126
|
+
}
|
|
182127
|
+
return null;
|
|
182128
|
+
}
|
|
182129
|
+
function getSuffix(path) {
|
|
182130
|
+
const idx = path.lastIndexOf(".");
|
|
182131
|
+
if (idx === -1) return "";
|
|
182132
|
+
if (idx <= Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\")) + 1) return "";
|
|
182133
|
+
return path.slice(idx).toLowerCase();
|
|
182134
|
+
}
|
|
182135
|
+
function detectFileType(path, header, type = "text") {
|
|
182136
|
+
const suffix = getSuffix(path);
|
|
182137
|
+
let mediaHint = null;
|
|
182138
|
+
if (suffix in TEXT_MIME_BY_SUFFIX) mediaHint = {
|
|
182139
|
+
kind: "text",
|
|
182140
|
+
mimeType: TEXT_MIME_BY_SUFFIX[suffix]
|
|
182141
|
+
};
|
|
182142
|
+
else if (suffix in IMAGE_MIME_BY_SUFFIX) mediaHint = {
|
|
182143
|
+
kind: "image",
|
|
182144
|
+
mimeType: IMAGE_MIME_BY_SUFFIX[suffix]
|
|
182145
|
+
};
|
|
182146
|
+
else if (suffix in VIDEO_MIME_BY_SUFFIX) mediaHint = {
|
|
182147
|
+
kind: "video",
|
|
182148
|
+
mimeType: VIDEO_MIME_BY_SUFFIX[suffix]
|
|
182149
|
+
};
|
|
182150
|
+
if (header !== void 0) {
|
|
182151
|
+
const buf = toBuffer(header);
|
|
182152
|
+
const sniffed = sniffMediaFromMagic(buf);
|
|
182153
|
+
if (sniffed) {
|
|
182154
|
+
if (type === "media") return sniffed;
|
|
182155
|
+
if (mediaHint) {
|
|
182156
|
+
if (sniffed.kind !== mediaHint.kind) return {
|
|
182157
|
+
kind: "unknown",
|
|
182158
|
+
mimeType: ""
|
|
182159
|
+
};
|
|
182160
|
+
return mediaHint;
|
|
182161
|
+
}
|
|
182162
|
+
return sniffed;
|
|
182163
|
+
}
|
|
182164
|
+
if (mediaHint?.kind === "image") return {
|
|
182165
|
+
kind: "unknown",
|
|
182166
|
+
mimeType: ""
|
|
182167
|
+
};
|
|
182168
|
+
if (type === "media" && mediaHint?.kind === "video") return mediaHint;
|
|
182169
|
+
if (buf.includes(0)) return {
|
|
182170
|
+
kind: "unknown",
|
|
182171
|
+
mimeType: ""
|
|
182172
|
+
};
|
|
182173
|
+
}
|
|
182174
|
+
if (mediaHint) return mediaHint;
|
|
182175
|
+
if (NON_TEXT_SUFFIXES.has(suffix)) return {
|
|
182176
|
+
kind: "unknown",
|
|
182177
|
+
mimeType: ""
|
|
182178
|
+
};
|
|
182179
|
+
return {
|
|
182180
|
+
kind: "text",
|
|
182181
|
+
mimeType: "text/plain"
|
|
182182
|
+
};
|
|
182183
|
+
}
|
|
182184
|
+
//#endregion
|
|
182185
|
+
//#region ../../packages/agent-core/src/utils/tokens.ts
|
|
182186
|
+
const messageTokenEstimateCache = /* @__PURE__ */ new WeakMap();
|
|
182187
|
+
/** Open assistant messages grow while streaming; completed history stays cached. */
|
|
182188
|
+
function invalidateMessageTokenEstimate(message) {
|
|
182189
|
+
messageTokenEstimateCache.delete(message);
|
|
182190
|
+
}
|
|
182191
|
+
/**
|
|
182192
|
+
* Estimate token count from text using a character-based heuristic.
|
|
182193
|
+
* - ASCII (~4 chars per token)
|
|
182194
|
+
* - CJK and other non-ASCII (~1 char per token)
|
|
182195
|
+
* The estimate is transient — the next LLM call returns the real count
|
|
182196
|
+
* and supersedes this value. Used to keep `tokenCountWithPending`
|
|
182197
|
+
* monotonic between LLM round-trips without paying for a tokenizer.
|
|
182198
|
+
*/
|
|
182199
|
+
function estimateTokens(text) {
|
|
182200
|
+
let asciiCount = 0;
|
|
182201
|
+
let nonAsciiCount = 0;
|
|
182202
|
+
for (const char of text) if (char.codePointAt(0) <= 127) asciiCount++;
|
|
182203
|
+
else nonAsciiCount++;
|
|
182204
|
+
return Math.ceil(asciiCount / 4) + nonAsciiCount;
|
|
182205
|
+
}
|
|
182206
|
+
function estimateTokensForMessages(messages) {
|
|
182207
|
+
let total = 0;
|
|
182208
|
+
for (const message of messages) total += estimateTokensForMessage(message);
|
|
182209
|
+
return total;
|
|
182210
|
+
}
|
|
182211
|
+
/** With stopAfter, the result is a lower bound once it exceeds that budget. */
|
|
182212
|
+
function estimateTokensForTools(tools, stopAfter = Infinity) {
|
|
182213
|
+
let total = 0;
|
|
182214
|
+
for (const tool of tools) {
|
|
182215
|
+
total += estimateTokens(tool.name);
|
|
182216
|
+
total += estimateTokens(tool.description);
|
|
182217
|
+
total += estimateTokens(JSON.stringify(tool.parameters));
|
|
182218
|
+
if (total > stopAfter) return total;
|
|
182219
|
+
}
|
|
182220
|
+
return total;
|
|
182221
|
+
}
|
|
182222
|
+
function estimateTokensForMessage(message) {
|
|
182223
|
+
const cached = messageTokenEstimateCache.get(message);
|
|
182224
|
+
if (cached !== void 0) return cached;
|
|
182225
|
+
let total = estimateTokens(message.role);
|
|
182226
|
+
total += estimateTokensForContentParts(message.content);
|
|
182227
|
+
if (message.toolCalls !== void 0) for (const call of message.toolCalls) {
|
|
182228
|
+
total += estimateTokens(call.name);
|
|
182229
|
+
total += estimateTokens(JSON.stringify(call.arguments));
|
|
182230
|
+
}
|
|
182231
|
+
messageTokenEstimateCache.set(message, total);
|
|
182232
|
+
return total;
|
|
182233
|
+
}
|
|
182234
|
+
function estimateTokensForContentParts(parts) {
|
|
182235
|
+
let total = 0;
|
|
182236
|
+
for (const part of parts) total += estimateTokensForContentPart(part);
|
|
182237
|
+
return total;
|
|
182238
|
+
}
|
|
182239
|
+
/**
|
|
182240
|
+
* Conservative transient fallback for media whose pixel dimensions or duration
|
|
182241
|
+
* are unavailable. Inline raster images use their transmitted dimensions below;
|
|
182242
|
+
* audio, video, remote images, and malformed image data keep this safe floor.
|
|
182243
|
+
* The next successful LLM round-trip replaces the estimate with reported usage.
|
|
182244
|
+
*/
|
|
182245
|
+
const MEDIA_TOKEN_ESTIMATE = 2e3;
|
|
182246
|
+
/** Enough header data for common JPEG metadata followed by the first SOF marker. */
|
|
182247
|
+
const MAX_IMAGE_HEADER_BYTES = 1024 * 1024;
|
|
182248
|
+
function imageDimensionsFromDataUrl(url) {
|
|
182249
|
+
const commaIndex = url.indexOf(",");
|
|
182250
|
+
if (commaIndex <= 0) return null;
|
|
182251
|
+
const metadata = url.slice(0, commaIndex).toLowerCase();
|
|
182252
|
+
if (!metadata.startsWith("data:image/") || !metadata.split(";").includes("base64")) return null;
|
|
182253
|
+
const maxBase64Chars = Math.ceil(MAX_IMAGE_HEADER_BYTES / 3) * 4;
|
|
182254
|
+
const encodedHeader = url.slice(commaIndex + 1, commaIndex + 1 + maxBase64Chars);
|
|
182255
|
+
if (encodedHeader.length === 0) return null;
|
|
182256
|
+
try {
|
|
182257
|
+
const dimensions = sniffImageDimensions(Buffer.from(encodedHeader, "base64"));
|
|
182258
|
+
if (dimensions === null || !Number.isSafeInteger(dimensions.width) || !Number.isSafeInteger(dimensions.height) || dimensions.width <= 0 || dimensions.height <= 0) return null;
|
|
182259
|
+
return dimensions;
|
|
182260
|
+
} catch {
|
|
182261
|
+
return null;
|
|
182262
|
+
}
|
|
182263
|
+
}
|
|
182264
|
+
function estimateImageTokensFromDimensions(width, height) {
|
|
182265
|
+
if (!Number.isSafeInteger(width) || !Number.isSafeInteger(height) || width <= 0 || height <= 0) return MEDIA_TOKEN_ESTIMATE;
|
|
182266
|
+
const patchSize = BigInt(32);
|
|
182267
|
+
const tokens = (BigInt(width) + patchSize - 1n) / patchSize * ((BigInt(height) + patchSize - 1n) / patchSize);
|
|
182268
|
+
return tokens > BigInt(Number.MAX_SAFE_INTEGER) ? Number.MAX_SAFE_INTEGER : Number(tokens);
|
|
182269
|
+
}
|
|
182270
|
+
function estimateImageTokens(url) {
|
|
182271
|
+
const dimensions = imageDimensionsFromDataUrl(url);
|
|
182272
|
+
return dimensions === null ? MEDIA_TOKEN_ESTIMATE : estimateImageTokensFromDimensions(dimensions.width, dimensions.height);
|
|
182273
|
+
}
|
|
182274
|
+
function estimateTokensForContentPart(part) {
|
|
182275
|
+
switch (part.type) {
|
|
182276
|
+
case "text": return estimateTokens(part.text);
|
|
182277
|
+
case "think": return estimateTokens(part.think);
|
|
182278
|
+
case "image_url": return estimateImageTokens(part.imageUrl.url);
|
|
182279
|
+
case "audio_url":
|
|
182280
|
+
case "video_url": return MEDIA_TOKEN_ESTIMATE;
|
|
182281
|
+
default: return 0;
|
|
182282
|
+
}
|
|
182283
|
+
}
|
|
182284
|
+
const MAX_TOOL_CONTINUITY_SERIALIZED_BYTES = 4096;
|
|
182285
|
+
function saturatingAdd(left, right) {
|
|
182286
|
+
return left + Math.min(right, Number.MAX_SAFE_INTEGER - left);
|
|
182287
|
+
}
|
|
182288
|
+
function renderUnchecked(value) {
|
|
182289
|
+
return [
|
|
182290
|
+
"",
|
|
182291
|
+
"",
|
|
182292
|
+
"<tool-continuity>",
|
|
182293
|
+
"Observed tool-result flags; may be synthetic, not verified job success or permission. omitted counts excluded observations cumulatively, not jobs.",
|
|
182294
|
+
JSON.stringify(value).replaceAll(/[<>&]/g, (character) => {
|
|
182295
|
+
return `\\u${character.codePointAt(0).toString(16).padStart(4, "0")}`;
|
|
182296
|
+
}),
|
|
182297
|
+
"</tool-continuity>"
|
|
182298
|
+
].join("\n");
|
|
182299
|
+
}
|
|
182300
|
+
function hasExactKeys(value, expected) {
|
|
182301
|
+
const prototype = Object.getPrototypeOf(value);
|
|
182302
|
+
if (prototype !== Object.prototype && prototype !== null) return false;
|
|
182303
|
+
return Reflect.ownKeys(value).length === expected.length && expected.every((key) => {
|
|
182304
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
182305
|
+
return descriptor !== void 0 && descriptor.enumerable === true && Object.hasOwn(descriptor, "value");
|
|
182306
|
+
});
|
|
182307
|
+
}
|
|
182308
|
+
function isDataArray(value) {
|
|
182309
|
+
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype || value.length > 8 || Reflect.ownKeys(value).length !== value.length + 1) return false;
|
|
182310
|
+
for (let index = 0; index < value.length; index++) {
|
|
182311
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
182312
|
+
if (descriptor === void 0 || descriptor.enumerable !== true || !Object.hasOwn(descriptor, "value")) return false;
|
|
182313
|
+
}
|
|
182314
|
+
return true;
|
|
182315
|
+
}
|
|
182316
|
+
/** Validate restored metadata without interpreting any summarizer or tool prose. */
|
|
182317
|
+
function isToolContinuity(value) {
|
|
182318
|
+
try {
|
|
182319
|
+
if (value === null || typeof value !== "object" || !hasExactKeys(value, ["receipts", "omitted"])) return false;
|
|
182320
|
+
const candidate = value;
|
|
182321
|
+
if (!Number.isSafeInteger(candidate["omitted"]) || candidate["omitted"] < 0 || !isDataArray(candidate["receipts"]) || candidate["receipts"].length > 8) return false;
|
|
182322
|
+
for (const receipt of candidate["receipts"]) if (receipt === null || typeof receipt !== "object" || !hasExactKeys(receipt, ["toolCallId", "observedIsError"]) || !("toolCallId" in receipt) || !("observedIsError" in receipt) || typeof receipt.toolCallId !== "string" || receipt.toolCallId.length === 0 || Buffer.byteLength(receipt.toolCallId, "utf8") > 256 || receipt.observedIsError !== null && typeof receipt.observedIsError !== "boolean") return false;
|
|
182323
|
+
return Buffer.byteLength(JSON.stringify(renderUnchecked(value)), "utf8") <= MAX_TOOL_CONTINUITY_SERIALIZED_BYTES;
|
|
182324
|
+
} catch {
|
|
182325
|
+
return false;
|
|
182326
|
+
}
|
|
182327
|
+
}
|
|
182328
|
+
function renderToolContinuity(value) {
|
|
182329
|
+
if (!isToolContinuity(value) || value.receipts.length === 0 && value.omitted === 0) return void 0;
|
|
182330
|
+
return renderUnchecked(value);
|
|
182331
|
+
}
|
|
182332
|
+
/** The caller passes only the compactable prefix, excluding the preserved tool suffix. */
|
|
182333
|
+
function collectToolContinuity(messages) {
|
|
182334
|
+
const observed = /* @__PURE__ */ new Map();
|
|
182335
|
+
let ordinal = 0;
|
|
182336
|
+
let inheritedOmitted = 0;
|
|
182337
|
+
let excluded = 0;
|
|
182338
|
+
const remember = (toolCallId, observedIsError) => {
|
|
182339
|
+
if (toolCallId.length === 0 || Buffer.byteLength(toolCallId, "utf8") > 256) {
|
|
182340
|
+
excluded = saturatingAdd(excluded, 1);
|
|
182341
|
+
return;
|
|
182342
|
+
}
|
|
182343
|
+
const key = JSON.stringify([toolCallId, observedIsError]);
|
|
182344
|
+
observed.set(key, {
|
|
182345
|
+
toolCallId,
|
|
182346
|
+
observedIsError,
|
|
182347
|
+
ordinal: ordinal++
|
|
182348
|
+
});
|
|
182349
|
+
};
|
|
182350
|
+
for (const message of messages) if (message.role === "tool" && typeof message.toolCallId === "string") remember(message.toolCallId, typeof message.isError === "boolean" ? message.isError : null);
|
|
182351
|
+
else if (message.role === "user" && message.origin?.kind === "compaction_summary") {
|
|
182352
|
+
const previous = message.origin.toolContinuity;
|
|
182353
|
+
if (!isToolContinuity(previous)) continue;
|
|
182354
|
+
for (const receipt of previous.receipts.toReversed()) remember(receipt.toolCallId, receipt.observedIsError);
|
|
182355
|
+
inheritedOmitted = Math.max(inheritedOmitted, previous.omitted);
|
|
182356
|
+
}
|
|
182357
|
+
const prioritized = [...observed.values()].toSorted((left, right) => Number(right.observedIsError === true) - Number(left.observedIsError === true) || right.ordinal - left.ordinal);
|
|
182358
|
+
const receipts = prioritized.slice(0, 8).map(({ toolCallId, observedIsError }) => ({
|
|
182359
|
+
toolCallId,
|
|
182360
|
+
observedIsError
|
|
182361
|
+
}));
|
|
182362
|
+
let omitted = saturatingAdd(saturatingAdd(inheritedOmitted, excluded), prioritized.length - receipts.length);
|
|
182363
|
+
while (true) {
|
|
182364
|
+
const result = {
|
|
182365
|
+
receipts: [...receipts],
|
|
182366
|
+
omitted
|
|
182367
|
+
};
|
|
182368
|
+
if (renderToolContinuity(result) !== void 0) return result;
|
|
182369
|
+
if (receipts.length === 0) return void 0;
|
|
182370
|
+
receipts.pop();
|
|
182371
|
+
omitted = saturatingAdd(omitted, 1);
|
|
182372
|
+
}
|
|
182373
|
+
}
|
|
182374
|
+
/** Fit complete tuples and their disclaimer; never start a new failure or retry path. */
|
|
182375
|
+
function fitToolContinuity(value, additionalTokenBudget) {
|
|
182376
|
+
if (value === void 0 || !isToolContinuity(value) || !(additionalTokenBudget > 0)) return void 0;
|
|
182377
|
+
const receipts = [...value.receipts];
|
|
182378
|
+
let omitted = value.omitted;
|
|
182379
|
+
while (true) {
|
|
182380
|
+
const continuity = {
|
|
182381
|
+
receipts: [...receipts],
|
|
182382
|
+
omitted
|
|
182383
|
+
};
|
|
182384
|
+
const text = renderToolContinuity(continuity);
|
|
182385
|
+
if (text !== void 0 && estimateTokens(text) <= additionalTokenBudget) return {
|
|
182386
|
+
continuity,
|
|
182387
|
+
text
|
|
182388
|
+
};
|
|
182389
|
+
if (receipts.length === 0) return void 0;
|
|
182390
|
+
receipts.pop();
|
|
182391
|
+
omitted = saturatingAdd(omitted, 1);
|
|
182392
|
+
}
|
|
182393
|
+
}
|
|
181523
182394
|
//#endregion
|
|
181524
182395
|
//#region ../../packages/agent-core/src/agent/records/resume-snapshot.ts
|
|
181525
182396
|
const integer$1 = number$1().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
@@ -181614,6 +182485,7 @@ const stateRecordSchema = union([
|
|
|
181614
182485
|
verificationScope: _enum(GOAL_VERIFICATION_SCOPES).optional()
|
|
181615
182486
|
}),
|
|
181616
182487
|
record$1("goal.update", {
|
|
182488
|
+
objective: text.min(1).max(4e3).regex(/\S/).optional(),
|
|
181617
182489
|
status: _enum([
|
|
181618
182490
|
"active",
|
|
181619
182491
|
"paused",
|
|
@@ -181665,7 +182537,7 @@ const originCase = (kind, shape = {}) => object({
|
|
|
181665
182537
|
}).passthrough();
|
|
181666
182538
|
const origin = union([
|
|
181667
182539
|
originCase("user"),
|
|
181668
|
-
originCase("compaction_summary"),
|
|
182540
|
+
originCase("compaction_summary", { toolContinuity: custom$1(isToolContinuity).optional() }),
|
|
181669
182541
|
originCase("skill_activation", {
|
|
181670
182542
|
activationId: text,
|
|
181671
182543
|
skillName: text,
|
|
@@ -182016,6 +182888,7 @@ async function writeResumeCheckpoint(wirePath, position, snapshot) {
|
|
|
182016
182888
|
if (Buffer.byteLength(bytes) > MAX_CHECKPOINT_BYTES) return false;
|
|
182017
182889
|
const target = resumeCheckpointPath(wirePath);
|
|
182018
182890
|
const temporary = `${target}.tmp-${process.pid}-${randomBytes(8).toString("hex")}`;
|
|
182891
|
+
let renamed = false;
|
|
182019
182892
|
try {
|
|
182020
182893
|
const output = await open(temporary, "wx", 384);
|
|
182021
182894
|
try {
|
|
@@ -182025,10 +182898,11 @@ async function writeResumeCheckpoint(wirePath, position, snapshot) {
|
|
|
182025
182898
|
await output.close();
|
|
182026
182899
|
}
|
|
182027
182900
|
await rename(temporary, target);
|
|
182901
|
+
renamed = true;
|
|
182028
182902
|
await syncDir(dirname$3(target));
|
|
182029
182903
|
return true;
|
|
182030
182904
|
} finally {
|
|
182031
|
-
await rm(temporary, { force: true }).catch(() => {});
|
|
182905
|
+
if (!renamed) await rm(temporary, { force: true }).catch(() => {});
|
|
182032
182906
|
}
|
|
182033
182907
|
}
|
|
182034
182908
|
//#endregion
|
|
@@ -185365,501 +186239,6 @@ var TodoListTool = class {
|
|
|
185365
186239
|
})));
|
|
185366
186240
|
}
|
|
185367
186241
|
};
|
|
185368
|
-
const IMAGE_MIME_BY_SUFFIX = Object.freeze({
|
|
185369
|
-
".png": "image/png",
|
|
185370
|
-
".jpg": "image/jpeg",
|
|
185371
|
-
".jpeg": "image/jpeg",
|
|
185372
|
-
".gif": "image/gif",
|
|
185373
|
-
".bmp": "image/bmp",
|
|
185374
|
-
".tif": "image/tiff",
|
|
185375
|
-
".tiff": "image/tiff",
|
|
185376
|
-
".webp": "image/webp",
|
|
185377
|
-
".ico": "image/x-icon",
|
|
185378
|
-
".heic": "image/heic",
|
|
185379
|
-
".heif": "image/heif",
|
|
185380
|
-
".avif": "image/avif",
|
|
185381
|
-
".svgz": "image/svg+xml"
|
|
185382
|
-
});
|
|
185383
|
-
const VIDEO_MIME_BY_SUFFIX = Object.freeze({
|
|
185384
|
-
".mp4": "video/mp4",
|
|
185385
|
-
".mpg": "video/mpeg",
|
|
185386
|
-
".mpeg": "video/mpeg",
|
|
185387
|
-
".mkv": "video/x-matroska",
|
|
185388
|
-
".avi": "video/x-msvideo",
|
|
185389
|
-
".mov": "video/quicktime",
|
|
185390
|
-
".ogv": "video/ogg",
|
|
185391
|
-
".wmv": "video/x-ms-wmv",
|
|
185392
|
-
".webm": "video/webm",
|
|
185393
|
-
".m4v": "video/x-m4v",
|
|
185394
|
-
".flv": "video/x-flv",
|
|
185395
|
-
".3gp": "video/3gpp",
|
|
185396
|
-
".3g2": "video/3gpp2"
|
|
185397
|
-
});
|
|
185398
|
-
const TEXT_MIME_BY_SUFFIX = Object.freeze({ ".svg": "image/svg+xml" });
|
|
185399
|
-
const NON_TEXT_SUFFIXES = new Set([
|
|
185400
|
-
".icns",
|
|
185401
|
-
".psd",
|
|
185402
|
-
".ai",
|
|
185403
|
-
".eps",
|
|
185404
|
-
".pdf",
|
|
185405
|
-
".doc",
|
|
185406
|
-
".docx",
|
|
185407
|
-
".dot",
|
|
185408
|
-
".dotx",
|
|
185409
|
-
".rtf",
|
|
185410
|
-
".odt",
|
|
185411
|
-
".xls",
|
|
185412
|
-
".xlsx",
|
|
185413
|
-
".xlsm",
|
|
185414
|
-
".xlt",
|
|
185415
|
-
".xltx",
|
|
185416
|
-
".xltm",
|
|
185417
|
-
".ods",
|
|
185418
|
-
".ppt",
|
|
185419
|
-
".pptx",
|
|
185420
|
-
".pptm",
|
|
185421
|
-
".pps",
|
|
185422
|
-
".ppsx",
|
|
185423
|
-
".odp",
|
|
185424
|
-
".pages",
|
|
185425
|
-
".numbers",
|
|
185426
|
-
".key",
|
|
185427
|
-
".zip",
|
|
185428
|
-
".rar",
|
|
185429
|
-
".7z",
|
|
185430
|
-
".tar",
|
|
185431
|
-
".gz",
|
|
185432
|
-
".tgz",
|
|
185433
|
-
".bz2",
|
|
185434
|
-
".xz",
|
|
185435
|
-
".zst",
|
|
185436
|
-
".lz",
|
|
185437
|
-
".lz4",
|
|
185438
|
-
".br",
|
|
185439
|
-
".cab",
|
|
185440
|
-
".ar",
|
|
185441
|
-
".deb",
|
|
185442
|
-
".rpm",
|
|
185443
|
-
".mp3",
|
|
185444
|
-
".wav",
|
|
185445
|
-
".flac",
|
|
185446
|
-
".ogg",
|
|
185447
|
-
".oga",
|
|
185448
|
-
".opus",
|
|
185449
|
-
".aac",
|
|
185450
|
-
".m4a",
|
|
185451
|
-
".wma",
|
|
185452
|
-
".ttf",
|
|
185453
|
-
".otf",
|
|
185454
|
-
".woff",
|
|
185455
|
-
".woff2",
|
|
185456
|
-
".exe",
|
|
185457
|
-
".dll",
|
|
185458
|
-
".so",
|
|
185459
|
-
".dylib",
|
|
185460
|
-
".bin",
|
|
185461
|
-
".apk",
|
|
185462
|
-
".ipa",
|
|
185463
|
-
".jar",
|
|
185464
|
-
".class",
|
|
185465
|
-
".pyc",
|
|
185466
|
-
".pyo",
|
|
185467
|
-
".wasm",
|
|
185468
|
-
".dmg",
|
|
185469
|
-
".iso",
|
|
185470
|
-
".img",
|
|
185471
|
-
".sqlite",
|
|
185472
|
-
".sqlite3",
|
|
185473
|
-
".db",
|
|
185474
|
-
".db3"
|
|
185475
|
-
]);
|
|
185476
|
-
const ASF_HEADER = Buffer.from([
|
|
185477
|
-
48,
|
|
185478
|
-
38,
|
|
185479
|
-
178,
|
|
185480
|
-
117,
|
|
185481
|
-
142,
|
|
185482
|
-
102,
|
|
185483
|
-
207,
|
|
185484
|
-
17,
|
|
185485
|
-
166,
|
|
185486
|
-
217,
|
|
185487
|
-
0,
|
|
185488
|
-
170,
|
|
185489
|
-
0,
|
|
185490
|
-
98,
|
|
185491
|
-
206,
|
|
185492
|
-
108
|
|
185493
|
-
]);
|
|
185494
|
-
const FTYP_IMAGE_BRANDS = Object.freeze({
|
|
185495
|
-
avif: "image/avif",
|
|
185496
|
-
avis: "image/avif",
|
|
185497
|
-
heic: "image/heic",
|
|
185498
|
-
heif: "image/heif",
|
|
185499
|
-
heix: "image/heif",
|
|
185500
|
-
hevc: "image/heic",
|
|
185501
|
-
mif1: "image/heif",
|
|
185502
|
-
msf1: "image/heif"
|
|
185503
|
-
});
|
|
185504
|
-
const FTYP_VIDEO_BRANDS = Object.freeze({
|
|
185505
|
-
isom: "video/mp4",
|
|
185506
|
-
iso2: "video/mp4",
|
|
185507
|
-
iso5: "video/mp4",
|
|
185508
|
-
mp41: "video/mp4",
|
|
185509
|
-
mp42: "video/mp4",
|
|
185510
|
-
avc1: "video/mp4",
|
|
185511
|
-
mp4v: "video/mp4",
|
|
185512
|
-
m4v: "video/x-m4v",
|
|
185513
|
-
qt: "video/quicktime",
|
|
185514
|
-
"3gp4": "video/3gpp",
|
|
185515
|
-
"3gp5": "video/3gpp",
|
|
185516
|
-
"3gp6": "video/3gpp",
|
|
185517
|
-
"3gp7": "video/3gpp",
|
|
185518
|
-
"3g2": "video/3gpp2"
|
|
185519
|
-
});
|
|
185520
|
-
function toBuffer(data) {
|
|
185521
|
-
return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
185522
|
-
}
|
|
185523
|
-
function startsWith(buf, prefix) {
|
|
185524
|
-
const needle = Buffer.isBuffer(prefix) ? prefix : Buffer.from(prefix);
|
|
185525
|
-
if (buf.length < needle.length) return false;
|
|
185526
|
-
for (let i = 0; i < needle.length; i += 1) if (buf[i] !== needle[i]) return false;
|
|
185527
|
-
return true;
|
|
185528
|
-
}
|
|
185529
|
-
function sniffFtypBrand(header) {
|
|
185530
|
-
if (header.length < 12) return null;
|
|
185531
|
-
if (header.subarray(4, 8).toString("latin1") !== "ftyp") return null;
|
|
185532
|
-
return header.subarray(8, 12).toString("latin1").toLowerCase().replaceAll(/[\s\u0000]+$/g, "").trim();
|
|
185533
|
-
}
|
|
185534
|
-
function sniffMediaFromMagic(data) {
|
|
185535
|
-
const buf = toBuffer(data);
|
|
185536
|
-
const header = buf.length > 512 ? buf.subarray(0, 512) : buf;
|
|
185537
|
-
if (startsWith(header, [
|
|
185538
|
-
137,
|
|
185539
|
-
80,
|
|
185540
|
-
78,
|
|
185541
|
-
71,
|
|
185542
|
-
13,
|
|
185543
|
-
10,
|
|
185544
|
-
26,
|
|
185545
|
-
10
|
|
185546
|
-
])) return {
|
|
185547
|
-
kind: "image",
|
|
185548
|
-
mimeType: "image/png"
|
|
185549
|
-
};
|
|
185550
|
-
if (startsWith(header, [
|
|
185551
|
-
255,
|
|
185552
|
-
216,
|
|
185553
|
-
255
|
|
185554
|
-
])) return {
|
|
185555
|
-
kind: "image",
|
|
185556
|
-
mimeType: "image/jpeg"
|
|
185557
|
-
};
|
|
185558
|
-
if (startsWith(header, Buffer.from("GIF87a")) || startsWith(header, Buffer.from("GIF89a"))) return {
|
|
185559
|
-
kind: "image",
|
|
185560
|
-
mimeType: "image/gif"
|
|
185561
|
-
};
|
|
185562
|
-
if (startsWith(header, Buffer.from("BM"))) return {
|
|
185563
|
-
kind: "image",
|
|
185564
|
-
mimeType: "image/bmp"
|
|
185565
|
-
};
|
|
185566
|
-
if (startsWith(header, [
|
|
185567
|
-
73,
|
|
185568
|
-
73,
|
|
185569
|
-
42,
|
|
185570
|
-
0
|
|
185571
|
-
]) || startsWith(header, [
|
|
185572
|
-
77,
|
|
185573
|
-
77,
|
|
185574
|
-
0,
|
|
185575
|
-
42
|
|
185576
|
-
])) return {
|
|
185577
|
-
kind: "image",
|
|
185578
|
-
mimeType: "image/tiff"
|
|
185579
|
-
};
|
|
185580
|
-
if (startsWith(header, [
|
|
185581
|
-
0,
|
|
185582
|
-
0,
|
|
185583
|
-
1,
|
|
185584
|
-
0
|
|
185585
|
-
])) return {
|
|
185586
|
-
kind: "image",
|
|
185587
|
-
mimeType: "image/x-icon"
|
|
185588
|
-
};
|
|
185589
|
-
if (startsWith(header, Buffer.from("RIFF")) && header.length >= 12) {
|
|
185590
|
-
const chunk = header.subarray(8, 12).toString("latin1");
|
|
185591
|
-
if (chunk === "WEBP") return {
|
|
185592
|
-
kind: "image",
|
|
185593
|
-
mimeType: "image/webp"
|
|
185594
|
-
};
|
|
185595
|
-
if (chunk === "AVI ") return {
|
|
185596
|
-
kind: "video",
|
|
185597
|
-
mimeType: "video/x-msvideo"
|
|
185598
|
-
};
|
|
185599
|
-
}
|
|
185600
|
-
if (startsWith(header, Buffer.from("FLV"))) return {
|
|
185601
|
-
kind: "video",
|
|
185602
|
-
mimeType: "video/x-flv"
|
|
185603
|
-
};
|
|
185604
|
-
if (startsWith(header, ASF_HEADER)) return {
|
|
185605
|
-
kind: "video",
|
|
185606
|
-
mimeType: "video/x-ms-wmv"
|
|
185607
|
-
};
|
|
185608
|
-
if (startsWith(header, [
|
|
185609
|
-
26,
|
|
185610
|
-
69,
|
|
185611
|
-
223,
|
|
185612
|
-
163
|
|
185613
|
-
])) {
|
|
185614
|
-
const lowered = header.toString("latin1").toLowerCase();
|
|
185615
|
-
if (lowered.includes("webm")) return {
|
|
185616
|
-
kind: "video",
|
|
185617
|
-
mimeType: "video/webm"
|
|
185618
|
-
};
|
|
185619
|
-
if (lowered.includes("matroska")) return {
|
|
185620
|
-
kind: "video",
|
|
185621
|
-
mimeType: "video/x-matroska"
|
|
185622
|
-
};
|
|
185623
|
-
}
|
|
185624
|
-
const brand = sniffFtypBrand(header);
|
|
185625
|
-
if (brand !== null && brand !== "") {
|
|
185626
|
-
if (brand in FTYP_IMAGE_BRANDS) return {
|
|
185627
|
-
kind: "image",
|
|
185628
|
-
mimeType: FTYP_IMAGE_BRANDS[brand]
|
|
185629
|
-
};
|
|
185630
|
-
if (brand in FTYP_VIDEO_BRANDS) return {
|
|
185631
|
-
kind: "video",
|
|
185632
|
-
mimeType: FTYP_VIDEO_BRANDS[brand]
|
|
185633
|
-
};
|
|
185634
|
-
}
|
|
185635
|
-
return null;
|
|
185636
|
-
}
|
|
185637
|
-
/**
|
|
185638
|
-
* Best-effort pixel-dimension reader for common raster formats.
|
|
185639
|
-
*
|
|
185640
|
-
* Inspects only the fixed region near the start of the file where each
|
|
185641
|
-
* format records its dimensions (the IHDR/DIB header, the RIFF chunk
|
|
185642
|
-
* after the `WEBP` tag, or the first JPEG SOFn segment). Returns `null`
|
|
185643
|
-
* for formats whose dimensions are not locatable from that region, or
|
|
185644
|
-
* when the supplied buffer is too short to cover it.
|
|
185645
|
-
*/
|
|
185646
|
-
function sniffImageDimensions(data) {
|
|
185647
|
-
const buf = toBuffer(data);
|
|
185648
|
-
if (startsWith(buf, [
|
|
185649
|
-
137,
|
|
185650
|
-
80,
|
|
185651
|
-
78,
|
|
185652
|
-
71,
|
|
185653
|
-
13,
|
|
185654
|
-
10,
|
|
185655
|
-
26,
|
|
185656
|
-
10
|
|
185657
|
-
]) && buf.length >= 24) return {
|
|
185658
|
-
width: buf.readUInt32BE(16),
|
|
185659
|
-
height: buf.readUInt32BE(20)
|
|
185660
|
-
};
|
|
185661
|
-
if ((startsWith(buf, Buffer.from("GIF87a")) || startsWith(buf, Buffer.from("GIF89a"))) && buf.length >= 10) return {
|
|
185662
|
-
width: buf.readUInt16LE(6),
|
|
185663
|
-
height: buf.readUInt16LE(8)
|
|
185664
|
-
};
|
|
185665
|
-
if (startsWith(buf, Buffer.from("BM")) && buf.length >= 26) return {
|
|
185666
|
-
width: buf.readInt32LE(18),
|
|
185667
|
-
height: Math.abs(buf.readInt32LE(22))
|
|
185668
|
-
};
|
|
185669
|
-
if (startsWith(buf, Buffer.from("RIFF")) && buf.length >= 30) {
|
|
185670
|
-
const fourCc = buf.subarray(12, 16).toString("latin1");
|
|
185671
|
-
if (fourCc === "VP8 ") return {
|
|
185672
|
-
width: buf.readUInt16LE(26) & 16383,
|
|
185673
|
-
height: buf.readUInt16LE(28) & 16383
|
|
185674
|
-
};
|
|
185675
|
-
if (fourCc === "VP8L" && buf.length >= 25) {
|
|
185676
|
-
const bits = buf.readUInt32LE(21);
|
|
185677
|
-
return {
|
|
185678
|
-
width: (bits & 16383) + 1,
|
|
185679
|
-
height: (bits >> 14 & 16383) + 1
|
|
185680
|
-
};
|
|
185681
|
-
}
|
|
185682
|
-
if (fourCc === "VP8X") return {
|
|
185683
|
-
width: 1 + (buf[24] | buf[25] << 8 | buf[26] << 16),
|
|
185684
|
-
height: 1 + (buf[27] | buf[28] << 8 | buf[29] << 16)
|
|
185685
|
-
};
|
|
185686
|
-
}
|
|
185687
|
-
if (startsWith(buf, [255, 216])) {
|
|
185688
|
-
let offset = 2;
|
|
185689
|
-
while (offset + 9 < buf.length) {
|
|
185690
|
-
if (buf[offset] !== 255) {
|
|
185691
|
-
offset += 1;
|
|
185692
|
-
continue;
|
|
185693
|
-
}
|
|
185694
|
-
const marker = buf[offset + 1];
|
|
185695
|
-
if (marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204) return {
|
|
185696
|
-
height: buf.readUInt16BE(offset + 5),
|
|
185697
|
-
width: buf.readUInt16BE(offset + 7)
|
|
185698
|
-
};
|
|
185699
|
-
if (marker === 216 || marker === 217 || marker >= 208 && marker <= 215) {
|
|
185700
|
-
offset += 2;
|
|
185701
|
-
continue;
|
|
185702
|
-
}
|
|
185703
|
-
const segmentLength = buf.readUInt16BE(offset + 2);
|
|
185704
|
-
if (segmentLength < 2) break;
|
|
185705
|
-
offset += 2 + segmentLength;
|
|
185706
|
-
}
|
|
185707
|
-
}
|
|
185708
|
-
return null;
|
|
185709
|
-
}
|
|
185710
|
-
function getSuffix(path) {
|
|
185711
|
-
const idx = path.lastIndexOf(".");
|
|
185712
|
-
if (idx === -1) return "";
|
|
185713
|
-
if (idx <= Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\")) + 1) return "";
|
|
185714
|
-
return path.slice(idx).toLowerCase();
|
|
185715
|
-
}
|
|
185716
|
-
function detectFileType(path, header, type = "text") {
|
|
185717
|
-
const suffix = getSuffix(path);
|
|
185718
|
-
let mediaHint = null;
|
|
185719
|
-
if (suffix in TEXT_MIME_BY_SUFFIX) mediaHint = {
|
|
185720
|
-
kind: "text",
|
|
185721
|
-
mimeType: TEXT_MIME_BY_SUFFIX[suffix]
|
|
185722
|
-
};
|
|
185723
|
-
else if (suffix in IMAGE_MIME_BY_SUFFIX) mediaHint = {
|
|
185724
|
-
kind: "image",
|
|
185725
|
-
mimeType: IMAGE_MIME_BY_SUFFIX[suffix]
|
|
185726
|
-
};
|
|
185727
|
-
else if (suffix in VIDEO_MIME_BY_SUFFIX) mediaHint = {
|
|
185728
|
-
kind: "video",
|
|
185729
|
-
mimeType: VIDEO_MIME_BY_SUFFIX[suffix]
|
|
185730
|
-
};
|
|
185731
|
-
if (header !== void 0) {
|
|
185732
|
-
const buf = toBuffer(header);
|
|
185733
|
-
const sniffed = sniffMediaFromMagic(buf);
|
|
185734
|
-
if (sniffed) {
|
|
185735
|
-
if (type === "media") return sniffed;
|
|
185736
|
-
if (mediaHint) {
|
|
185737
|
-
if (sniffed.kind !== mediaHint.kind) return {
|
|
185738
|
-
kind: "unknown",
|
|
185739
|
-
mimeType: ""
|
|
185740
|
-
};
|
|
185741
|
-
return mediaHint;
|
|
185742
|
-
}
|
|
185743
|
-
return sniffed;
|
|
185744
|
-
}
|
|
185745
|
-
if (mediaHint?.kind === "image") return {
|
|
185746
|
-
kind: "unknown",
|
|
185747
|
-
mimeType: ""
|
|
185748
|
-
};
|
|
185749
|
-
if (type === "media" && mediaHint?.kind === "video") return mediaHint;
|
|
185750
|
-
if (buf.includes(0)) return {
|
|
185751
|
-
kind: "unknown",
|
|
185752
|
-
mimeType: ""
|
|
185753
|
-
};
|
|
185754
|
-
}
|
|
185755
|
-
if (mediaHint) return mediaHint;
|
|
185756
|
-
if (NON_TEXT_SUFFIXES.has(suffix)) return {
|
|
185757
|
-
kind: "unknown",
|
|
185758
|
-
mimeType: ""
|
|
185759
|
-
};
|
|
185760
|
-
return {
|
|
185761
|
-
kind: "text",
|
|
185762
|
-
mimeType: "text/plain"
|
|
185763
|
-
};
|
|
185764
|
-
}
|
|
185765
|
-
//#endregion
|
|
185766
|
-
//#region ../../packages/agent-core/src/utils/tokens.ts
|
|
185767
|
-
const messageTokenEstimateCache = /* @__PURE__ */ new WeakMap();
|
|
185768
|
-
/** Open assistant messages grow while streaming; completed history stays cached. */
|
|
185769
|
-
function invalidateMessageTokenEstimate(message) {
|
|
185770
|
-
messageTokenEstimateCache.delete(message);
|
|
185771
|
-
}
|
|
185772
|
-
/**
|
|
185773
|
-
* Estimate token count from text using a character-based heuristic.
|
|
185774
|
-
* - ASCII (~4 chars per token)
|
|
185775
|
-
* - CJK and other non-ASCII (~1 char per token)
|
|
185776
|
-
* The estimate is transient — the next LLM call returns the real count
|
|
185777
|
-
* and supersedes this value. Used to keep `tokenCountWithPending`
|
|
185778
|
-
* monotonic between LLM round-trips without paying for a tokenizer.
|
|
185779
|
-
*/
|
|
185780
|
-
function estimateTokens(text) {
|
|
185781
|
-
let asciiCount = 0;
|
|
185782
|
-
let nonAsciiCount = 0;
|
|
185783
|
-
for (const char of text) if (char.codePointAt(0) <= 127) asciiCount++;
|
|
185784
|
-
else nonAsciiCount++;
|
|
185785
|
-
return Math.ceil(asciiCount / 4) + nonAsciiCount;
|
|
185786
|
-
}
|
|
185787
|
-
function estimateTokensForMessages(messages) {
|
|
185788
|
-
let total = 0;
|
|
185789
|
-
for (const message of messages) total += estimateTokensForMessage(message);
|
|
185790
|
-
return total;
|
|
185791
|
-
}
|
|
185792
|
-
function estimateTokensForTools(tools) {
|
|
185793
|
-
let total = 0;
|
|
185794
|
-
for (const tool of tools) {
|
|
185795
|
-
total += estimateTokens(tool.name);
|
|
185796
|
-
total += estimateTokens(tool.description);
|
|
185797
|
-
total += estimateTokens(JSON.stringify(tool.parameters));
|
|
185798
|
-
}
|
|
185799
|
-
return total;
|
|
185800
|
-
}
|
|
185801
|
-
function estimateTokensForMessage(message) {
|
|
185802
|
-
const cached = messageTokenEstimateCache.get(message);
|
|
185803
|
-
if (cached !== void 0) return cached;
|
|
185804
|
-
let total = estimateTokens(message.role);
|
|
185805
|
-
total += estimateTokensForContentParts(message.content);
|
|
185806
|
-
if (message.toolCalls !== void 0) for (const call of message.toolCalls) {
|
|
185807
|
-
total += estimateTokens(call.name);
|
|
185808
|
-
total += estimateTokens(JSON.stringify(call.arguments));
|
|
185809
|
-
}
|
|
185810
|
-
messageTokenEstimateCache.set(message, total);
|
|
185811
|
-
return total;
|
|
185812
|
-
}
|
|
185813
|
-
function estimateTokensForContentParts(parts) {
|
|
185814
|
-
let total = 0;
|
|
185815
|
-
for (const part of parts) total += estimateTokensForContentPart(part);
|
|
185816
|
-
return total;
|
|
185817
|
-
}
|
|
185818
|
-
/**
|
|
185819
|
-
* Conservative transient fallback for media whose pixel dimensions or duration
|
|
185820
|
-
* are unavailable. Inline raster images use their transmitted dimensions below;
|
|
185821
|
-
* audio, video, remote images, and malformed image data keep this safe floor.
|
|
185822
|
-
* The next successful LLM round-trip replaces the estimate with reported usage.
|
|
185823
|
-
*/
|
|
185824
|
-
const MEDIA_TOKEN_ESTIMATE = 2e3;
|
|
185825
|
-
/** Enough header data for common JPEG metadata followed by the first SOF marker. */
|
|
185826
|
-
const MAX_IMAGE_HEADER_BYTES = 1024 * 1024;
|
|
185827
|
-
function imageDimensionsFromDataUrl(url) {
|
|
185828
|
-
const commaIndex = url.indexOf(",");
|
|
185829
|
-
if (commaIndex <= 0) return null;
|
|
185830
|
-
const metadata = url.slice(0, commaIndex).toLowerCase();
|
|
185831
|
-
if (!metadata.startsWith("data:image/") || !metadata.split(";").includes("base64")) return null;
|
|
185832
|
-
const maxBase64Chars = Math.ceil(MAX_IMAGE_HEADER_BYTES / 3) * 4;
|
|
185833
|
-
const encodedHeader = url.slice(commaIndex + 1, commaIndex + 1 + maxBase64Chars);
|
|
185834
|
-
if (encodedHeader.length === 0) return null;
|
|
185835
|
-
try {
|
|
185836
|
-
const dimensions = sniffImageDimensions(Buffer.from(encodedHeader, "base64"));
|
|
185837
|
-
if (dimensions === null || !Number.isSafeInteger(dimensions.width) || !Number.isSafeInteger(dimensions.height) || dimensions.width <= 0 || dimensions.height <= 0) return null;
|
|
185838
|
-
return dimensions;
|
|
185839
|
-
} catch {
|
|
185840
|
-
return null;
|
|
185841
|
-
}
|
|
185842
|
-
}
|
|
185843
|
-
function estimateImageTokensFromDimensions(width, height) {
|
|
185844
|
-
if (!Number.isSafeInteger(width) || !Number.isSafeInteger(height) || width <= 0 || height <= 0) return MEDIA_TOKEN_ESTIMATE;
|
|
185845
|
-
const patchSize = BigInt(32);
|
|
185846
|
-
const tokens = (BigInt(width) + patchSize - 1n) / patchSize * ((BigInt(height) + patchSize - 1n) / patchSize);
|
|
185847
|
-
return tokens > BigInt(Number.MAX_SAFE_INTEGER) ? Number.MAX_SAFE_INTEGER : Number(tokens);
|
|
185848
|
-
}
|
|
185849
|
-
function estimateImageTokens(url) {
|
|
185850
|
-
const dimensions = imageDimensionsFromDataUrl(url);
|
|
185851
|
-
return dimensions === null ? MEDIA_TOKEN_ESTIMATE : estimateImageTokensFromDimensions(dimensions.width, dimensions.height);
|
|
185852
|
-
}
|
|
185853
|
-
function estimateTokensForContentPart(part) {
|
|
185854
|
-
switch (part.type) {
|
|
185855
|
-
case "text": return estimateTokens(part.text);
|
|
185856
|
-
case "think": return estimateTokens(part.think);
|
|
185857
|
-
case "image_url": return estimateImageTokens(part.imageUrl.url);
|
|
185858
|
-
case "audio_url":
|
|
185859
|
-
case "video_url": return MEDIA_TOKEN_ESTIMATE;
|
|
185860
|
-
default: return 0;
|
|
185861
|
-
}
|
|
185862
|
-
}
|
|
185863
186242
|
//#endregion
|
|
185864
186243
|
//#region ../../node_modules/.pnpm/bmp-ts@1.0.9/node_modules/bmp-ts/dist/esm/header-types.js
|
|
185865
186244
|
var HeaderTypes, header_types_default;
|
|
@@ -228325,6 +228704,8 @@ async function compressImageForModel(bytes, mimeType, options = {}) {
|
|
|
228325
228704
|
if (bytes.length <= byteBudget && (longestEdge > 0 && longestEdge <= maxEdge || longestEdge === 0)) return passthrough();
|
|
228326
228705
|
if (dims && dims.width * dims.height > MAX_DECODE_PIXELS) return passthrough();
|
|
228327
228706
|
if (bytes.length > maxDecodeBytes) return passthrough();
|
|
228707
|
+
const detected = detectFileType("", bytes.subarray(0, 512), "media");
|
|
228708
|
+
if (!RECODABLE_MIME.has(detected.mimeType)) return passthrough();
|
|
228328
228709
|
try {
|
|
228329
228710
|
const { Jimp } = await Promise.resolve().then(() => (init_esm(), esm_exports$3));
|
|
228330
228711
|
const image = await Jimp.fromBuffer(Buffer.from(bytes));
|
|
@@ -230115,7 +230496,7 @@ function buildCompactionSummaryText(summary) {
|
|
|
230115
230496
|
const MAX_SESSION_COMPACTION_FAILURES = 2;
|
|
230116
230497
|
const DEFAULT_COMPACTION_MAX_COMPLETION_TOKENS = 128 * 1024;
|
|
230117
230498
|
const COMPACTION_SUMMARY_RESERVE_RATIO = .1;
|
|
230118
|
-
const BLUN_COMPACTION_REQUEST_BUDGET_BYTES =
|
|
230499
|
+
const BLUN_COMPACTION_REQUEST_BUDGET_BYTES = 48e4;
|
|
230119
230500
|
const MAX_HIERARCHICAL_COMPACTION_PASSES = 64;
|
|
230120
230501
|
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:";
|
|
230121
230502
|
var CompactionTruncatedError = class extends Error {
|
|
@@ -230235,16 +230616,19 @@ var FullCompaction = class {
|
|
|
230235
230616
|
const projected = context.additionalMessages === void 0 ? messages : [...messages, ...context.additionalMessages];
|
|
230236
230617
|
const historyBudget = this.requestHistoryByteBudget(projected);
|
|
230237
230618
|
const historyThresholdReached = historyBudget !== void 0 && historyBudget.usedHistoryBytes >= historyBudget.thresholdHistoryBytes;
|
|
230619
|
+
const requestBudget = this.requestBodyByteBudget(projected, context);
|
|
230620
|
+
const requestThresholdReached = requestBudget !== void 0 && requestBudget.usedRequestBytesEstimate >= requestBudget.thresholdRequestBytes;
|
|
230238
230621
|
if (this.sessionCompactionFailures >= MAX_SESSION_COMPACTION_FAILURES) reason = "session_stopped";
|
|
230239
230622
|
else if (this.isCompacting) reason = "already_compacting";
|
|
230240
|
-
else if (thresholdTokens === void 0 && historyBudget === void 0) reason = "no_budget";
|
|
230241
|
-
else if (!historyThresholdReached && (thresholdTokens === void 0 || !Number.isFinite(usedTokens) || usedTokens < thresholdTokens)) reason = "below_threshold";
|
|
230623
|
+
else if (thresholdTokens === void 0 && historyBudget === void 0 && requestBudget === void 0) reason = "no_budget";
|
|
230624
|
+
else if (!historyThresholdReached && !requestThresholdReached && (thresholdTokens === void 0 || !Number.isFinite(usedTokens) || usedTokens < thresholdTokens)) reason = "below_threshold";
|
|
230242
230625
|
else if (!this.hasShrinkableHistory(projected)) reason = "nothing_to_compact";
|
|
230243
230626
|
return {
|
|
230244
230627
|
eligible: reason === "eligible",
|
|
230245
230628
|
usedTokens,
|
|
230246
230629
|
thresholdTokens,
|
|
230247
230630
|
...historyBudget,
|
|
230631
|
+
...requestBudget,
|
|
230248
230632
|
reason
|
|
230249
230633
|
};
|
|
230250
230634
|
}
|
|
@@ -230266,6 +230650,19 @@ var FullCompaction = class {
|
|
|
230266
230650
|
thresholdHistoryBytes: limit
|
|
230267
230651
|
};
|
|
230268
230652
|
}
|
|
230653
|
+
requestBodyByteBudget(messages, context) {
|
|
230654
|
+
const limit = this.agent.blunConfig?.loopControl?.maxRequestHistoryBytes;
|
|
230655
|
+
if (!this.agent.config.hasProvider || this.strategy.compactionBudgetTokens === void 0 || limit !== void 0 && (!Number.isSafeInteger(limit) || limit <= 0)) return void 0;
|
|
230656
|
+
const model = this.agent.activeResponderModel ?? this.agent.config.modelAlias;
|
|
230657
|
+
if (model === void 0 || this.agent.config.runtimeModel(model).provider.name !== "blun") return void 0;
|
|
230658
|
+
const systemPrompt = context.systemPrompt ?? this.agent.effectiveSystemPrompt;
|
|
230659
|
+
const tools = context.tools ?? this.agent.tools.loopTools;
|
|
230660
|
+
if (estimateBlunSerializedBodyBytes(systemPrompt, [], []) + 4096 >= BLUN_COMPACTION_REQUEST_BUDGET_BYTES) return void 0;
|
|
230661
|
+
return {
|
|
230662
|
+
usedRequestBytesEstimate: estimateBlunSerializedBodyBytes(systemPrompt, tools, messages) + 4096,
|
|
230663
|
+
thresholdRequestBytes: BLUN_COMPACTION_REQUEST_BUDGET_BYTES
|
|
230664
|
+
};
|
|
230665
|
+
}
|
|
230269
230666
|
requestProactiveCompaction(context = {}) {
|
|
230270
230667
|
const status = this.proactiveCompactionStatus(context);
|
|
230271
230668
|
if (status.eligible && !this.proactiveCompactionRequested) {
|
|
@@ -230274,7 +230671,9 @@ var FullCompaction = class {
|
|
|
230274
230671
|
used_tokens: status.usedTokens,
|
|
230275
230672
|
threshold_tokens: status.thresholdTokens,
|
|
230276
230673
|
used_history_bytes: status.usedHistoryBytes,
|
|
230277
|
-
threshold_history_bytes: status.thresholdHistoryBytes
|
|
230674
|
+
threshold_history_bytes: status.thresholdHistoryBytes,
|
|
230675
|
+
used_request_bytes_estimate: status.usedRequestBytesEstimate,
|
|
230676
|
+
threshold_request_bytes: status.thresholdRequestBytes
|
|
230278
230677
|
});
|
|
230279
230678
|
}
|
|
230280
230679
|
return status;
|
|
@@ -230403,7 +230802,9 @@ var FullCompaction = class {
|
|
|
230403
230802
|
const requestTokens = this.estimateCurrentRequestTokens(requestContext);
|
|
230404
230803
|
const budget = this.getCompactionBudgetTokens();
|
|
230405
230804
|
const historyBudget = this.requestHistoryByteBudget(projectedMessages);
|
|
230406
|
-
const
|
|
230805
|
+
const historyThresholdReached = historyBudget !== void 0 && historyBudget.usedHistoryBytes >= historyBudget.thresholdHistoryBytes;
|
|
230806
|
+
const requestBudget = this.requestBodyByteBudget(projectedMessages, requestContext);
|
|
230807
|
+
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);
|
|
230407
230808
|
if (this.checkAutoCompaction(true, requestTokens, projectedMessages, proactive) && (proactive || this.strategy.shouldBlock(requestTokens))) await this.block(signal);
|
|
230408
230809
|
signal.throwIfAborted();
|
|
230409
230810
|
const compacted = this.agent.context.history !== historyBefore;
|
|
@@ -230613,7 +231014,7 @@ var FullCompaction = class {
|
|
|
230613
231014
|
dropOrphanResults: true
|
|
230614
231015
|
}), createUserMessage(requestInstruction)], capability));
|
|
230615
231016
|
};
|
|
230616
|
-
const estimateRequestBytes = (messages) =>
|
|
231017
|
+
const estimateRequestBytes = (messages) => estimateBlunSerializedBodyBytes(this.agent.effectiveSystemPrompt, compactionTools, messages) + 4096;
|
|
230617
231018
|
while (true) {
|
|
230618
231019
|
signal.throwIfAborted();
|
|
230619
231020
|
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: {
|
|
@@ -231292,6 +231693,13 @@ const CronRunStatusSchema = _enum([
|
|
|
231292
231693
|
]);
|
|
231293
231694
|
const counter = number$1().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
231294
231695
|
const timestamp$1 = string().datetime();
|
|
231696
|
+
const CronProviderUsageSchema = object({
|
|
231697
|
+
inputOther: counter,
|
|
231698
|
+
inputCacheRead: counter,
|
|
231699
|
+
inputCacheCreation: counter,
|
|
231700
|
+
output: counter,
|
|
231701
|
+
outputReasoning: counter.optional()
|
|
231702
|
+
}).strict();
|
|
231295
231703
|
const CronRunReceiptSchema = object({
|
|
231296
231704
|
runId: CronRunIdSchema,
|
|
231297
231705
|
jobId: CronJobIdSchema,
|
|
@@ -231312,6 +231720,7 @@ const CronRunReceiptSchema = object({
|
|
|
231312
231720
|
names: array(string().regex(/^[\w.:-]{1,160}$/)).max(64),
|
|
231313
231721
|
excessNames: counter
|
|
231314
231722
|
}).strict(),
|
|
231723
|
+
providerUsage: CronProviderUsageSchema.nullable().optional(),
|
|
231315
231724
|
outputs: array(object({
|
|
231316
231725
|
rootRef: string().regex(/^(workspace|additional:[0-9]+)$/),
|
|
231317
231726
|
path: string().min(1).max(1024).refine((value) => Buffer.byteLength(value) <= 1024 && !value.startsWith("/") && !value.includes("\\") && !value.includes(":") && !value.split("/").some((part) => part === ".." || part === ".") && !/[\u0000-\u001F\u007F]/.test(value))
|
|
@@ -231347,6 +231756,7 @@ function publicCronRun(run) {
|
|
|
231347
231756
|
coalescedCount: receipt.coalescedCount,
|
|
231348
231757
|
toolCalls: receipt.toolSummary.calls,
|
|
231349
231758
|
toolErrors: receipt.toolSummary.errors,
|
|
231759
|
+
providerUsage: receipt.providerUsage ?? null,
|
|
231350
231760
|
outputCount: receipt.outputs.length,
|
|
231351
231761
|
finalMessageAvailable: run.finalMessage !== null,
|
|
231352
231762
|
durable: run.durable
|
|
@@ -231548,6 +231958,8 @@ var CronRunOutputCollector = class {
|
|
|
231548
231958
|
errors = 0;
|
|
231549
231959
|
excessNames = 0;
|
|
231550
231960
|
outputs = [];
|
|
231961
|
+
providerUsage;
|
|
231962
|
+
usageComplete = true;
|
|
231551
231963
|
invalid = false;
|
|
231552
231964
|
constructor(roots) {
|
|
231553
231965
|
this.roots = roots;
|
|
@@ -231568,6 +231980,7 @@ var CronRunOutputCollector = class {
|
|
|
231568
231980
|
}
|
|
231569
231981
|
if (event.type === "step.retrying") {
|
|
231570
231982
|
if (event.turnId !== String(this.turnId)) return;
|
|
231983
|
+
this.usageComplete = false;
|
|
231571
231984
|
if (this.step === void 0 || this.step.id !== event.stepUuid || this.step.step !== event.step || this.step.tools) this.invalid = true;
|
|
231572
231985
|
else {
|
|
231573
231986
|
this.step = {
|
|
@@ -231636,19 +232049,29 @@ var CronRunOutputCollector = class {
|
|
|
231636
232049
|
} else if (event.type === "step.end") {
|
|
231637
232050
|
const step = this.step;
|
|
231638
232051
|
if (step === void 0 || event.uuid !== step.id || event.step !== step.step) this.invalid = true;
|
|
231639
|
-
else
|
|
231640
|
-
const
|
|
231641
|
-
|
|
231642
|
-
|
|
231643
|
-
|
|
231644
|
-
|
|
231645
|
-
|
|
231646
|
-
|
|
231647
|
-
|
|
231648
|
-
|
|
231649
|
-
|
|
231650
|
-
|
|
231651
|
-
|
|
232052
|
+
else {
|
|
232053
|
+
const usage = event.usage === void 0 ? void 0 : CronProviderUsageSchema.safeParse(event.usage);
|
|
232054
|
+
if (usage?.success !== true) this.usageComplete = false;
|
|
232055
|
+
else {
|
|
232056
|
+
const total = this.providerUsage === void 0 ? usage.data : addUsage(this.providerUsage, usage.data);
|
|
232057
|
+
const checked = CronProviderUsageSchema.safeParse(total);
|
|
232058
|
+
if (checked.success) this.providerUsage = checked.data;
|
|
232059
|
+
else this.usageComplete = false;
|
|
232060
|
+
}
|
|
232061
|
+
if (event.finishReason === "end_turn" && !step.tools && !this.invalid) {
|
|
232062
|
+
const clipped = prefix(step.text);
|
|
232063
|
+
const truncated = step.chars > clipped.length;
|
|
232064
|
+
const text = clipped + (truncated ? CRON_RUN_TRUNCATION_MARKER : "");
|
|
232065
|
+
if (text) this.candidate = {
|
|
232066
|
+
stepId: step.id,
|
|
232067
|
+
turnId: this.turnId,
|
|
232068
|
+
message: {
|
|
232069
|
+
text,
|
|
232070
|
+
truncated,
|
|
232071
|
+
chars: step.chars
|
|
232072
|
+
}
|
|
232073
|
+
};
|
|
232074
|
+
}
|
|
231652
232075
|
}
|
|
231653
232076
|
this.step = void 0;
|
|
231654
232077
|
}
|
|
@@ -231663,6 +232086,7 @@ var CronRunOutputCollector = class {
|
|
|
231663
232086
|
excessNames: this.excessNames
|
|
231664
232087
|
},
|
|
231665
232088
|
outputs: structuredClone(this.outputs),
|
|
232089
|
+
providerUsage: complete && this.usageComplete && this.providerUsage !== void 0 ? structuredClone(this.providerUsage) : null,
|
|
231666
232090
|
final: complete ? this.candidate : void 0,
|
|
231667
232091
|
complete
|
|
231668
232092
|
};
|
|
@@ -232821,6 +233245,7 @@ var CronManager = class {
|
|
|
232821
233245
|
status,
|
|
232822
233246
|
endedAt: new Date(this.clocks.wallNow()).toISOString(),
|
|
232823
233247
|
toolSummary: result.toolSummary,
|
|
233248
|
+
providerUsage: completed ? result.providerUsage : null,
|
|
232824
233249
|
outputs: result.outputs,
|
|
232825
233250
|
finalMessageRef: final === void 0 ? null : {
|
|
232826
233251
|
stepId: final.stepId,
|
|
@@ -233008,6 +233433,7 @@ var CronManager = class {
|
|
|
233008
233433
|
names: [],
|
|
233009
233434
|
excessNames: 0
|
|
233010
233435
|
},
|
|
233436
|
+
providerUsage: null,
|
|
233011
233437
|
outputs: [],
|
|
233012
233438
|
finalMessageRef: null,
|
|
233013
233439
|
unavailableReason
|
|
@@ -234063,6 +234489,10 @@ const SYNTHETIC_TOOL_RESULT_TEXT = "Tool result is not available in the current
|
|
|
234063
234489
|
function repairToolExchangeAdjacency(messages, options) {
|
|
234064
234490
|
let lastNonToolIndex = messages.length - 1;
|
|
234065
234491
|
while (lastNonToolIndex >= 0 && messages[lastNonToolIndex]?.role === "tool") lastNonToolIndex -= 1;
|
|
234492
|
+
let remainingResults;
|
|
234493
|
+
const consumeResult = (toolCallId) => {
|
|
234494
|
+
if (remainingResults !== void 0) remainingResults.set(toolCallId, (remainingResults.get(toolCallId) ?? 0) - 1);
|
|
234495
|
+
};
|
|
234066
234496
|
const out = [];
|
|
234067
234497
|
const consumed = /* @__PURE__ */ new Set();
|
|
234068
234498
|
for (let i = 0; i < messages.length; i++) {
|
|
@@ -234070,12 +234500,15 @@ function repairToolExchangeAdjacency(messages, options) {
|
|
|
234070
234500
|
const message = messages[i];
|
|
234071
234501
|
if (message.role !== "assistant" || message.toolCalls.length === 0) {
|
|
234072
234502
|
out.push(message);
|
|
234503
|
+
if (message.role === "tool" && message.toolCallId !== void 0) consumeResult(message.toolCallId);
|
|
234073
234504
|
continue;
|
|
234074
234505
|
}
|
|
234075
234506
|
out.push(message);
|
|
234076
234507
|
const pending = new Set(message.toolCalls.map((toolCall) => toolCall.id));
|
|
234508
|
+
const counts = remainingResults;
|
|
234509
|
+
let searchable = counts === void 0 ? void 0 : new Set([...pending].filter((id) => (counts.get(id) ?? 0) > 0));
|
|
234077
234510
|
let foreignBetween = false;
|
|
234078
|
-
for (let j = i + 1; j < messages.length && pending.size > 0; j++) {
|
|
234511
|
+
for (let j = i + 1; j < messages.length && (searchable ?? pending).size > 0; j++) {
|
|
234079
234512
|
if (consumed.has(j)) continue;
|
|
234080
234513
|
const next = messages[j];
|
|
234081
234514
|
const toolCallId = next.toolCallId;
|
|
@@ -234083,11 +234516,25 @@ function repairToolExchangeAdjacency(messages, options) {
|
|
|
234083
234516
|
out.push(next);
|
|
234084
234517
|
consumed.add(j);
|
|
234085
234518
|
pending.delete(toolCallId);
|
|
234519
|
+
searchable?.delete(toolCallId);
|
|
234520
|
+
consumeResult(toolCallId);
|
|
234086
234521
|
if (foreignBetween) options?.onAnomaly?.({
|
|
234087
234522
|
kind: "tool_result_reordered",
|
|
234088
234523
|
toolCallId
|
|
234089
234524
|
});
|
|
234090
|
-
} else
|
|
234525
|
+
} else {
|
|
234526
|
+
foreignBetween = true;
|
|
234527
|
+
if (remainingResults === void 0) {
|
|
234528
|
+
remainingResults = /* @__PURE__ */ new Map();
|
|
234529
|
+
for (let index = j; index < messages.length; index += 1) {
|
|
234530
|
+
if (consumed.has(index)) continue;
|
|
234531
|
+
const result = messages[index];
|
|
234532
|
+
if (result.role === "tool" && result.toolCallId !== void 0) remainingResults.set(result.toolCallId, (remainingResults.get(result.toolCallId) ?? 0) + 1);
|
|
234533
|
+
}
|
|
234534
|
+
}
|
|
234535
|
+
const counts = remainingResults;
|
|
234536
|
+
searchable ??= new Set([...pending].filter((id) => (counts.get(id) ?? 0) > 0));
|
|
234537
|
+
}
|
|
234091
234538
|
}
|
|
234092
234539
|
const isMidHistory = i < lastNonToolIndex;
|
|
234093
234540
|
if (options?.synthesizeMissing === true || isMidHistory) for (const missingId of pending) {
|
|
@@ -234193,8 +234640,9 @@ function makeSyntheticToolResult(toolCallId) {
|
|
|
234193
234640
|
}
|
|
234194
234641
|
function mergeAdjacentUserMessages(history, onAnomaly) {
|
|
234195
234642
|
const out = [];
|
|
234196
|
-
|
|
234197
|
-
|
|
234643
|
+
const latestUserIndex = history.findLastIndex((message) => message.role === "user" && message.partial !== true && (message.origin === void 0 || message.origin.kind === "user"));
|
|
234644
|
+
for (const [index, source] of history.entries()) {
|
|
234645
|
+
const message = prepareMessageForProjection(source, onAnomaly, index < latestUserIndex);
|
|
234198
234646
|
if (message === null) continue;
|
|
234199
234647
|
const previous = out.at(-1);
|
|
234200
234648
|
if (canMergeUserMessage(message) && previous !== void 0 && canMergeUserMessage(previous)) {
|
|
@@ -234205,7 +234653,7 @@ function mergeAdjacentUserMessages(history, onAnomaly) {
|
|
|
234205
234653
|
}
|
|
234206
234654
|
return out.map(stripContextMetadata);
|
|
234207
234655
|
}
|
|
234208
|
-
function prepareMessageForProjection(message, onAnomaly) {
|
|
234656
|
+
function prepareMessageForProjection(message, onAnomaly, historical = false) {
|
|
234209
234657
|
if (message.partial === true) return null;
|
|
234210
234658
|
let content;
|
|
234211
234659
|
for (const [index, part] of message.content.entries()) {
|
|
@@ -234217,6 +234665,19 @@ function prepareMessageForProjection(message, onAnomaly) {
|
|
|
234217
234665
|
});
|
|
234218
234666
|
continue;
|
|
234219
234667
|
}
|
|
234668
|
+
if (historical && message.role === "user" && part.type === "text") {
|
|
234669
|
+
const text = withoutHistoricalTelegramGroupReminder(part.text);
|
|
234670
|
+
if (text !== part.text) {
|
|
234671
|
+
content ??= message.content.slice(0, index);
|
|
234672
|
+
const shortened = {
|
|
234673
|
+
...part,
|
|
234674
|
+
text
|
|
234675
|
+
};
|
|
234676
|
+
copyRequestTextOrigin(part, shortened, message.origin);
|
|
234677
|
+
content.push(shortened);
|
|
234678
|
+
continue;
|
|
234679
|
+
}
|
|
234680
|
+
}
|
|
234220
234681
|
content?.push(part);
|
|
234221
234682
|
}
|
|
234222
234683
|
const next = content === void 0 ? message : {
|
|
@@ -234226,6 +234687,14 @@ function prepareMessageForProjection(message, onAnomaly) {
|
|
|
234226
234687
|
if (next.role === "tool" && next.content.length === 0) throw new BlunError(ErrorCodes.REQUEST_INVALID, "Tool result message content cannot be empty after removing empty text blocks.", { details: { toolCallId: next.toolCallId } });
|
|
234227
234688
|
return next.content.length === 0 && next.toolCalls.length === 0 ? null : next;
|
|
234228
234689
|
}
|
|
234690
|
+
function withoutHistoricalTelegramGroupReminder(text) {
|
|
234691
|
+
if (!text.startsWith("<channel source=\"telegram\"") && !text.startsWith("You are connected to a Telegram channel.")) return text;
|
|
234692
|
+
const start = text.lastIndexOf(`</channel>\n[GRUPPENANTWORT:`);
|
|
234693
|
+
if (start < 0) return text;
|
|
234694
|
+
const reminder = text.slice(start + 10 + 1);
|
|
234695
|
+
if (!/^\[GRUPPENANTWORT:[^\r\n]*\]$/.test(reminder)) return text;
|
|
234696
|
+
return text.slice(0, start + 10);
|
|
234697
|
+
}
|
|
234229
234698
|
function canMergeUserMessage(message) {
|
|
234230
234699
|
return message.role === "user" && message.origin?.kind === "user";
|
|
234231
234700
|
}
|
|
@@ -234290,6 +234759,8 @@ function checkedRemovalIndexes(indexes, length) {
|
|
|
234290
234759
|
}
|
|
234291
234760
|
var ContextMemory = class {
|
|
234292
234761
|
agent;
|
|
234762
|
+
mutationGeneration = randomUUID();
|
|
234763
|
+
mutationRevision = 0;
|
|
234293
234764
|
_history = [];
|
|
234294
234765
|
_tokenCount = 0;
|
|
234295
234766
|
tokenCountCoveredMessageCount = 0;
|
|
@@ -234301,6 +234772,15 @@ var ContextMemory = class {
|
|
|
234301
234772
|
constructor(agent) {
|
|
234302
234773
|
this.agent = agent;
|
|
234303
234774
|
}
|
|
234775
|
+
publishMutation(reason) {
|
|
234776
|
+
if (this.agent.records.restoring) return;
|
|
234777
|
+
this.agent.emitEvent({
|
|
234778
|
+
type: "context.changed",
|
|
234779
|
+
generation: this.mutationGeneration,
|
|
234780
|
+
revision: ++this.mutationRevision,
|
|
234781
|
+
reason
|
|
234782
|
+
});
|
|
234783
|
+
}
|
|
234304
234784
|
get lastAssistantAt() {
|
|
234305
234785
|
return this._lastAssistantAt;
|
|
234306
234786
|
}
|
|
@@ -234432,17 +234912,29 @@ var ContextMemory = class {
|
|
|
234432
234912
|
deferredIndexes: [...deferredIndexes]
|
|
234433
234913
|
});
|
|
234434
234914
|
const removedMessages = /* @__PURE__ */ new Set();
|
|
234915
|
+
let shiftedSlots = -historyIndexes.size * (historyIndexes.size - 1) / 2;
|
|
234916
|
+
for (const index of historyIndexes) shiftedSlots += this._history.length - 1 - index;
|
|
234917
|
+
const compactHistory = shiftedSlots > this._history.length * 64;
|
|
234435
234918
|
for (let i = this._history.length - 1; i >= 0; i--) {
|
|
234436
234919
|
const message = this._history[i];
|
|
234437
234920
|
if (message === void 0 || !historyIndexes.has(i)) continue;
|
|
234438
234921
|
removedMessages.add(message);
|
|
234439
|
-
this._history.splice(i, 1);
|
|
234922
|
+
if (!compactHistory) this._history.splice(i, 1);
|
|
234440
234923
|
this.agent.injection.onContextMessageRemoved(i);
|
|
234441
234924
|
if (i < this.tokenCountCoveredMessageCount) {
|
|
234442
234925
|
this.tokenCountCoveredMessageCount--;
|
|
234443
234926
|
this._tokenCount -= estimateTokensForMessages([message]);
|
|
234444
234927
|
}
|
|
234445
234928
|
}
|
|
234929
|
+
if (compactHistory) {
|
|
234930
|
+
let retained = 0;
|
|
234931
|
+
for (let index = 0; index < this._history.length; index++) {
|
|
234932
|
+
if (historyIndexes.has(index)) continue;
|
|
234933
|
+
if (retained !== index) this._history[retained] = this._history[index];
|
|
234934
|
+
retained++;
|
|
234935
|
+
}
|
|
234936
|
+
this._history.length = retained;
|
|
234937
|
+
}
|
|
234446
234938
|
this.deferredMessages = this.deferredMessages.filter((message, index) => {
|
|
234447
234939
|
if (!deferredIndexes.has(index)) return true;
|
|
234448
234940
|
removedMessages.add(message);
|
|
@@ -234454,6 +234946,7 @@ var ContextMemory = class {
|
|
|
234454
234946
|
return removedMessages.size;
|
|
234455
234947
|
}
|
|
234456
234948
|
clear() {
|
|
234949
|
+
const changed = this._history.length > 0;
|
|
234457
234950
|
this.agent.records.logRecord({ type: "context.clear" });
|
|
234458
234951
|
this._history = [];
|
|
234459
234952
|
this._tokenCount = 0;
|
|
@@ -234465,6 +234958,7 @@ var ContextMemory = class {
|
|
|
234465
234958
|
this.agent.microCompaction.reset();
|
|
234466
234959
|
this.agent.injection.onContextClear();
|
|
234467
234960
|
this.agent.emitStatusUpdated();
|
|
234961
|
+
if (changed) this.publishMutation("clear");
|
|
234468
234962
|
}
|
|
234469
234963
|
undo(count) {
|
|
234470
234964
|
if (count <= 0) return;
|
|
@@ -234502,6 +234996,7 @@ var ContextMemory = class {
|
|
|
234502
234996
|
this.deferredMessages = [];
|
|
234503
234997
|
this.agent.microCompaction.reset(this._history.length);
|
|
234504
234998
|
this.agent.emitStatusUpdated();
|
|
234999
|
+
if (removedMessages.size > 0) this.publishMutation("undo");
|
|
234505
235000
|
if (!this.agent.records.restoring && (stoppedAtBoundary || removedUserCount < count)) throw new BlunError(ErrorCodes.REQUEST_INVALID, formatUndoUnavailableMessage(count, removedUserCount, stoppedAtBoundary), { details: {
|
|
234506
235001
|
reason: "undo_limit",
|
|
234507
235002
|
requestedCount: count,
|
|
@@ -234510,6 +235005,7 @@ var ContextMemory = class {
|
|
|
234510
235005
|
} });
|
|
234511
235006
|
}
|
|
234512
235007
|
applyCompaction(input, options = {}) {
|
|
235008
|
+
if (this.agent.records.restoring !== null && input.toolContinuity !== void 0 && !isToolContinuity(input.toolContinuity)) throw new Error("Invalid compaction tool continuity");
|
|
234513
235009
|
let preservedToolTailCount = input.preservedToolTailCount;
|
|
234514
235010
|
if (this.agent.records.restoring === null && this.hasOpenToolExchange()) {
|
|
234515
235011
|
const start = this._history.findIndex((message) => message.role === "assistant" && message.toolCalls.some((call) => this.pendingToolResultIds.has(call.id)));
|
|
@@ -234546,25 +235042,75 @@ var ContextMemory = class {
|
|
|
234546
235042
|
elisionMessage,
|
|
234547
235043
|
...selection.tail
|
|
234548
235044
|
];
|
|
234549
|
-
|
|
234550
|
-
|
|
235045
|
+
let contextSummary = input.contextSummary ?? input.summary;
|
|
235046
|
+
let toolContinuity = this.agent.records.restoring === null ? void 0 : input.toolContinuity;
|
|
235047
|
+
let summaryMessage = {
|
|
234551
235048
|
role: "user",
|
|
234552
235049
|
content: [{
|
|
234553
235050
|
type: "text",
|
|
234554
235051
|
text: contextSummary
|
|
234555
235052
|
}],
|
|
234556
235053
|
toolCalls: [],
|
|
234557
|
-
origin: {
|
|
235054
|
+
origin: {
|
|
235055
|
+
kind: "compaction_summary",
|
|
235056
|
+
...toolContinuity === void 0 ? {} : { toolContinuity }
|
|
235057
|
+
}
|
|
234558
235058
|
};
|
|
234559
|
-
|
|
235059
|
+
let replacement = [
|
|
234560
235060
|
...keptMessages,
|
|
234561
235061
|
summaryMessage,
|
|
234562
235062
|
...preservedToolTail
|
|
234563
235063
|
];
|
|
235064
|
+
const previousHistoryTokens = options.requireReduction && this.agent.records.restoring === null ? estimateTokensForMessages(project(this.agent.microCompaction.compact(this._history), { dropOrphanResults: true })) : void 0;
|
|
235065
|
+
if (this.agent.records.restoring === null) {
|
|
235066
|
+
toolContinuity = void 0;
|
|
235067
|
+
const observations = collectToolContinuity(this._history.slice(0, tailStart));
|
|
235068
|
+
if (observations !== void 0) {
|
|
235069
|
+
const baseProjected = project(replacement, { dropOrphanResults: true });
|
|
235070
|
+
const baseTokens = estimateTokensForMessages(baseProjected);
|
|
235071
|
+
let extraTokens = previousHistoryTokens === void 0 ? Number.POSITIVE_INFINITY : Math.max(0, previousHistoryTokens - baseTokens - 1);
|
|
235072
|
+
if (this.agent.config.hasProvider) {
|
|
235073
|
+
const window = this.agent.fullCompaction.getEffectiveMaxContextTokens();
|
|
235074
|
+
const budget = this.agent.fullCompaction.getCompactionBudgetTokens();
|
|
235075
|
+
const requestLimit = Math.min(window > 0 ? window - 1 : Number.POSITIVE_INFINITY, budget ?? Number.POSITIVE_INFINITY);
|
|
235076
|
+
extraTokens = Math.min(extraTokens, Math.max(0, requestLimit - this.agent.fullCompaction.estimateProjectedRequestTokens({ messages: baseProjected }) - 1));
|
|
235077
|
+
}
|
|
235078
|
+
let fitted = fitToolContinuity(observations, extraTokens);
|
|
235079
|
+
while (fitted !== void 0) {
|
|
235080
|
+
const candidateSummary = {
|
|
235081
|
+
...summaryMessage,
|
|
235082
|
+
content: [{
|
|
235083
|
+
type: "text",
|
|
235084
|
+
text: contextSummary + fitted.text
|
|
235085
|
+
}],
|
|
235086
|
+
origin: {
|
|
235087
|
+
kind: "compaction_summary",
|
|
235088
|
+
toolContinuity: fitted.continuity
|
|
235089
|
+
}
|
|
235090
|
+
};
|
|
235091
|
+
const candidate = [
|
|
235092
|
+
...keptMessages,
|
|
235093
|
+
candidateSummary,
|
|
235094
|
+
...preservedToolTail
|
|
235095
|
+
];
|
|
235096
|
+
const projected = project(candidate, { dropOrphanResults: true });
|
|
235097
|
+
const status = this.agent.fullCompaction.proactiveCompactionStatus({ messages: projected });
|
|
235098
|
+
const reducing = previousHistoryTokens === void 0 || estimateTokensForMessages(projected) < previousHistoryTokens;
|
|
235099
|
+
const bytesFit = (status.usedHistoryBytes === void 0 || status.thresholdHistoryBytes === void 0 || status.usedHistoryBytes < status.thresholdHistoryBytes) && (status.usedRequestBytesEstimate === void 0 || status.thresholdRequestBytes === void 0 || status.usedRequestBytesEstimate < status.thresholdRequestBytes);
|
|
235100
|
+
if (reducing && bytesFit) {
|
|
235101
|
+
toolContinuity = fitted.continuity;
|
|
235102
|
+
contextSummary += fitted.text;
|
|
235103
|
+
summaryMessage = candidateSummary;
|
|
235104
|
+
replacement = candidate;
|
|
235105
|
+
break;
|
|
235106
|
+
}
|
|
235107
|
+
fitted = fitToolContinuity(observations, estimateTokens(fitted.text) - 1);
|
|
235108
|
+
}
|
|
235109
|
+
}
|
|
235110
|
+
}
|
|
234564
235111
|
if (options.requireReduction && this.agent.records.restoring === null) {
|
|
234565
|
-
const previousHistoryTokens = estimateTokensForMessages(project(this.agent.microCompaction.compact(this._history), { dropOrphanResults: true }));
|
|
234566
235112
|
const nextHistoryTokens = estimateTokensForMessages(project(replacement, { dropOrphanResults: true }));
|
|
234567
|
-
if (nextHistoryTokens >= previousHistoryTokens) throw new BlunError(ErrorCodes.COMPACTION_FAILED, "Automatic compaction did not reduce the history. The conversation history was not changed.", { details: {
|
|
235113
|
+
if (previousHistoryTokens !== void 0 && nextHistoryTokens >= previousHistoryTokens) throw new BlunError(ErrorCodes.COMPACTION_FAILED, "Automatic compaction did not reduce the history. The conversation history was not changed.", { details: {
|
|
234568
235114
|
reason: "non_reducing_summary",
|
|
234569
235115
|
contextUnchanged: true,
|
|
234570
235116
|
previousHistoryTokens,
|
|
@@ -234577,6 +235123,7 @@ var ContextMemory = class {
|
|
|
234577
235123
|
const result = {
|
|
234578
235124
|
summary: input.summary,
|
|
234579
235125
|
contextSummary,
|
|
235126
|
+
...toolContinuity === void 0 ? {} : { toolContinuity },
|
|
234580
235127
|
compactedCount: input.compactedCount,
|
|
234581
235128
|
tokensBefore: input.tokensBefore,
|
|
234582
235129
|
tokensAfter,
|
|
@@ -234593,6 +235140,7 @@ var ContextMemory = class {
|
|
|
234593
235140
|
this.agent.replayBuilder.patchLast("compaction", { result: {
|
|
234594
235141
|
summary: result.summary,
|
|
234595
235142
|
contextSummary: result.contextSummary,
|
|
235143
|
+
...result.toolContinuity === void 0 ? {} : { toolContinuity: result.toolContinuity },
|
|
234596
235144
|
compactedCount: result.compactedCount,
|
|
234597
235145
|
tokensBefore: result.tokensBefore,
|
|
234598
235146
|
tokensAfter: result.tokensAfter,
|
|
@@ -236200,20 +236748,75 @@ function fingerprintTitle(title) {
|
|
|
236200
236748
|
return createHash("sha256").update(title.trim().toLowerCase()).digest("hex");
|
|
236201
236749
|
}
|
|
236202
236750
|
async function loadRegister(mistakeDir = defaultMistakeDir()) {
|
|
236751
|
+
const target = join(mistakeDir, REGISTER_FILENAME);
|
|
236203
236752
|
try {
|
|
236204
236753
|
await mkdir(mistakeDir, { recursive: true });
|
|
236205
|
-
const
|
|
236206
|
-
|
|
236207
|
-
|
|
236208
|
-
|
|
236754
|
+
const before = await lstat(target).catch((error) => {
|
|
236755
|
+
if (error.code === "ENOENT") return void 0;
|
|
236756
|
+
throw error;
|
|
236757
|
+
});
|
|
236758
|
+
if (before === void 0) return {
|
|
236209
236759
|
version: 1,
|
|
236210
236760
|
entries: []
|
|
236211
236761
|
};
|
|
236762
|
+
if (!before.isFile() || before.isSymbolicLink()) throw new Error("Mistake register must be a regular file.");
|
|
236763
|
+
const handle = await open(target, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
236764
|
+
let content;
|
|
236765
|
+
try {
|
|
236766
|
+
const opened = await handle.stat();
|
|
236767
|
+
if (!opened.isFile() || opened.dev !== before.dev || opened.ino !== before.ino) throw new Error("Mistake register changed while opening.");
|
|
236768
|
+
content = await handle.readFile("utf8");
|
|
236769
|
+
} finally {
|
|
236770
|
+
await handle.close();
|
|
236771
|
+
}
|
|
236772
|
+
let parsed;
|
|
236773
|
+
try {
|
|
236774
|
+
parsed = JSON.parse(content);
|
|
236775
|
+
} catch {
|
|
236776
|
+
throw new Error("Mistake register has invalid JSON.");
|
|
236777
|
+
}
|
|
236778
|
+
assertRegister(parsed);
|
|
236779
|
+
return parsed;
|
|
236780
|
+
} catch (error) {
|
|
236781
|
+
throw registerError(error, "read");
|
|
236212
236782
|
}
|
|
236213
236783
|
}
|
|
236214
236784
|
async function saveRegister(register, mistakeDir = defaultMistakeDir()) {
|
|
236215
|
-
|
|
236216
|
-
|
|
236785
|
+
assertRegister(register);
|
|
236786
|
+
const target = join(mistakeDir, REGISTER_FILENAME);
|
|
236787
|
+
const temporary = `${target}.tmp.${process.pid}.${randomUUID()}`;
|
|
236788
|
+
let created = false;
|
|
236789
|
+
try {
|
|
236790
|
+
await loadRegister(mistakeDir);
|
|
236791
|
+
const handle = await open(temporary, "wx", 384);
|
|
236792
|
+
created = true;
|
|
236793
|
+
try {
|
|
236794
|
+
await handle.writeFile(JSON.stringify(register, null, 2), "utf8");
|
|
236795
|
+
await handle.sync();
|
|
236796
|
+
} finally {
|
|
236797
|
+
await handle.close();
|
|
236798
|
+
}
|
|
236799
|
+
await rename(temporary, target);
|
|
236800
|
+
} catch (error) {
|
|
236801
|
+
throw registerError(error, "write");
|
|
236802
|
+
} finally {
|
|
236803
|
+
if (created) await unlink(temporary).catch(() => {});
|
|
236804
|
+
}
|
|
236805
|
+
}
|
|
236806
|
+
function assertRegister(value) {
|
|
236807
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("Mistake register has an invalid v1 schema.");
|
|
236808
|
+
const register = value;
|
|
236809
|
+
if (register["version"] !== 1 || !Array.isArray(register["entries"]) || !register["entries"].every((entry) => {
|
|
236810
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return false;
|
|
236811
|
+
const fields = entry;
|
|
236812
|
+
return typeof fields["entryIndex"] === "number" && Number.isSafeInteger(fields["entryIndex"]) && fields["entryIndex"] >= 0 && typeof fields["titleFingerprint"] === "string" && fields["titleFingerprint"].trim().length > 0 && typeof fields["title"] === "string" && fields["title"].trim().length > 0 && typeof fields["count"] === "number" && Number.isSafeInteger(fields["count"]) && fields["count"] >= 0 && typeof fields["lastHitAt"] === "string" && fields["lastHitAt"].trim().length > 0 && (fields["origin"] === "program" || fields["origin"] === "hand");
|
|
236813
|
+
})) throw new Error("Mistake register has an invalid v1 schema.");
|
|
236814
|
+
}
|
|
236815
|
+
function registerError(error, operation) {
|
|
236816
|
+
if (error instanceof Error && error.message.startsWith("Mistake register ")) return error;
|
|
236817
|
+
const code = typeof error === "object" && error !== null ? error.code : void 0;
|
|
236818
|
+
const suffix = typeof code === "string" && /^[A-Z0-9_]+$/u.test(code) ? ` (${code})` : "";
|
|
236819
|
+
return /* @__PURE__ */ new Error(`Mistake register ${operation} failed${suffix}.`);
|
|
236217
236820
|
}
|
|
236218
236821
|
/**
|
|
236219
236822
|
* Findet einen Register-Eintrag anhand des Titels (Fingerabdruck).
|
|
@@ -238906,6 +239509,7 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
238906
239509
|
const DEFERRED_TOOL_LOADER_NAME = "ToolSearch";
|
|
238907
239510
|
const MAX_PERSISTENT_DEFERRED_TOOLS = 12;
|
|
238908
239511
|
const MAX_TOOL_SEARCH_QUERY_CHARS = 1e3;
|
|
239512
|
+
const MAX_TOOL_CATALOG_RESULT_BYTES = 4096;
|
|
238909
239513
|
const MAX_AUTO_RANKED_TOOLS = 6;
|
|
238910
239514
|
const deferredToolLoaders = /* @__PURE__ */ new WeakSet();
|
|
238911
239515
|
const TOOL_RANK_EMBEDDED_CONTENT_RE = /<(attached_documents?|attachment_content|document_content|file_content)\b[^>]*>[\s\S]*?<\/\1>/giu;
|
|
@@ -238976,6 +239580,32 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
238976
239580
|
"suchen"
|
|
238977
239581
|
]);
|
|
238978
239582
|
const TOOL_SEARCH_RELATED_TERM_GROUPS = Object.freeze([
|
|
239583
|
+
Object.freeze([
|
|
239584
|
+
"persist",
|
|
239585
|
+
"save",
|
|
239586
|
+
"speichere",
|
|
239587
|
+
"speichern",
|
|
239588
|
+
"store"
|
|
239589
|
+
]),
|
|
239590
|
+
Object.freeze([
|
|
239591
|
+
"erinnerung",
|
|
239592
|
+
"erinnerungen",
|
|
239593
|
+
"fact",
|
|
239594
|
+
"facts",
|
|
239595
|
+
"fakt",
|
|
239596
|
+
"fakten",
|
|
239597
|
+
"memory",
|
|
239598
|
+
"memories",
|
|
239599
|
+
"merk",
|
|
239600
|
+
"merken",
|
|
239601
|
+
"remember"
|
|
239602
|
+
]),
|
|
239603
|
+
Object.freeze([
|
|
239604
|
+
"note",
|
|
239605
|
+
"notes",
|
|
239606
|
+
"notiz",
|
|
239607
|
+
"notizen"
|
|
239608
|
+
]),
|
|
238979
239609
|
Object.freeze([
|
|
238980
239610
|
"checklist",
|
|
238981
239611
|
"list",
|
|
@@ -239093,10 +239723,18 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239093
239723
|
if (VIDEO_MEDIA_TERM_RE.test(text)) selected.add("GenerateVideo");
|
|
239094
239724
|
return selected;
|
|
239095
239725
|
}
|
|
239726
|
+
function channelMessagesForTurnText(value) {
|
|
239727
|
+
return [...String(value || "").matchAll(/(?:^|\r?\n)<channel\b[^>]*>\r?\n([\s\S]*?)\r?\n<\/channel>(?=\r?\n|$)/giu)].map((match) => ({
|
|
239728
|
+
text: match[1],
|
|
239729
|
+
start: match.index,
|
|
239730
|
+
end: match.index + match[0].length,
|
|
239731
|
+
telegram: /^<channel\s+source=["']telegram["'](?:\s|>)/iu.test(match[0].trimStart())
|
|
239732
|
+
}));
|
|
239733
|
+
}
|
|
239096
239734
|
function mediaToolNamesForTurnText(value) {
|
|
239097
239735
|
const text = String(value || "");
|
|
239098
239736
|
const selected = /* @__PURE__ */ new Set();
|
|
239099
|
-
const channelBodies =
|
|
239737
|
+
const channelBodies = channelMessagesForTurnText(text).map((message) => message.text);
|
|
239100
239738
|
const intentTexts = channelBodies.length > 0 ? channelBodies : [text];
|
|
239101
239739
|
for (const intentText of intentTexts) for (const name of mediaGenerationToolNamesForText(intentText)) selected.add(name);
|
|
239102
239740
|
if (/\bimage_path\s*=\s*["'][^"']+["']/iu.test(text)) {
|
|
@@ -239124,6 +239762,27 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239124
239762
|
for (const leaf of leaves) leafCounts.set(leaf, (leafCounts.get(leaf) || 0) + 1);
|
|
239125
239763
|
return names.map((name, index) => leafCounts.get(leaves[index]) === 1 ? leaves[index] : name).sort((left, right) => left.localeCompare(right));
|
|
239126
239764
|
}
|
|
239765
|
+
function boundedDeferredToolCatalog(tools, filter) {
|
|
239766
|
+
const needle = filter.toLowerCase();
|
|
239767
|
+
const matched = deferredToolCatalog(tools).filter((name) => name.toLowerCase().includes(needle));
|
|
239768
|
+
const names = [];
|
|
239769
|
+
let bytes = Buffer.byteLength(JSON.stringify({
|
|
239770
|
+
names,
|
|
239771
|
+
total: matched.length,
|
|
239772
|
+
truncated: false
|
|
239773
|
+
}));
|
|
239774
|
+
for (const name of matched) {
|
|
239775
|
+
const nextBytes = Buffer.byteLength(JSON.stringify(name)) + (names.length > 0 ? 1 : 0);
|
|
239776
|
+
if (bytes + nextBytes > MAX_TOOL_CATALOG_RESULT_BYTES) break;
|
|
239777
|
+
names.push(name);
|
|
239778
|
+
bytes += nextBytes;
|
|
239779
|
+
}
|
|
239780
|
+
return JSON.stringify({
|
|
239781
|
+
names,
|
|
239782
|
+
total: matched.length,
|
|
239783
|
+
truncated: names.length < matched.length
|
|
239784
|
+
});
|
|
239785
|
+
}
|
|
239127
239786
|
function normalizeDeferredToolQuery(value) {
|
|
239128
239787
|
const query = String(value ?? "").trim();
|
|
239129
239788
|
if (query.length <= MAX_TOOL_SEARCH_QUERY_CHARS) return query;
|
|
@@ -239173,22 +239832,39 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239173
239832
|
function relatedSearchTerms(token) {
|
|
239174
239833
|
return TOOL_SEARCH_RELATED_TERM_GROUPS.find((terms) => terms.includes(token)) || [token];
|
|
239175
239834
|
}
|
|
239835
|
+
function withoutFencedCode(value) {
|
|
239836
|
+
const visibleLines = [];
|
|
239837
|
+
let fence = null;
|
|
239838
|
+
for (const line of String(value || "").split(/\r?\n/)) {
|
|
239839
|
+
const marker = line.match(/^ {0,3}(`{3,}|~{3,})/u)?.[1];
|
|
239840
|
+
if (fence) {
|
|
239841
|
+
if (marker?.[0] === fence[0] && marker.length >= fence.length && /^ {0,3}(?:`{3,}|~{3,})[ \t]*$/u.test(line)) fence = null;
|
|
239842
|
+
continue;
|
|
239843
|
+
}
|
|
239844
|
+
if (marker) {
|
|
239845
|
+
fence = marker;
|
|
239846
|
+
continue;
|
|
239847
|
+
}
|
|
239848
|
+
visibleLines.push(line);
|
|
239849
|
+
}
|
|
239850
|
+
return visibleLines.join("\n");
|
|
239851
|
+
}
|
|
239176
239852
|
function rankingIntentTexts(value) {
|
|
239177
239853
|
const text = String(value || "");
|
|
239178
|
-
const channelBodies =
|
|
239179
|
-
return (channelBodies.length > 0 ? channelBodies : [text]).map((intentText) => normalizeDeferredToolQuery(intentText.replace(TOOL_RANK_EMBEDDED_CONTENT_RE, " ")));
|
|
239854
|
+
const channelBodies = channelMessagesForTurnText(text).map((message) => message.text);
|
|
239855
|
+
return (channelBodies.length > 0 ? channelBodies : [text]).map((intentText) => normalizeDeferredToolQuery(withoutFencedCode(intentText.replace(TOOL_RANK_EMBEDDED_CONTENT_RE, " "))));
|
|
239180
239856
|
}
|
|
239181
239857
|
function rankingTokens(value) {
|
|
239182
239858
|
return [...new Set(String(value || "").normalize("NFKC").toLowerCase().match(/[\p{L}\p{N}]{3,}/gu) || [])].filter((token) => !TOOL_RANK_STOP_WORDS.has(token));
|
|
239183
239859
|
}
|
|
239184
|
-
function toolRankingDocument(tool) {
|
|
239860
|
+
function toolRankingDocument(tool, trustedToolNames) {
|
|
239185
239861
|
const name = String(tool?.name || "");
|
|
239186
239862
|
const leaf = name.split(/__|:/).at(-1) || name;
|
|
239187
239863
|
const splitToolName = (value) => String(value || "").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replaceAll("_", " ");
|
|
239188
239864
|
const nameTokens = rankingTokens(`${splitToolName(name)} ${splitToolName(leaf)}`);
|
|
239189
239865
|
const descriptionTokens = rankingTokens(tool?.description);
|
|
239190
239866
|
const parameterText = [];
|
|
239191
|
-
const properties = tool?.parameters?.properties;
|
|
239867
|
+
const properties = /^mcp__/iu.test(name) && !trustedToolNames?.has(name) ? void 0 : tool?.parameters?.properties;
|
|
239192
239868
|
if (properties && typeof properties === "object") for (const [parameterName, definition] of Object.entries(properties)) parameterText.push(parameterName, definition?.description || "");
|
|
239193
239869
|
const exampleText = Array.isArray(tool?.examples) ? tool.examples.map((example) => example?.prompt || "").join(" ") : "";
|
|
239194
239870
|
return {
|
|
@@ -239220,7 +239896,7 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239220
239896
|
const queryTokens = [...new Set(rankingIntentTexts(value).flatMap(rankingTokens))];
|
|
239221
239897
|
if (queryTokens.length === 0) return /* @__PURE__ */ new Set();
|
|
239222
239898
|
const ranked = (Array.isArray(tools) ? tools : []).map((tool) => {
|
|
239223
|
-
const document = toolRankingDocument(tool);
|
|
239899
|
+
const document = toolRankingDocument(tool, options.trustedToolNames);
|
|
239224
239900
|
if (!document.name) return null;
|
|
239225
239901
|
let score = 0;
|
|
239226
239902
|
let matchedTokens = 0;
|
|
@@ -239234,7 +239910,7 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239234
239910
|
if (document.nameTokens.has(token)) exactNameMatches += 1;
|
|
239235
239911
|
else if (relatedSearchTerms(token).some((term) => document.nameTokens.has(term))) relatedNameMatches += 1;
|
|
239236
239912
|
}
|
|
239237
|
-
return matchedTokens >= 2 || exactNameMatches >= 1 && score >= 10 || relatedNameMatches >= 1 && score >= 5 ? {
|
|
239913
|
+
return matchedTokens >= 2 || exactNameMatches >= 1 && score >= 10 || queryTokens.length === 1 && relatedNameMatches >= 1 && score >= 5 ? {
|
|
239238
239914
|
name: document.name,
|
|
239239
239915
|
score,
|
|
239240
239916
|
matchedTokens,
|
|
@@ -239252,17 +239928,15 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239252
239928
|
if (!supportChoice.match(/^(?:tool|skill)\s*:\s*(.+)$/iu)?.[1]) return /* @__PURE__ */ new Set();
|
|
239253
239929
|
return rankedToolNamesForTurnText(tools, supportChoice, { maxTools: 1 });
|
|
239254
239930
|
}
|
|
239255
|
-
function searchRelatedDeferredTools(tools, query
|
|
239931
|
+
function searchRelatedDeferredTools(tools, query) {
|
|
239256
239932
|
const normalized = normalizeDeferredToolQuery(query).toLowerCase();
|
|
239257
239933
|
if (!normalized || normalized.startsWith("select:")) return [];
|
|
239258
|
-
const tokens = normalized.
|
|
239259
|
-
const
|
|
239260
|
-
const
|
|
239261
|
-
const requiredNameTokens = relaxRequiredNameTokens ? [] : requestedNameTokens;
|
|
239262
|
-
const searchTokens = [...tokens.filter((token) => !token.startsWith("+")), ...relaxRequiredNameTokens ? requestedNameTokens : []].filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token));
|
|
239934
|
+
const tokens = normalized.match(/\+?[\p{L}\p{N}_-]+/gu) || [];
|
|
239935
|
+
const requiredNameTokens = tokens.filter((token) => token.startsWith("+")).map((token) => token.slice(1)).filter(Boolean);
|
|
239936
|
+
const searchTokens = tokens.filter((token) => !token.startsWith("+")).filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token) && !TOOL_RANK_STOP_WORDS.has(token));
|
|
239263
239937
|
if (searchTokens.length < 2 && !TOOL_SEARCH_SINGLE_TERM_RELATED_FALLBACKS.has(searchTokens[0])) return [];
|
|
239264
239938
|
const minimumMatchedTokens = searchTokens.length === 1 ? 1 : Math.max(2, Math.ceil(searchTokens.length * .75));
|
|
239265
|
-
|
|
239939
|
+
return tools.map((tool) => {
|
|
239266
239940
|
const name = String(tool?.name || "").toLowerCase();
|
|
239267
239941
|
const description = String(tool?.description || "").toLowerCase();
|
|
239268
239942
|
if (!requiredNameTokens.every((token) => name.includes(token))) return null;
|
|
@@ -239293,12 +239967,7 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239293
239967
|
score,
|
|
239294
239968
|
matchedTokens
|
|
239295
239969
|
} : null;
|
|
239296
|
-
}).filter(Boolean).sort((left, right) => right.matchedTokens - left.matchedTokens || right.score - left.score || String(left.tool.name).localeCompare(String(right.tool.name)));
|
|
239297
|
-
if (relaxRequiredNameTokens && ranked.length > 0) {
|
|
239298
|
-
const best = ranked[0];
|
|
239299
|
-
return ranked.filter((entry) => entry.matchedTokens === best.matchedTokens && entry.score === best.score).slice(0, 5).map((entry) => entry.tool);
|
|
239300
|
-
}
|
|
239301
|
-
return ranked.slice(0, 5).map((entry) => entry.tool);
|
|
239970
|
+
}).filter(Boolean).sort((left, right) => right.matchedTokens - left.matchedTokens || right.score - left.score || String(left.tool.name).localeCompare(String(right.tool.name))).slice(0, 5).map((entry) => entry.tool);
|
|
239302
239971
|
}
|
|
239303
239972
|
function rememberLoadedTool(loadedToolNames, name) {
|
|
239304
239973
|
loadedToolNames.delete(name);
|
|
@@ -239323,13 +239992,12 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239323
239992
|
const usedNames = new Set([...selectedTools, ...available.values()].map((tool) => String(tool?.name ?? "")));
|
|
239324
239993
|
let loaderName = DEFERRED_TOOL_LOADER_NAME;
|
|
239325
239994
|
for (let suffix = 1; usedNames.has(loaderName); suffix += 1) loaderName = `${DEFERRED_TOOL_LOADER_NAME}_${suffix}`;
|
|
239326
|
-
const deferredCount = available.size;
|
|
239327
239995
|
const loader = {
|
|
239328
239996
|
name: loaderName,
|
|
239329
239997
|
description: [
|
|
239330
|
-
|
|
239331
|
-
"Use select:leaf_name for one known tool, plain keywords to search,
|
|
239332
|
-
`Loaded tools are available in the next step;
|
|
239998
|
+
"Search deferred tool schemas without loading all definitions.",
|
|
239999
|
+
"Use select:leaf_name for one known tool, plain keywords to search, +word to require a name word, or catalog:fragment to list matching names.",
|
|
240000
|
+
`Loaded tools are available in the next step; up to ${MAX_PERSISTENT_DEFERRED_TOOLS} recently selected schemas remain loaded when the context budget allows.`
|
|
239333
240001
|
].join("\n"),
|
|
239334
240002
|
parameters: {
|
|
239335
240003
|
type: "object",
|
|
@@ -239346,17 +240014,18 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239346
240014
|
return {
|
|
239347
240015
|
description: query ? `Searching tool schemas for ${query}` : "Searching tool schemas",
|
|
239348
240016
|
approvalRule: loaderName,
|
|
239349
|
-
execute: async () => {
|
|
240017
|
+
execute: async (context) => {
|
|
240018
|
+
context?.signal?.throwIfAborted();
|
|
240019
|
+
if (query.toLowerCase().startsWith("catalog:")) return {
|
|
240020
|
+
isError: false,
|
|
240021
|
+
output: boundedDeferredToolCatalog([...available.values()], query.slice(8).trim())
|
|
240022
|
+
};
|
|
239350
240023
|
let matches = searchDeferredTools([...available.values()], query);
|
|
239351
240024
|
let relatedFallback = false;
|
|
239352
240025
|
if (matches.length === 0) {
|
|
239353
240026
|
matches = searchRelatedDeferredTools([...available.values()], query);
|
|
239354
240027
|
relatedFallback = matches.length > 0;
|
|
239355
240028
|
}
|
|
239356
|
-
if (matches.length === 0) {
|
|
239357
|
-
matches = searchRelatedDeferredTools([...available.values()], query, { relaxRequiredNameTokens: true });
|
|
239358
|
-
relatedFallback = matches.length > 0;
|
|
239359
|
-
}
|
|
239360
240029
|
if (matches.length === 0) {
|
|
239361
240030
|
const alreadyLoaded = query.toLowerCase().startsWith("select:") ? searchDeferredTools(selectedTools.filter((tool) => tool?.name !== loaderName), query) : [];
|
|
239362
240031
|
if (alreadyLoaded.length === 1) return {
|
|
@@ -239395,6 +240064,7 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
|
|
|
239395
240064
|
return loader;
|
|
239396
240065
|
}
|
|
239397
240066
|
module.exports = {
|
|
240067
|
+
channelMessagesForTurnText,
|
|
239398
240068
|
isDeferredToolLoader: (tool) => deferredToolLoaders.has(tool),
|
|
239399
240069
|
CORE_TOOL_NAMES,
|
|
239400
240070
|
DEFERRED_TOOL_LOADER_NAME,
|
|
@@ -240697,10 +241367,14 @@ var ReplayBuilder = class {
|
|
|
240697
241367
|
return this.records;
|
|
240698
241368
|
}
|
|
240699
241369
|
removeMessagesFrom(records, removedMessages) {
|
|
240700
|
-
|
|
240701
|
-
|
|
240702
|
-
|
|
241370
|
+
let retained = 0;
|
|
241371
|
+
for (let index = 0; index < records.length; index++) {
|
|
241372
|
+
const record = records[index];
|
|
241373
|
+
if (record.type === "message" && removedMessages.has(record.message)) continue;
|
|
241374
|
+
if (retained !== index) records[retained] = record;
|
|
241375
|
+
retained++;
|
|
240703
241376
|
}
|
|
241377
|
+
records.length = retained;
|
|
240704
241378
|
}
|
|
240705
241379
|
};
|
|
240706
241380
|
//#endregion
|
|
@@ -241639,6 +242313,7 @@ function withThinkingOnlyRecovery(llm, onTimeout, observeExecution) {
|
|
|
241639
242313
|
systemPrompt: llm.systemPrompt,
|
|
241640
242314
|
modelName: llm.modelName,
|
|
241641
242315
|
capability: llm.capability,
|
|
242316
|
+
rebuildsMessagesAtRequestBoundary: llm.rebuildsMessagesAtRequestBoundary,
|
|
241642
242317
|
prepareRequestBoundary: llm.prepareRequestBoundary?.bind(llm),
|
|
241643
242318
|
isRetryableError: llm.isRetryableError === void 0 ? void 0 : (error) => !recoveryCallbackFailed && !(error instanceof ThinkingOnlyTimeoutError) && (llm.isRetryableError?.(error) ?? false),
|
|
241644
242319
|
async chat(params) {
|
|
@@ -249872,7 +250547,9 @@ async function executeLoopStep(deps) {
|
|
|
249872
250547
|
if (beforeStep?.block === true) throw new Error(beforeStep.reason ?? `Step ${String(currentStep)} was blocked`);
|
|
249873
250548
|
}
|
|
249874
250549
|
signal.throwIfAborted();
|
|
249875
|
-
const
|
|
250550
|
+
const prepareRequestBoundary = llm.prepareRequestBoundary?.bind(llm);
|
|
250551
|
+
const deferMessageBuild = prepareRequestBoundary !== void 0 && llm.rebuildsMessagesAtRequestBoundary === true;
|
|
250552
|
+
const messages = deferMessageBuild ? [] : await buildMessages();
|
|
249876
250553
|
signal.throwIfAborted();
|
|
249877
250554
|
const stepUuid = randomUUID();
|
|
249878
250555
|
const stepEvents = createStepEventGate({
|
|
@@ -249882,7 +250559,6 @@ async function executeLoopStep(deps) {
|
|
|
249882
250559
|
stepUuid,
|
|
249883
250560
|
onStepStarted
|
|
249884
250561
|
});
|
|
249885
|
-
const prepareRequestBoundary = llm.prepareRequestBoundary?.bind(llm);
|
|
249886
250562
|
const step = {
|
|
249887
250563
|
tools,
|
|
249888
250564
|
hooks,
|
|
@@ -249962,7 +250638,7 @@ async function executeLoopStep(deps) {
|
|
|
249962
250638
|
turnStep: `${turnId}.${String(currentStep)}`,
|
|
249963
250639
|
model: llm.modelName
|
|
249964
250640
|
});
|
|
249965
|
-
const strictMessages = await buildMessagesStrict();
|
|
250641
|
+
const strictMessages = deferMessageBuild ? [] : await buildMessagesStrict();
|
|
249966
250642
|
signal.throwIfAborted();
|
|
249967
250643
|
let strictParams = {
|
|
249968
250644
|
...chatParams,
|
|
@@ -250063,7 +250739,8 @@ function logStepTiming(log, turnId, step, response) {
|
|
|
250063
250739
|
inputOtherTokens: response.usage.inputOther,
|
|
250064
250740
|
cacheReadTokens: response.usage.inputCacheRead,
|
|
250065
250741
|
cacheCreationTokens: response.usage.inputCacheCreation,
|
|
250066
|
-
outputTokens: response.usage.output
|
|
250742
|
+
outputTokens: response.usage.output,
|
|
250743
|
+
...response.usage.outputReasoning === void 0 ? {} : { outputReasoningTokens: response.usage.outputReasoning }
|
|
250067
250744
|
});
|
|
250068
250745
|
}
|
|
250069
250746
|
function deriveStepStopReason(response) {
|
|
@@ -251051,6 +251728,7 @@ const MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE = "mcp.oauth.authorization_url";
|
|
|
251051
251728
|
const tokenUsageSchema = object({
|
|
251052
251729
|
inputOther: number$1(),
|
|
251053
251730
|
output: number$1(),
|
|
251731
|
+
outputReasoning: number$1().optional(),
|
|
251054
251732
|
inputCacheRead: number$1(),
|
|
251055
251733
|
inputCacheCreation: number$1()
|
|
251056
251734
|
});
|
|
@@ -251210,7 +251888,11 @@ const goalChangeStatsSchema = object({
|
|
|
251210
251888
|
wallClockMs: number$1()
|
|
251211
251889
|
});
|
|
251212
251890
|
const goalChangeSchema = object({
|
|
251213
|
-
kind: _enum([
|
|
251891
|
+
kind: _enum([
|
|
251892
|
+
"lifecycle",
|
|
251893
|
+
"completion",
|
|
251894
|
+
"edited"
|
|
251895
|
+
]),
|
|
251214
251896
|
status: goalStatusSchema.optional(),
|
|
251215
251897
|
reason: string().optional(),
|
|
251216
251898
|
stats: goalChangeStatsSchema.optional(),
|
|
@@ -251361,6 +252043,12 @@ const turnEndReasonSchema = _enum([
|
|
|
251361
252043
|
"failed",
|
|
251362
252044
|
"filtered"
|
|
251363
252045
|
]);
|
|
252046
|
+
const contextChangedEventSchema = object({
|
|
252047
|
+
type: literal("context.changed"),
|
|
252048
|
+
generation: string().uuid(),
|
|
252049
|
+
revision: number$1().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
252050
|
+
reason: _enum(["clear", "undo"])
|
|
252051
|
+
});
|
|
251364
252052
|
const agentStatusUpdatedEventSchema = object({
|
|
251365
252053
|
type: literal("agent.status.updated"),
|
|
251366
252054
|
model: string().optional(),
|
|
@@ -251680,6 +252368,7 @@ const eventSchema = discriminatedUnion("type", [
|
|
|
251680
252368
|
errorEventSchema,
|
|
251681
252369
|
warningEventSchema,
|
|
251682
252370
|
agentStatusUpdatedEventSchema,
|
|
252371
|
+
contextChangedEventSchema,
|
|
251683
252372
|
sessionMetaUpdatedEventSchema,
|
|
251684
252373
|
sessionCreatedEventSchema,
|
|
251685
252374
|
workspaceCreatedEventSchema,
|
|
@@ -265080,9 +265769,16 @@ var ToolCallDeduplicator = class {
|
|
|
265080
265769
|
//#region ../../packages/agent-core/src/agent/turn/tool-result-budget.ts
|
|
265081
265770
|
const TOOL_RESULT_MAX_CHARS = 5e4;
|
|
265082
265771
|
const TOOL_RESULT_PREVIEW_CHARS = 2e3;
|
|
265772
|
+
function toolResultMaxChars(maxContextTokens) {
|
|
265773
|
+
if (maxContextTokens === void 0 || !Number.isFinite(maxContextTokens) || maxContextTokens <= 0) return TOOL_RESULT_MAX_CHARS;
|
|
265774
|
+
if (maxContextTokens < 1e5) return 16e3;
|
|
265775
|
+
if (maxContextTokens < 2e5) return 32e3;
|
|
265776
|
+
return TOOL_RESULT_MAX_CHARS;
|
|
265777
|
+
}
|
|
265083
265778
|
async function budgetToolResultForModel(options) {
|
|
265084
265779
|
const text = persistableToolResultText(options.result.output);
|
|
265085
|
-
|
|
265780
|
+
const maxChars = toolResultMaxChars(options.maxContextTokens);
|
|
265781
|
+
if (text === void 0 || text.length <= maxChars) return options.result;
|
|
265086
265782
|
if (options.result.truncated === true) return options.result;
|
|
265087
265783
|
if (options.homedir === void 0) return options.result;
|
|
265088
265784
|
if (text.includes("\0") || Buffer.from(text, "utf8").toString("utf8") !== text || text.split("\n").some((line) => line.length > 2e3)) return options.result;
|
|
@@ -265093,7 +265789,7 @@ async function budgetToolResultForModel(options) {
|
|
|
265093
265789
|
toolCallId: options.toolCallId
|
|
265094
265790
|
}, text);
|
|
265095
265791
|
if (outputPath === void 0) return options.result;
|
|
265096
|
-
const output = renderPersistedToolResult(options.toolName, options.toolCallId, text, outputPath);
|
|
265792
|
+
const output = renderPersistedToolResult(options.toolName, options.toolCallId, text, outputPath, maxChars);
|
|
265097
265793
|
return options.result.isError === true ? {
|
|
265098
265794
|
...options.result,
|
|
265099
265795
|
output,
|
|
@@ -265125,9 +265821,9 @@ async function saveToolResult(options, text) {
|
|
|
265125
265821
|
return;
|
|
265126
265822
|
}
|
|
265127
265823
|
}
|
|
265128
|
-
function renderPersistedToolResult(toolName, toolCallId, text, outputPath) {
|
|
265824
|
+
function renderPersistedToolResult(toolName, toolCallId, text, outputPath, maxChars) {
|
|
265129
265825
|
const lines = [
|
|
265130
|
-
`Tool output exceeded ${String(
|
|
265826
|
+
`Tool output exceeded ${String(maxChars)} characters; showing a preview only.`,
|
|
265131
265827
|
`tool_name: ${toolName}`,
|
|
265132
265828
|
`tool_call_id: ${toolCallId}`,
|
|
265133
265829
|
`output_size_chars: ${String(text.length)}`,
|
|
@@ -265135,7 +265831,9 @@ function renderPersistedToolResult(toolName, toolCallId, text, outputPath) {
|
|
|
265135
265831
|
`output_path: ${outputPath}`,
|
|
265136
265832
|
"next_step: Use Read with output_path to page through the full output."
|
|
265137
265833
|
];
|
|
265138
|
-
|
|
265834
|
+
let preview = text.slice(0, TOOL_RESULT_PREVIEW_CHARS);
|
|
265835
|
+
if (/[\uD800-\uDBFF]$/.test(preview)) preview = preview.slice(0, -1);
|
|
265836
|
+
lines.push("", "[preview]", preview);
|
|
265139
265837
|
return lines.join("\n");
|
|
265140
265838
|
}
|
|
265141
265839
|
function safeToolResultFileStem(toolName, toolCallId) {
|
|
@@ -266692,6 +267390,48 @@ var HistoricalToolProjection = class {
|
|
|
266692
267390
|
}
|
|
266693
267391
|
};
|
|
266694
267392
|
//#endregion
|
|
267393
|
+
//#region ../../packages/agent-core/src/agent/turn/baseline-skill-projection.ts
|
|
267394
|
+
const BASELINE_ORIGIN = "baseline_skill:blun-design-dna";
|
|
267395
|
+
const NONVISUAL_TASK = /\b(?:backend|back-end|serverseitig|server-side|datenbank|database|sql|api[- ](?:endpoint|route)|memory broker)\b/i;
|
|
267396
|
+
const VISUAL_TASK = /\b(?:ui|ux|frontend|front-end|website|webseite|web|page|screen|screenshot|bild|image|design|layout|css|html|react|vue|svelte|komponente|component|button|formular|form|style|visual|visuell|interaction|interaktion|interface|oberfl[aä]che|dashboard|landing|mobile|responsive|accessibility|barrierefreiheit|tui|terminal|konsole|console|browser|diagram|chart|graph)\b/i;
|
|
267397
|
+
const SHORT_REFERENCE = [
|
|
267398
|
+
"<system-reminder>",
|
|
267399
|
+
"The BLUN Design DNA baseline is retained in the session. Its visual rules are dormant for this explicitly non-visual backend or data task. Preserve security, privacy, accessibility, permissions, and verification. If the work turns visual or interactive, use the complete baseline before continuing.",
|
|
267400
|
+
"</system-reminder>"
|
|
267401
|
+
].join("\n");
|
|
267402
|
+
function shortNonVisualText(text) {
|
|
267403
|
+
return text.length <= 500 && !/[<>]/.test(text) && !/https?:\/\//i.test(text) && NONVISUAL_TASK.test(text) && !VISUAL_TASK.test(text);
|
|
267404
|
+
}
|
|
267405
|
+
function clearlyNonVisual(input, origin) {
|
|
267406
|
+
if (origin.kind !== "user" || input.length !== 1 || input[0]?.type !== "text") return false;
|
|
267407
|
+
const text = input[0].text;
|
|
267408
|
+
if (text.length > 16e3 || /\b(?:image_path|attachment_file_id)\s*=|Telegram-Anhang:/i.test(text)) return false;
|
|
267409
|
+
const messages = (0, import_turn_tool_performance_policy.channelMessagesForTurnText)(text);
|
|
267410
|
+
if (messages.length === 0) return shortNonVisualText(text);
|
|
267411
|
+
if (messages.some((message) => !message.telegram || !shortNonVisualText(message.text)) || messages.reduce((size, message) => size + message.text.length, 0) > 500) return false;
|
|
267412
|
+
let cursor = 0;
|
|
267413
|
+
let remainder = "";
|
|
267414
|
+
for (const message of messages) {
|
|
267415
|
+
remainder += text.slice(cursor, message.start);
|
|
267416
|
+
cursor = message.end;
|
|
267417
|
+
}
|
|
267418
|
+
remainder += text.slice(cursor);
|
|
267419
|
+
return !VISUAL_TASK.test(remainder) && remainder.split(/\r?\n/).every((line) => line.trim().length === 0 || /^\[(?:GRUPPENANTWORT|REPLY-PFLICHT|SEMANTISCHE ADRESSIERUNG|NUR MITLESEN)\b[^\r\n]*\]$/.test(line.trim()));
|
|
267420
|
+
}
|
|
267421
|
+
/** Request-only view; the context, records, and resume state keep the full skill. */
|
|
267422
|
+
function projectBaselineSkillForTurn(history, input, origin, turnAnchor) {
|
|
267423
|
+
if (!clearlyNonVisual(input, origin)) return history;
|
|
267424
|
+
const anchorIndex = turnAnchor === void 0 ? -1 : history.indexOf(turnAnchor);
|
|
267425
|
+
if (anchorIndex >= 0 && history.slice(anchorIndex + 1).some((message) => message.role === "tool" && message.content.some((part) => part.type !== "text" || VISUAL_TASK.test(part.text)))) return history;
|
|
267426
|
+
return history.map((message) => message.origin?.kind === "injection" && message.origin.variant === BASELINE_ORIGIN ? {
|
|
267427
|
+
...message,
|
|
267428
|
+
content: [{
|
|
267429
|
+
type: "text",
|
|
267430
|
+
text: SHORT_REFERENCE
|
|
267431
|
+
}]
|
|
267432
|
+
} : message);
|
|
267433
|
+
}
|
|
267434
|
+
//#endregion
|
|
266695
267435
|
//#region ../../packages/agent-core/src/agent/response-review-decision.ts
|
|
266696
267436
|
const STAGES = [
|
|
266697
267437
|
"setup",
|
|
@@ -267000,6 +267740,23 @@ function createReviewedOutputDispatcher(options) {
|
|
|
267000
267740
|
}
|
|
267001
267741
|
//#endregion
|
|
267002
267742
|
//#region ../../packages/agent-core/src/agent/turn/index.ts
|
|
267743
|
+
function restoreRecentMcpToolNames(history, loadedNames) {
|
|
267744
|
+
const successfulResults = /* @__PURE__ */ new Set();
|
|
267745
|
+
const recentNames = [];
|
|
267746
|
+
const start = Math.max(0, history.length - 256);
|
|
267747
|
+
for (let index = history.length - 1; index >= start && recentNames.length < import_turn_tool_performance_policy.MAX_PERSISTENT_DEFERRED_TOOLS; index--) {
|
|
267748
|
+
const message = history[index];
|
|
267749
|
+
if (message.role === "tool" && message.isError !== true && message.toolCallId !== void 0) {
|
|
267750
|
+
if (successfulResults.size < 64) successfulResults.add(message.toolCallId);
|
|
267751
|
+
} else if (message.role === "assistant") for (let callIndex = message.toolCalls.length - 1; callIndex >= 0; callIndex--) {
|
|
267752
|
+
const call = message.toolCalls[callIndex];
|
|
267753
|
+
if (!successfulResults.delete(call.id) || !/^mcp__[\w.:-]{1,160}$/.test(call.name) || recentNames.includes(call.name)) continue;
|
|
267754
|
+
recentNames.push(call.name);
|
|
267755
|
+
if (recentNames.length >= import_turn_tool_performance_policy.MAX_PERSISTENT_DEFERRED_TOOLS) break;
|
|
267756
|
+
}
|
|
267757
|
+
}
|
|
267758
|
+
for (const name of recentNames.reverse()) loadedNames.add(name);
|
|
267759
|
+
}
|
|
267003
267760
|
function blunExtractText(content) {
|
|
267004
267761
|
if (typeof content === "string") return content;
|
|
267005
267762
|
if (Array.isArray(content)) return content.map((c) => typeof c === "string" ? c : c && typeof c === "object" && "text" in c && typeof c.text === "string" ? c.text : "").join(" ");
|
|
@@ -267019,7 +267776,7 @@ function blunTurnNeedsTools(input, origin) {
|
|
|
267019
267776
|
return !/^(?:hi|hallo|hey|hello|hoi|moin|servus|yo|danke|thanks|thx|bye|tschau|ciao)[.!?]*$/.test(text) && !/^(?:wer bist du|who are you|wie geht(?: es dir)?|how are you|na)[.!?]*$/.test(text);
|
|
267020
267777
|
}
|
|
267021
267778
|
function blunThinkingIntentInput(input) {
|
|
267022
|
-
const channelText =
|
|
267779
|
+
const channelText = (0, import_turn_tool_performance_policy.channelMessagesForTurnText)(blunExtractText(input)).at(-1)?.text;
|
|
267023
267780
|
return channelText === void 0 ? input : [{
|
|
267024
267781
|
type: "text",
|
|
267025
267782
|
text: channelText
|
|
@@ -267093,14 +267850,51 @@ function blunToolsForOrigin(tools, origin) {
|
|
|
267093
267850
|
* the ordinary permission pipeline.
|
|
267094
267851
|
*/
|
|
267095
267852
|
function blunSelectTurnTools(tools, maxContextTokens, loadedToolNames = /* @__PURE__ */ new Set(), requiredToolNames = /* @__PURE__ */ new Set(), selected = []) {
|
|
267096
|
-
|
|
267853
|
+
const schemaBudget = (0, import_turn_tool_performance_policy.toolSchemaBudgetTokens)(maxContextTokens);
|
|
267854
|
+
const estimates = /* @__PURE__ */ new Map();
|
|
267855
|
+
const estimateSummary = (tool) => {
|
|
267856
|
+
let estimate = estimates.get(tool);
|
|
267857
|
+
if (estimate === void 0) {
|
|
267858
|
+
estimate = { summary: estimateTokens(tool.name) + estimateTokens(tool.description) };
|
|
267859
|
+
estimates.set(tool, estimate);
|
|
267860
|
+
}
|
|
267861
|
+
return estimate;
|
|
267862
|
+
};
|
|
267863
|
+
const estimateSelection = (candidates) => {
|
|
267864
|
+
let total = 0;
|
|
267865
|
+
for (const candidate of candidates) {
|
|
267866
|
+
const estimate = estimateSummary(candidate);
|
|
267867
|
+
if (estimate.complete === void 0) estimate.complete = estimate.summary + estimateTokens(JSON.stringify(candidate.parameters));
|
|
267868
|
+
total += estimate.complete;
|
|
267869
|
+
if (total > schemaBudget) break;
|
|
267870
|
+
}
|
|
267871
|
+
return total;
|
|
267872
|
+
};
|
|
267873
|
+
let summaryTokens = 0;
|
|
267874
|
+
for (const tool of tools) {
|
|
267875
|
+
summaryTokens += estimateSummary(tool).summary;
|
|
267876
|
+
if (summaryTokens > schemaBudget) break;
|
|
267877
|
+
}
|
|
267878
|
+
if (tools.some(import_turn_tool_performance_policy.isDeferredToolLoader) || summaryTokens <= schemaBudget && estimateSelection(tools) <= schemaBudget) {
|
|
267097
267879
|
selected.splice(0, selected.length, ...tools);
|
|
267098
267880
|
return selected;
|
|
267099
267881
|
}
|
|
267100
|
-
|
|
267101
|
-
const
|
|
267102
|
-
const
|
|
267103
|
-
|
|
267882
|
+
const priorLoaderIndex = selected.findIndex(import_turn_tool_performance_policy.isDeferredToolLoader);
|
|
267883
|
+
const justLoaded = new Set(priorLoaderIndex < 0 ? [] : selected.slice(priorLoaderIndex + 1).filter((tool) => loadedToolNames.has(tool.name)).map((tool) => tool.name));
|
|
267884
|
+
const remembered = new Set(loadedToolNames);
|
|
267885
|
+
const choose = () => {
|
|
267886
|
+
selected.splice(0, selected.length, ...tools.filter((tool) => BLUN_LEAN_TOOL_NAMES.has(tool.name) || BLUN_LEAN_KEEP_RE.test(tool.name) || BLUN_LANGUAGE_REVIEW_TOOL_NAMES.has(tool.name) || remembered.has(tool.name) || requiredToolNames.has(tool.name)));
|
|
267887
|
+
const names = new Set(selected.map((tool) => tool.name));
|
|
267888
|
+
const deferred = tools.filter((tool) => !names.has(tool.name));
|
|
267889
|
+
if (deferred.length > 0) selected.push((0, import_turn_tool_performance_policy.createDeferredToolLoader)(selected, deferred, loadedToolNames));
|
|
267890
|
+
};
|
|
267891
|
+
choose();
|
|
267892
|
+
for (const name of loadedToolNames) {
|
|
267893
|
+
if (estimateSelection(selected) <= schemaBudget) break;
|
|
267894
|
+
if (justLoaded.has(name)) continue;
|
|
267895
|
+
if (!remembered.delete(name)) continue;
|
|
267896
|
+
choose();
|
|
267897
|
+
}
|
|
267104
267898
|
return selected;
|
|
267105
267899
|
}
|
|
267106
267900
|
const LLM_NOT_SET_MESSAGE = "LLM not set, send \"/login\" to login";
|
|
@@ -267460,6 +268254,7 @@ var TurnFlow = class {
|
|
|
267460
268254
|
}
|
|
267461
268255
|
finishResume() {
|
|
267462
268256
|
if (this.activeTurn === "resuming") this.activeTurn = null;
|
|
268257
|
+
restoreRecentMcpToolNames(this.agent.context.history, this.loadedToolNames);
|
|
267463
268258
|
this.steerBuffer.length = 0;
|
|
267464
268259
|
}
|
|
267465
268260
|
/**
|
|
@@ -267590,6 +268385,7 @@ var TurnFlow = class {
|
|
|
267590
268385
|
const appendedMessage = this.agent.context.history.at(-1);
|
|
267591
268386
|
const turnAnchor = appendedMessage !== previousLastMessage && appendedMessage?.role === "user" && appendedMessage.origin === origin ? appendedMessage : void 0;
|
|
267592
268387
|
const startedAt = Date.now();
|
|
268388
|
+
const preRequestHookStartedAt = performance.now();
|
|
267593
268389
|
let ended;
|
|
267594
268390
|
let blockedByUserPromptHook = false;
|
|
267595
268391
|
let completedStopReason;
|
|
@@ -267615,6 +268411,13 @@ var TurnFlow = class {
|
|
|
267615
268411
|
this.agent.log.warn("Turn-start observation failed");
|
|
267616
268412
|
}
|
|
267617
268413
|
signal.throwIfAborted();
|
|
268414
|
+
if (this.agent.type === "main" && process.env["BLUN_DIAG_PRE_REQUEST_PHASES"] === "1") try {
|
|
268415
|
+
this.agent.log.info("turn pre-request phase", {
|
|
268416
|
+
turnId,
|
|
268417
|
+
phase: "turn-hooks",
|
|
268418
|
+
durationMs: Math.max(0, Math.round(performance.now() - preRequestHookStartedAt))
|
|
268419
|
+
});
|
|
268420
|
+
} catch {}
|
|
267618
268421
|
const stopReason = await this.runStepLoop(turnId, signal, input, origin, turnAnchor, (response) => {
|
|
267619
268422
|
completedResponse = response;
|
|
267620
268423
|
});
|
|
@@ -267726,6 +268529,10 @@ var TurnFlow = class {
|
|
|
267726
268529
|
signal.throwIfAborted();
|
|
267727
268530
|
const blockResult = renderUserPromptHookBlockResult(promptHookResults);
|
|
267728
268531
|
if (blockResult !== void 0) {
|
|
268532
|
+
this.agent.log.warn("turn blocked by UserPromptSubmit hook", {
|
|
268533
|
+
turnId,
|
|
268534
|
+
reason: blockResult.message
|
|
268535
|
+
});
|
|
267729
268536
|
this.agent.context.appendMessage({
|
|
267730
268537
|
role: "assistant",
|
|
267731
268538
|
content: [{
|
|
@@ -267784,9 +268591,26 @@ var TurnFlow = class {
|
|
|
267784
268591
|
let stopHookContinuationUsed = false;
|
|
267785
268592
|
let goalOutcomeMessageContinuationUsed = false;
|
|
267786
268593
|
const deduper = new ToolCallDeduplicator({ telemetry: this.agent.telemetry });
|
|
268594
|
+
const diagnosePreRequest = this.agent.type === "main" && process.env["BLUN_DIAG_PRE_REQUEST_PHASES"] === "1";
|
|
268595
|
+
const recordPreRequestPhase = (phase, startedAt) => {
|
|
268596
|
+
if (!diagnosePreRequest) return;
|
|
268597
|
+
try {
|
|
268598
|
+
this.agent.log.info("turn pre-request phase", {
|
|
268599
|
+
turnId,
|
|
268600
|
+
phase,
|
|
268601
|
+
durationMs: Math.max(0, Math.round(performance.now() - startedAt))
|
|
268602
|
+
});
|
|
268603
|
+
} catch {}
|
|
268604
|
+
};
|
|
268605
|
+
let phaseStartedAt = performance.now();
|
|
267787
268606
|
await this.agent.mcp?.waitForInitialLoad(signal);
|
|
268607
|
+
recordPreRequestPhase("mcp-initial-load", phaseStartedAt);
|
|
268608
|
+
phaseStartedAt = performance.now();
|
|
267788
268609
|
const personalMemoryRecall = await this.agent.injection.injectPersonalMemoryForTurn(turnId, input, origin, signal);
|
|
268610
|
+
recordPreRequestPhase("personal-memory-recall", phaseStartedAt);
|
|
268611
|
+
phaseStartedAt = performance.now();
|
|
267789
268612
|
await this.agent.injection.injectGoal();
|
|
268613
|
+
recordPreRequestPhase("goal-injection", phaseStartedAt);
|
|
267790
268614
|
this.setActiveSteerAcceptance(turnId, true);
|
|
267791
268615
|
const turnNeedsThinking = blunTurnNeedsTools(blunThinkingIntentInput(input), origin);
|
|
267792
268616
|
let toolInput = input;
|
|
@@ -267797,23 +268621,27 @@ var TurnFlow = class {
|
|
|
267797
268621
|
const raw = [...this.agent.context.history];
|
|
267798
268622
|
const history = personalMemoryRecall === void 0 ? raw : [...raw, personalMemoryRecall];
|
|
267799
268623
|
const selected = taskToolsNeeded ? history : greetingHistory(history, greetingAnchor);
|
|
268624
|
+
const projectionStartedAt = performance.now();
|
|
267800
268625
|
const projected = await this.historicalToolProjection.project(selected, turnAnchor, tools, {
|
|
267801
268626
|
turnId: String(turnId),
|
|
267802
268627
|
stepNumber: this.currentStep,
|
|
267803
268628
|
signal,
|
|
267804
268629
|
llm: turnLLM
|
|
267805
268630
|
});
|
|
268631
|
+
recordPreRequestPhase("historical-tool-projection", projectionStartedAt);
|
|
267806
268632
|
const current = this.agent.context.history;
|
|
267807
268633
|
if (current.length !== raw.length || current.some((message, index) => message !== raw[index])) {
|
|
267808
268634
|
const latest = personalMemoryRecall === void 0 ? current : [...current, personalMemoryRecall];
|
|
267809
268635
|
const retained = taskToolsNeeded ? latest : greetingHistory(latest, greetingAnchor);
|
|
267810
|
-
|
|
267811
|
-
|
|
268636
|
+
const request = projectBaselineSkillForTurn(retained, toolInput, origin, turnAnchor);
|
|
268637
|
+
partialContext = retained.length < latest.length || request !== retained;
|
|
268638
|
+
return request;
|
|
267812
268639
|
}
|
|
267813
|
-
|
|
267814
|
-
|
|
268640
|
+
const request = projectBaselineSkillForTurn(projected.history, toolInput, origin, turnAnchor);
|
|
268641
|
+
partialContext = selected.length < history.length || projected.changed || request !== projected.history;
|
|
268642
|
+
return request;
|
|
267815
268643
|
};
|
|
267816
|
-
const turnLLM = this.agent.llmForTurn(turnNeedsThinking ? void 0 : "off");
|
|
268644
|
+
const turnLLM = this.agent.llmForTurn(turnNeedsThinking ? void 0 : "off", turnId);
|
|
267817
268645
|
const turnTools = this.agent.tools.captureTurnTools();
|
|
267818
268646
|
while (true) {
|
|
267819
268647
|
signal.throwIfAborted();
|
|
@@ -267823,18 +268651,22 @@ var TurnFlow = class {
|
|
|
267823
268651
|
try {
|
|
267824
268652
|
const selectedTools = [];
|
|
267825
268653
|
this.refreshSelectedTools = (snapshot) => {
|
|
268654
|
+
const selectionStartedAt = performance.now();
|
|
267826
268655
|
if (snapshot.messages.length > 0) toolInput = snapshot.messages.flatMap((message) => message.content);
|
|
267827
268656
|
const eligibleTools = blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, turnTools()), origin);
|
|
267828
268657
|
const intent = blunThinkingIntentInput(toolInput);
|
|
267829
268658
|
taskToolsNeeded ||= blunTurnNeedsTools(intent, origin) || blunTurnHasAttachment(toolInput);
|
|
267830
268659
|
const required = (0, import_turn_tool_performance_policy.mediaToolNamesForTurnText)(blunExtractText(toolInput));
|
|
267831
268660
|
if (taskToolsNeeded) {
|
|
267832
|
-
|
|
267833
|
-
|
|
268661
|
+
const maxContextTokens = this.agent.fullCompaction.getEffectiveMaxContextTokens();
|
|
268662
|
+
blunSelectTurnTools(eligibleTools, maxContextTokens, this.loadedToolNames, required, selectedTools);
|
|
268663
|
+
const trustedToolNames = new Set(eligibleTools.filter((tool) => this.agent.tools.isUserTool(tool)).map((tool) => tool.name));
|
|
268664
|
+
for (const name of (0, import_turn_tool_performance_policy.rankedToolNamesForTurnText)(eligibleTools, blunExtractText(intent), { trustedToolNames })) {
|
|
267834
268665
|
const tool = eligibleTools.find((candidate) => candidate.name === name);
|
|
267835
|
-
if (tool !== void 0 && !selectedTools.some((candidate) => candidate.name === name) && estimateTokensForTools([...selectedTools, tool]) <= (0, import_turn_tool_performance_policy.toolSchemaBudgetTokens)(
|
|
268666
|
+
if (tool !== void 0 && !selectedTools.some((candidate) => candidate.name === name) && estimateTokensForTools([...selectedTools, tool]) <= (0, import_turn_tool_performance_policy.toolSchemaBudgetTokens)(maxContextTokens)) selectedTools.push(tool);
|
|
267836
268667
|
}
|
|
267837
268668
|
} 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)));
|
|
268669
|
+
recordPreRequestPhase("tool-selection", selectionStartedAt);
|
|
267838
268670
|
return selectedTools;
|
|
267839
268671
|
};
|
|
267840
268672
|
return (await runTurn({
|
|
@@ -267847,14 +268679,24 @@ var TurnFlow = class {
|
|
|
267847
268679
|
}, completion);
|
|
267848
268680
|
},
|
|
267849
268681
|
llm: turnLLM,
|
|
267850
|
-
buildMessages: async () =>
|
|
267851
|
-
|
|
267852
|
-
|
|
267853
|
-
|
|
267854
|
-
|
|
267855
|
-
|
|
267856
|
-
|
|
267857
|
-
|
|
268682
|
+
buildMessages: async () => {
|
|
268683
|
+
const startedAt = performance.now();
|
|
268684
|
+
const messages = this.agent.context.project(await turnHistory(selectedTools), { dropOrphanResults: true });
|
|
268685
|
+
recordPreRequestPhase("message-build", startedAt);
|
|
268686
|
+
return messages;
|
|
268687
|
+
},
|
|
268688
|
+
buildMessagesStrict: async () => {
|
|
268689
|
+
const startedAt = performance.now();
|
|
268690
|
+
const messages = this.agent.context.project(await turnHistory(selectedTools), {
|
|
268691
|
+
synthesizeMissing: true,
|
|
268692
|
+
dropOrphanResults: true,
|
|
268693
|
+
dedupeDuplicateToolCalls: true,
|
|
268694
|
+
dropLeadingNonUser: true,
|
|
268695
|
+
mergeConsecutiveAssistants: true
|
|
268696
|
+
});
|
|
268697
|
+
recordPreRequestPhase("message-build-strict", startedAt);
|
|
268698
|
+
return messages;
|
|
268699
|
+
},
|
|
267858
268700
|
dispatchEvent: this.buildDispatchEvent(turnId, signal, onFinalResponse, () => partialContext),
|
|
267859
268701
|
tools: selectedTools,
|
|
267860
268702
|
log: this.agent.log,
|
|
@@ -267871,8 +268713,10 @@ var TurnFlow = class {
|
|
|
267871
268713
|
},
|
|
267872
268714
|
hooks: {
|
|
267873
268715
|
beforeStep: async ({ signal: stepSignal, llm }) => {
|
|
268716
|
+
const injectionStartedAt = performance.now();
|
|
267874
268717
|
this.agent.microCompaction.detect();
|
|
267875
268718
|
await this.agent.injection.inject();
|
|
268719
|
+
recordPreRequestPhase("step-injection", injectionStartedAt);
|
|
267876
268720
|
stepSignal.throwIfAborted();
|
|
267877
268721
|
deduper.beginStep();
|
|
267878
268722
|
},
|
|
@@ -267910,6 +268754,17 @@ var TurnFlow = class {
|
|
|
267910
268754
|
signal.throwIfAborted();
|
|
267911
268755
|
if (stopBlock !== void 0) {
|
|
267912
268756
|
stopHookContinuationUsed = true;
|
|
268757
|
+
this.agent.log.warn("turn continuation blocked by Stop hook", {
|
|
268758
|
+
turnId,
|
|
268759
|
+
reason: stopBlock.reason
|
|
268760
|
+
});
|
|
268761
|
+
this.agent.emitEvent({
|
|
268762
|
+
type: "hook.result",
|
|
268763
|
+
turnId,
|
|
268764
|
+
hookEvent: "Stop",
|
|
268765
|
+
content: stopBlock.reason,
|
|
268766
|
+
blocked: true
|
|
268767
|
+
});
|
|
267913
268768
|
this.agent.context.appendUserMessage([{
|
|
267914
268769
|
type: "text",
|
|
267915
268770
|
text: stopBlock.reason
|
|
@@ -267949,6 +268804,7 @@ var TurnFlow = class {
|
|
|
267949
268804
|
});
|
|
267950
268805
|
return budgetToolResultForModel({
|
|
267951
268806
|
homedir: this.agent.homedir,
|
|
268807
|
+
maxContextTokens: this.agent.fullCompaction.getEffectiveMaxContextTokens(),
|
|
267952
268808
|
toolName: ctx.toolCall.name,
|
|
267953
268809
|
toolCallId: ctx.toolCall.id,
|
|
267954
268810
|
result: finalResult
|
|
@@ -268806,10 +269662,10 @@ var BashTool = class {
|
|
|
268806
269662
|
},
|
|
268807
269663
|
approvalRule: literalRulePattern(this.name, args.command),
|
|
268808
269664
|
matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.command),
|
|
268809
|
-
execute: ({ signal, onUpdate, onForegroundTaskStart }) => this.execution(args, signal, onUpdate, onForegroundTaskStart)
|
|
269665
|
+
execute: ({ signal, onUpdate, onForegroundTaskStart, executionOrigin }) => this.execution(args, signal, onUpdate, onForegroundTaskStart, executionOrigin)
|
|
268810
269666
|
};
|
|
268811
269667
|
}
|
|
268812
|
-
spawn(effectiveCwd, command) {
|
|
269668
|
+
spawn(effectiveCwd, command, executionOrigin) {
|
|
268813
269669
|
const shellCwd = this.isWindowsBash ? windowsPathToPosixPath(effectiveCwd) : effectiveCwd;
|
|
268814
269670
|
const shellArgs = [
|
|
268815
269671
|
this.kaos.osEnv.shellPath,
|
|
@@ -268826,9 +269682,11 @@ var BashTool = class {
|
|
|
268826
269682
|
...process.env,
|
|
268827
269683
|
...noninteractiveEnv
|
|
268828
269684
|
};
|
|
269685
|
+
delete mergedEnv["BLUN_SHELL"];
|
|
269686
|
+
if (executionOrigin === "operator_shell") mergedEnv["BLUN_SHELL"] = "operator-local";
|
|
268829
269687
|
return this.kaos.execWithEnv(shellArgs, mergedEnv);
|
|
268830
269688
|
}
|
|
268831
|
-
async execution(args, signal, onUpdate, onForegroundTaskStart) {
|
|
269689
|
+
async execution(args, signal, onUpdate, onForegroundTaskStart, executionOrigin) {
|
|
268832
269690
|
const validationError = this.validateRunRequest(args, signal);
|
|
268833
269691
|
if (validationError !== void 0) return validationError;
|
|
268834
269692
|
const startsInBackground = args.run_in_background === true;
|
|
@@ -268840,7 +269698,7 @@ var BashTool = class {
|
|
|
268840
269698
|
const builder = new ToolResultBuilder();
|
|
268841
269699
|
let proc;
|
|
268842
269700
|
try {
|
|
268843
|
-
proc = await this.spawn(effectiveCwd, command);
|
|
269701
|
+
proc = await this.spawn(effectiveCwd, command, executionOrigin);
|
|
268844
269702
|
} catch (error) {
|
|
268845
269703
|
return {
|
|
268846
269704
|
isError: true,
|
|
@@ -269204,14 +270062,14 @@ function classifySearchError(error) {
|
|
|
269204
270062
|
}
|
|
269205
270063
|
//#endregion
|
|
269206
270064
|
//#region ../../packages/agent-core/src/tools/builtin/search/codebase-search.md?raw
|
|
269207
|
-
var codebase_search_default = "Find code by **meaning**, not by keywords.\n\nThis tool runs a semantic search over the codebase index. It understands what a file or function *does*, not just what words appear in it. Use it when you are looking for *where* something is handled, *which file* implements a concept, or *how* a particular concern is addressed — even when the exact term never appears in the source.\n\n**When to use this tool:**\n- \"Where is keyboard input handled?\" — finds the handler even if the word \"keyboard\" never appears.\n- \"Which file manages the retry logic for API calls?\"\n- \"How does the app decide which model to route a message to?\"\n- \"Find the code that handles user authentication flow.\"\n- Any question where you want to locate code by its *purpose* or *behavior*.\n\n**When NOT to use this tool — use a different one instead:**\n- Exact string matches, regex patterns, or specific identifiers → `Grep`\n- Finding files by name, extension, or path glob → `Glob`\n- Reading a known file path → `Read`\n\n**Parameters:**\n- `query` (required): A natural-language question, concept, or phrase describing what the code does. Examples: `\"keyboard event handling\"`, `\"retry with exponential backoff\"`, `\"where chat messages are routed to the model\"`.\n- `top` (optional, default 5): Maximum number of results to return.\n\n**Output:**\nEach result includes a file path and a relevance
|
|
270065
|
+
var codebase_search_default = "Find code by **meaning**, not by keywords.\n\nThis tool runs a semantic search over the codebase index. It understands what a file or function *does*, not just what words appear in it. Use it when you are looking for *where* something is handled, *which file* implements a concept, or *how* a particular concern is addressed — even when the exact term never appears in the source.\n\n**When to use this tool:**\n- \"Where is keyboard input handled?\" — finds the handler even if the word \"keyboard\" never appears.\n- \"Which file manages the retry logic for API calls?\"\n- \"How does the app decide which model to route a message to?\"\n- \"Find the code that handles user authentication flow.\"\n- Any question where you want to locate code by its *purpose* or *behavior*.\n\n**When NOT to use this tool — use a different one instead:**\n- Exact string matches, regex patterns, or specific identifiers → `Grep`\n- Finding files by name, extension, or path glob → `Glob`\n- Reading a known file path → `Read`\n\n**Parameters:**\n- `query` (required): A natural-language question, concept, or phrase describing what the code does. Examples: `\"keyboard event handling\"`, `\"retry with exponential backoff\"`, `\"where chat messages are routed to the model\"`.\n- `top` (optional, default 5, maximum 100): Maximum number of results to return.\n\n**Output:**\nEach result includes a file path and a relevance score, plus the index model and revision. The index is rebuilt incrementally; if a file was recently added it may not appear until the next index update. Always verify the finding by reading the file before relying on it.\n";
|
|
269208
270066
|
//#endregion
|
|
269209
270067
|
//#region ../../packages/agent-core/src/tools/builtin/search/codebase-search.ts
|
|
269210
270068
|
/**
|
|
269211
270069
|
* CodebaseSearchTool — semantic code search via the codebase-index.
|
|
269212
270070
|
*
|
|
269213
270071
|
* Shells out to `python codebase_index.py query <repo> "<frage>" --top N`
|
|
269214
|
-
* through
|
|
270072
|
+
* through asynchronous execFile. The script lives at
|
|
269215
270073
|
* `packages/codebase-index/codebase_index.py` relative to the workspace root.
|
|
269216
270074
|
*
|
|
269217
270075
|
* Unlike Grep (keyword/regex) or Glob (file-name patterns), this tool finds
|
|
@@ -269219,11 +270077,13 @@ var codebase_search_default = "Find code by **meaning**, not by keywords.\n\nThi
|
|
|
269219
270077
|
* to the query, so it can locate a keyboard handler even when the word
|
|
269220
270078
|
* "keyboard" never appears in the source.
|
|
269221
270079
|
*/
|
|
270080
|
+
const MAX_SEARCH_RESULTS = 100;
|
|
269222
270081
|
const CodebaseSearchInputSchema = object({
|
|
269223
270082
|
query: string().min(1, "Query cannot be empty.").describe("A natural-language question or concept describing what the code does. Examples: \"keyboard event handling\", \"retry with exponential backoff\", \"where chat messages are routed to the model\"."),
|
|
269224
|
-
top: number$1().int().positive().default(5).describe(
|
|
270083
|
+
top: number$1().int().positive().max(MAX_SEARCH_RESULTS).default(5).describe(`Maximum number of results to return (1-${String(MAX_SEARCH_RESULTS)}). Defaults to 5.`)
|
|
269225
270084
|
});
|
|
269226
270085
|
const SCRIPT_TIMEOUT_MS = 6e4;
|
|
270086
|
+
const SCRIPT_MAX_BUFFER = 1024 * 1024;
|
|
269227
270087
|
function isScriptFile(path) {
|
|
269228
270088
|
try {
|
|
269229
270089
|
return statSync(path).isFile();
|
|
@@ -269262,45 +270122,72 @@ var CodebaseSearchTool = class {
|
|
|
269262
270122
|
},
|
|
269263
270123
|
approvalRule: literalRulePattern(this.name, args.query),
|
|
269264
270124
|
matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.query),
|
|
269265
|
-
execute: () =>
|
|
270125
|
+
execute: async (context) => {
|
|
270126
|
+
context.signal.throwIfAborted();
|
|
270127
|
+
return this.execution(args, context.signal);
|
|
270128
|
+
}
|
|
269266
270129
|
};
|
|
269267
270130
|
}
|
|
269268
|
-
execution(args) {
|
|
270131
|
+
async execution(args, signal) {
|
|
269269
270132
|
const builder = new ToolResultBuilder();
|
|
269270
|
-
if (
|
|
270133
|
+
if (!Number.isSafeInteger(args.top) || args.top < 1 || args.top > MAX_SEARCH_RESULTS) return builder.error(`Codebase search top must be between 1 and ${String(MAX_SEARCH_RESULTS)}.`);
|
|
270134
|
+
if (this.scriptPath.length === 0) return builder.error("Could not locate codebase_index.py. Set CODEBASE_INDEX_SCRIPT to its absolute path.");
|
|
269271
270135
|
try {
|
|
269272
|
-
const result =
|
|
269273
|
-
|
|
269274
|
-
|
|
269275
|
-
|
|
269276
|
-
|
|
269277
|
-
|
|
269278
|
-
|
|
269279
|
-
|
|
269280
|
-
|
|
269281
|
-
|
|
269282
|
-
|
|
269283
|
-
|
|
269284
|
-
|
|
269285
|
-
|
|
270136
|
+
const result = await new Promise((resolve) => {
|
|
270137
|
+
let closed = false;
|
|
270138
|
+
let output;
|
|
270139
|
+
const finish = () => {
|
|
270140
|
+
if (closed && output !== void 0) resolve(output);
|
|
270141
|
+
};
|
|
270142
|
+
execFile("python", [
|
|
270143
|
+
this.scriptPath,
|
|
270144
|
+
"query",
|
|
270145
|
+
this.cwd,
|
|
270146
|
+
args.query,
|
|
270147
|
+
"--top",
|
|
270148
|
+
String(args.top),
|
|
270149
|
+
"--model",
|
|
270150
|
+
"auto"
|
|
270151
|
+
], {
|
|
270152
|
+
cwd: this.cwd,
|
|
270153
|
+
timeout: SCRIPT_TIMEOUT_MS,
|
|
270154
|
+
encoding: "utf-8",
|
|
270155
|
+
windowsHide: true,
|
|
270156
|
+
shell: false,
|
|
270157
|
+
maxBuffer: SCRIPT_MAX_BUFFER,
|
|
270158
|
+
signal
|
|
270159
|
+
}, (error, stdout, stderr) => {
|
|
270160
|
+
output = {
|
|
270161
|
+
error,
|
|
270162
|
+
stdout,
|
|
270163
|
+
stderr
|
|
270164
|
+
};
|
|
270165
|
+
finish();
|
|
270166
|
+
}).once("close", () => {
|
|
270167
|
+
closed = true;
|
|
270168
|
+
finish();
|
|
270169
|
+
});
|
|
269286
270170
|
});
|
|
269287
|
-
|
|
270171
|
+
signal.throwIfAborted();
|
|
270172
|
+
if (result.error !== null && typeof result.error.code !== "number") {
|
|
269288
270173
|
const msg = result.error instanceof Error ? result.error.message : String(result.error);
|
|
269289
|
-
|
|
270174
|
+
builder.write(result.stdout + result.stderr);
|
|
270175
|
+
return builder.error(`Failed to run codebase_index.py: ${msg}`);
|
|
269290
270176
|
}
|
|
269291
270177
|
const stdout = result.stdout ?? "";
|
|
269292
270178
|
const stderr = result.stderr ?? "";
|
|
269293
|
-
const exitCode = result.
|
|
270179
|
+
const exitCode = result.error?.code ?? 0;
|
|
269294
270180
|
if (exitCode !== 0) {
|
|
269295
270181
|
const combined = stderr.trim().length > 0 ? `${stdout}${stdout.length > 0 ? "\n" : ""}Error: ${stderr.trim()}` : stdout;
|
|
269296
270182
|
builder.write(combined.length > 0 ? combined : `codebase_index.py exited with code ${String(exitCode)}`);
|
|
269297
|
-
return
|
|
270183
|
+
return builder.error(`Codebase search failed with exit code ${String(exitCode)}.`);
|
|
269298
270184
|
}
|
|
269299
270185
|
builder.write(stdout.length > 0 ? stdout : "No results found.");
|
|
269300
|
-
return
|
|
270186
|
+
return builder.ok();
|
|
269301
270187
|
} catch (error) {
|
|
270188
|
+
signal.throwIfAborted();
|
|
269302
270189
|
const msg = error instanceof Error ? error.message : String(error);
|
|
269303
|
-
return
|
|
270190
|
+
return builder.error(`Codebase search error: ${msg}`);
|
|
269304
270191
|
}
|
|
269305
270192
|
}
|
|
269306
270193
|
};
|
|
@@ -270540,6 +271427,7 @@ var ToolManager = class {
|
|
|
270540
271427
|
const result = await execution.execute({
|
|
270541
271428
|
turnId: "",
|
|
270542
271429
|
toolCallId: "shell-command",
|
|
271430
|
+
executionOrigin: "operator_shell",
|
|
270543
271431
|
signal: controller.signal,
|
|
270544
271432
|
onUpdate: (update) => {
|
|
270545
271433
|
if (update.kind === "stdout") stdout += update.text ?? "";
|
|
@@ -270628,6 +271516,9 @@ var ToolManager = class {
|
|
|
270628
271516
|
hasUserTool(name) {
|
|
270629
271517
|
return this.userTools.has(name);
|
|
270630
271518
|
}
|
|
271519
|
+
isUserTool(tool) {
|
|
271520
|
+
return this.userTools.get(tool.name) === tool;
|
|
271521
|
+
}
|
|
270631
271522
|
inheritUserTools(parent) {
|
|
270632
271523
|
for (const tool of parent.userTools.values()) {
|
|
270633
271524
|
if (!parent.enabledTools.has(tool.name)) continue;
|
|
@@ -271327,15 +272218,17 @@ var FallbackLLM = class {
|
|
|
271327
272218
|
onModelChanged;
|
|
271328
272219
|
prepareRequest;
|
|
271329
272220
|
onContextOverflow;
|
|
272221
|
+
messagePreparation;
|
|
271330
272222
|
currentIndex = 0;
|
|
271331
272223
|
attemptedProviders = /* @__PURE__ */ new Set();
|
|
271332
272224
|
errorsAfterOutput = /* @__PURE__ */ new WeakSet();
|
|
271333
272225
|
rebuildBoundaryMessages;
|
|
271334
|
-
constructor(candidates, onModelChanged = () => {}, prepareRequest, onContextOverflow) {
|
|
272226
|
+
constructor(candidates, onModelChanged = () => {}, prepareRequest, onContextOverflow, messagePreparation = "eager") {
|
|
271335
272227
|
this.candidates = candidates;
|
|
271336
272228
|
this.onModelChanged = onModelChanged;
|
|
271337
272229
|
this.prepareRequest = prepareRequest;
|
|
271338
272230
|
this.onContextOverflow = onContextOverflow;
|
|
272231
|
+
this.messagePreparation = messagePreparation;
|
|
271339
272232
|
if (candidates.length === 0) throw new Error("FallbackLLM requires at least one model candidate.");
|
|
271340
272233
|
}
|
|
271341
272234
|
get activeAlias() {
|
|
@@ -271350,6 +272243,9 @@ var FallbackLLM = class {
|
|
|
271350
272243
|
get capability() {
|
|
271351
272244
|
return this.current.llm.capability;
|
|
271352
272245
|
}
|
|
272246
|
+
get rebuildsMessagesAtRequestBoundary() {
|
|
272247
|
+
return this.messagePreparation === "boundary" && this.prepareRequest !== void 0;
|
|
272248
|
+
}
|
|
271353
272249
|
async prepareRequestBoundary(params, rebuildMessages) {
|
|
271354
272250
|
params.signal.throwIfAborted();
|
|
271355
272251
|
this.rebuildBoundaryMessages = rebuildMessages;
|
|
@@ -271412,6 +272308,7 @@ var FallbackLLM = class {
|
|
|
271412
272308
|
throw new Error("Fallback request preparation requires a fresh request boundary.");
|
|
271413
272309
|
}
|
|
271414
272310
|
let requestParams = params;
|
|
272311
|
+
let messagesReady = false;
|
|
271415
272312
|
const rebuildRequestMessages = async () => {
|
|
271416
272313
|
const messages = await rebuildMessages();
|
|
271417
272314
|
const suffix = requestParams.boundaryMessageSuffix;
|
|
@@ -271420,7 +272317,14 @@ var FallbackLLM = class {
|
|
|
271420
272317
|
while (true) {
|
|
271421
272318
|
const candidate = this.current;
|
|
271422
272319
|
try {
|
|
271423
|
-
|
|
272320
|
+
const prepared = await this.prepareRequest?.(candidate, requestParams, rebuildRequestMessages);
|
|
272321
|
+
if (prepared !== void 0) if ("messagesReady" in prepared) {
|
|
272322
|
+
requestParams = prepared.params;
|
|
272323
|
+
messagesReady = true;
|
|
272324
|
+
} else {
|
|
272325
|
+
requestParams = prepared;
|
|
272326
|
+
messagesReady = false;
|
|
272327
|
+
}
|
|
271424
272328
|
} catch (error) {
|
|
271425
272329
|
if (!isFallbackCandidateError(error) && !isUnavailableFallbackCandidate(error)) throw error;
|
|
271426
272330
|
const nextIndex = this.findNextCandidateIndex();
|
|
@@ -271430,13 +272334,14 @@ var FallbackLLM = class {
|
|
|
271430
272334
|
...requestParams,
|
|
271431
272335
|
messages: await rebuildRequestMessages()
|
|
271432
272336
|
};
|
|
272337
|
+
messagesReady = false;
|
|
271433
272338
|
requestParams.signal.throwIfAborted();
|
|
271434
272339
|
this.currentIndex = nextIndex;
|
|
271435
272340
|
this.onModelChanged(this.current.alias);
|
|
271436
272341
|
continue;
|
|
271437
272342
|
}
|
|
271438
272343
|
requestParams.signal.throwIfAborted();
|
|
271439
|
-
const messages = await rebuildRequestMessages();
|
|
272344
|
+
const messages = messagesReady ? requestParams.messages : await rebuildRequestMessages();
|
|
271440
272345
|
requestParams.signal.throwIfAborted();
|
|
271441
272346
|
return {
|
|
271442
272347
|
...requestParams,
|
|
@@ -271538,8 +272443,13 @@ var LlmRequestLogger = class {
|
|
|
271538
272443
|
toolsEstimatedTokens = 0;
|
|
271539
272444
|
requestSequence = 0;
|
|
271540
272445
|
lastTurnRequest;
|
|
271541
|
-
|
|
272446
|
+
serializedPrefixKey;
|
|
272447
|
+
requestSignatures = /* @__PURE__ */ new Map();
|
|
272448
|
+
prefixComparisons = /* @__PURE__ */ new Map();
|
|
272449
|
+
lastSerializedRequest;
|
|
272450
|
+
constructor(log, serializedPrefixDiagnostic = process.env["BLUN_DIAG_SERIALIZED_PREFIX"] === "1") {
|
|
271542
272451
|
this.log = log;
|
|
272452
|
+
this.serializedPrefixKey = serializedPrefixDiagnostic ? randomBytes(32) : void 0;
|
|
271543
272453
|
}
|
|
271544
272454
|
logRequest(input) {
|
|
271545
272455
|
const sequence = ++this.requestSequence;
|
|
@@ -271556,6 +272466,10 @@ var LlmRequestLogger = class {
|
|
|
271556
272466
|
toolsHash: fingerprint(JSON.stringify(toolSignature(tools)))
|
|
271557
272467
|
};
|
|
271558
272468
|
const signature = JSON.stringify(config);
|
|
272469
|
+
if (this.serializedPrefixKey !== void 0) {
|
|
272470
|
+
this.requestSignatures.set(sequence, signature);
|
|
272471
|
+
if (this.requestSignatures.size > 32) this.requestSignatures.delete(this.requestSignatures.keys().next().value);
|
|
272472
|
+
}
|
|
271559
272473
|
if (signature !== this.lastConfigLogSignature) {
|
|
271560
272474
|
this.lastConfigLogSignature = signature;
|
|
271561
272475
|
this.configRevision++;
|
|
@@ -271585,6 +272499,20 @@ var LlmRequestLogger = class {
|
|
|
271585
272499
|
}
|
|
271586
272500
|
};
|
|
271587
272501
|
if (partialMessageCount > 0) requestFields.partialMessageCount = partialMessageCount;
|
|
272502
|
+
const source = input.systemPromptContributions;
|
|
272503
|
+
if (source?.version === 1 && [
|
|
272504
|
+
source.totalBytes,
|
|
272505
|
+
source.instructionBytes,
|
|
272506
|
+
source.skillListingBytes,
|
|
272507
|
+
source.runtimeMemoryBytes,
|
|
272508
|
+
source.otherBytes
|
|
272509
|
+
].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 = {
|
|
272510
|
+
totalBytes: source.totalBytes,
|
|
272511
|
+
instructionBytes: source.instructionBytes,
|
|
272512
|
+
skillListingBytes: source.skillListingBytes,
|
|
272513
|
+
runtimeMemoryBytes: source.runtimeMemoryBytes,
|
|
272514
|
+
otherBytes: source.otherBytes
|
|
272515
|
+
};
|
|
271588
272516
|
this.log.info("llm request", requestFields);
|
|
271589
272517
|
if (fields?.turnStep !== void 0 && /^\d+\.\d+$/.test(fields.turnStep)) {
|
|
271590
272518
|
const historyTextOrigins = summarizeRequestTextOrigins(messages);
|
|
@@ -271610,10 +272538,51 @@ var LlmRequestLogger = class {
|
|
|
271610
272538
|
getLastTurnRequest() {
|
|
271611
272539
|
return this.lastTurnRequest === void 0 ? void 0 : structuredClone(this.lastTurnRequest);
|
|
271612
272540
|
}
|
|
272541
|
+
get serializedPrefixDiagnosticEnabled() {
|
|
272542
|
+
return this.serializedPrefixKey !== void 0;
|
|
272543
|
+
}
|
|
272544
|
+
observeSerializedRequest(body, fields, sequence) {
|
|
272545
|
+
const key = this.serializedPrefixKey;
|
|
272546
|
+
if (key === void 0 || !/^\d+\.\d+$/.test(fields?.turnStep ?? "")) return;
|
|
272547
|
+
const signature = this.requestSignatures.get(sequence);
|
|
272548
|
+
if (signature === void 0) return;
|
|
272549
|
+
try {
|
|
272550
|
+
const bytes = Buffer.from(body, "utf8");
|
|
272551
|
+
const granularityBytes = 1024;
|
|
272552
|
+
const chunks = [];
|
|
272553
|
+
for (let start = 0; start + granularityBytes <= bytes.length; start += granularityBytes) chunks.push(createHmac("sha256", key).update(bytes.subarray(start, start + granularityBytes)).digest("hex"));
|
|
272554
|
+
const previous = this.lastSerializedRequest;
|
|
272555
|
+
if (previous !== void 0 && previous.signature === signature) {
|
|
272556
|
+
let common = 0;
|
|
272557
|
+
while (common < previous.chunks.length && common < chunks.length && previous.chunks[common] === chunks[common]) common++;
|
|
272558
|
+
this.prefixComparisons.set(sequence, {
|
|
272559
|
+
version: 1,
|
|
272560
|
+
granularityBytes,
|
|
272561
|
+
previousBytes: previous.bytes,
|
|
272562
|
+
currentBytes: bytes.length,
|
|
272563
|
+
commonPrefixBytesLowerBound: common * granularityBytes,
|
|
272564
|
+
previousSequence: previous.sequence,
|
|
272565
|
+
currentSequence: sequence
|
|
272566
|
+
});
|
|
272567
|
+
if (this.prefixComparisons.size > 32) this.prefixComparisons.delete(this.prefixComparisons.keys().next().value);
|
|
272568
|
+
}
|
|
272569
|
+
this.lastSerializedRequest = {
|
|
272570
|
+
sequence,
|
|
272571
|
+
signature,
|
|
272572
|
+
bytes: bytes.length,
|
|
272573
|
+
chunks
|
|
272574
|
+
};
|
|
272575
|
+
} catch {
|
|
272576
|
+
this.lastSerializedRequest = void 0;
|
|
272577
|
+
}
|
|
272578
|
+
}
|
|
271613
272579
|
logTransportAttempt(stats, fields, sequence) {
|
|
272580
|
+
const serializedPrefix = sequence === void 0 ? void 0 : this.prefixComparisons.get(sequence);
|
|
271614
272581
|
this.log.info("llm transport attempt", {
|
|
271615
272582
|
...fields,
|
|
271616
|
-
...stats
|
|
272583
|
+
...stats,
|
|
272584
|
+
...this.serializedPrefixKey === void 0 || sequence === void 0 ? {} : { requestSequence: sequence },
|
|
272585
|
+
...serializedPrefix === void 0 ? {} : { serializedPrefix }
|
|
271617
272586
|
});
|
|
271618
272587
|
if (sequence === void 0 || this.lastTurnRequest?.sequence !== sequence) return;
|
|
271619
272588
|
const breakdown = stats.requestBreakdown;
|
|
@@ -271635,6 +272604,11 @@ var LlmRequestLogger = class {
|
|
|
271635
272604
|
systemMessageBytes: breakdown.systemMessageBytes,
|
|
271636
272605
|
conversationMessageBytes: breakdown.conversationMessageBytes,
|
|
271637
272606
|
toolResultMessageBytes: breakdown.toolResultMessageBytes,
|
|
272607
|
+
...breakdown.toolResultByTool === void 0 ? {} : { toolResultByTool: breakdown.toolResultByTool.map((tool) => ({
|
|
272608
|
+
count: tool.count,
|
|
272609
|
+
bytes: tool.bytes,
|
|
272610
|
+
...tool.name === void 0 ? {} : { name: tool.name }
|
|
272611
|
+
})) },
|
|
271638
272612
|
toolSchemaBytes: breakdown.toolSchemaBytes,
|
|
271639
272613
|
otherBytes: breakdown.otherBytes,
|
|
271640
272614
|
...breakdown.toolArrayOverheadBytes === void 0 ? {} : { toolArrayOverheadBytes: breakdown.toolArrayOverheadBytes },
|
|
@@ -271696,7 +272670,8 @@ function copyContributions(value) {
|
|
|
271696
272670
|
version: source.version,
|
|
271697
272671
|
totalBytes: source.totalBytes,
|
|
271698
272672
|
generatedBytes: source.generatedBytes,
|
|
271699
|
-
files: source.files.map((file) => copyInstructionFileBytes(file))
|
|
272673
|
+
files: source.files.map((file) => copyInstructionFileBytes(file)),
|
|
272674
|
+
...source.notLoadedCandidates === void 0 ? {} : { notLoadedCandidates: [...source.notLoadedCandidates] }
|
|
271700
272675
|
} }
|
|
271701
272676
|
};
|
|
271702
272677
|
}
|
|
@@ -271792,7 +272767,11 @@ var Agent$1 = class {
|
|
|
271792
272767
|
errorMemory;
|
|
271793
272768
|
replayBuilder;
|
|
271794
272769
|
additionalDirs;
|
|
272770
|
+
systemPromptStartedAt = /* @__PURE__ */ new Date();
|
|
271795
272771
|
activeProfile;
|
|
272772
|
+
rawSystemPromptContext;
|
|
272773
|
+
profileSystemPromptText;
|
|
272774
|
+
agentsMdRequestWarningShown = false;
|
|
271796
272775
|
brandHome;
|
|
271797
272776
|
_activeResponderModel;
|
|
271798
272777
|
allowModelFallback = true;
|
|
@@ -271879,6 +272858,7 @@ var Agent$1 = class {
|
|
|
271879
272858
|
const retryScope = providerRetryScope(modelAlias, provider);
|
|
271880
272859
|
await this.providerRetryWait.wait(retryScope, generateOptions?.signal);
|
|
271881
272860
|
const callerTransportAttempt = generateOptions?.onTransportAttempt;
|
|
272861
|
+
const callerSerializedRequest = generateOptions?.onSerializedRequest;
|
|
271882
272862
|
const ownedGenerateOptions = {
|
|
271883
272863
|
...generateOptions,
|
|
271884
272864
|
transportMaxRetries: 0
|
|
@@ -271901,6 +272881,12 @@ var Agent$1 = class {
|
|
|
271901
272881
|
callerTransportAttempt?.(stats);
|
|
271902
272882
|
this.llmRequestLogger.logTransportAttempt(stats, requestLogFields, requestSequence);
|
|
271903
272883
|
},
|
|
272884
|
+
...callerSerializedRequest !== void 0 || this.llmRequestLogger.serializedPrefixDiagnosticEnabled ? { onSerializedRequest: (body) => {
|
|
272885
|
+
try {
|
|
272886
|
+
callerSerializedRequest?.(body);
|
|
272887
|
+
} catch {}
|
|
272888
|
+
this.llmRequestLogger.observeSerializedRequest(body, requestLogFields, requestSequence);
|
|
272889
|
+
} } : {},
|
|
271904
272890
|
onRequestStart: () => {
|
|
271905
272891
|
requestOptions?.onRequestStart?.();
|
|
271906
272892
|
requestStarted = true;
|
|
@@ -271926,7 +272912,7 @@ var Agent$1 = class {
|
|
|
271926
272912
|
get llm() {
|
|
271927
272913
|
return this.llmForTurn();
|
|
271928
272914
|
}
|
|
271929
|
-
llmForTurn(thinkingEffort) {
|
|
272915
|
+
llmForTurn(thinkingEffort, diagnosticTurnId) {
|
|
271930
272916
|
const selectedAlias = this.config.model;
|
|
271931
272917
|
const modelProvider = this.modelProvider;
|
|
271932
272918
|
if (modelProvider === void 0) throw new BlunError(ErrorCodes.MODEL_NOT_CONFIGURED, "Provider not set");
|
|
@@ -271940,7 +272926,18 @@ var Agent$1 = class {
|
|
|
271940
272926
|
tools: requestTools,
|
|
271941
272927
|
messages: await rebuildMessages()
|
|
271942
272928
|
};
|
|
272929
|
+
if (this.activeProfile !== void 0 && this.rawSystemPromptContext !== void 0 && this.config.systemPrompt === this.profileSystemPromptText) this.updateSystemPromptFromProfile(this.activeProfile, this.fitProfileInstructions(this.activeProfile, this.rawSystemPromptContext, requestTools, true));
|
|
271943
272930
|
let systemPrompt = this.effectiveSystemPrompt;
|
|
272931
|
+
if (this.config.runtimeModel(_candidate.alias).provider.name === "blun") {
|
|
272932
|
+
const fixedTools = requestTools.filter((tool) => tool.name !== "CompactConversation");
|
|
272933
|
+
const fixedRequestBytes = estimateBlunSerializedBodyBytes(systemPrompt, fixedTools, []) + 4096;
|
|
272934
|
+
if (fixedRequestBytes >= 5e5) throw new BlunError(ErrorCodes.CONTEXT_OVERFLOW, "Fixed instructions or tools exceed the BLUN request limit; compaction cannot reduce them.", { details: {
|
|
272935
|
+
contextBrakeBlocked: true,
|
|
272936
|
+
estimatedRequestBytes: fixedRequestBytes,
|
|
272937
|
+
requestBudgetBytes: 5e5
|
|
272938
|
+
} });
|
|
272939
|
+
}
|
|
272940
|
+
const preflightStartedAt = performance.now();
|
|
271944
272941
|
const compacted = await this.fullCompaction.beforeStep(params.signal, {
|
|
271945
272942
|
messages: params.messages,
|
|
271946
272943
|
additionalMessages: steers.messages,
|
|
@@ -271949,21 +272946,42 @@ var Agent$1 = class {
|
|
|
271949
272946
|
rebuildSystemPrompt: () => systemPrompt = this.effectiveSystemPrompt,
|
|
271950
272947
|
tools: params.tools
|
|
271951
272948
|
});
|
|
272949
|
+
if (this.type === "main" && diagnosticTurnId !== void 0 && process.env["BLUN_DIAG_PRE_REQUEST_PHASES"] === "1") try {
|
|
272950
|
+
this.log.info("turn pre-request phase", {
|
|
272951
|
+
turnId: diagnosticTurnId,
|
|
272952
|
+
phase: "compaction-preflight",
|
|
272953
|
+
durationMs: Math.max(0, Math.round(performance.now() - preflightStartedAt))
|
|
272954
|
+
});
|
|
272955
|
+
} catch {}
|
|
271952
272956
|
const tools = params.tools.some((tool) => tool.name === "CompactConversation") && !this.fullCompaction.proactiveCompactionStatus({
|
|
271953
272957
|
messages: compacted ? await rebuildMessages() : params.messages,
|
|
271954
272958
|
additionalMessages: steers.messages,
|
|
271955
272959
|
systemPrompt,
|
|
271956
272960
|
tools: params.tools
|
|
271957
272961
|
}).eligible ? params.tools.filter((tool) => tool.name !== "CompactConversation") : params.tools;
|
|
271958
|
-
this.turn.commitPendingSteers(steers);
|
|
271959
|
-
|
|
272962
|
+
const steersCommitted = this.turn.commitPendingSteers(steers);
|
|
272963
|
+
if (compacted || steersCommitted) params = {
|
|
271960
272964
|
...params,
|
|
271961
|
-
|
|
271962
|
-
|
|
272965
|
+
messages: await rebuildMessages()
|
|
272966
|
+
};
|
|
272967
|
+
if (this.config.runtimeModel(_candidate.alias).provider.name === "blun") {
|
|
272968
|
+
const requestBytes = estimateBlunSerializedBodyBytes(systemPrompt, tools, params.messages) + 4096;
|
|
272969
|
+
if (requestBytes >= 5e5) throw new BlunError(ErrorCodes.CONTEXT_OVERFLOW, "The BLUN request is too large after compaction. Shorten fixed instructions or tools.", { details: {
|
|
272970
|
+
estimatedRequestBytes: requestBytes,
|
|
272971
|
+
requestBudgetBytes: 5e5
|
|
272972
|
+
} });
|
|
272973
|
+
}
|
|
272974
|
+
return {
|
|
272975
|
+
params: {
|
|
272976
|
+
...params,
|
|
272977
|
+
systemPrompt,
|
|
272978
|
+
tools
|
|
272979
|
+
},
|
|
272980
|
+
messagesReady: true
|
|
271963
272981
|
};
|
|
271964
272982
|
}, (candidate, _params, error) => {
|
|
271965
272983
|
this.fullCompaction.observeContextOverflow(error, candidate.alias);
|
|
271966
|
-
});
|
|
272984
|
+
}, "boundary");
|
|
271967
272985
|
}
|
|
271968
272986
|
createKosongLLM(modelAlias, thinkingEffort) {
|
|
271969
272987
|
const runtimeModel = this.config.runtimeModel(modelAlias);
|
|
@@ -272031,8 +273049,14 @@ var Agent$1 = class {
|
|
|
272031
273049
|
}
|
|
272032
273050
|
useProfile(profile, context, brandHome) {
|
|
272033
273051
|
this.setActiveProfile(profile, brandHome);
|
|
272034
|
-
this.
|
|
273052
|
+
this.rawSystemPromptContext = context;
|
|
273053
|
+
if (context?.agentsMdText === void 0) {
|
|
273054
|
+
this.updateSystemPromptFromProfile(profile, context);
|
|
273055
|
+
this.tools.setActiveTools(profile.tools);
|
|
273056
|
+
return;
|
|
273057
|
+
}
|
|
272035
273058
|
this.tools.setActiveTools(profile.tools);
|
|
273059
|
+
this.updateSystemPromptFromProfile(profile, this.fitProfileInstructions(profile, context));
|
|
272036
273060
|
}
|
|
272037
273061
|
setActiveProfile(profile, brandHome) {
|
|
272038
273062
|
this.activeProfile = profile;
|
|
@@ -272047,12 +273071,74 @@ var Agent$1 = class {
|
|
|
272047
273071
|
async refreshSystemPrompt() {
|
|
272048
273072
|
if (this.activeProfile === void 0) return;
|
|
272049
273073
|
const context = this.systemPromptContextProvider === void 0 ? await prepareSystemPromptContext(this.kaos, this.brandHome, { additionalDirs: this.additionalDirs }) : await this.systemPromptContextProvider();
|
|
272050
|
-
this.
|
|
273074
|
+
this.rawSystemPromptContext = context;
|
|
273075
|
+
this.updateSystemPromptFromProfile(this.activeProfile, this.fitProfileInstructions(this.activeProfile, context));
|
|
273076
|
+
}
|
|
273077
|
+
fitProfileInstructions(profile, context, tools = this.tools.loopTools, notify = false) {
|
|
273078
|
+
if (context?.agentsMdText === void 0 || this.config.modelAlias === void 0) return context;
|
|
273079
|
+
if (this.config.runtimeModel(this.config.modelAlias).provider.name !== "blun") return context;
|
|
273080
|
+
const renderFixedPrompt = (candidate) => {
|
|
273081
|
+
const rendered = profile.systemPrompt({
|
|
273082
|
+
osEnv: this.kaos.osEnv,
|
|
273083
|
+
now: this.systemPromptStartedAt,
|
|
273084
|
+
cwd: this.config.cwd,
|
|
273085
|
+
skills: this.skills?.registry,
|
|
273086
|
+
cwdListing: candidate.cwdListing,
|
|
273087
|
+
agentsMd: candidate.agentsMd,
|
|
273088
|
+
additionalDirsInfo: candidate.additionalDirsInfo
|
|
273089
|
+
});
|
|
273090
|
+
const compact = this.skills?.registry === void 0 ? rendered : compactLegacyModelSkillListing(rendered, this.skills.registry);
|
|
273091
|
+
return this.runtimeSystemPromptAppend.length === 0 ? compact : compact.length === 0 ? this.runtimeSystemPromptAppend : `${compact}\n\n${this.runtimeSystemPromptAppend}`;
|
|
273092
|
+
};
|
|
273093
|
+
const fitted = fitAgentsMdContext(context, 4e5, (candidate) => {
|
|
273094
|
+
return estimateBlunSerializedBodyBytes(renderFixedPrompt(candidate), tools, []) + 4096;
|
|
273095
|
+
});
|
|
273096
|
+
const describeFixedEstimate = () => {
|
|
273097
|
+
const systemPrompt = renderFixedPrompt(fitted.context);
|
|
273098
|
+
const envelopeBytes = estimateBlunSerializedBodyBytes("", [], []);
|
|
273099
|
+
const withoutToolsBytes = estimateBlunSerializedBodyBytes(systemPrompt, [], []);
|
|
273100
|
+
return {
|
|
273101
|
+
estimationStage: notify ? "request" : "profile",
|
|
273102
|
+
toolCount: tools.length,
|
|
273103
|
+
serializedPromptBytes: withoutToolsBytes - envelopeBytes,
|
|
273104
|
+
serializedToolsBytes: fitted.fixedRequestBytes - 4096 - withoutToolsBytes,
|
|
273105
|
+
envelopeBytes,
|
|
273106
|
+
reserveBytes: 4096,
|
|
273107
|
+
instructionBytes: fitted.context.agentsMdSources?.totalBytes ?? 0,
|
|
273108
|
+
runtimeAppendBytes: Buffer.byteLength(this.runtimeSystemPromptAppend, "utf8")
|
|
273109
|
+
};
|
|
273110
|
+
};
|
|
273111
|
+
if (!fitted.fits) this.log.warn("fixed BLUN request exceeds 400000 bytes without AGENTS.md", {
|
|
273112
|
+
fixedRequestBytes: fitted.fixedRequestBytes,
|
|
273113
|
+
...describeFixedEstimate()
|
|
273114
|
+
});
|
|
273115
|
+
else if (fitted.omittedBytes > 0) {
|
|
273116
|
+
this.log.warn("AGENTS.md content shortened for BLUN request budget", {
|
|
273117
|
+
omittedBytes: fitted.omittedBytes,
|
|
273118
|
+
fixedRequestBytes: fitted.fixedRequestBytes,
|
|
273119
|
+
...describeFixedEstimate()
|
|
273120
|
+
});
|
|
273121
|
+
if (notify && !this.agentsMdRequestWarningShown) {
|
|
273122
|
+
this.agentsMdRequestWarningShown = true;
|
|
273123
|
+
const retained = new Map(fitted.context.agentsMdSources?.files.map((file) => [file.path, file.bytes]));
|
|
273124
|
+
const files = context.agentsMdSources?.files.flatMap((file) => {
|
|
273125
|
+
const read = retained.get(file.path) ?? 0;
|
|
273126
|
+
return read < file.bytes ? [`${file.path}: ${file.bytes} bytes, ${read} read, ${file.bytes - read} omitted`] : [];
|
|
273127
|
+
}) ?? [];
|
|
273128
|
+
this.emitEvent({
|
|
273129
|
+
type: "warning",
|
|
273130
|
+
code: "agents-md-request-truncated",
|
|
273131
|
+
message: `Instructions shortened for the request size limit: ${files.join("; ")}.`
|
|
273132
|
+
});
|
|
273133
|
+
}
|
|
273134
|
+
}
|
|
273135
|
+
return fitted.context;
|
|
272051
273136
|
}
|
|
272052
273137
|
updateSystemPromptFromProfile(profile, context) {
|
|
272053
273138
|
let contributions;
|
|
272054
273139
|
const systemPrompt = profile.systemPrompt({
|
|
272055
273140
|
osEnv: this.kaos.osEnv,
|
|
273141
|
+
now: this.systemPromptStartedAt,
|
|
272056
273142
|
cwd: this.config.cwd,
|
|
272057
273143
|
skills: this.skills?.registry,
|
|
272058
273144
|
cwdListing: context?.cwdListing,
|
|
@@ -272067,6 +273153,7 @@ var Agent$1 = class {
|
|
|
272067
273153
|
profileName: profile.name,
|
|
272068
273154
|
systemPrompt
|
|
272069
273155
|
});
|
|
273156
|
+
this.profileSystemPromptText = systemPrompt;
|
|
272070
273157
|
this.renderedPromptContributions = contributions === void 0 ? void 0 : {
|
|
272071
273158
|
text: systemPrompt,
|
|
272072
273159
|
value: structuredClone(contributions)
|
|
@@ -272243,6 +273330,9 @@ var Agent$1 = class {
|
|
|
272243
273330
|
},
|
|
272244
273331
|
startBtw: () => this.subagentHost.startBtw(),
|
|
272245
273332
|
createGoal: (payload) => this.goal.createGoal(payload),
|
|
273333
|
+
editGoal: (payload) => this.goal.editGoal(payload),
|
|
273334
|
+
blockGoal: (payload) => this.goal.blockGoal(payload),
|
|
273335
|
+
completeGoal: () => this.goal.completeGoal(),
|
|
272246
273336
|
getGoal: () => this.goal.getGoal(),
|
|
272247
273337
|
pauseGoal: () => this.goal.pauseGoal(),
|
|
272248
273338
|
resumeGoal: () => this.goal.resumeGoal(),
|
|
@@ -336497,6 +337587,15 @@ var SessionAPIImpl = class {
|
|
|
336497
337587
|
async createGoal({ agentId, ...payload }) {
|
|
336498
337588
|
return (await this.getAgent(agentId)).createGoal(payload);
|
|
336499
337589
|
}
|
|
337590
|
+
async editGoal({ agentId, ...payload }) {
|
|
337591
|
+
return (await this.getAgent(agentId)).editGoal(payload);
|
|
337592
|
+
}
|
|
337593
|
+
async blockGoal({ agentId, ...payload }) {
|
|
337594
|
+
return (await this.getAgent(agentId)).blockGoal(payload);
|
|
337595
|
+
}
|
|
337596
|
+
async completeGoal({ agentId }) {
|
|
337597
|
+
return (await this.getAgent(agentId)).completeGoal({});
|
|
337598
|
+
}
|
|
336500
337599
|
async getGoal({ agentId, ...payload }) {
|
|
336501
337600
|
return (await this.getAgent(agentId, true)).getGoal(payload);
|
|
336502
337601
|
}
|
|
@@ -337741,6 +338840,15 @@ var BlunCore = class {
|
|
|
337741
338840
|
getGoal({ sessionId, ...payload }) {
|
|
337742
338841
|
return Promise.resolve(this.sessionApi(sessionId).getGoal(payload));
|
|
337743
338842
|
}
|
|
338843
|
+
editGoal({ sessionId, ...payload }) {
|
|
338844
|
+
return Promise.resolve(this.sessionApi(sessionId).editGoal(payload));
|
|
338845
|
+
}
|
|
338846
|
+
blockGoal({ sessionId, ...payload }) {
|
|
338847
|
+
return Promise.resolve(this.sessionApi(sessionId).blockGoal(payload));
|
|
338848
|
+
}
|
|
338849
|
+
completeGoal({ sessionId, ...payload }) {
|
|
338850
|
+
return Promise.resolve(this.sessionApi(sessionId).completeGoal(payload));
|
|
338851
|
+
}
|
|
337744
338852
|
pauseGoal({ sessionId, ...payload }) {
|
|
337745
338853
|
return Promise.resolve(this.sessionApi(sessionId).pauseGoal(payload));
|
|
337746
338854
|
}
|
|
@@ -344942,7 +346050,10 @@ function reduceWireRecords(records) {
|
|
|
344942
346050
|
text: record.summary
|
|
344943
346051
|
}],
|
|
344944
346052
|
toolCalls: [],
|
|
344945
|
-
origin: {
|
|
346053
|
+
origin: {
|
|
346054
|
+
kind: "compaction_summary",
|
|
346055
|
+
...record.toolContinuity === void 0 ? {} : { toolContinuity: record.toolContinuity }
|
|
346056
|
+
}
|
|
344946
346057
|
},
|
|
344947
346058
|
time: record.time
|
|
344948
346059
|
};
|
|
@@ -347193,6 +348304,24 @@ var Session = class {
|
|
|
347193
348304
|
this.ensureOpen();
|
|
347194
348305
|
return this.rpc.getGoal({ sessionId: this.id });
|
|
347195
348306
|
}
|
|
348307
|
+
async editGoal(input) {
|
|
348308
|
+
this.ensureOpen();
|
|
348309
|
+
return this.rpc.editGoal({
|
|
348310
|
+
sessionId: this.id,
|
|
348311
|
+
objective: input.objective
|
|
348312
|
+
});
|
|
348313
|
+
}
|
|
348314
|
+
async blockGoal(input = {}) {
|
|
348315
|
+
this.ensureOpen();
|
|
348316
|
+
return this.rpc.blockGoal({
|
|
348317
|
+
sessionId: this.id,
|
|
348318
|
+
reason: input.reason
|
|
348319
|
+
});
|
|
348320
|
+
}
|
|
348321
|
+
async completeGoal() {
|
|
348322
|
+
this.ensureOpen();
|
|
348323
|
+
return this.rpc.completeGoal({ sessionId: this.id });
|
|
348324
|
+
}
|
|
347196
348325
|
async pauseGoal() {
|
|
347197
348326
|
this.ensureOpen();
|
|
347198
348327
|
return this.rpc.pauseGoal({ sessionId: this.id });
|
|
@@ -347752,6 +348881,39 @@ var BlunAuthFacade = class {
|
|
|
347752
348881
|
}
|
|
347753
348882
|
return this.toolkit.status(providerName, this.resolveRuntimeManagedAuth(providerName).oauthRef);
|
|
347754
348883
|
}
|
|
348884
|
+
async getCachedMemoryWorkspaceId() {
|
|
348885
|
+
const apiKey = nonEmpty(this.resolveManagedAuth(BLUN_PROVIDER_NAME$1).apiKey);
|
|
348886
|
+
if (apiKey !== void 0) {
|
|
348887
|
+
const provider = readConfigFileForUpdate(this.options.configPath).providers[BLUN_PROVIDER_NAME$1];
|
|
348888
|
+
if (provider?.apiKey !== apiKey || provider.memoryApiKeyHash !== memoryApiKeyHash(apiKey)) return;
|
|
348889
|
+
return provider.memoryWorkspaceId;
|
|
348890
|
+
}
|
|
348891
|
+
return this.toolkit.getCachedMemoryWorkspaceId(this.resolveRuntimeManagedAuth(BLUN_PROVIDER_NAME$1).oauthRef);
|
|
348892
|
+
}
|
|
348893
|
+
async cacheMemoryWorkspaceId(workspaceId) {
|
|
348894
|
+
const apiKey = nonEmpty(this.resolveManagedAuth(BLUN_PROVIDER_NAME$1).apiKey);
|
|
348895
|
+
if (apiKey !== void 0) {
|
|
348896
|
+
const hash = memoryApiKeyHash(apiKey);
|
|
348897
|
+
return mutateConfigFile(this.options.configPath, (config) => {
|
|
348898
|
+
const provider = config.providers[BLUN_PROVIDER_NAME$1];
|
|
348899
|
+
if (provider?.apiKey !== apiKey) return {
|
|
348900
|
+
config,
|
|
348901
|
+
result: false
|
|
348902
|
+
};
|
|
348903
|
+
if (provider.memoryApiKeyHash === hash && provider.memoryWorkspaceId !== void 0 && provider.memoryWorkspaceId !== workspaceId) return {
|
|
348904
|
+
config,
|
|
348905
|
+
result: false
|
|
348906
|
+
};
|
|
348907
|
+
provider.memoryApiKeyHash = hash;
|
|
348908
|
+
provider.memoryWorkspaceId = workspaceId;
|
|
348909
|
+
return {
|
|
348910
|
+
config,
|
|
348911
|
+
result: true
|
|
348912
|
+
};
|
|
348913
|
+
});
|
|
348914
|
+
}
|
|
348915
|
+
return this.toolkit.cacheMemoryWorkspaceId(workspaceId, this.resolveRuntimeManagedAuth(BLUN_PROVIDER_NAME$1).oauthRef);
|
|
348916
|
+
}
|
|
347755
348917
|
async login(providerName = BLUN_PROVIDER_NAME$1, options = {}) {
|
|
347756
348918
|
const auth = this.resolveManagedAuth(providerName);
|
|
347757
348919
|
const loginAuth = resolveBlunCodeLoginAuth({
|
|
@@ -348057,6 +349219,9 @@ function nonEmpty(value) {
|
|
|
348057
349219
|
const normalized = value?.trim();
|
|
348058
349220
|
return normalized === void 0 || normalized.length === 0 ? void 0 : normalized;
|
|
348059
349221
|
}
|
|
349222
|
+
function memoryApiKeyHash(apiKey) {
|
|
349223
|
+
return createHash("sha256").update(apiKey).digest("hex");
|
|
349224
|
+
}
|
|
348060
349225
|
function transitionAggregateError(message, primary, secondary) {
|
|
348061
349226
|
return new AggregateError([primary, secondary], message, { cause: primary });
|
|
348062
349227
|
}
|
|
@@ -348537,6 +349702,26 @@ var SDKRpcClientBase = class {
|
|
|
348537
349702
|
replace: input.replace
|
|
348538
349703
|
});
|
|
348539
349704
|
}
|
|
349705
|
+
async editGoal(input) {
|
|
349706
|
+
return (await this.getRpc()).editGoal({
|
|
349707
|
+
sessionId: input.sessionId,
|
|
349708
|
+
agentId: this.interactiveAgentId,
|
|
349709
|
+
objective: input.objective
|
|
349710
|
+
});
|
|
349711
|
+
}
|
|
349712
|
+
async blockGoal(input) {
|
|
349713
|
+
return (await this.getRpc()).blockGoal({
|
|
349714
|
+
sessionId: input.sessionId,
|
|
349715
|
+
agentId: this.interactiveAgentId,
|
|
349716
|
+
reason: input.reason
|
|
349717
|
+
});
|
|
349718
|
+
}
|
|
349719
|
+
async completeGoal(input) {
|
|
349720
|
+
return (await this.getRpc()).completeGoal({
|
|
349721
|
+
sessionId: input.sessionId,
|
|
349722
|
+
agentId: this.interactiveAgentId
|
|
349723
|
+
});
|
|
349724
|
+
}
|
|
348540
349725
|
async getGoal(input) {
|
|
348541
349726
|
return (await this.getRpc()).getGoal({
|
|
348542
349727
|
sessionId: input.sessionId,
|
|
@@ -348785,6 +349970,7 @@ var SDKRpcClient = class extends SDKRpcClientBase {
|
|
|
348785
349970
|
core;
|
|
348786
349971
|
ready;
|
|
348787
349972
|
usesDefaultConfigPath;
|
|
349973
|
+
restoreProfileModel;
|
|
348788
349974
|
constructor(options = {}) {
|
|
348789
349975
|
super();
|
|
348790
349976
|
this.identity = options.identity === void 0 ? void 0 : assertBlunHostIdentity(options.identity);
|
|
@@ -348794,9 +349980,11 @@ var SDKRpcClient = class extends SDKRpcClientBase {
|
|
|
348794
349980
|
configPath: options.configPath
|
|
348795
349981
|
});
|
|
348796
349982
|
this.usesDefaultConfigPath = options.configPath === void 0;
|
|
349983
|
+
const authHomeDir = authHomeForProfile(this.homeDir);
|
|
349984
|
+
this.restoreProfileModel = this.usesDefaultConfigPath && authHomeDir !== this.homeDir;
|
|
348797
349985
|
this.telemetry = options.telemetry ?? noopTelemetryClient;
|
|
348798
349986
|
this.auth = new BlunAuthFacade({
|
|
348799
|
-
homeDir:
|
|
349987
|
+
homeDir: authHomeDir,
|
|
348800
349988
|
configPath: this.configPath,
|
|
348801
349989
|
identity: this.identity,
|
|
348802
349990
|
onRefresh: options.onOAuthRefresh
|
|
@@ -348816,7 +350004,7 @@ var SDKRpcClient = class extends SDKRpcClientBase {
|
|
|
348816
350004
|
}
|
|
348817
350005
|
async ensureConfigFile() {
|
|
348818
350006
|
await ensureConfigFile(this.configPath);
|
|
348819
|
-
if (this.
|
|
350007
|
+
if (this.restoreProfileModel) await this.auth.restoreMissingProfileModel();
|
|
348820
350008
|
}
|
|
348821
350009
|
async close() {
|
|
348822
350010
|
try {
|