blun-king-cli 9.1.611 → 9.1.613

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/worker-host.mjs CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- // BLUN_BUILD_INPUT_SHA256:0533ca113dc07cc119988be5e76555dec986b6881903f8e2b537f5adf96cc2c5
2
+ // BLUN_BUILD_INPUT_SHA256:5c7277a864ffcc0a6909494ad5ada6956f900fe23735200c5aca26b1e7d78834
3
3
  import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
4
4
  import { dirname as __cjsShimDirname } from 'node:path';
5
5
  const __filename = __cjsShimFileURLToPath(import.meta.url);
6
6
  const __dirname = __cjsShimDirname(__filename);
7
7
  import { createRequire } from "node:module";
8
- import crypto$1, { createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
8
+ import crypto$1, { createHash, createHmac, randomBytes, randomInt, randomUUID } from "node:crypto";
9
9
  import * as fs$12 from "node:fs";
10
10
  import Kt, { appendFileSync, chmodSync, closeSync, constants, createReadStream, createWriteStream, existsSync, fstatSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, opendirSync, promises, readFileSync, readSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
11
11
  import * as path$11 from "node:path";
@@ -1888,6 +1888,9 @@ var FetchTransport = class {
1888
1888
  const maxRetries = normalizeMaxRetries(requestOptions?.maxRetries);
1889
1889
  const requestBytes = exactBodyBytes(init.body);
1890
1890
  const requestBreakdown = pathname === "/chat/completions" && requestOptions?.onTransportAttempt !== void 0 && typeof init.body === "string" && requestBytes !== void 0 ? measureSerializedRequest(init.body, requestBytes) : void 0;
1891
+ if (pathname === "/chat/completions" && typeof init.body === "string") try {
1892
+ requestOptions?.onSerializedRequest?.(init.body);
1893
+ } catch {}
1891
1894
  let attempt = 0;
1892
1895
  while (true) {
1893
1896
  const headers = new Headers(init.headers);
@@ -1896,6 +1899,9 @@ var FetchTransport = class {
1896
1899
  const startedAt = performance.now();
1897
1900
  const startedAtMs = Date.now();
1898
1901
  try {
1902
+ try {
1903
+ requestOptions?.onRequestSent?.();
1904
+ } catch {}
1899
1905
  const response = await this.fetch(`${this.baseUrl}${pathname}`, {
1900
1906
  ...init,
1901
1907
  headers
@@ -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,13 @@ function collectBlunVisionAttachments(messages) {
2648
2687
  }
2649
2688
  return attachments;
2650
2689
  }
2690
+ function estimateBlunRequestExtraBytes(tools, messages) {
2691
+ const attachments = collectBlunVisionAttachments(messages);
2692
+ return {
2693
+ toolsBytes: tools.length === 0 ? 0 : Buffer.byteLength(JSON.stringify({ tools: tools.map(convertTool) }), "utf8"),
2694
+ visionBytes: attachments.length === 0 ? 0 : Buffer.byteLength(JSON.stringify({ visionAttachments: attachments }), "utf8")
2695
+ };
2696
+ }
2651
2697
  function convertMessage(message) {
2652
2698
  let reasoningContent = "";
2653
2699
  const nonThinkParts = [];
@@ -2957,12 +3003,13 @@ var BlunChatProvider = class {
2957
3003
  if (this._stream) createParams["stream_options"] = { include_usage: true };
2958
3004
  try {
2959
3005
  const client = this._createClient(options?.auth);
2960
- const requestOptions = options?.signal !== void 0 || options?.transportMaxRetries !== void 0 || options?.onTransportAttempt !== void 0 ? {
3006
+ const requestOptions = options?.signal !== void 0 || options?.transportMaxRetries !== void 0 || options?.onRequestSent !== void 0 || options?.onSerializedRequest !== void 0 || options?.onTransportAttempt !== void 0 ? {
2961
3007
  ...options.signal !== void 0 ? { signal: options.signal } : {},
2962
3008
  ...options.transportMaxRetries !== void 0 ? { maxRetries: options.transportMaxRetries } : {},
3009
+ ...options.onRequestSent !== void 0 ? { onRequestSent: options.onRequestSent } : {},
3010
+ ...options.onSerializedRequest !== void 0 ? { onSerializedRequest: options.onSerializedRequest } : {},
2963
3011
  ...options.onTransportAttempt !== void 0 ? { onTransportAttempt: options.onTransportAttempt } : {}
2964
3012
  } : void 0;
2965
- options?.onRequestSent?.();
2966
3013
  let response;
2967
3014
  try {
2968
3015
  response = await client.chat.completions.create(createParams, requestOptions);
@@ -2971,7 +3018,6 @@ var BlunChatProvider = class {
2971
3018
  const cap = rejection instanceof APIContextOverflowError ? contextOverflowOutputCap(rejection, createParams["max_completion_tokens"]) : void 0;
2972
3019
  if (cap === void 0) throw rejection;
2973
3020
  options?.signal?.throwIfAborted();
2974
- options?.onRequestSent?.();
2975
3021
  response = await client.chat.completions.create({
2976
3022
  ...createParams,
2977
3023
  max_completion_tokens: cap
@@ -3358,9 +3404,11 @@ function emptyUsage() {
3358
3404
  * Sum two TokenUsage values.
3359
3405
  */
3360
3406
  function addUsage(a, b) {
3407
+ 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
3408
  return {
3362
3409
  inputOther: a.inputOther + b.inputOther,
3363
3410
  output: a.output + b.output,
3411
+ ...outputReasoning === void 0 ? {} : { outputReasoning },
3364
3412
  inputCacheRead: a.inputCacheRead + b.inputCacheRead,
3365
3413
  inputCacheCreation: a.inputCacheCreation + b.inputCacheCreation
3366
3414
  };
@@ -9770,6 +9818,8 @@ const StringRecordSchema = record$2(string(), string());
9770
9818
  const ProviderConfigSchema = object({
9771
9819
  type: ProviderTypeSchema,
9772
9820
  apiKey: string().optional(),
9821
+ memoryWorkspaceId: string().regex(/^blun-[0-9a-f]{64}$/u).optional(),
9822
+ memoryApiKeyHash: string().regex(/^[0-9a-f]{64}$/u).optional(),
9773
9823
  baseUrl: string().optional(),
9774
9824
  defaultModel: string().optional(),
9775
9825
  oauth: OAuthRefSchema.optional(),
@@ -10318,7 +10368,8 @@ function tokenToWire(token) {
10318
10368
  expires_at: token.expiresAt,
10319
10369
  scope: token.scope,
10320
10370
  token_type: token.tokenType,
10321
- expires_in: token.expiresIn
10371
+ expires_in: token.expiresIn,
10372
+ ...token.memoryWorkspaceId === void 0 ? {} : { memory_workspace_id: token.memoryWorkspaceId }
10322
10373
  };
10323
10374
  }
10324
10375
  function tokenFromWire(wire) {
@@ -10328,7 +10379,8 @@ function tokenFromWire(wire) {
10328
10379
  expiresAt: typeof wire.expires_at === "number" ? wire.expires_at : 0,
10329
10380
  scope: wire.scope ?? "",
10330
10381
  tokenType: wire.token_type ?? "",
10331
- expiresIn: typeof wire.expires_in === "number" ? wire.expires_in : 0
10382
+ expiresIn: typeof wire.expires_in === "number" ? wire.expires_in : 0,
10383
+ ...typeof wire.memory_workspace_id === "string" && wire.memory_workspace_id.length > 0 ? { memoryWorkspaceId: wire.memory_workspace_id } : {}
10332
10384
  };
10333
10385
  }
10334
10386
  //#endregion
@@ -12719,6 +12771,27 @@ var OAuthManager = class {
12719
12771
  const state = await this.loadState();
12720
12772
  return state.kind === "valid" ? state.token.accessToken : void 0;
12721
12773
  }
12774
+ async getCachedMemoryWorkspaceId() {
12775
+ const state = await this.loadState();
12776
+ return state.kind === "valid" && state.token.expiresAt > this.now() ? state.token.memoryWorkspaceId : void 0;
12777
+ }
12778
+ async cacheMemoryWorkspaceId(workspaceId) {
12779
+ if (workspaceId.length === 0) return false;
12780
+ const release = await this.acquireRefreshLock();
12781
+ try {
12782
+ const state = await this.loadState();
12783
+ if (state.kind !== "valid" || state.token.expiresAt <= this.now()) return false;
12784
+ if (state.token.memoryWorkspaceId === workspaceId) return true;
12785
+ if (state.token.memoryWorkspaceId !== void 0) return false;
12786
+ await this.storage.save(this.config.name, {
12787
+ ...state.token,
12788
+ memoryWorkspaceId: workspaceId
12789
+ });
12790
+ return true;
12791
+ } finally {
12792
+ await release();
12793
+ }
12794
+ }
12722
12795
  async logout() {
12723
12796
  await this.inFlightRefresh?.promise.catch(() => void 0);
12724
12797
  const release = await this.acquireRefreshLock();
@@ -12786,7 +12859,10 @@ var OAuthManager = class {
12786
12859
  if (activeToken.refreshToken.length === 0) throw new OAuthUnauthorizedError(`Token for "${this.config.name}" has no refresh_token; re-login required.`);
12787
12860
  try {
12788
12861
  const refreshed = await this.refreshImpl(this.config, activeToken.refreshToken);
12789
- await this.storage.save(this.config.name, refreshed);
12862
+ await this.storage.save(this.config.name, {
12863
+ ...refreshed,
12864
+ memoryWorkspaceId: activeToken.memoryWorkspaceId
12865
+ });
12790
12866
  this.notifyRefresh({ success: true });
12791
12867
  return refreshed.accessToken;
12792
12868
  } catch (error) {
@@ -14163,6 +14239,16 @@ var BlunOAuthToolkit = class {
14163
14239
  hasToken: await this.managerFor(name, oauthKey, oauthHost).hasToken()
14164
14240
  }] };
14165
14241
  }
14242
+ async getCachedMemoryWorkspaceId(oauthRef) {
14243
+ const oauthHost = this.oauthHostFor(oauthRef);
14244
+ const oauthKey = oauthRef?.key ?? this.defaultOAuthKey(void 0, oauthHost);
14245
+ return this.managerFor(BLUN_PROVIDER_NAME$1, oauthKey, oauthHost).getCachedMemoryWorkspaceId();
14246
+ }
14247
+ async cacheMemoryWorkspaceId(workspaceId, oauthRef) {
14248
+ const oauthHost = this.oauthHostFor(oauthRef);
14249
+ const oauthKey = oauthRef?.key ?? this.defaultOAuthKey(void 0, oauthHost);
14250
+ return this.managerFor(BLUN_PROVIDER_NAME$1, oauthKey, oauthHost).cacheMemoryWorkspaceId(workspaceId);
14251
+ }
14166
14252
  async login(providerName, options = {}) {
14167
14253
  const name = providerName ?? "managed:blun";
14168
14254
  const oauthHost = this.oauthHostFor(options.oauthRef, options.oauthHost);
@@ -16230,6 +16316,8 @@ function providerToToml(provider, rawProvider) {
16230
16316
  for (const key of [
16231
16317
  "type",
16232
16318
  "apiKey",
16319
+ "memoryWorkspaceId",
16320
+ "memoryApiKeyHash",
16233
16321
  "baseUrl",
16234
16322
  "defaultModel",
16235
16323
  "oauth",
@@ -21757,10 +21845,15 @@ async function loadAgentsMdForRoots(kaos, brandHome, workDirs) {
21757
21845
  const discovered = [];
21758
21846
  const emptySources = /* @__PURE__ */ new Map();
21759
21847
  const seen = /* @__PURE__ */ new Set();
21848
+ const notLoadedCandidates = /* @__PURE__ */ new Set();
21760
21849
  const collect = async (path) => {
21761
21850
  const file = await readAgentFile(kaos, path);
21762
- if (file === void 0) return false;
21851
+ if (file === void 0) {
21852
+ notLoadedCandidates.add(kaos.normpath(path));
21853
+ return false;
21854
+ }
21763
21855
  const key = kaos.normpath(file.path);
21856
+ notLoadedCandidates.delete(key);
21764
21857
  if (file.content.length === 0) {
21765
21858
  emptySources.set(key, InstructionText.file(file.path, "", file.sourceTextBytes));
21766
21859
  return false;
@@ -21796,7 +21889,10 @@ async function loadAgentsMdForRoots(kaos, brandHome, workDirs) {
21796
21889
  return {
21797
21890
  content,
21798
21891
  warning: totalBytes > AGENTS_MD_RECOMMENDED_MAX_BYTES ? `AGENTS.md total ${formatKB(totalBytes)} KB exceeds the recommended ${formatKB(AGENTS_MD_RECOMMENDED_MAX_BYTES)} KB. Large instruction files increase cost and may impact performance; consider trimming.` : void 0,
21799
- sources: rendered.measure()
21892
+ sources: {
21893
+ ...rendered.measure(),
21894
+ ...notLoadedCandidates.size === 0 ? {} : { notLoadedCandidates: [...notLoadedCandidates] }
21895
+ }
21800
21896
  };
21801
21897
  }
21802
21898
  async function loadAdditionalDirsInfo(kaos, additionalDirs) {
@@ -28778,17 +28874,20 @@ function createSystemPromptRenderer(merged) {
28778
28874
  const counts = renderPromptContributions(merged.systemPromptTemplate, vars, rendered, true) ?? renderPromptContributions(merged.systemPromptTemplate, vars, rendered);
28779
28875
  const sources = context.agentsMdSources;
28780
28876
  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;
28877
+ 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;
28878
+ const notLoadedCandidates = sourceMatches && sources.notLoadedCandidates !== void 0 ? { notLoadedCandidates: [...sources.notLoadedCandidates] } : {};
28782
28879
  const instructionSources = copies === 0 ? {
28783
28880
  version: 1,
28784
28881
  totalBytes: 0,
28785
28882
  generatedBytes: 0,
28786
- files: sourceMatches ? sources.files.map((file) => copyInstructionFileBytes(file, 0)) : []
28883
+ files: sourceMatches ? sources.files.map((file) => copyInstructionFileBytes(file, 0)) : [],
28884
+ ...notLoadedCandidates
28787
28885
  } : !sourceMatches ? void 0 : {
28788
28886
  version: 1,
28789
28887
  totalBytes: sources.totalBytes * copies,
28790
28888
  generatedBytes: sources.generatedBytes * copies,
28791
- files: sources.files.map((file) => copyInstructionFileBytes(file, copies))
28889
+ files: sources.files.map((file) => copyInstructionFileBytes(file, copies)),
28890
+ ...notLoadedCandidates
28792
28891
  };
28793
28892
  const skillListingSources = counts === void 0 ? void 0 : scaleSkillListingSources(skillSources, vars["BLUN_SKILLS"] ?? "", counts.skillListingBytes);
28794
28893
  context.onContributions(counts === void 0 ? void 0 : {
@@ -230235,16 +230334,19 @@ var FullCompaction = class {
230235
230334
  const projected = context.additionalMessages === void 0 ? messages : [...messages, ...context.additionalMessages];
230236
230335
  const historyBudget = this.requestHistoryByteBudget(projected);
230237
230336
  const historyThresholdReached = historyBudget !== void 0 && historyBudget.usedHistoryBytes >= historyBudget.thresholdHistoryBytes;
230337
+ const requestBudget = this.requestBodyByteBudget(projected, context);
230338
+ const requestThresholdReached = requestBudget !== void 0 && requestBudget.usedRequestBytesEstimate >= requestBudget.thresholdRequestBytes;
230238
230339
  if (this.sessionCompactionFailures >= MAX_SESSION_COMPACTION_FAILURES) reason = "session_stopped";
230239
230340
  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";
230341
+ else if (thresholdTokens === void 0 && historyBudget === void 0 && requestBudget === void 0) reason = "no_budget";
230342
+ else if (!historyThresholdReached && !requestThresholdReached && (thresholdTokens === void 0 || !Number.isFinite(usedTokens) || usedTokens < thresholdTokens)) reason = "below_threshold";
230242
230343
  else if (!this.hasShrinkableHistory(projected)) reason = "nothing_to_compact";
230243
230344
  return {
230244
230345
  eligible: reason === "eligible",
230245
230346
  usedTokens,
230246
230347
  thresholdTokens,
230247
230348
  ...historyBudget,
230349
+ ...requestBudget,
230248
230350
  reason
230249
230351
  };
230250
230352
  }
@@ -230266,6 +230368,35 @@ var FullCompaction = class {
230266
230368
  thresholdHistoryBytes: limit
230267
230369
  };
230268
230370
  }
230371
+ requestBodyByteBudget(messages, context) {
230372
+ const limit = this.agent.blunConfig?.loopControl?.maxRequestHistoryBytes;
230373
+ if (!this.agent.config.hasProvider || this.strategy.compactionBudgetTokens === void 0 || limit !== void 0 && (!Number.isSafeInteger(limit) || limit <= 0)) return void 0;
230374
+ const model = this.agent.activeResponderModel ?? this.agent.config.modelAlias;
230375
+ if (model === void 0 || this.agent.config.runtimeModel(model).provider.name !== "blun") return void 0;
230376
+ const systemPrompt = context.systemPrompt ?? this.agent.effectiveSystemPrompt;
230377
+ const tools = (context.tools ?? this.agent.tools.loopTools).map((tool) => ({
230378
+ name: tool.name,
230379
+ description: tool.description,
230380
+ parameters: tool.parameters
230381
+ }));
230382
+ let extraBytes;
230383
+ try {
230384
+ extraBytes = estimateBlunRequestExtraBytes(tools, messages);
230385
+ } catch {
230386
+ return;
230387
+ }
230388
+ if (Buffer.byteLength(JSON.stringify({
230389
+ systemPrompt,
230390
+ messages: []
230391
+ }), "utf8") >= BLUN_COMPACTION_REQUEST_BUDGET_BYTES) return void 0;
230392
+ return {
230393
+ usedRequestBytesEstimate: Buffer.byteLength(JSON.stringify({
230394
+ systemPrompt,
230395
+ messages
230396
+ }), "utf8") + extraBytes.toolsBytes + extraBytes.visionBytes,
230397
+ thresholdRequestBytes: BLUN_COMPACTION_REQUEST_BUDGET_BYTES
230398
+ };
230399
+ }
230269
230400
  requestProactiveCompaction(context = {}) {
230270
230401
  const status = this.proactiveCompactionStatus(context);
230271
230402
  if (status.eligible && !this.proactiveCompactionRequested) {
@@ -230274,7 +230405,9 @@ var FullCompaction = class {
230274
230405
  used_tokens: status.usedTokens,
230275
230406
  threshold_tokens: status.thresholdTokens,
230276
230407
  used_history_bytes: status.usedHistoryBytes,
230277
- threshold_history_bytes: status.thresholdHistoryBytes
230408
+ threshold_history_bytes: status.thresholdHistoryBytes,
230409
+ used_request_bytes_estimate: status.usedRequestBytesEstimate,
230410
+ threshold_request_bytes: status.thresholdRequestBytes
230278
230411
  });
230279
230412
  }
230280
230413
  return status;
@@ -230403,7 +230536,9 @@ var FullCompaction = class {
230403
230536
  const requestTokens = this.estimateCurrentRequestTokens(requestContext);
230404
230537
  const budget = this.getCompactionBudgetTokens();
230405
230538
  const historyBudget = this.requestHistoryByteBudget(projectedMessages);
230406
- const proactive = (historyBudget !== void 0 && historyBudget.usedHistoryBytes >= historyBudget.thresholdHistoryBytes || !this.isCompacting && budget !== void 0 && Number.isFinite(requestTokens) && requestTokens >= Math.max(1, Math.floor(budget * .9))) && this.hasShrinkableHistory(projectedMessages);
230539
+ const historyThresholdReached = historyBudget !== void 0 && historyBudget.usedHistoryBytes >= historyBudget.thresholdHistoryBytes;
230540
+ const requestBudget = this.requestBodyByteBudget(projectedMessages, requestContext);
230541
+ 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
230542
  if (this.checkAutoCompaction(true, requestTokens, projectedMessages, proactive) && (proactive || this.strategy.shouldBlock(requestTokens))) await this.block(signal);
230408
230543
  signal.throwIfAborted();
230409
230544
  const compacted = this.agent.context.history !== historyBefore;
@@ -230613,7 +230748,10 @@ var FullCompaction = class {
230613
230748
  dropOrphanResults: true
230614
230749
  }), createUserMessage(requestInstruction)], capability));
230615
230750
  };
230616
- const estimateRequestBytes = (messages) => Buffer.byteLength(JSON.stringify(messages), "utf8") + Buffer.byteLength(this.agent.config.systemPrompt, "utf8");
230751
+ const estimateRequestBytes = (messages) => Buffer.byteLength(JSON.stringify({
230752
+ systemPrompt: this.agent.effectiveSystemPrompt,
230753
+ messages
230754
+ }), "utf8");
230617
230755
  while (true) {
230618
230756
  signal.throwIfAborted();
230619
230757
  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: {
@@ -238976,6 +239114,32 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
238976
239114
  "suchen"
238977
239115
  ]);
238978
239116
  const TOOL_SEARCH_RELATED_TERM_GROUPS = Object.freeze([
239117
+ Object.freeze([
239118
+ "persist",
239119
+ "save",
239120
+ "speichere",
239121
+ "speichern",
239122
+ "store"
239123
+ ]),
239124
+ Object.freeze([
239125
+ "erinnerung",
239126
+ "erinnerungen",
239127
+ "fact",
239128
+ "facts",
239129
+ "fakt",
239130
+ "fakten",
239131
+ "memory",
239132
+ "memories",
239133
+ "merk",
239134
+ "merken",
239135
+ "remember"
239136
+ ]),
239137
+ Object.freeze([
239138
+ "note",
239139
+ "notes",
239140
+ "notiz",
239141
+ "notizen"
239142
+ ]),
238979
239143
  Object.freeze([
238980
239144
  "checklist",
238981
239145
  "list",
@@ -239173,10 +239337,27 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
239173
239337
  function relatedSearchTerms(token) {
239174
239338
  return TOOL_SEARCH_RELATED_TERM_GROUPS.find((terms) => terms.includes(token)) || [token];
239175
239339
  }
239340
+ function withoutFencedCode(value) {
239341
+ const visibleLines = [];
239342
+ let fence = null;
239343
+ for (const line of String(value || "").split(/\r?\n/)) {
239344
+ const marker = line.match(/^ {0,3}(`{3,}|~{3,})/u)?.[1];
239345
+ if (fence) {
239346
+ if (marker?.[0] === fence[0] && marker.length >= fence.length && /^ {0,3}(?:`{3,}|~{3,})[ \t]*$/u.test(line)) fence = null;
239347
+ continue;
239348
+ }
239349
+ if (marker) {
239350
+ fence = marker;
239351
+ continue;
239352
+ }
239353
+ visibleLines.push(line);
239354
+ }
239355
+ return visibleLines.join("\n");
239356
+ }
239176
239357
  function rankingIntentTexts(value) {
239177
239358
  const text = String(value || "");
239178
239359
  const channelBodies = [...text.matchAll(/(?:^|\r?\n)<channel\b[^>]*>\r?\n([\s\S]*?)\r?\n<\/channel>(?=\r?\n|$)/giu)].map((match) => match[1]);
239179
- return (channelBodies.length > 0 ? channelBodies : [text]).map((intentText) => normalizeDeferredToolQuery(intentText.replace(TOOL_RANK_EMBEDDED_CONTENT_RE, " ")));
239360
+ return (channelBodies.length > 0 ? channelBodies : [text]).map((intentText) => normalizeDeferredToolQuery(withoutFencedCode(intentText.replace(TOOL_RANK_EMBEDDED_CONTENT_RE, " "))));
239180
239361
  }
239181
239362
  function rankingTokens(value) {
239182
239363
  return [...new Set(String(value || "").normalize("NFKC").toLowerCase().match(/[\p{L}\p{N}]{3,}/gu) || [])].filter((token) => !TOOL_RANK_STOP_WORDS.has(token));
@@ -239234,7 +239415,7 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
239234
239415
  if (document.nameTokens.has(token)) exactNameMatches += 1;
239235
239416
  else if (relatedSearchTerms(token).some((term) => document.nameTokens.has(term))) relatedNameMatches += 1;
239236
239417
  }
239237
- return matchedTokens >= 2 || exactNameMatches >= 1 && score >= 10 || relatedNameMatches >= 1 && score >= 5 ? {
239418
+ return matchedTokens >= 2 || exactNameMatches >= 1 && score >= 10 || queryTokens.length === 1 && relatedNameMatches >= 1 && score >= 5 ? {
239238
239419
  name: document.name,
239239
239420
  score,
239240
239421
  matchedTokens,
@@ -239255,11 +239436,11 @@ var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((expor
239255
239436
  function searchRelatedDeferredTools(tools, query, options = {}) {
239256
239437
  const normalized = normalizeDeferredToolQuery(query).toLowerCase();
239257
239438
  if (!normalized || normalized.startsWith("select:")) return [];
239258
- const tokens = normalized.split(/\s+/).filter(Boolean);
239439
+ const tokens = normalized.match(/\+?[\p{L}\p{N}_-]+/gu) || [];
239259
239440
  const requestedNameTokens = tokens.filter((token) => token.startsWith("+")).map((token) => token.slice(1)).filter(Boolean);
239260
239441
  const relaxRequiredNameTokens = options.relaxRequiredNameTokens === true && requestedNameTokens.length > 0;
239261
239442
  const requiredNameTokens = relaxRequiredNameTokens ? [] : requestedNameTokens;
239262
- const searchTokens = [...tokens.filter((token) => !token.startsWith("+")), ...relaxRequiredNameTokens ? requestedNameTokens : []].filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token));
239443
+ const searchTokens = [...tokens.filter((token) => !token.startsWith("+")), ...relaxRequiredNameTokens ? requestedNameTokens : []].filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token) && !TOOL_RANK_STOP_WORDS.has(token));
239263
239444
  if (searchTokens.length < 2 && !TOOL_SEARCH_SINGLE_TERM_RELATED_FALLBACKS.has(searchTokens[0])) return [];
239264
239445
  const minimumMatchedTokens = searchTokens.length === 1 ? 1 : Math.max(2, Math.ceil(searchTokens.length * .75));
239265
239446
  const ranked = tools.map((tool) => {
@@ -250063,7 +250244,8 @@ function logStepTiming(log, turnId, step, response) {
250063
250244
  inputOtherTokens: response.usage.inputOther,
250064
250245
  cacheReadTokens: response.usage.inputCacheRead,
250065
250246
  cacheCreationTokens: response.usage.inputCacheCreation,
250066
- outputTokens: response.usage.output
250247
+ outputTokens: response.usage.output,
250248
+ ...response.usage.outputReasoning === void 0 ? {} : { outputReasoningTokens: response.usage.outputReasoning }
250067
250249
  });
250068
250250
  }
250069
250251
  function deriveStepStopReason(response) {
@@ -251051,6 +251233,7 @@ const MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE = "mcp.oauth.authorization_url";
251051
251233
  const tokenUsageSchema = object({
251052
251234
  inputOther: number$1(),
251053
251235
  output: number$1(),
251236
+ outputReasoning: number$1().optional(),
251054
251237
  inputCacheRead: number$1(),
251055
251238
  inputCacheCreation: number$1()
251056
251239
  });
@@ -267590,6 +267773,7 @@ var TurnFlow = class {
267590
267773
  const appendedMessage = this.agent.context.history.at(-1);
267591
267774
  const turnAnchor = appendedMessage !== previousLastMessage && appendedMessage?.role === "user" && appendedMessage.origin === origin ? appendedMessage : void 0;
267592
267775
  const startedAt = Date.now();
267776
+ const preRequestHookStartedAt = performance.now();
267593
267777
  let ended;
267594
267778
  let blockedByUserPromptHook = false;
267595
267779
  let completedStopReason;
@@ -267615,6 +267799,13 @@ var TurnFlow = class {
267615
267799
  this.agent.log.warn("Turn-start observation failed");
267616
267800
  }
267617
267801
  signal.throwIfAborted();
267802
+ if (this.agent.type === "main" && process.env["BLUN_DIAG_PRE_REQUEST_PHASES"] === "1") try {
267803
+ this.agent.log.info("turn pre-request phase", {
267804
+ turnId,
267805
+ phase: "turn-hooks",
267806
+ durationMs: Math.max(0, Math.round(performance.now() - preRequestHookStartedAt))
267807
+ });
267808
+ } catch {}
267618
267809
  const stopReason = await this.runStepLoop(turnId, signal, input, origin, turnAnchor, (response) => {
267619
267810
  completedResponse = response;
267620
267811
  });
@@ -267726,6 +267917,10 @@ var TurnFlow = class {
267726
267917
  signal.throwIfAborted();
267727
267918
  const blockResult = renderUserPromptHookBlockResult(promptHookResults);
267728
267919
  if (blockResult !== void 0) {
267920
+ this.agent.log.warn("turn blocked by UserPromptSubmit hook", {
267921
+ turnId,
267922
+ reason: blockResult.message
267923
+ });
267729
267924
  this.agent.context.appendMessage({
267730
267925
  role: "assistant",
267731
267926
  content: [{
@@ -267784,9 +267979,26 @@ var TurnFlow = class {
267784
267979
  let stopHookContinuationUsed = false;
267785
267980
  let goalOutcomeMessageContinuationUsed = false;
267786
267981
  const deduper = new ToolCallDeduplicator({ telemetry: this.agent.telemetry });
267982
+ const diagnosePreRequest = this.agent.type === "main" && process.env["BLUN_DIAG_PRE_REQUEST_PHASES"] === "1";
267983
+ const recordPreRequestPhase = (phase, startedAt) => {
267984
+ if (!diagnosePreRequest) return;
267985
+ try {
267986
+ this.agent.log.info("turn pre-request phase", {
267987
+ turnId,
267988
+ phase,
267989
+ durationMs: Math.max(0, Math.round(performance.now() - startedAt))
267990
+ });
267991
+ } catch {}
267992
+ };
267993
+ let phaseStartedAt = performance.now();
267787
267994
  await this.agent.mcp?.waitForInitialLoad(signal);
267995
+ recordPreRequestPhase("mcp-initial-load", phaseStartedAt);
267996
+ phaseStartedAt = performance.now();
267788
267997
  const personalMemoryRecall = await this.agent.injection.injectPersonalMemoryForTurn(turnId, input, origin, signal);
267998
+ recordPreRequestPhase("personal-memory-recall", phaseStartedAt);
267999
+ phaseStartedAt = performance.now();
267789
268000
  await this.agent.injection.injectGoal();
268001
+ recordPreRequestPhase("goal-injection", phaseStartedAt);
267790
268002
  this.setActiveSteerAcceptance(turnId, true);
267791
268003
  const turnNeedsThinking = blunTurnNeedsTools(blunThinkingIntentInput(input), origin);
267792
268004
  let toolInput = input;
@@ -267797,12 +268009,14 @@ var TurnFlow = class {
267797
268009
  const raw = [...this.agent.context.history];
267798
268010
  const history = personalMemoryRecall === void 0 ? raw : [...raw, personalMemoryRecall];
267799
268011
  const selected = taskToolsNeeded ? history : greetingHistory(history, greetingAnchor);
268012
+ const projectionStartedAt = performance.now();
267800
268013
  const projected = await this.historicalToolProjection.project(selected, turnAnchor, tools, {
267801
268014
  turnId: String(turnId),
267802
268015
  stepNumber: this.currentStep,
267803
268016
  signal,
267804
268017
  llm: turnLLM
267805
268018
  });
268019
+ recordPreRequestPhase("historical-tool-projection", projectionStartedAt);
267806
268020
  const current = this.agent.context.history;
267807
268021
  if (current.length !== raw.length || current.some((message, index) => message !== raw[index])) {
267808
268022
  const latest = personalMemoryRecall === void 0 ? current : [...current, personalMemoryRecall];
@@ -267813,7 +268027,7 @@ var TurnFlow = class {
267813
268027
  partialContext = selected.length < history.length || projected.changed;
267814
268028
  return projected.history;
267815
268029
  };
267816
- const turnLLM = this.agent.llmForTurn(turnNeedsThinking ? void 0 : "off");
268030
+ const turnLLM = this.agent.llmForTurn(turnNeedsThinking ? void 0 : "off", turnId);
267817
268031
  const turnTools = this.agent.tools.captureTurnTools();
267818
268032
  while (true) {
267819
268033
  signal.throwIfAborted();
@@ -267823,6 +268037,7 @@ var TurnFlow = class {
267823
268037
  try {
267824
268038
  const selectedTools = [];
267825
268039
  this.refreshSelectedTools = (snapshot) => {
268040
+ const selectionStartedAt = performance.now();
267826
268041
  if (snapshot.messages.length > 0) toolInput = snapshot.messages.flatMap((message) => message.content);
267827
268042
  const eligibleTools = blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, turnTools()), origin);
267828
268043
  const intent = blunThinkingIntentInput(toolInput);
@@ -267835,6 +268050,7 @@ var TurnFlow = class {
267835
268050
  if (tool !== void 0 && !selectedTools.some((candidate) => candidate.name === name) && estimateTokensForTools([...selectedTools, tool]) <= (0, import_turn_tool_performance_policy.toolSchemaBudgetTokens)(this.agent.config.modelCapabilities?.max_context_tokens)) selectedTools.push(tool);
267836
268051
  }
267837
268052
  } 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)));
268053
+ recordPreRequestPhase("tool-selection", selectionStartedAt);
267838
268054
  return selectedTools;
267839
268055
  };
267840
268056
  return (await runTurn({
@@ -267847,14 +268063,24 @@ var TurnFlow = class {
267847
268063
  }, completion);
267848
268064
  },
267849
268065
  llm: turnLLM,
267850
- buildMessages: async () => this.agent.context.project(await turnHistory(selectedTools), { dropOrphanResults: true }),
267851
- buildMessagesStrict: async () => this.agent.context.project(await turnHistory(selectedTools), {
267852
- synthesizeMissing: true,
267853
- dropOrphanResults: true,
267854
- dedupeDuplicateToolCalls: true,
267855
- dropLeadingNonUser: true,
267856
- mergeConsecutiveAssistants: true
267857
- }),
268066
+ buildMessages: async () => {
268067
+ const startedAt = performance.now();
268068
+ const messages = this.agent.context.project(await turnHistory(selectedTools), { dropOrphanResults: true });
268069
+ recordPreRequestPhase("message-build", startedAt);
268070
+ return messages;
268071
+ },
268072
+ buildMessagesStrict: async () => {
268073
+ const startedAt = performance.now();
268074
+ const messages = this.agent.context.project(await turnHistory(selectedTools), {
268075
+ synthesizeMissing: true,
268076
+ dropOrphanResults: true,
268077
+ dedupeDuplicateToolCalls: true,
268078
+ dropLeadingNonUser: true,
268079
+ mergeConsecutiveAssistants: true
268080
+ });
268081
+ recordPreRequestPhase("message-build-strict", startedAt);
268082
+ return messages;
268083
+ },
267858
268084
  dispatchEvent: this.buildDispatchEvent(turnId, signal, onFinalResponse, () => partialContext),
267859
268085
  tools: selectedTools,
267860
268086
  log: this.agent.log,
@@ -267871,8 +268097,10 @@ var TurnFlow = class {
267871
268097
  },
267872
268098
  hooks: {
267873
268099
  beforeStep: async ({ signal: stepSignal, llm }) => {
268100
+ const injectionStartedAt = performance.now();
267874
268101
  this.agent.microCompaction.detect();
267875
268102
  await this.agent.injection.inject();
268103
+ recordPreRequestPhase("step-injection", injectionStartedAt);
267876
268104
  stepSignal.throwIfAborted();
267877
268105
  deduper.beginStep();
267878
268106
  },
@@ -267910,6 +268138,17 @@ var TurnFlow = class {
267910
268138
  signal.throwIfAborted();
267911
268139
  if (stopBlock !== void 0) {
267912
268140
  stopHookContinuationUsed = true;
268141
+ this.agent.log.warn("turn continuation blocked by Stop hook", {
268142
+ turnId,
268143
+ reason: stopBlock.reason
268144
+ });
268145
+ this.agent.emitEvent({
268146
+ type: "hook.result",
268147
+ turnId,
268148
+ hookEvent: "Stop",
268149
+ content: stopBlock.reason,
268150
+ blocked: true
268151
+ });
267913
268152
  this.agent.context.appendUserMessage([{
267914
268153
  type: "text",
267915
268154
  text: stopBlock.reason
@@ -271412,6 +271651,7 @@ var FallbackLLM = class {
271412
271651
  throw new Error("Fallback request preparation requires a fresh request boundary.");
271413
271652
  }
271414
271653
  let requestParams = params;
271654
+ let messagesReady = false;
271415
271655
  const rebuildRequestMessages = async () => {
271416
271656
  const messages = await rebuildMessages();
271417
271657
  const suffix = requestParams.boundaryMessageSuffix;
@@ -271420,7 +271660,14 @@ var FallbackLLM = class {
271420
271660
  while (true) {
271421
271661
  const candidate = this.current;
271422
271662
  try {
271423
- requestParams = await this.prepareRequest?.(candidate, requestParams, rebuildRequestMessages) ?? requestParams;
271663
+ const prepared = await this.prepareRequest?.(candidate, requestParams, rebuildRequestMessages);
271664
+ if (prepared !== void 0) if ("messagesReady" in prepared) {
271665
+ requestParams = prepared.params;
271666
+ messagesReady = true;
271667
+ } else {
271668
+ requestParams = prepared;
271669
+ messagesReady = false;
271670
+ }
271424
271671
  } catch (error) {
271425
271672
  if (!isFallbackCandidateError(error) && !isUnavailableFallbackCandidate(error)) throw error;
271426
271673
  const nextIndex = this.findNextCandidateIndex();
@@ -271430,13 +271677,14 @@ var FallbackLLM = class {
271430
271677
  ...requestParams,
271431
271678
  messages: await rebuildRequestMessages()
271432
271679
  };
271680
+ messagesReady = false;
271433
271681
  requestParams.signal.throwIfAborted();
271434
271682
  this.currentIndex = nextIndex;
271435
271683
  this.onModelChanged(this.current.alias);
271436
271684
  continue;
271437
271685
  }
271438
271686
  requestParams.signal.throwIfAborted();
271439
- const messages = await rebuildRequestMessages();
271687
+ const messages = messagesReady ? requestParams.messages : await rebuildRequestMessages();
271440
271688
  requestParams.signal.throwIfAborted();
271441
271689
  return {
271442
271690
  ...requestParams,
@@ -271538,8 +271786,13 @@ var LlmRequestLogger = class {
271538
271786
  toolsEstimatedTokens = 0;
271539
271787
  requestSequence = 0;
271540
271788
  lastTurnRequest;
271541
- constructor(log) {
271789
+ serializedPrefixKey;
271790
+ requestSignatures = /* @__PURE__ */ new Map();
271791
+ prefixComparisons = /* @__PURE__ */ new Map();
271792
+ lastSerializedRequest;
271793
+ constructor(log, serializedPrefixDiagnostic = process.env["BLUN_DIAG_SERIALIZED_PREFIX"] === "1") {
271542
271794
  this.log = log;
271795
+ this.serializedPrefixKey = serializedPrefixDiagnostic ? randomBytes(32) : void 0;
271543
271796
  }
271544
271797
  logRequest(input) {
271545
271798
  const sequence = ++this.requestSequence;
@@ -271556,6 +271809,10 @@ var LlmRequestLogger = class {
271556
271809
  toolsHash: fingerprint(JSON.stringify(toolSignature(tools)))
271557
271810
  };
271558
271811
  const signature = JSON.stringify(config);
271812
+ if (this.serializedPrefixKey !== void 0) {
271813
+ this.requestSignatures.set(sequence, signature);
271814
+ if (this.requestSignatures.size > 32) this.requestSignatures.delete(this.requestSignatures.keys().next().value);
271815
+ }
271559
271816
  if (signature !== this.lastConfigLogSignature) {
271560
271817
  this.lastConfigLogSignature = signature;
271561
271818
  this.configRevision++;
@@ -271585,6 +271842,20 @@ var LlmRequestLogger = class {
271585
271842
  }
271586
271843
  };
271587
271844
  if (partialMessageCount > 0) requestFields.partialMessageCount = partialMessageCount;
271845
+ const source = input.systemPromptContributions;
271846
+ if (source?.version === 1 && [
271847
+ source.totalBytes,
271848
+ source.instructionBytes,
271849
+ source.skillListingBytes,
271850
+ source.runtimeMemoryBytes,
271851
+ source.otherBytes
271852
+ ].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 = {
271853
+ totalBytes: source.totalBytes,
271854
+ instructionBytes: source.instructionBytes,
271855
+ skillListingBytes: source.skillListingBytes,
271856
+ runtimeMemoryBytes: source.runtimeMemoryBytes,
271857
+ otherBytes: source.otherBytes
271858
+ };
271588
271859
  this.log.info("llm request", requestFields);
271589
271860
  if (fields?.turnStep !== void 0 && /^\d+\.\d+$/.test(fields.turnStep)) {
271590
271861
  const historyTextOrigins = summarizeRequestTextOrigins(messages);
@@ -271610,10 +271881,51 @@ var LlmRequestLogger = class {
271610
271881
  getLastTurnRequest() {
271611
271882
  return this.lastTurnRequest === void 0 ? void 0 : structuredClone(this.lastTurnRequest);
271612
271883
  }
271884
+ get serializedPrefixDiagnosticEnabled() {
271885
+ return this.serializedPrefixKey !== void 0;
271886
+ }
271887
+ observeSerializedRequest(body, fields, sequence) {
271888
+ const key = this.serializedPrefixKey;
271889
+ if (key === void 0 || !/^\d+\.\d+$/.test(fields?.turnStep ?? "")) return;
271890
+ const signature = this.requestSignatures.get(sequence);
271891
+ if (signature === void 0) return;
271892
+ try {
271893
+ const bytes = Buffer.from(body, "utf8");
271894
+ const granularityBytes = 1024;
271895
+ const chunks = [];
271896
+ for (let start = 0; start + granularityBytes <= bytes.length; start += granularityBytes) chunks.push(createHmac("sha256", key).update(bytes.subarray(start, start + granularityBytes)).digest("hex"));
271897
+ const previous = this.lastSerializedRequest;
271898
+ if (previous !== void 0 && previous.signature === signature) {
271899
+ let common = 0;
271900
+ while (common < previous.chunks.length && common < chunks.length && previous.chunks[common] === chunks[common]) common++;
271901
+ this.prefixComparisons.set(sequence, {
271902
+ version: 1,
271903
+ granularityBytes,
271904
+ previousBytes: previous.bytes,
271905
+ currentBytes: bytes.length,
271906
+ commonPrefixBytesLowerBound: common * granularityBytes,
271907
+ previousSequence: previous.sequence,
271908
+ currentSequence: sequence
271909
+ });
271910
+ if (this.prefixComparisons.size > 32) this.prefixComparisons.delete(this.prefixComparisons.keys().next().value);
271911
+ }
271912
+ this.lastSerializedRequest = {
271913
+ sequence,
271914
+ signature,
271915
+ bytes: bytes.length,
271916
+ chunks
271917
+ };
271918
+ } catch {
271919
+ this.lastSerializedRequest = void 0;
271920
+ }
271921
+ }
271613
271922
  logTransportAttempt(stats, fields, sequence) {
271923
+ const serializedPrefix = sequence === void 0 ? void 0 : this.prefixComparisons.get(sequence);
271614
271924
  this.log.info("llm transport attempt", {
271615
271925
  ...fields,
271616
- ...stats
271926
+ ...stats,
271927
+ ...this.serializedPrefixKey === void 0 || sequence === void 0 ? {} : { requestSequence: sequence },
271928
+ ...serializedPrefix === void 0 ? {} : { serializedPrefix }
271617
271929
  });
271618
271930
  if (sequence === void 0 || this.lastTurnRequest?.sequence !== sequence) return;
271619
271931
  const breakdown = stats.requestBreakdown;
@@ -271635,6 +271947,11 @@ var LlmRequestLogger = class {
271635
271947
  systemMessageBytes: breakdown.systemMessageBytes,
271636
271948
  conversationMessageBytes: breakdown.conversationMessageBytes,
271637
271949
  toolResultMessageBytes: breakdown.toolResultMessageBytes,
271950
+ ...breakdown.toolResultByTool === void 0 ? {} : { toolResultByTool: breakdown.toolResultByTool.map((tool) => ({
271951
+ count: tool.count,
271952
+ bytes: tool.bytes,
271953
+ ...tool.name === void 0 ? {} : { name: tool.name }
271954
+ })) },
271638
271955
  toolSchemaBytes: breakdown.toolSchemaBytes,
271639
271956
  otherBytes: breakdown.otherBytes,
271640
271957
  ...breakdown.toolArrayOverheadBytes === void 0 ? {} : { toolArrayOverheadBytes: breakdown.toolArrayOverheadBytes },
@@ -271696,7 +272013,8 @@ function copyContributions(value) {
271696
272013
  version: source.version,
271697
272014
  totalBytes: source.totalBytes,
271698
272015
  generatedBytes: source.generatedBytes,
271699
- files: source.files.map((file) => copyInstructionFileBytes(file))
272016
+ files: source.files.map((file) => copyInstructionFileBytes(file)),
272017
+ ...source.notLoadedCandidates === void 0 ? {} : { notLoadedCandidates: [...source.notLoadedCandidates] }
271700
272018
  } }
271701
272019
  };
271702
272020
  }
@@ -271792,6 +272110,7 @@ var Agent$1 = class {
271792
272110
  errorMemory;
271793
272111
  replayBuilder;
271794
272112
  additionalDirs;
272113
+ systemPromptStartedAt = /* @__PURE__ */ new Date();
271795
272114
  activeProfile;
271796
272115
  brandHome;
271797
272116
  _activeResponderModel;
@@ -271879,6 +272198,7 @@ var Agent$1 = class {
271879
272198
  const retryScope = providerRetryScope(modelAlias, provider);
271880
272199
  await this.providerRetryWait.wait(retryScope, generateOptions?.signal);
271881
272200
  const callerTransportAttempt = generateOptions?.onTransportAttempt;
272201
+ const callerSerializedRequest = generateOptions?.onSerializedRequest;
271882
272202
  const ownedGenerateOptions = {
271883
272203
  ...generateOptions,
271884
272204
  transportMaxRetries: 0
@@ -271901,6 +272221,12 @@ var Agent$1 = class {
271901
272221
  callerTransportAttempt?.(stats);
271902
272222
  this.llmRequestLogger.logTransportAttempt(stats, requestLogFields, requestSequence);
271903
272223
  },
272224
+ ...callerSerializedRequest !== void 0 || this.llmRequestLogger.serializedPrefixDiagnosticEnabled ? { onSerializedRequest: (body) => {
272225
+ try {
272226
+ callerSerializedRequest?.(body);
272227
+ } catch {}
272228
+ this.llmRequestLogger.observeSerializedRequest(body, requestLogFields, requestSequence);
272229
+ } } : {},
271904
272230
  onRequestStart: () => {
271905
272231
  requestOptions?.onRequestStart?.();
271906
272232
  requestStarted = true;
@@ -271926,7 +272252,7 @@ var Agent$1 = class {
271926
272252
  get llm() {
271927
272253
  return this.llmForTurn();
271928
272254
  }
271929
- llmForTurn(thinkingEffort) {
272255
+ llmForTurn(thinkingEffort, diagnosticTurnId) {
271930
272256
  const selectedAlias = this.config.model;
271931
272257
  const modelProvider = this.modelProvider;
271932
272258
  if (modelProvider === void 0) throw new BlunError(ErrorCodes.MODEL_NOT_CONFIGURED, "Provider not set");
@@ -271941,6 +272267,7 @@ var Agent$1 = class {
271941
272267
  messages: await rebuildMessages()
271942
272268
  };
271943
272269
  let systemPrompt = this.effectiveSystemPrompt;
272270
+ const preflightStartedAt = performance.now();
271944
272271
  const compacted = await this.fullCompaction.beforeStep(params.signal, {
271945
272272
  messages: params.messages,
271946
272273
  additionalMessages: steers.messages,
@@ -271949,17 +272276,31 @@ var Agent$1 = class {
271949
272276
  rebuildSystemPrompt: () => systemPrompt = this.effectiveSystemPrompt,
271950
272277
  tools: params.tools
271951
272278
  });
272279
+ if (this.type === "main" && diagnosticTurnId !== void 0 && process.env["BLUN_DIAG_PRE_REQUEST_PHASES"] === "1") try {
272280
+ this.log.info("turn pre-request phase", {
272281
+ turnId: diagnosticTurnId,
272282
+ phase: "compaction-preflight",
272283
+ durationMs: Math.max(0, Math.round(performance.now() - preflightStartedAt))
272284
+ });
272285
+ } catch {}
271952
272286
  const tools = params.tools.some((tool) => tool.name === "CompactConversation") && !this.fullCompaction.proactiveCompactionStatus({
271953
272287
  messages: compacted ? await rebuildMessages() : params.messages,
271954
272288
  additionalMessages: steers.messages,
271955
272289
  systemPrompt,
271956
272290
  tools: params.tools
271957
272291
  }).eligible ? params.tools.filter((tool) => tool.name !== "CompactConversation") : params.tools;
271958
- this.turn.commitPendingSteers(steers);
271959
- return {
272292
+ const steersCommitted = this.turn.commitPendingSteers(steers);
272293
+ if (compacted || steersCommitted) params = {
271960
272294
  ...params,
271961
- systemPrompt,
271962
- tools
272295
+ messages: await rebuildMessages()
272296
+ };
272297
+ return {
272298
+ params: {
272299
+ ...params,
272300
+ systemPrompt,
272301
+ tools
272302
+ },
272303
+ messagesReady: true
271963
272304
  };
271964
272305
  }, (candidate, _params, error) => {
271965
272306
  this.fullCompaction.observeContextOverflow(error, candidate.alias);
@@ -272053,6 +272394,7 @@ var Agent$1 = class {
272053
272394
  let contributions;
272054
272395
  const systemPrompt = profile.systemPrompt({
272055
272396
  osEnv: this.kaos.osEnv,
272397
+ now: this.systemPromptStartedAt,
272056
272398
  cwd: this.config.cwd,
272057
272399
  skills: this.skills?.registry,
272058
272400
  cwdListing: context?.cwdListing,
@@ -347752,6 +348094,39 @@ var BlunAuthFacade = class {
347752
348094
  }
347753
348095
  return this.toolkit.status(providerName, this.resolveRuntimeManagedAuth(providerName).oauthRef);
347754
348096
  }
348097
+ async getCachedMemoryWorkspaceId() {
348098
+ const apiKey = nonEmpty(this.resolveManagedAuth(BLUN_PROVIDER_NAME$1).apiKey);
348099
+ if (apiKey !== void 0) {
348100
+ const provider = readConfigFileForUpdate(this.options.configPath).providers[BLUN_PROVIDER_NAME$1];
348101
+ if (provider?.apiKey !== apiKey || provider.memoryApiKeyHash !== memoryApiKeyHash(apiKey)) return;
348102
+ return provider.memoryWorkspaceId;
348103
+ }
348104
+ return this.toolkit.getCachedMemoryWorkspaceId(this.resolveRuntimeManagedAuth(BLUN_PROVIDER_NAME$1).oauthRef);
348105
+ }
348106
+ async cacheMemoryWorkspaceId(workspaceId) {
348107
+ const apiKey = nonEmpty(this.resolveManagedAuth(BLUN_PROVIDER_NAME$1).apiKey);
348108
+ if (apiKey !== void 0) {
348109
+ const hash = memoryApiKeyHash(apiKey);
348110
+ return mutateConfigFile(this.options.configPath, (config) => {
348111
+ const provider = config.providers[BLUN_PROVIDER_NAME$1];
348112
+ if (provider?.apiKey !== apiKey) return {
348113
+ config,
348114
+ result: false
348115
+ };
348116
+ if (provider.memoryApiKeyHash === hash && provider.memoryWorkspaceId !== void 0 && provider.memoryWorkspaceId !== workspaceId) return {
348117
+ config,
348118
+ result: false
348119
+ };
348120
+ provider.memoryApiKeyHash = hash;
348121
+ provider.memoryWorkspaceId = workspaceId;
348122
+ return {
348123
+ config,
348124
+ result: true
348125
+ };
348126
+ });
348127
+ }
348128
+ return this.toolkit.cacheMemoryWorkspaceId(workspaceId, this.resolveRuntimeManagedAuth(BLUN_PROVIDER_NAME$1).oauthRef);
348129
+ }
347755
348130
  async login(providerName = BLUN_PROVIDER_NAME$1, options = {}) {
347756
348131
  const auth = this.resolveManagedAuth(providerName);
347757
348132
  const loginAuth = resolveBlunCodeLoginAuth({
@@ -348057,6 +348432,9 @@ function nonEmpty(value) {
348057
348432
  const normalized = value?.trim();
348058
348433
  return normalized === void 0 || normalized.length === 0 ? void 0 : normalized;
348059
348434
  }
348435
+ function memoryApiKeyHash(apiKey) {
348436
+ return createHash("sha256").update(apiKey).digest("hex");
348437
+ }
348060
348438
  function transitionAggregateError(message, primary, secondary) {
348061
348439
  return new AggregateError([primary, secondary], message, { cause: primary });
348062
348440
  }