blun-king-cli 9.1.550 → 9.1.561

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/blun.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // BLUN_BUILD_INPUT_SHA256:804ef7d1988621941a7f328013311dcf55daa850695958e9d322a7eb3f92e699
2
+ // BLUN_BUILD_INPUT_SHA256:058cccc03f986fac95f89d198bb56bfa928b0c5117340651158d2f731509129c
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);
@@ -2798,8 +2798,6 @@ var init_blun = __esmMin((() => {
2798
2798
  }
2799
2799
  const kwargs = { ...this._generationKwargs };
2800
2800
  for (const key of Object.keys(kwargs)) if (kwargs[key] === void 0) delete kwargs[key];
2801
- if (kwargs["max_completion_tokens"] === void 0 && kwargs["max_tokens"] !== void 0) kwargs["max_completion_tokens"] = kwargs["max_tokens"];
2802
- delete kwargs["max_tokens"];
2803
2801
  const { extra_body: extraBody, ...requestKwargs } = kwargs;
2804
2802
  const extraBodyRecord = typeof extraBody === "object" && extraBody !== null ? { ...extraBody } : {};
2805
2803
  const thinking = sanitizeThinkingConfig(extraBodyRecord.thinking);
@@ -2910,7 +2908,7 @@ var init_blun = __esmMin((() => {
2910
2908
  withMaxCompletionTokens(maxCompletionTokens, options) {
2911
2909
  let cap = maxCompletionTokens;
2912
2910
  if (options?.usedContextTokens !== void 0 && options?.maxContextTokens !== void 0 && options.maxContextTokens > 0) cap = Math.min(cap, options.maxContextTokens - options.usedContextTokens);
2913
- return this._withGenerationKwargs({ max_completion_tokens: Math.max(1, cap) });
2911
+ return this._withGenerationKwargs({ max_tokens: Math.max(1, cap) });
2914
2912
  }
2915
2913
  withExtraBody(extraBody) {
2916
2914
  const oldExtra = this._generationKwargs.extra_body ?? {};
@@ -15931,6 +15929,8 @@ function loadRuntimeConfigSafe(filePath, env = process.env) {
15931
15929
  } catch (error) {
15932
15930
  envWarnings.push(`Ignoring BLUN_MODEL_* environment overrides: ${describeUnknownError(error)}`);
15933
15931
  }
15932
+ const { applyDefaultModelOutputBudget } = createRequire(import.meta.url)("./bin/default-model-output-budget-policy.cjs");
15933
+ config = applyDefaultModelOutputBudget(config);
15934
15934
  return {
15935
15935
  config,
15936
15936
  fileWarnings,
@@ -30347,7 +30347,6 @@ function resolveCompletionBudget(args) {
30347
30347
  const fromLegacy = parseEnvBudget(env["BLUN_MODEL_MAX_TOKENS"]);
30348
30348
  if (fromLegacy !== "absent") return fromLegacy === "disabled" ? void 0 : { hardCap: fromLegacy };
30349
30349
  if (args.maxOutputSize !== void 0 && args.maxOutputSize > 0) return { hardCap: args.maxOutputSize };
30350
- if (args.reservedContextSize !== void 0 && args.reservedContextSize > 0) return { fallback: args.reservedContextSize };
30351
30350
  return { fallback: DEFAULT_UNKNOWN_CONTEXT_FALLBACK };
30352
30351
  }
30353
30352
  function parseEnvBudget(raw) {
@@ -30400,13 +30399,12 @@ function applyCompletionBudgetWithDetails(args) {
30400
30399
  var MIN_FLOOR, DEFAULT_UNKNOWN_CONTEXT_FALLBACK, MIN_THINKING_COMPLETION_TOKENS, COMPLETION_CONTEXT_SAFETY_MARGIN;
30401
30400
  var init_completion_budget = __esmMin((() => {
30402
30401
  MIN_FLOOR = 1;
30403
- DEFAULT_UNKNOWN_CONTEXT_FALLBACK = 32e3;
30402
+ DEFAULT_UNKNOWN_CONTEXT_FALLBACK = 65536;
30404
30403
  MIN_THINKING_COMPLETION_TOKENS = 1024;
30405
30404
  COMPLETION_CONTEXT_SAFETY_MARGIN = 1e4;
30406
30405
  }));
30407
30406
  //#endregion
30408
30407
  //#region ../../packages/agent-core/src/loop/retry.ts
30409
- var { nextThinkingEffortForExhaustedEmpty } = createRequire(import.meta.url)("./bin/empty-response-retry-policy.cjs");
30410
30408
  async function chatWithRetry(input) {
30411
30409
  const maxAttempts = input.maxAttempts ?? 3;
30412
30410
  if (input.llm.isRetryableError === void 0 || maxAttempts <= 1) {
@@ -30420,10 +30418,9 @@ async function chatWithRetry(input) {
30420
30418
  }
30421
30419
  const delays = retryBackoffDelays(maxAttempts);
30422
30420
  let completionBudgetRetry;
30423
- let thinkingEffortRetry;
30424
30421
  let emptyRetryKind;
30425
30422
  for (let attempt = 1;; attempt += 1) try {
30426
- return await input.llm.chat(paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry, thinkingEffortRetry));
30423
+ return await input.llm.chat(paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry));
30427
30424
  } catch (error) {
30428
30425
  if (error instanceof APIEmptyResponseError && (emptyRetryKind !== void 0 || error.emptyResponseKind === "length" || error.emptyResponseKind === "stop")) {
30429
30426
  logEmptyResponse(input, error, attempt);
@@ -30433,24 +30430,24 @@ async function chatWithRetry(input) {
30433
30430
  throw terminal;
30434
30431
  }
30435
30432
  completionBudgetRetry = completionBudgetRetryForEmpty(error);
30436
- thinkingEffortRetry = nextThinkingEffortForExhaustedEmpty({
30437
- emptyResponseKind: error.emptyResponseKind,
30438
- maxCompletionTokens: error.maxCompletionTokens,
30439
- completionTokens: error.completionTokens,
30440
- thinkingEffort: input.llm.thinkingEffort
30441
- });
30442
30433
  emptyRetryKind = error.emptyResponseKind;
30443
30434
  input.params.signal.throwIfAborted();
30444
- input.dispatchEvent({
30445
- type: "step.retrying",
30446
- turnId: input.turnId,
30447
- step: input.currentStep,
30448
- stepUuid: input.stepUuid,
30449
- failedAttempt: attempt,
30450
- nextAttempt: attempt + 1,
30451
- maxAttempts,
30452
- delayMs: 0,
30453
- ...retryErrorFields(error)
30435
+ await persistRetrySchedule({
30436
+ dispatchRetrying: input.dispatchEvent,
30437
+ flush: input.checkpointBeforeRetryWait,
30438
+ signal: input.params.signal,
30439
+ event: {
30440
+ type: "step.retrying",
30441
+ turnId: input.turnId,
30442
+ step: input.currentStep,
30443
+ stepUuid: input.stepUuid,
30444
+ failedAttempt: attempt,
30445
+ nextAttempt: attempt + 1,
30446
+ maxAttempts,
30447
+ delayMs: 0,
30448
+ ...completionBudgetIntervention(error, completionBudgetRetry),
30449
+ ...retryErrorFields(error)
30450
+ }
30454
30451
  });
30455
30452
  continue;
30456
30453
  }
@@ -30460,17 +30457,22 @@ async function chatWithRetry(input) {
30460
30457
  }
30461
30458
  const delayMs = retryDelayForError(error, delays[attempt - 1] ?? 0);
30462
30459
  input.params.signal.throwIfAborted();
30463
- input.dispatchEvent({
30464
- type: "step.retrying",
30465
- turnId: input.turnId,
30466
- step: input.currentStep,
30467
- stepUuid: input.stepUuid,
30468
- failedAttempt: attempt,
30469
- nextAttempt: attempt + 1,
30470
- maxAttempts,
30471
- delayMs,
30472
- outputMayHaveStarted: input.llm.didErrorEmitPartialOutput?.(error) === true,
30473
- ...retryErrorFields(error)
30460
+ await persistRetrySchedule({
30461
+ dispatchRetrying: input.dispatchEvent,
30462
+ flush: input.checkpointBeforeRetryWait,
30463
+ signal: input.params.signal,
30464
+ event: {
30465
+ type: "step.retrying",
30466
+ turnId: input.turnId,
30467
+ step: input.currentStep,
30468
+ stepUuid: input.stepUuid,
30469
+ failedAttempt: attempt,
30470
+ nextAttempt: attempt + 1,
30471
+ maxAttempts,
30472
+ delayMs,
30473
+ outputMayHaveStarted: input.llm.didErrorEmitPartialOutput?.(error) === true,
30474
+ ...retryErrorFields(error)
30475
+ }
30474
30476
  });
30475
30477
  await sleepForRetry(delayMs, input.params.signal);
30476
30478
  }
@@ -30482,6 +30484,14 @@ function completionBudgetRetryForEmpty(error) {
30482
30484
  multiplier: 2
30483
30485
  };
30484
30486
  }
30487
+ function completionBudgetIntervention(error, retryBudget) {
30488
+ const before = Number(error.maxCompletionTokens);
30489
+ if (retryBudget === void 0 || !Number.isFinite(before) || before <= 0) return {};
30490
+ return {
30491
+ completionBudgetBefore: before,
30492
+ completionBudgetAfter: Math.max(retryBudget.minimumCompletionTokens, Math.ceil(before * retryBudget.multiplier))
30493
+ };
30494
+ }
30485
30495
  function retryDelayForError(error, fallbackDelayMs) {
30486
30496
  if (!(error instanceof APIProviderRateLimitError) || error.retryAfterMs === null) return fallbackDelayMs;
30487
30497
  return Math.max(fallbackDelayMs, error.retryAfterMs);
@@ -30495,12 +30505,11 @@ function logRequestFailure(input, error, attempt, maxAttempts) {
30495
30505
  ...retryErrorFields(error)
30496
30506
  });
30497
30507
  }
30498
- function paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry, thinkingEffortRetry) {
30508
+ function paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry) {
30499
30509
  const turnStep = `${input.turnId}.${String(input.currentStep)}`;
30500
30510
  return {
30501
30511
  ...input.params,
30502
30512
  completionBudgetRetry,
30503
- thinkingEffortRetry,
30504
30513
  requestLogFields: attempt === 1 ? { turnStep } : {
30505
30514
  turnStep,
30506
30515
  attempt: `${String(attempt)}/${String(maxAttempts)}`
@@ -30508,19 +30517,12 @@ function paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry, th
30508
30517
  };
30509
30518
  }
30510
30519
  function logEmptyResponse(input, error, attempt) {
30511
- const retryThinkingEffort = nextThinkingEffortForExhaustedEmpty({
30512
- emptyResponseKind: error.emptyResponseKind,
30513
- maxCompletionTokens: error.maxCompletionTokens,
30514
- completionTokens: error.completionTokens,
30515
- thinkingEffort: input.llm.thinkingEffort
30516
- });
30517
30520
  input.log?.warn(`[leer] fall=${error.emptyResponseKind}`, {
30518
30521
  turnStep: `${input.turnId}.${String(input.currentStep)}`,
30519
30522
  attempt,
30520
30523
  budget: error.maxCompletionTokens,
30521
30524
  completion: error.completionTokens,
30522
- reasoningLength: error.reasoningLength,
30523
- ...retryThinkingEffort === void 0 ? {} : { retryThinkingEffort }
30525
+ reasoningLength: error.reasoningLength
30524
30526
  });
30525
30527
  }
30526
30528
  function retryBackoffDelays(maxAttempts) {
@@ -30548,7 +30550,7 @@ function maybeStatusCode(error) {
30548
30550
  const statusCode = error.statusCode;
30549
30551
  return typeof statusCode === "number" ? statusCode : void 0;
30550
30552
  }
30551
- var import_retry$1, RETRY_MIN_TIMEOUT_MS, RETRY_MAX_TIMEOUT_MS, RETRY_FACTOR;
30553
+ var import_retry$1, RETRY_MIN_TIMEOUT_MS, RETRY_MAX_TIMEOUT_MS, RETRY_FACTOR, persistRetrySchedule;
30552
30554
  var init_retry = __esmMin((() => {
30553
30555
  init_dist$4();
30554
30556
  init_src$4();
@@ -30556,6 +30558,7 @@ var init_retry = __esmMin((() => {
30556
30558
  init_abort();
30557
30559
  init_completion_budget();
30558
30560
  init_errors$4();
30561
+ ({ persistRetrySchedule } = createRequire(import.meta.url)("./bin/retry-checkpoint-policy.cjs"));
30559
30562
  RETRY_MIN_TIMEOUT_MS = 300;
30560
30563
  RETRY_MAX_TIMEOUT_MS = 5e3;
30561
30564
  RETRY_FACTOR = 2;
@@ -74933,6 +74936,25 @@ var init_kosong_llm = __esmMin((() => {
74933
74936
  get thinkingEffort() {
74934
74937
  return this.provider.thinkingEffort;
74935
74938
  }
74939
+ describeRequest(messages, tools, retry) {
74940
+ const outgoingRequestTokens = estimateSystemPromptTokens(this.systemPrompt) + estimateTokensForTools(tools) + estimateTokensForMessages(messages);
74941
+ const reportedContextTokens = this.reportedContextTokens?.() ?? 0;
74942
+ const details = applyCompletionBudgetWithDetails({
74943
+ provider: this.provider,
74944
+ budget: this.completionBudgetConfig,
74945
+ capability: this.capability,
74946
+ usedContextTokens: Math.max(outgoingRequestTokens, reportedContextTokens),
74947
+ retry: retry ?? (thinkingEnabled(this.provider.thinkingEffort) ? {
74948
+ minimumCompletionTokens: 1024,
74949
+ multiplier: 1
74950
+ } : void 0)
74951
+ });
74952
+ return {
74953
+ thinkingEffort: this.provider.thinkingEffort,
74954
+ completionBudget: details.maxCompletionTokens,
74955
+ details
74956
+ };
74957
+ }
74936
74958
  notifyMediaDropped(dropped) {
74937
74959
  if (this.onMediaDropped === void 0) return;
74938
74960
  const fresh = dropped.filter((part) => {
@@ -74975,25 +74997,12 @@ var init_kosong_llm = __esmMin((() => {
74975
74997
  let result;
74976
74998
  let completionBudget;
74977
74999
  try {
74978
- const requestProvider = params.thinkingEffortRetry === void 0 ? this.provider : this.provider.withThinking(params.thinkingEffortRetry);
74979
75000
  const enrichedMessages = this.visionReader === void 0 ? params.messages : await enrichMessagesWithVision(params.messages, this.visionReader, params.signal, this.onVisionUsage);
74980
75001
  const tools = [...params.tools];
74981
75002
  const outgoingMessages = downgradeUnsupportedMedia(enrichedMessages, this.capability, (dropped) => {
74982
75003
  this.notifyMediaDropped(dropped);
74983
75004
  });
74984
- const outgoingRequestTokens = estimateSystemPromptTokens(this.systemPrompt) + estimateTokensForTools(tools) + estimateTokensForMessages(outgoingMessages);
74985
- const reportedContextTokens = this.reportedContextTokens?.() ?? 0;
74986
- const usedContextTokens = Math.max(outgoingRequestTokens, reportedContextTokens);
74987
- completionBudget = applyCompletionBudgetWithDetails({
74988
- provider: requestProvider,
74989
- budget: this.completionBudgetConfig,
74990
- capability: this.capability,
74991
- usedContextTokens,
74992
- retry: params.completionBudgetRetry ?? (thinkingEnabled(requestProvider.thinkingEffort) ? {
74993
- minimumCompletionTokens: 1024,
74994
- multiplier: 1
74995
- } : void 0)
74996
- });
75005
+ completionBudget = this.describeRequest(outgoingMessages, tools, params.completionBudgetRetry).details;
74997
75006
  result = await this.generate(completionBudget.provider, this.systemPrompt, tools, outgoingMessages, callbacks, options);
74998
75007
  } catch (error) {
74999
75008
  if (error instanceof APIEmptyResponseError) throw error.withMetadata({ maxCompletionTokens: completionBudget === void 0 ? null : completionBudget.maxCompletionTokens ?? null });
@@ -75516,12 +75525,13 @@ function extractCompactionSummary(response) {
75516
75525
  if (summary.trim().length === 0) throw new APIEmptyResponseError("The compaction response did not contain a non-empty summary.");
75517
75526
  return summary;
75518
75527
  }
75519
- var archiveCompactionHistory, buildCompactionArchiveNotice, capCompactionCompletionTokens, capCompactionStageTarget, proactiveCompactionEligibility, waitForAbortableCompletion, COMPACTION_THINKING_EFFORT, COMPACTION_SYSTEM_PROMPT, COMPACTION_SUMMARY_RESERVE_RATIO, MAX_HIERARCHICAL_COMPACTION_PASSES, HIERARCHICAL_COMPACTION_PREFIX, CompactionTruncatedError, CompactionStallError, COMPACTION_STALL_MEASUREMENT_MULTIPLIER, REBUILT_AFTER_COMPACTION_INJECTION_VARIANTS, FullCompaction, MAX_COMPACTION_OVERFLOW_SHRINK_ATTEMPTS, COMPACTION_OVERFLOW_SHRINK_RATIOS;
75528
+ var archiveCompactionHistory, buildCompactionArchiveNotice, capCompactionCompletionTokens, capCompactionStageTarget, proactiveCompactionEligibility, assertBalancedToolPairs, createCompactionTransaction, endCompactionTransaction, summarizeCompactionTransaction, waitForAbortableCompletion, COMPACTION_THINKING_EFFORT, COMPACTION_SYSTEM_PROMPT, COMPACTION_SUMMARY_RESERVE_RATIO, MAX_HIERARCHICAL_COMPACTION_PASSES, HIERARCHICAL_COMPACTION_PREFIX, CompactionTruncatedError, CompactionStallError, COMPACTION_STALL_MEASUREMENT_MULTIPLIER, REBUILT_AFTER_COMPACTION_INJECTION_VARIANTS, FullCompaction, MAX_COMPACTION_OVERFLOW_SHRINK_ATTEMPTS, COMPACTION_OVERFLOW_SHRINK_RATIOS;
75520
75529
  var init_full = __esmMin((() => {
75521
75530
  ({ archiveCompactionHistory, buildCompactionArchiveNotice } = createRequire(import.meta.url)("./bin/compaction-history-archive.cjs"));
75522
75531
  ({ waitForAbortableCompletion } = createRequire(import.meta.url)("./bin/abort-listener-policy.cjs"));
75523
75532
  ({ capCompactionCompletionTokens, capCompactionStageTarget } = createRequire(import.meta.url)("./bin/compaction-stage-policy.cjs"));
75524
75533
  ({ proactiveCompactionEligibility } = createRequire(import.meta.url)("./bin/proactive-compaction-policy.cjs"));
75534
+ ({ assertBalancedToolPairs, createCompactionTransaction, endCompactionTransaction, summarizeCompactionTransaction } = createRequire(import.meta.url)("./bin/compaction-transaction-policy.cjs"));
75525
75535
  init_errors$8();
75526
75536
  init_src$4();
75527
75537
  init_errors$4();
@@ -75672,6 +75682,15 @@ var init_full = __esmMin((() => {
75672
75682
  }
75673
75683
  if (this.agent.context.history.length === 0) throw new BlunError(ErrorCodes.COMPACTION_UNABLE, "No messages to compact in current history.");
75674
75684
  if (data.source === "manual" && this.agent.turn.hasActiveTurn) throw new BlunError(ErrorCodes.COMPACTION_UNABLE, "Cannot compact while a turn is active. Wait for it to finish, then retry.");
75685
+ const history = this.agent.context.history;
75686
+ assertBalancedToolPairs(history, "history selected for full compaction");
75687
+ const { transaction, record: transactionStart } = createCompactionTransaction({
75688
+ source: data.source,
75689
+ turnId: this.agent.turn.hasActiveTurn ? this.agent.turn.currentId : null,
75690
+ tokensBefore: estimateTokensForMessages(history),
75691
+ messageCountBefore: history.length
75692
+ });
75693
+ this.agent.records.logRecord(transactionStart);
75675
75694
  this.agent.records.logRecord({
75676
75695
  type: "full_compaction.begin",
75677
75696
  ...data
@@ -75684,20 +75703,32 @@ var init_full = __esmMin((() => {
75684
75703
  const abortController = new AbortController();
75685
75704
  this.compacting = {
75686
75705
  abortController,
75687
- promise: this.compactionWorker(abortController.signal, data),
75706
+ promise: this.compactionWorker(abortController.signal, data, transaction),
75707
+ transaction,
75688
75708
  blockedByTurn: false
75689
75709
  };
75690
75710
  }
75691
- cancel() {
75711
+ closeTransaction(status, error) {
75712
+ const transaction = this.compacting?.transaction;
75713
+ if (transaction === void 0) return;
75714
+ const record = endCompactionTransaction(transaction, {
75715
+ status,
75716
+ ...error === void 0 ? {} : { error: error instanceof Error ? `${error.name}: ${error.message}` : String(error) }
75717
+ });
75718
+ if (record !== void 0) this.agent.records.logRecord(record);
75719
+ }
75720
+ cancel(error) {
75692
75721
  this.agent.replayBuilder.patchLast("compaction", { result: "cancelled" });
75693
75722
  if (!this.compacting) return;
75694
75723
  this.agent.records.logRecord({ type: "full_compaction.cancel" });
75724
+ this.closeTransaction(error === void 0 ? "cancelled" : "failed", error);
75695
75725
  this.compacting.abortController.abort();
75696
75726
  this.compacting = null;
75697
75727
  this.agent.emitEvent({ type: "compaction.cancelled" });
75698
75728
  }
75699
75729
  markCompleted() {
75700
75730
  this.agent.records.logRecord({ type: "full_compaction.complete" });
75731
+ this.closeTransaction("success");
75701
75732
  this.compacting = null;
75702
75733
  }
75703
75734
  get tokenCountWithPending() {
@@ -75806,9 +75837,9 @@ var init_full = __esmMin((() => {
75806
75837
  await waitForAbortableCompletion(signal, active.promise, onAbort);
75807
75838
  }
75808
75839
  }
75809
- async compactionWorker(signal, data) {
75840
+ async compactionWorker(signal, data, transaction) {
75810
75841
  try {
75811
- const output = await this.compactionRound(signal, data);
75842
+ const output = await this.compactionRound(signal, data, transaction);
75812
75843
  if (!output) return;
75813
75844
  const { result, stageCount } = output;
75814
75845
  try {
@@ -75833,9 +75864,12 @@ var init_full = __esmMin((() => {
75833
75864
  });
75834
75865
  this.triggerPostCompactHook(data, result);
75835
75866
  } catch (error) {
75836
- if (isAbortError$4(error)) return;
75867
+ if (isAbortError$4(error)) {
75868
+ if (this.compacting?.transaction === transaction) this.cancel();
75869
+ return;
75870
+ }
75837
75871
  const blockedByTurn = this.compacting?.blockedByTurn === true;
75838
- this.cancel();
75872
+ this.cancel(error);
75839
75873
  this.agent.log.error("compaction failed", { error });
75840
75874
  if (blockedByTurn) throw error;
75841
75875
  this.agent.emitEvent({
@@ -75855,7 +75889,7 @@ var init_full = __esmMin((() => {
75855
75889
  const todoMarkdown = renderTodoList(todos, "## TODO List");
75856
75890
  return `${summary.trim()}\n\n${todoMarkdown}`;
75857
75891
  }
75858
- async compactionRound(signal, data) {
75892
+ async compactionRound(signal, data, transaction) {
75859
75893
  const startedAt = Date.now();
75860
75894
  const originalHistory = [...this.agent.context.history];
75861
75895
  const tokensBefore = estimateTokensForMessages(originalHistory);
@@ -76131,7 +76165,9 @@ var init_full = __esmMin((() => {
76131
76165
  contextSummary,
76132
76166
  compactedCount: originalHistory.length,
76133
76167
  tokensBefore,
76134
- droppedCount: droppedCount === 0 ? void 0 : droppedCount
76168
+ droppedCount: droppedCount === 0 ? void 0 : droppedCount,
76169
+ transaction,
76170
+ historyBefore: originalHistory
76135
76171
  });
76136
76172
  this.agent.telemetry.track("compaction_finished", {
76137
76173
  source: data.source,
@@ -76242,10 +76278,18 @@ var init_full = __esmMin((() => {
76242
76278
  }));
76243
76279
  //#endregion
76244
76280
  //#region ../../packages/agent-core/src/agent/compaction/micro.ts
76245
- var selectMicroCompactionCutoff, MICRO_COMPACTION_RECENT_MESSAGES, MICRO_COMPACTION_TOOL_ARGUMENTS_ENABLED, MICRO_COMPACTION_TOOL_ARGUMENT_MIN_TOKENS, isPersistedToolResultReference, freshToolResultIds, projectHistoricalUnaddressedTelegramMessages, dedupeRepeatedUserMessages, projectRepeatedAssistantResponses, compactHistoricalSkillActivations, dedupeRecurringCronWakeups, dedupeRepeatedInjections, projectLoopEventForRecord, projectUsageModelForRecord, projectUsageForRecord, resolveCompletedStepUuid, resolveStepEventUuid, restoreUsageFromRecord, restoreUsageModelFromRecord, isWireOnlyProgrammaticEvent, DEFAULT_CONFIG, MicroCompaction;
76281
+ function repeatedToolResultReference(marker, newestToolCallId) {
76282
+ if (newestToolCallId === void 0) return marker;
76283
+ return [
76284
+ marker,
76285
+ `same_as_tool_call_id: ${newestToolCallId}`,
76286
+ "reason: identical successful result for the same tool call arguments"
76287
+ ].join("\n");
76288
+ }
76289
+ var selectMicroCompactionCutoff, redundantHistoricalToolResultReferences, MICRO_COMPACTION_RECENT_MESSAGES, MICRO_COMPACTION_TOOL_ARGUMENTS_ENABLED, MICRO_COMPACTION_TOOL_ARGUMENT_MIN_TOKENS, isPersistedToolResultReference, freshToolResultIds, projectHistoricalUnaddressedTelegramMessages, dedupeRepeatedUserMessages, projectRepeatedAssistantResponses, compactHistoricalSkillActivations, dedupeRecurringCronWakeups, dedupeRepeatedInjections, projectLoopEventForRecord, projectUsageModelForRecord, projectUsageForRecord, resolveCompletedStepUuid, resolveStepEventUuid, restoreUsageFromRecord, restoreUsageModelFromRecord, isWireOnlyProgrammaticEvent, DEFAULT_CONFIG, MicroCompaction;
76246
76290
  var init_micro = __esmMin((() => {
76247
76291
  ({ isWireOnlyProgrammaticEvent } = createRequire(import.meta.url)("./bin/programmatic-context-isolation.cjs"));
76248
- ({ selectMicroCompactionCutoff, MICRO_COMPACTION_RECENT_MESSAGES, MICRO_COMPACTION_TOOL_ARGUMENTS_ENABLED, MICRO_COMPACTION_TOOL_ARGUMENT_MIN_TOKENS } = createRequire(import.meta.url)("./bin/micro-compaction-policy.cjs"));
76292
+ ({ selectMicroCompactionCutoff, redundantHistoricalToolResultReferences, MICRO_COMPACTION_RECENT_MESSAGES, MICRO_COMPACTION_TOOL_ARGUMENTS_ENABLED, MICRO_COMPACTION_TOOL_ARGUMENT_MIN_TOKENS } = createRequire(import.meta.url)("./bin/micro-compaction-policy.cjs"));
76249
76293
  ({ isPersistedToolResultReference, freshToolResultIds } = createRequire(import.meta.url)("./bin/tool-result-offload-policy.cjs"));
76250
76294
  ({ projectHistoricalUnaddressedTelegramMessages } = createRequire(import.meta.url)("./bin/telegram-context-projection-policy.cjs"));
76251
76295
  ({ dedupeRepeatedUserMessages } = createRequire(import.meta.url)("./bin/repeated-user-message-projection.cjs"));
@@ -76260,7 +76304,7 @@ var init_micro = __esmMin((() => {
76260
76304
  compactToolArguments: MICRO_COMPACTION_TOOL_ARGUMENTS_ENABLED,
76261
76305
  minToolArgumentTokens: MICRO_COMPACTION_TOOL_ARGUMENT_MIN_TOKENS,
76262
76306
  cacheMissedThresholdMs: 3600 * 1e3,
76263
- truncatedMarker: "[Old tool result content cleared]",
76307
+ truncatedMarker: "[Repeated tool result omitted]",
76264
76308
  truncatedArgumentsMarker: "[Old tool call arguments cleared]",
76265
76309
  minContextUsageRatio: .5
76266
76310
  };
@@ -76308,10 +76352,18 @@ var init_micro = __esmMin((() => {
76308
76352
  const effect = this.measureEffect(history, selection.cutoff);
76309
76353
  const previousEffect = this.measureEffect(history, previousCutoff);
76310
76354
  if (effect.truncatedToolResultCount <= previousEffect.truncatedToolResultCount && effect.truncatedToolArgumentCount <= previousEffect.truncatedToolArgumentCount) return;
76311
- this.apply(selection.cutoff);
76312
76355
  const rawContextTokens = estimateTokensForMessages(history);
76313
76356
  const tokensBefore = rawContextTokens - previousEffect.truncatedToolResultTokensBefore + previousEffect.truncatedToolResultTokensAfter - previousEffect.truncatedToolArgumentTokensBefore + previousEffect.truncatedToolArgumentTokensAfter;
76314
76357
  const tokensAfter = rawContextTokens - effect.truncatedToolResultTokensBefore + effect.truncatedToolResultTokensAfter - effect.truncatedToolArgumentTokensBefore + effect.truncatedToolArgumentTokensAfter;
76358
+ this.apply(selection.cutoff);
76359
+ this.agent.records.logRecord({
76360
+ type: "policy.intervention",
76361
+ policy: "repeated_tool_result_projection",
76362
+ location: "MicroCompaction.detect",
76363
+ size_before: tokensBefore,
76364
+ size_after: tokensAfter,
76365
+ unit: "tokens"
76366
+ });
76315
76367
  this.agent.telemetry.track("micro_compaction_finished", {
76316
76368
  trigger: selection.trigger,
76317
76369
  keep_recent_messages: config.keepRecentMessages,
@@ -76343,15 +76395,16 @@ var init_micro = __esmMin((() => {
76343
76395
  const historicalArgumentCutoff = Math.max(this.cutoff, messages.length - config.keepRecentMessages);
76344
76396
  const completedToolCallIds = new Set(messages.filter((message) => message?.role === "tool" && message.toolCallId !== void 0).map((message) => message.toolCallId));
76345
76397
  const protectedToolResultIds = freshToolResultIds(messages);
76398
+ const reducibleToolResultIds = redundantHistoricalToolResultReferences(messages, this.cutoff);
76346
76399
  const serializedArgumentsMarker = JSON.stringify({ _blun_compacted: config.truncatedArgumentsMarker });
76347
76400
  const result = [];
76348
76401
  let i = 0;
76349
76402
  for (const msg of messages) {
76350
- if (i < this.cutoff && msg.role === "tool" && msg.toolCallId !== void 0 && !protectedToolResultIds.has(msg.toolCallId) && !isPersistedToolResultReference(msg.content) && estimateTokensForContentParts(msg.content) >= config.minContentTokens) result.push({
76403
+ if (i < this.cutoff && msg.role === "tool" && msg.toolCallId !== void 0 && reducibleToolResultIds.has(msg.toolCallId) && !protectedToolResultIds.has(msg.toolCallId) && !isPersistedToolResultReference(msg.content) && estimateTokensForContentParts(msg.content) >= config.minContentTokens) result.push({
76351
76404
  ...msg,
76352
76405
  content: [{
76353
76406
  type: "text",
76354
- text: config.truncatedMarker
76407
+ text: repeatedToolResultReference(config.truncatedMarker, reducibleToolResultIds.get(msg.toolCallId))
76355
76408
  }]
76356
76409
  });
76357
76410
  else if (config.compactToolArguments && i < historicalArgumentCutoff && msg.role === "assistant" && Array.isArray(msg.toolCalls)) {
@@ -76380,7 +76433,6 @@ var init_micro = __esmMin((() => {
76380
76433
  return result;
76381
76434
  }
76382
76435
  measureEffect(messages, cutoff) {
76383
- let markerTokenCount;
76384
76436
  let argumentsMarkerTokenCount;
76385
76437
  let truncatedToolResultCount = 0;
76386
76438
  let truncatedToolResultTokensBefore = 0;
@@ -76390,19 +76442,20 @@ var init_micro = __esmMin((() => {
76390
76442
  let truncatedToolArgumentTokensAfter = 0;
76391
76443
  const completedToolCallIds = new Set(messages.filter((message) => message?.role === "tool" && message.toolCallId !== void 0).map((message) => message.toolCallId));
76392
76444
  const protectedToolResultIds = freshToolResultIds(messages);
76445
+ const reducibleToolResultIds = redundantHistoricalToolResultReferences(messages, cutoff);
76393
76446
  const serializedArgumentsMarker = JSON.stringify({ _blun_compacted: this.config.truncatedArgumentsMarker });
76394
76447
  for (let i = 0; i < messages.length && i < cutoff; i++) {
76395
76448
  const message = messages[i];
76396
- if (message?.role === "tool" && message.toolCallId !== void 0 && !protectedToolResultIds.has(message.toolCallId) && !isPersistedToolResultReference(message.content)) {
76449
+ if (message?.role === "tool" && message.toolCallId !== void 0 && reducibleToolResultIds.has(message.toolCallId) && !protectedToolResultIds.has(message.toolCallId) && !isPersistedToolResultReference(message.content)) {
76397
76450
  const contentTokens = estimateTokensForContentParts(message.content);
76398
76451
  if (contentTokens >= this.config.minContentTokens) {
76399
- markerTokenCount ??= estimateTokensForContentParts([{
76400
- type: "text",
76401
- text: this.config.truncatedMarker
76402
- }]);
76403
76452
  truncatedToolResultCount += 1;
76404
76453
  truncatedToolResultTokensBefore += contentTokens;
76405
- truncatedToolResultTokensAfter += markerTokenCount;
76454
+ const replacement = repeatedToolResultReference(this.config.truncatedMarker, reducibleToolResultIds.get(message.toolCallId));
76455
+ truncatedToolResultTokensAfter += estimateTokensForContentParts([{
76456
+ type: "text",
76457
+ text: replacement
76458
+ }]);
76406
76459
  }
76407
76460
  }
76408
76461
  if (!this.config.compactToolArguments || message?.role !== "assistant" || !Array.isArray(message.toolCalls)) continue;
@@ -79395,6 +79448,24 @@ var init_context$2 = __esmMin((() => {
79395
79448
  keptHeadUserMessageCount,
79396
79449
  droppedCount: input.droppedCount
79397
79450
  };
79451
+ const summaryMessage = {
79452
+ role: "user",
79453
+ content: [{
79454
+ type: "text",
79455
+ text: contextSummary
79456
+ }],
79457
+ toolCalls: [],
79458
+ origin: { kind: "compaction_summary" }
79459
+ };
79460
+ const isLegacyRestore = this.agent.records.restoring !== null && input.keptUserMessageCount === void 0 && input.compactedCount < this._history.length;
79461
+ const nextHistory = isLegacyRestore ? [summaryMessage, ...this._history.slice(input.compactedCount)] : [...keptMessages, summaryMessage];
79462
+ if (input.transaction !== void 0) this.agent.records.logRecord(summarizeCompactionTransaction(input.transaction, {
79463
+ summary: contextSummary,
79464
+ historyBefore: input.historyBefore ?? this._history,
79465
+ historyAfter: nextHistory,
79466
+ tokensAfter: result.tokensAfter,
79467
+ messageCountAfter: nextHistory.length
79468
+ }));
79398
79469
  this.agent.records.logRecord({
79399
79470
  type: "policy.intervention",
79400
79471
  policy: "full_context_compaction",
@@ -79417,17 +79488,7 @@ var init_context$2 = __esmMin((() => {
79417
79488
  keptHeadUserMessageCount: result.keptHeadUserMessageCount,
79418
79489
  droppedCount: result.droppedCount
79419
79490
  } });
79420
- const summaryMessage = {
79421
- role: "user",
79422
- content: [{
79423
- type: "text",
79424
- text: contextSummary
79425
- }],
79426
- toolCalls: [],
79427
- origin: { kind: "compaction_summary" }
79428
- };
79429
- const isLegacyRestore = this.agent.records.restoring !== null && input.keptUserMessageCount === void 0 && input.compactedCount < this._history.length;
79430
- this._history = isLegacyRestore ? [summaryMessage, ...this._history.slice(input.compactedCount)] : [...keptMessages, summaryMessage];
79491
+ this._history = nextHistory;
79431
79492
  this.markPendingTokenEstimateDirty();
79432
79493
  this.openSteps.clear();
79433
79494
  this.pendingToolResultIds.clear();
@@ -244545,6 +244606,7 @@ function createNestedToolInvoker(step, parentToolCall) {
244545
244606
  ...step,
244546
244607
  signal: nestedSignal,
244547
244608
  toolCalls: [nestedToolCall],
244609
+ checkpointBeforeToolExecution: void 0,
244548
244610
  dispatchEvent: (event) => step.dispatchEvent(markProgrammaticNestedEvent(event))
244549
244611
  };
244550
244612
  const preflight = preflightToolCall(nestedStep, nestedToolCall);
@@ -244679,6 +244741,16 @@ async function prepareToolCall(step, call, approvalEditCount = 0) {
244679
244741
  }
244680
244742
  const executionMetadata = authorization?.executionMetadata ?? decision.metadata;
244681
244743
  await dispatchToolCall(step, call, effectiveArgs, displayFields);
244744
+ if (step.checkpointBeforeToolExecution !== void 0) {
244745
+ const checkpoint = await checkpointBeforeExternalSideEffect({
244746
+ flush: step.checkpointBeforeToolExecution,
244747
+ signal: step.signal
244748
+ });
244749
+ if (!checkpoint.allowed) return {
244750
+ task: makeResolvedToolCallTask(makeErrorToolResult(call, effectiveArgs, `${checkpoint.code}: ${checkpoint.error}`)),
244751
+ stopBatchAfterThis: true
244752
+ };
244753
+ }
244682
244754
  return {
244683
244755
  task: {
244684
244756
  accesses: execution.accesses ?? ToolAccesses.all(),
@@ -244985,9 +245057,10 @@ async function dispatchToolCall(step, call, args, displayFields) {
244985
245057
  display: displayFields?.display
244986
245058
  });
244987
245059
  }
244988
- var markProgrammaticNestedEvent, GRACE_TIMEOUT_MS, TOOL_OUTPUT_EMPTY, TOOL_OUTPUT_NON_TEXT, validators;
245060
+ var markProgrammaticNestedEvent, checkpointBeforeExternalSideEffect, GRACE_TIMEOUT_MS, TOOL_OUTPUT_EMPTY, TOOL_OUTPUT_NON_TEXT, validators;
244989
245061
  var init_tool_call = __esmMin((() => {
244990
245062
  ({ markProgrammaticNestedEvent } = createRequire(import.meta.url)("./bin/programmatic-context-isolation.cjs"));
245063
+ ({ checkpointBeforeExternalSideEffect } = createRequire(import.meta.url)("./bin/session-checkpoint-policy.cjs"));
244991
245064
  init_args_validator();
244992
245065
  init_path_access();
244993
245066
  init_abort();
@@ -245011,7 +245084,7 @@ var init_tool_call = __esmMin((() => {
245011
245084
  * does not lose model usage that was already spent.
245012
245085
  */
245013
245086
  async function executeLoopStep(deps) {
245014
- const { turnId, signal, buildMessages, buildMessagesStrict, dispatchEvent, llm, tools, hooks, log, currentStep, maxRetryAttempts, recordUsage, onStepStarted } = deps;
245087
+ const { turnId, signal, buildMessages, buildMessagesStrict, dispatchEvent, llm, tools, hooks, log, currentStep, maxRetryAttempts, recordUsage, onStepStarted, checkpointBeforeToolExecution, checkpointBeforeRetryWait } = deps;
245015
245088
  const beforeStep = hooks?.beforeStep === void 0 ? void 0 : await hooks.beforeStep({
245016
245089
  turnId,
245017
245090
  stepNumber: currentStep,
@@ -245027,12 +245100,15 @@ async function executeLoopStep(deps) {
245027
245100
  const messages = await stepBuildMessages();
245028
245101
  signal.throwIfAborted();
245029
245102
  const stepUuid = randomUUID();
245103
+ const requestMetadata = stepLLM.describeRequest?.(messages, stepTools ?? []);
245030
245104
  const stepEvents = createStepEventGate({
245031
245105
  dispatchEvent,
245032
245106
  turnId,
245033
245107
  currentStep,
245034
245108
  stepUuid,
245035
- onStepStarted
245109
+ onStepStarted,
245110
+ requestMetadata,
245111
+ maxAttempts: maxRetryAttempts
245036
245112
  });
245037
245113
  const prepareRequestBoundary = stepLLM.prepareRequestBoundary?.bind(stepLLM);
245038
245114
  const step = {
@@ -245044,7 +245120,8 @@ async function executeLoopStep(deps) {
245044
245120
  signal,
245045
245121
  turnId,
245046
245122
  currentStep,
245047
- stepUuid
245123
+ stepUuid,
245124
+ checkpointBeforeToolExecution
245048
245125
  };
245049
245126
  let chatParams = {
245050
245127
  messages,
@@ -245057,9 +245134,8 @@ async function executeLoopStep(deps) {
245057
245134
  signal.throwIfAborted();
245058
245135
  const retryInput = {
245059
245136
  llm: stepLLM,
245060
- dispatchEvent: (event) => {
245061
- stepEvents.dispatchRetrying(event);
245062
- },
245137
+ dispatchEvent: (event) => stepEvents.dispatchRetrying(event),
245138
+ checkpointBeforeRetryWait,
245063
245139
  turnId,
245064
245140
  currentStep,
245065
245141
  stepUuid,
@@ -245219,29 +245295,33 @@ async function chatWithLiveResponseRepetitionRecovery(deps) {
245219
245295
  occurrences: repetition.count,
245220
245296
  wordCount: repetition.wordCount
245221
245297
  });
245222
- await stepEvents.dispatchRetrying({
245223
- type: "step.retrying",
245224
- turnId: retryInput.turnId,
245225
- step: retryInput.currentStep,
245226
- stepUuid: retryInput.stepUuid,
245227
- failedAttempt: 1,
245228
- nextAttempt: 2,
245229
- maxAttempts: 2,
245230
- delayMs: 0,
245231
- outputMayHaveStarted: true,
245232
- errorName: "LiveResponseRepetitionError",
245233
- errorMessage: "Repeated assistant text detected during streaming"
245298
+ await persistRetrySchedule({
245299
+ dispatchRetrying: (event) => stepEvents.dispatchRetrying(event),
245300
+ flush: checkpointBeforeRetryWait,
245301
+ signal,
245302
+ event: {
245303
+ type: "step.retrying",
245304
+ turnId: retryInput.turnId,
245305
+ step: retryInput.currentStep,
245306
+ stepUuid: retryInput.stepUuid,
245307
+ failedAttempt: 1,
245308
+ nextAttempt: 2,
245309
+ maxAttempts: 2,
245310
+ delayMs: 0,
245311
+ outputMayHaveStarted: true,
245312
+ errorName: "LiveResponseRepetitionError",
245313
+ errorMessage: "Repeated assistant text detected during streaming"
245314
+ }
245234
245315
  });
245235
245316
  }
245236
245317
  }
245237
245318
  throw new Error("Live response repetition recovery exhausted");
245238
245319
  }
245239
245320
  function createStepEventGate(deps) {
245240
- const { dispatchEvent, turnId, currentStep, stepUuid, onStepStarted } = deps;
245321
+ const { dispatchEvent, turnId, currentStep, stepUuid, onStepStarted, requestMetadata, maxAttempts } = deps;
245241
245322
  let startPromise;
245242
245323
  let eventQueue = Promise.resolve();
245243
245324
  let hasOutput = false;
245244
- const pendingBeforeStart = [];
245245
245325
  let liveRepetitionGuard;
245246
245326
  let liveRepetitionController;
245247
245327
  let liveRepetitionResult = null;
@@ -245251,10 +245331,13 @@ function createStepEventGate(deps) {
245251
245331
  type: "step.begin",
245252
245332
  uuid: stepUuid,
245253
245333
  turnId,
245254
- step: currentStep
245334
+ step: currentStep,
245335
+ thinkingEffort: requestMetadata?.thinkingEffort,
245336
+ completionBudget: requestMetadata?.completionBudget,
245337
+ attempt: 1,
245338
+ maxAttempts
245255
245339
  });
245256
245340
  onStepStarted?.();
245257
- for (const dispatch of pendingBeforeStart.splice(0)) await dispatch();
245258
245341
  })();
245259
245342
  return startPromise;
245260
245343
  };
@@ -245289,14 +245372,9 @@ function createStepEventGate(deps) {
245289
245372
  return AbortSignal.any([signal, liveRepetitionController.signal]);
245290
245373
  },
245291
245374
  dispatchRetrying: async (event) => {
245292
- if (startPromise === void 0) {
245293
- pendingBeforeStart.push(() => {
245294
- dispatchEvent(event);
245295
- });
245296
- return;
245297
- }
245298
- const queued = eventQueue.then(() => {
245299
- dispatchEvent(event);
245375
+ const queued = eventQueue.then(async () => {
245376
+ await start();
245377
+ await dispatchEvent(event);
245300
245378
  });
245301
245379
  eventQueue = queued;
245302
245380
  await queued;
@@ -245360,7 +245438,7 @@ var init_turn_step = __esmMin((() => {
245360
245438
  //#endregion
245361
245439
  //#region ../../packages/agent-core/src/loop/run-turn.ts
245362
245440
  async function runTurn(input) {
245363
- const { turnId, signal, llm, buildMessages, buildMessagesStrict, dispatchEvent, tools, hooks, log, maxSteps, maxRetryAttempts, recordStepUsage: hostRecordStepUsage } = input;
245441
+ const { turnId, signal, llm, buildMessages, buildMessagesStrict, dispatchEvent, tools, hooks, log, maxSteps, maxRetryAttempts, checkpointBeforeToolExecution, checkpointBeforeRetryWait, recordStepUsage: hostRecordStepUsage } = input;
245364
245442
  let usage = emptyUsage();
245365
245443
  let steps = 0;
245366
245444
  let stopReason = "end_turn";
@@ -245390,6 +245468,8 @@ async function runTurn(input) {
245390
245468
  log,
245391
245469
  currentStep: stepNumber,
245392
245470
  maxRetryAttempts,
245471
+ checkpointBeforeToolExecution,
245472
+ checkpointBeforeRetryWait,
245393
245473
  recordUsage: recordStepUsage,
245394
245474
  onStepStarted: setActiveStep.bind(void 0, stepNumber)
245395
245475
  });
@@ -246762,7 +246842,11 @@ var init_events$1 = __esmMin((() => {
246762
246842
  type: literal("turn.step.started"),
246763
246843
  turnId: number$1(),
246764
246844
  step: number$1(),
246765
- stepId: string().optional()
246845
+ stepId: string().optional(),
246846
+ thinkingEffort: string().optional(),
246847
+ completionBudget: number$1().int().positive().optional(),
246848
+ attempt: number$1().int().positive().optional(),
246849
+ maxAttempts: number$1().int().positive().optional()
246766
246850
  });
246767
246851
  turnStepCompletedEventSchema = object({
246768
246852
  type: literal("turn.step.completed"),
@@ -246792,7 +246876,9 @@ var init_events$1 = __esmMin((() => {
246792
246876
  outputMayHaveStarted: boolean$1().optional(),
246793
246877
  errorName: string(),
246794
246878
  errorMessage: string(),
246795
- statusCode: number$1().optional()
246879
+ statusCode: number$1().optional(),
246880
+ completionBudgetBefore: number$1().int().positive().optional(),
246881
+ completionBudgetAfter: number$1().int().positive().optional()
246796
246882
  });
246797
246883
  turnStepInterruptedEventSchema = object({
246798
246884
  type: literal("turn.step.interrupted"),
@@ -254607,7 +254693,15 @@ function replaceOnceLiteral(content, oldString, newString) {
254607
254693
  if (index === -1) return content;
254608
254694
  return content.slice(0, index) + newString + content.slice(index + oldString.length);
254609
254695
  }
254610
- var EditInputSchema, EditTool, findDegenerateGeneratedStatementRun;
254696
+ async function observedFileStat(kaos, path) {
254697
+ try {
254698
+ return await kaos.stat(path);
254699
+ } catch (error) {
254700
+ if (error?.code === "ENOENT" || error?.code === "ENOTDIR") return null;
254701
+ throw error;
254702
+ }
254703
+ }
254704
+ var EditInputSchema, EditTool, findDegenerateGeneratedStatementRun, writeToolTextAtomic;
254611
254705
  var init_edit = __esmMin((() => {
254612
254706
  init_zod$1();
254613
254707
  init_tool_access();
@@ -254619,6 +254713,7 @@ var init_edit = __esmMin((() => {
254619
254713
  init_edit$1();
254620
254714
  init_lsp_diagnostics();
254621
254715
  ({ findDegenerateGeneratedStatementRun } = createRequire(import.meta.url)("./bin/generated-source-health.cjs"));
254716
+ ({ writeToolTextAtomic } = createRequire(import.meta.url)("./bin/tool-file-persistence.cjs"));
254622
254717
  EditInputSchema = object({
254623
254718
  path: string().describe("Path to the text file to edit. Relative paths resolve against the working directory; a path outside the working directory must be absolute."),
254624
254719
  old_string: string().min(1).describe("Exact content to replace from the Read output view, without the line-number prefix. Use LF for pure CRLF files; use actual \\r escapes where Read shows \\r."),
@@ -254632,14 +254727,16 @@ var init_edit = __esmMin((() => {
254632
254727
  workspace;
254633
254728
  history;
254634
254729
  lsp;
254730
+ fileObservation;
254635
254731
  name = "Edit";
254636
254732
  description = edit_default;
254637
254733
  parameters = toInputJsonSchema(EditInputSchema);
254638
- constructor(kaos, workspace, history, lsp) {
254734
+ constructor(kaos, workspace, history, lsp, fileObservation) {
254639
254735
  this.kaos = kaos;
254640
254736
  this.workspace = workspace;
254641
254737
  this.history = history;
254642
254738
  this.lsp = lsp;
254739
+ this.fileObservation = fileObservation;
254643
254740
  }
254644
254741
  resolveExecution(args) {
254645
254742
  const path = resolvePathAccessPath(args.path, {
@@ -254677,6 +254774,12 @@ var init_edit = __esmMin((() => {
254677
254774
  output: `Refused to edit ${args.path}: generated source contains a runaway repeated statement ${String(degenerateStatementRun.count)} times from line ${String(degenerateStatementRun.line)} (starts with ${JSON.stringify(degenerateStatementRun.preview)}). Regenerate that section in a smaller focused chunk. No file was written.`
254678
254775
  };
254679
254776
  try {
254777
+ const currentStat = await observedFileStat(this.kaos, safePath);
254778
+ const authorization = this.fileObservation.authorizeEdit(safePath, currentStat);
254779
+ if (!authorization.allowed) return {
254780
+ isError: true,
254781
+ output: `[${authorization.code}] ${authorization.error}`
254782
+ };
254680
254783
  const raw = await this.kaos.readText(safePath);
254681
254784
  const modelView = toModelTextView(raw);
254682
254785
  const content = modelView.text;
@@ -254699,7 +254802,7 @@ var init_edit = __esmMin((() => {
254699
254802
  output: `old_string is not unique in ${args.path} (found ${String(count)} occurrences). To replace every occurrence, set replace_all=true. To replace only one occurrence, include more surrounding context in old_string.`
254700
254803
  };
254701
254804
  const newContent = replaceOnceLiteral(content, args.old_string, args.new_string);
254702
- return this.writeReplacement(args, safePath, raw, newContent, modelView.lineEndingStyle, 1);
254805
+ return this.writeReplacement(args, safePath, raw, newContent, modelView.lineEndingStyle, 1, authorization.version);
254703
254806
  }
254704
254807
  const parts = content.split(args.old_string);
254705
254808
  const replacementCount = parts.length - 1;
@@ -254709,7 +254812,7 @@ var init_edit = __esmMin((() => {
254709
254812
  `
254710
254813
  };
254711
254814
  const newContent = parts.join(args.new_string);
254712
- return this.writeReplacement(args, safePath, raw, newContent, modelView.lineEndingStyle, replacementCount);
254815
+ return this.writeReplacement(args, safePath, raw, newContent, modelView.lineEndingStyle, replacementCount, authorization.version);
254713
254816
  } catch (error) {
254714
254817
  if (error?.code === "EISDIR") return {
254715
254818
  isError: true,
@@ -254721,7 +254824,7 @@ var init_edit = __esmMin((() => {
254721
254824
  };
254722
254825
  }
254723
254826
  }
254724
- async writeReplacement(args, safePath, currentContent, nextContent, lineEndingStyle, replacementCount) {
254827
+ async writeReplacement(args, safePath, currentContent, nextContent, lineEndingStyle, replacementCount, observedVersion) {
254725
254828
  const materialized = materializeModelText(nextContent, lineEndingStyle);
254726
254829
  const lineLimit = evaluateSourceFileLineLimit(safePath, materialized, {
254727
254830
  currentContent,
@@ -254732,7 +254835,14 @@ var init_edit = __esmMin((() => {
254732
254835
  isError: true,
254733
254836
  output: lineLimit.error
254734
254837
  };
254735
- await this.kaos.writeText(safePath, materialized);
254838
+ const latestStat = await observedFileStat(this.kaos, safePath);
254839
+ const freshness = this.fileObservation.verifyUnchanged(safePath, observedVersion, latestStat);
254840
+ if (!freshness.allowed) return {
254841
+ isError: true,
254842
+ output: `[${freshness.code}] ${freshness.error}`
254843
+ };
254844
+ await writeToolTextAtomic(safePath, materialized);
254845
+ this.fileObservation.recordPresent(safePath, await this.kaos.stat(safePath));
254736
254846
  const occurrence = replacementCount === 1 ? "occurrence" : "occurrences";
254737
254847
  const notice = lineLimit.notice === void 0 ? "" : ` ${lineLimit.notice}`;
254738
254848
  return appendLspDiagnostics({ output: `Replaced ${String(replacementCount)} ${occurrence} in ${args.path}.` + notice }, safePath, this.lsp);
@@ -260327,13 +260437,15 @@ var init_read = __esmMin((() => {
260327
260437
  kaos;
260328
260438
  workspace;
260329
260439
  contextWindowState;
260440
+ fileObservation;
260330
260441
  name = "Read";
260331
260442
  description = READ_DESCRIPTION;
260332
260443
  parameters = toInputJsonSchema(ReadInputSchema);
260333
- constructor(kaos, workspace, contextWindowState = () => ({})) {
260444
+ constructor(kaos, workspace, contextWindowState = () => ({}), fileObservation) {
260334
260445
  this.kaos = kaos;
260335
260446
  this.workspace = workspace;
260336
260447
  this.contextWindowState = contextWindowState;
260448
+ this.fileObservation = fileObservation;
260337
260449
  }
260338
260450
  modelVisibleBytes() {
260339
260451
  return readModelVisibleBytes(this.contextWindowState());
@@ -260370,10 +260482,13 @@ var init_read = __esmMin((() => {
260370
260482
  try {
260371
260483
  stat = await this.kaos.stat(safePath);
260372
260484
  } catch (error) {
260373
- if (isFileNotFoundError(error)) return {
260374
- isError: true,
260375
- output: `"${args.path}" does not exist.`
260376
- };
260485
+ if (isFileNotFoundError(error)) {
260486
+ this.fileObservation.recordAbsent(safePath);
260487
+ return {
260488
+ isError: true,
260489
+ output: `"${args.path}" does not exist.`
260490
+ };
260491
+ }
260377
260492
  throw error;
260378
260493
  }
260379
260494
  if (!isRegularFileMode(stat.stMode)) return {
@@ -260394,8 +260509,17 @@ var init_read = __esmMin((() => {
260394
260509
  const requestedLines = args.n_lines ?? maxLines;
260395
260510
  const effectiveLimit = Math.min(requestedLines, maxLines);
260396
260511
  const maxBytes = this.modelVisibleBytes();
260397
- if (lineOffset < 0) return await this.readTail(safePath, args.path, lineOffset, effectiveLimit, requestedLines, maxBytes, maxLines);
260398
- return await this.readForward(safePath, args.path, lineOffset, effectiveLimit, requestedLines, maxBytes, maxLines);
260512
+ const result = lineOffset < 0
260513
+ ? await this.readTail(safePath, args.path, lineOffset, effectiveLimit, requestedLines, maxBytes, maxLines)
260514
+ : await this.readForward(safePath, args.path, lineOffset, effectiveLimit, requestedLines, maxBytes, maxLines);
260515
+ if (result.isError === true) return result;
260516
+ const afterStat = await observedFileStat(this.kaos, safePath);
260517
+ const stability = this.fileObservation.verifyStableRead(safePath, stat, afterStat);
260518
+ if (!stability.allowed) return {
260519
+ isError: true,
260520
+ output: `[${stability.code}] ${stability.error}`
260521
+ };
260522
+ return result;
260399
260523
  } catch (error) {
260400
260524
  if (isTextDecodeError(error)) return {
260401
260525
  isError: true,
@@ -260662,10 +260786,10 @@ var init_read = __esmMin((() => {
260662
260786
  name = "ReadBatch";
260663
260787
  description = READ_BATCH_DESCRIPTION;
260664
260788
  parameters = toInputJsonSchema(ReadBatchInputSchema);
260665
- constructor(kaos, workspace, contextWindowState) {
260789
+ constructor(kaos, workspace, contextWindowState, fileObservation) {
260666
260790
  this.kaos = kaos;
260667
260791
  this.workspace = workspace;
260668
- this.reader = new ReadTool(kaos, workspace, contextWindowState);
260792
+ this.reader = new ReadTool(kaos, workspace, contextWindowState, fileObservation);
260669
260793
  }
260670
260794
  resolveExecution(args) {
260671
260795
  const items = args.requests.map((request) => ({
@@ -261090,7 +261214,7 @@ function countCompletedLines(content) {
261090
261214
  for (const character of content) if (character === "\n") count += 1;
261091
261215
  return count;
261092
261216
  }
261093
- var S_IFMT, S_IFDIR, DEFAULT_CONTINUATION_CHUNK_BYTES, MIN_CONTINUATION_CHUNK_BYTES, MAX_CONTINUATION_CHUNK_BYTES, CONTINUATION_CHUNK_BYTES_ENV, WriteContinuationSchema, WriteInputSchema, WriteTool, resolveWriteContinuationContract, resolvePlainWriteContract, splitNativeWriteBytes, writeNativeLargeContentOnDisk;
261217
+ var S_IFMT, S_IFDIR, DEFAULT_CONTINUATION_CHUNK_BYTES, MIN_CONTINUATION_CHUNK_BYTES, MAX_CONTINUATION_CHUNK_BYTES, CONTINUATION_CHUNK_BYTES_ENV, WriteContinuationSchema, WriteInputSchema, WriteTool, resolveWriteContinuationContract, resolvePlainWriteContract, splitNativeWriteBytes, writeNativeLargeContentOnDisk, writeToolTextAtomic;
261094
261218
  var init_write = __esmMin((() => {
261095
261219
  init_dist$6();
261096
261220
  init_zod$1();
@@ -261104,6 +261228,7 @@ var init_write = __esmMin((() => {
261104
261228
  init_lsp_diagnostics();
261105
261229
  ({ resolveWriteContinuationContract, resolvePlainWriteContract, splitNativeWriteBytes } = createRequire(import.meta.url)("./bin/write-continuation-policy.cjs"));
261106
261230
  ({ writeNativeLargeContentOnDisk } = createRequire(import.meta.url)("./bin/native-large-file-io.cjs"));
261231
+ ({ writeToolTextAtomic } = createRequire(import.meta.url)("./bin/tool-file-persistence.cjs"));
261107
261232
  S_IFMT = 61440;
261108
261233
  S_IFDIR = 16384;
261109
261234
  DEFAULT_CONTINUATION_CHUNK_BYTES = 2048;
@@ -261133,17 +261258,19 @@ bytesWritten: number$1().int().nonnegative() });
261133
261258
  workspace;
261134
261259
  history;
261135
261260
  lsp;
261261
+ fileObservation;
261136
261262
  maxContinuationChunkBytes;
261137
261263
  name = "Write";
261138
261264
  description = write_default;
261139
261265
  parameters = toInputJsonSchema(WriteInputSchema);
261140
261266
  pendingContinuations = /* @__PURE__ */ new Map();
261141
261267
  continuationRequiredPaths = /* @__PURE__ */ new Set();
261142
- constructor(kaos, workspace, history, lsp, maxContinuationChunkBytes = resolveWriteContinuationChunkBytes()) {
261268
+ constructor(kaos, workspace, history, lsp, fileObservation, maxContinuationChunkBytes = resolveWriteContinuationChunkBytes()) {
261143
261269
  this.kaos = kaos;
261144
261270
  this.workspace = workspace;
261145
261271
  this.history = history;
261146
261272
  this.lsp = lsp;
261273
+ this.fileObservation = fileObservation;
261147
261274
  this.maxContinuationChunkBytes = maxContinuationChunkBytes;
261148
261275
  }
261149
261276
  resolveExecution(args) {
@@ -261312,6 +261439,12 @@ bytesWritten: number$1().int().nonnegative() });
261312
261439
  isError: true,
261313
261440
  output: `Refused to write ${args.path}: generated source contains a runaway repeated statement ${String(degenerateStatementRun.count)} times from line ${String(degenerateStatementRun.line)} (starts with ${JSON.stringify(degenerateStatementRun.preview)}). Regenerate that section in a smaller focused chunk. No file was written.`
261314
261441
  };
261442
+ const currentStat = await observedFileStat(this.kaos, safePath);
261443
+ const authorization = this.fileObservation.authorizeWrite(safePath, currentStat);
261444
+ if (!authorization.allowed) return {
261445
+ isError: true,
261446
+ output: `[${authorization.code}] ${authorization.error}`
261447
+ };
261315
261448
  let currentContent;
261316
261449
  if (isSourceFilePath(safePath)) try {
261317
261450
  currentContent = await this.kaos.readText(safePath);
@@ -261339,9 +261472,16 @@ bytesWritten: number$1().int().nonnegative() });
261339
261472
  continuationRequired: this.continuationRequiredPaths.has(safePath)
261340
261473
  });
261341
261474
  if (!allowLargeContent && !plainWrite.allowed) {
261475
+ const latestStat = await observedFileStat(this.kaos, safePath);
261476
+ const freshness = this.fileObservation.verifyUnchanged(safePath, authorization.version, latestStat);
261477
+ if (!freshness.allowed) return {
261478
+ isError: true,
261479
+ output: `[${freshness.code}] ${freshness.error}`
261480
+ };
261342
261481
  const chunks = splitNativeWriteBytes(args.content, this.maxContinuationChunkBytes);
261343
261482
  const nativeResult = await this.writeNativeLargeContent(safePath, chunks, mode);
261344
261483
  if (nativeResult.isError === true) return nativeResult;
261484
+ this.fileObservation.recordPresent(safePath, await this.kaos.stat(safePath));
261345
261485
  this.continuationRequiredPaths.delete(safePath);
261346
261486
  const notice = lineLimit.notice === void 0 ? "" : ` ${lineLimit.notice}`;
261347
261487
  return appendLspDiagnostics({
@@ -261354,8 +261494,15 @@ bytesWritten: number$1().int().nonnegative() });
261354
261494
  output: parentError
261355
261495
  };
261356
261496
  try {
261497
+ const latestStat = await observedFileStat(this.kaos, safePath);
261498
+ const freshness = this.fileObservation.verifyUnchanged(safePath, authorization.version, latestStat);
261499
+ if (!freshness.allowed) return {
261500
+ isError: true,
261501
+ output: `[${freshness.code}] ${freshness.error}`
261502
+ };
261357
261503
  if (mode === "append") await this.kaos.writeText(safePath, args.content, { mode: "a" });
261358
- else await this.kaos.writeText(safePath, args.content);
261504
+ else await writeToolTextAtomic(safePath, args.content);
261505
+ this.fileObservation.recordPresent(safePath, await this.kaos.stat(safePath));
261359
261506
  const bytesWritten = Buffer.byteLength(args.content, "utf8");
261360
261507
  const notice = lineLimit.notice === void 0 ? "" : ` ${lineLimit.notice}`;
261361
261508
  return appendLspDiagnostics({ output: `${mode === "append" ? "Appended" : "Wrote"} ${String(bytesWritten)} bytes to ${args.path}.${notice}` }, safePath, this.lsp);
@@ -261904,7 +262051,8 @@ var init_tool_dedup = __esmMin((() => {
261904
262051
  //#region ../../packages/agent-core/src/agent/turn/tool-result-budget.ts
261905
262052
  async function budgetToolResultForModel(options) {
261906
262053
  const text = persistableToolResultText(options.result.output);
261907
- if (text === void 0 || shouldKeepFreshToolResult(options.toolName) || !shouldOffloadToolResult(text.length)) return options.result;
262054
+ const contextUsageRatio = Number.isFinite(options.maxContextTokens) && options.maxContextTokens > 0 ? Number(options.contextTokens) / options.maxContextTokens : 1;
262055
+ if (text === void 0 || shouldKeepFreshToolResult(options.toolName) || !shouldOffloadToolResult(text.length, { contextUsageRatio })) return options.result;
261908
262056
  const readSourcePath = reusableReadSourcePath(options);
261909
262057
  if (readSourcePath !== void 0) return referenceReadSourceForModel(options, text, readSourcePath);
261910
262058
  return persistToolResultForModel(options, text);
@@ -262688,7 +262836,11 @@ function mapLoopEvent(event, turnId) {
262688
262836
  type: "turn.step.started",
262689
262837
  turnId,
262690
262838
  step: event.step,
262691
- stepId: event.uuid
262839
+ stepId: event.uuid,
262840
+ thinkingEffort: event.thinkingEffort,
262841
+ completionBudget: event.completionBudget,
262842
+ attempt: event.attempt,
262843
+ maxAttempts: event.maxAttempts
262692
262844
  };
262693
262845
  case "step.end": return {
262694
262846
  type: "turn.step.completed",
@@ -262718,7 +262870,9 @@ function mapLoopEvent(event, turnId) {
262718
262870
  outputMayHaveStarted: event.outputMayHaveStarted,
262719
262871
  errorName: event.errorName,
262720
262872
  errorMessage: event.errorMessage,
262721
- statusCode: event.statusCode
262873
+ statusCode: event.statusCode,
262874
+ completionBudgetBefore: event.completionBudgetBefore,
262875
+ completionBudgetAfter: event.completionBudgetAfter
262722
262876
  };
262723
262877
  case "content.part": return;
262724
262878
  case "tool.call": return {
@@ -263006,6 +263160,7 @@ var init_turn = __esmMin((() => {
263006
263160
  toolScopeByTurn = /* @__PURE__ */ new Map();
263007
263161
  interruptedTelemetryTurnIds = /* @__PURE__ */ new Set();
263008
263162
  stepFailureByTurn = /* @__PURE__ */ new Map();
263163
+ stepRequestStateByTurn = /* @__PURE__ */ new Map();
263009
263164
  currentStep = 0;
263010
263165
  cognitiveLifecycle;
263011
263166
  cognitiveLifecycleUnavailable = false;
@@ -263698,6 +263853,7 @@ var init_turn = __esmMin((() => {
263698
263853
  this.cognitiveExternalReportsByTurn.delete(turnId);
263699
263854
  this.cognitiveLocalClaimsByTurn.delete(turnId);
263700
263855
  this.stepFailureByTurn.delete(turnId);
263856
+ this.stepRequestStateByTurn.delete(turnId);
263701
263857
  await this.agent.records.flush();
263702
263858
  await this.agent.records.writeResumeCheckpoint();
263703
263859
  return {
@@ -263841,6 +263997,8 @@ var init_turn = __esmMin((() => {
263841
263997
  log: this.agent.log,
263842
263998
  maxSteps: loopControl?.maxStepsPerTurn,
263843
263999
  maxRetryAttempts: loopControl?.maxRetriesPerStep,
264000
+ checkpointBeforeToolExecution: () => this.agent.records.flush(),
264001
+ checkpointBeforeRetryWait: () => this.agent.records.flush(),
263844
264002
  recordStepUsage: async (usage) => {
263845
264003
  try {
263846
264004
  stopForGoalBudget = (await this.agent.goal.recordTokenUsage(grandTotal(usage)))?.budget.overBudget === true;
@@ -264038,14 +264196,25 @@ var init_turn = __esmMin((() => {
264038
264196
  toolOutput: isError === true ? void 0 : toolOutputText(output).slice(0, 2e3)
264039
264197
  }
264040
264198
  });
264041
- return budgetToolResultForModel({
264199
+ const budgetedResult = await budgetToolResultForModel({
264042
264200
  homedir: this.agent.homedir,
264043
264201
  toolName: ctx.toolCall.name,
264044
264202
  toolCallId: ctx.toolCall.id,
264045
264203
  toolArgs: ctx.args,
264046
264204
  result: finalResult,
264205
+ contextTokens: this.agent.context.tokenCountWithPending,
264206
+ maxContextTokens: this.agent.config.modelCapabilities.max_context_tokens,
264047
264207
  telemetry: this.agent.telemetry
264048
264208
  });
264209
+ if (budgetedResult !== finalResult) this.agent.records.logRecord({
264210
+ type: "policy.intervention",
264211
+ policy: "tool_result_spill",
264212
+ location: "budgetToolResultForModel",
264213
+ size_before: toolOutputText(finalResult.output).length,
264214
+ size_after: toolOutputText(budgetedResult.output).length,
264215
+ unit: "chars"
264216
+ });
264217
+ return budgetedResult;
264049
264218
  }
264050
264219
  }
264051
264220
  })).stopReason;
@@ -264094,6 +264263,26 @@ var init_turn = __esmMin((() => {
264094
264263
  emitLiveEvent: (event) => {
264095
264264
  this.noteFirstRequestEvent(event);
264096
264265
  this.trackLoopTelemetry(event, turnId);
264266
+ if (event.type === "thinking.delta" && event.delta.trim().length === 0) {
264267
+ const requestState = this.stepRequestStateByTurn.get(turnId);
264268
+ this.agent.records.logRecord({
264269
+ type: "thinking.heartbeat",
264270
+ turn_id: turnId,
264271
+ step: this.currentStepByTurn.get(turnId) ?? this.currentStep,
264272
+ attempt: requestState?.attempt ?? 1,
264273
+ max_attempts: requestState?.maxAttempts,
264274
+ completion_budget: requestState?.completionBudget,
264275
+ thinking_effort: requestState?.thinkingEffort
264276
+ });
264277
+ }
264278
+ if (event.type === "step.retrying" && event.completionBudgetBefore !== void 0 && event.completionBudgetAfter !== void 0) this.agent.records.logRecord({
264279
+ type: "policy.intervention",
264280
+ policy: "empty_response_completion_budget_retry",
264281
+ location: "chatWithRetry",
264282
+ size_before: event.completionBudgetBefore,
264283
+ size_after: event.completionBudgetAfter,
264284
+ unit: "tokens"
264285
+ });
264097
264286
  const mapped = mapLoopEvent(event, turnId);
264098
264287
  if (mapped !== void 0) return this.agent.emitEvent(mapped);
264099
264288
  }
@@ -264117,9 +264306,18 @@ var init_turn = __esmMin((() => {
264117
264306
  }
264118
264307
  trackLoopTelemetry(event, turnId) {
264119
264308
  if (event.type === "step.begin") {
264120
- this.beginTrackedStep(turnId, event.step);
264309
+ this.beginTrackedStep(turnId, event.step, event);
264121
264310
  return;
264122
264311
  }
264312
+ if (event.type === "step.retrying") {
264313
+ const previous = this.stepRequestStateByTurn.get(turnId) ?? {};
264314
+ this.stepRequestStateByTurn.set(turnId, {
264315
+ ...previous,
264316
+ attempt: event.nextAttempt,
264317
+ maxAttempts: event.maxAttempts,
264318
+ completionBudget: event.completionBudgetAfter ?? previous.completionBudget
264319
+ });
264320
+ }
264123
264321
  if (event.type === "turn.interrupted") {
264124
264322
  if (event.reason === "error" && event.activeStep !== void 0) this.stepFailureByTurn.set(turnId, event);
264125
264323
  this.trackTurnInterrupted(turnId, interruptedStep(event));
@@ -264127,9 +264325,15 @@ var init_turn = __esmMin((() => {
264127
264325
  }
264128
264326
  this.trackToolLifecycle(event, turnId);
264129
264327
  }
264130
- beginTrackedStep(turnId, step) {
264328
+ beginTrackedStep(turnId, step, event) {
264131
264329
  this.currentStepByTurn.set(turnId, step);
264132
264330
  this.currentStep = step;
264331
+ this.stepRequestStateByTurn.set(turnId, {
264332
+ thinkingEffort: event?.thinkingEffort,
264333
+ completionBudget: event?.completionBudget,
264334
+ attempt: event?.attempt ?? 1,
264335
+ maxAttempts: event?.maxAttempts
264336
+ });
264133
264337
  if (!this.stepToolCallKeys.has(step)) this.stepToolCallKeys.set(step, /* @__PURE__ */ new Set());
264134
264338
  }
264135
264339
  trackToolLifecycle(event, turnId) {
@@ -265838,7 +266042,7 @@ var init_builtin = __esmMin((() => {
265838
266042
  var init_types$3 = __esmMin((() => {}));
265839
266043
  //#endregion
265840
266044
  //#region ../../packages/agent-core/src/agent/tool/index.ts
265841
- var import_picomatch, profileToolExclusionPolicy, applyProfileToolExclusions, shouldRecordUserToolUnregister, SHELL_FOREGROUND_TIMEOUT_S, ToolManager;
266045
+ var import_picomatch, profileToolExclusionPolicy, applyProfileToolExclusions, shouldRecordUserToolUnregister, createFileObservationPolicy, SHELL_FOREGROUND_TIMEOUT_S, ToolManager;
265842
266046
  var init_tool$1 = __esmMin((() => {
265843
266047
  init_dist$4();
265844
266048
  import_picomatch = /* @__PURE__ */ __toESM(require_picomatch(), 1);
@@ -265854,6 +266058,7 @@ var init_tool$1 = __esmMin((() => {
265854
266058
  profileToolExclusionPolicy = createRequire(import.meta.url)("./bin/profile-tool-exclusion-policy.cjs");
265855
266059
  applyProfileToolExclusions = profileToolExclusionPolicy.applyProfileToolExclusions;
265856
266060
  ({ shouldRecordUserToolUnregister } = createRequire(import.meta.url)("./bin/user-tool-record-policy.cjs"));
266061
+ ({ createFileObservationPolicy } = createRequire(import.meta.url)("./bin/file-observation-policy.cjs"));
265857
266062
  SHELL_FOREGROUND_TIMEOUT_S = 120;
265858
266063
  ToolManager = class {
265859
266064
  agent;
@@ -266258,11 +266463,12 @@ var init_tool$1 = __esmMin((() => {
266258
266463
  contextTokens: this.agent.context.tokenCountWithPending,
266259
266464
  maxContextTokens: this.agent.fullCompaction.getEffectiveMaxContextTokens()
266260
266465
  });
266466
+ const fileObservation = createFileObservationPolicy({ pathClass: kaos.pathClass() });
266261
266467
  this.builtinTools = new Map([
266262
- new ReadTool(kaos, workspace, readBudget),
266263
- new ReadBatchTool(kaos, workspace, readBudget),
266264
- new WriteTool(kaos, workspace, () => this.agent.context.history, toolServices?.lsp),
266265
- new EditTool(kaos, workspace, () => this.agent.context.history, toolServices?.lsp),
266468
+ new ReadTool(kaos, workspace, readBudget, fileObservation),
266469
+ new ReadBatchTool(kaos, workspace, readBudget, fileObservation),
266470
+ new WriteTool(kaos, workspace, () => this.agent.context.history, toolServices?.lsp, fileObservation),
266471
+ new EditTool(kaos, workspace, () => this.agent.context.history, toolServices?.lsp, fileObservation),
266266
266472
  new GrepTool(kaos, workspace, this.agent.telemetry),
266267
266473
  new GlobTool(kaos, workspace, this.agent.telemetry),
266268
266474
  new BashTool(kaos, cwd, background, { allowBackground }),
@@ -266692,7 +266898,7 @@ var init_llm_request_logger = __esmMin((() => {
266692
266898
  function normalizeRuntimeSystemPromptAppend(value) {
266693
266899
  return value?.trim().slice(0, 16e3) ?? "";
266694
266900
  }
266695
- var PINNED_MODEL_ALIASES, createEffectiveSystemPromptResolver, resolveProviderIdleTimeoutMs, capCompletionBudgetForAdaptiveEffort, capTurnCompletionTokens, selectThinkingEffortForBufferedSteer, selectThinkingEffortForWorkStep, selectThinkingEffortForTurn, Agent$1;
266901
+ var PINNED_MODEL_ALIASES, createEffectiveSystemPromptResolver, resolveProviderIdleTimeoutMs, capCompletionBudgetForAdaptiveEffort, selectThinkingEffortForBufferedSteer, selectThinkingEffortForWorkStep, selectThinkingEffortForTurn, Agent$1;
266696
266902
  var init_agent = __esmMin((() => {
266697
266903
  init_dist$6();
266698
266904
  init_config$4();
@@ -266731,7 +266937,7 @@ var init_agent = __esmMin((() => {
266731
266937
  init_error_memory();
266732
266938
  ({ createEffectiveSystemPromptResolver } = createRequire(import.meta.url)("./bin/effective-system-prompt-cache-policy.cjs"));
266733
266939
  ({ resolveProviderIdleTimeoutMs } = createRequire(import.meta.url)("./bin/provider-idle-timeout-policy.cjs"));
266734
- ({ capCompletionBudgetForAdaptiveEffort, capTurnCompletionTokens, selectThinkingEffortForBufferedSteer, selectThinkingEffortForWorkStep, selectThinkingEffortForTurn } = createRequire(import.meta.url)("./bin/turn-thinking-policy.cjs"));
266940
+ ({ capCompletionBudgetForAdaptiveEffort, selectThinkingEffortForBufferedSteer, selectThinkingEffortForWorkStep, selectThinkingEffortForTurn } = createRequire(import.meta.url)("./bin/turn-thinking-policy.cjs"));
266735
266941
  PINNED_MODEL_ALIASES = new Set(["blun/king"]);
266736
266942
  Agent$1 = class {
266737
266943
  type;
@@ -266926,7 +267132,7 @@ var init_agent = __esmMin((() => {
266926
267132
  const provider = thinkingEffort === void 0 ? runtimeModel.provider : runtimeModel.provider.withThinking(thinkingEffort);
266927
267133
  const loopControl = this.blunConfig?.loopControl;
266928
267134
  const completionBudgetConfig = resolveCompletionBudget({
266929
- maxOutputSize: capTurnCompletionTokens(runtimeModel.maxOutputSize),
267135
+ maxOutputSize: runtimeModel.maxOutputSize,
266930
267136
  reservedContextSize: loopControl?.reservedContextSize
266931
267137
  });
266932
267138
  return new KosongLLM({
@@ -343755,7 +343961,7 @@ const DEFAULT_NOTIFICATIONS_CONFIG = {
343755
343961
  enabled: true,
343756
343962
  condition: "unfocused"
343757
343963
  };
343758
- const DEFAULT_UPGRADE_PREFERENCES = { autoInstall: true };
343964
+ const DEFAULT_UPGRADE_PREFERENCES = { autoInstall: false };
343759
343965
  /**
343760
343966
  * F2 Tippen-mit-Vorschlag: Code-Sprachen standardmäßig an, md/plain aus.
343761
343967
  * Unbekannte Sprachen fallen auf "an" zurück (Opt-out über tui.toml).
@@ -409266,6 +409472,9 @@ var TUI = class TUI extends Container {
409266
409472
  setClearOnShrink(enabled) {
409267
409473
  this.clearOnShrink = enabled;
409268
409474
  }
409475
+ getRenderHeight() {
409476
+ return this.terminal.rows;
409477
+ }
409269
409478
  setFocus(component) {
409270
409479
  this.setFocusInternal({
409271
409480
  component,
@@ -409874,7 +410083,7 @@ var TUI = class TUI extends Container {
409874
410083
  doRender() {
409875
410084
  if (this.stopped) return;
409876
410085
  const width = this.terminal.columns;
409877
- const height = this.terminal.rows;
410086
+ const height = this.getRenderHeight();
409878
410087
  const widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;
409879
410088
  const heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;
409880
410089
  const previousBufferLength = this.previousHeight > 0 ? this.previousViewportTop + this.previousHeight : height;
@@ -493584,12 +493793,28 @@ registerUiCatalogFragment({
493584
493793
  en: {
493585
493794
  "thinking.label": "{name} thinking",
493586
493795
  "thinking.aborted": "aborted",
493796
+ "thinking.step": "step {step}",
493797
+ "thinking.effort": "effort {effort}",
493798
+ "thinking.attempt": "attempt {attempt}/{maxAttempts}",
493799
+ "thinking.budget": "budget {budget}",
493800
+ "thinking.heartbeat": "hidden-thought heartbeat {seconds}s ago",
493801
+ "thinking.worked": "Worked {elapsed}",
493802
+ "thinking.finished": "done {time}",
493803
+ "thinking.emptyRetry": "Empty model response; {hint} · budget {before} → {after}",
493587
493804
  "thinking.tokens.one": "{count} Token",
493588
493805
  "thinking.tokens.other": "{count} Tokens"
493589
493806
  },
493590
493807
  de: {
493591
493808
  "thinking.label": "{name} denkt",
493592
493809
  "thinking.aborted": "abgebrochen",
493810
+ "thinking.step": "Schritt {step}",
493811
+ "thinking.effort": "Effort {effort}",
493812
+ "thinking.attempt": "Versuch {attempt}/{maxAttempts}",
493813
+ "thinking.budget": "Budget {budget}",
493814
+ "thinking.heartbeat": "Verdecktes Denken läuft · letzter Takt vor {seconds}s",
493815
+ "thinking.worked": "Gearbeitet {elapsed}",
493816
+ "thinking.finished": "fertig {time}",
493817
+ "thinking.emptyRetry": "Leere Modellantwort; {hint} · Budget {before} → {after}",
493593
493818
  "thinking.tokens.one": "{count} Token",
493594
493819
  "thinking.tokens.other": "{count} Tokens"
493595
493820
  },
@@ -493643,6 +493868,14 @@ var ThinkingComponent = class {
493643
493868
  thinkElapsedMs = 0;
493644
493869
  thinkAborted = false;
493645
493870
  estimatedOutputTokens = 0;
493871
+ step;
493872
+ thinkingEffort;
493873
+ attempt = 1;
493874
+ maxAttempts = 1;
493875
+ completionBudget;
493876
+ lastHeartbeatAtMs;
493877
+ activeToolName;
493878
+ finishedAtMs;
493646
493879
  textComponent;
493647
493880
  renderCache;
493648
493881
  constructor(text, showMarker = true, mode = "finalized", ui, metrics) {
@@ -493657,6 +493890,7 @@ var ThinkingComponent = class {
493657
493890
  this.thinkStartMs = metrics?.startedAtMs ?? Date.now();
493658
493891
  this.thinkAborted = false;
493659
493892
  this.estimatedOutputTokens = metrics?.estimatedOutputTokens ?? 0;
493893
+ this.applyLiveMetrics(metrics ?? {});
493660
493894
  }
493661
493895
  }
493662
493896
  markRenderDirty() {
@@ -493675,10 +493909,22 @@ var ThinkingComponent = class {
493675
493909
  }
493676
493910
  setLiveMetrics(metrics) {
493677
493911
  if (this.mode === "live" && !this.thinkAborted && metrics.startedAtMs !== void 0) this.thinkStartMs = metrics.startedAtMs;
493678
- if (metrics.estimatedOutputTokens === this.estimatedOutputTokens) return;
493912
+ const before = JSON.stringify([this.estimatedOutputTokens, this.step, this.thinkingEffort, this.attempt, this.maxAttempts, this.completionBudget, this.lastHeartbeatAtMs, this.activeToolName]);
493679
493913
  this.estimatedOutputTokens = metrics.estimatedOutputTokens;
493914
+ this.applyLiveMetrics(metrics);
493915
+ const after = JSON.stringify([this.estimatedOutputTokens, this.step, this.thinkingEffort, this.attempt, this.maxAttempts, this.completionBudget, this.lastHeartbeatAtMs, this.activeToolName]);
493916
+ if (before === after) return;
493680
493917
  this.markRenderDirty();
493681
493918
  }
493919
+ applyLiveMetrics(metrics) {
493920
+ this.step = metrics.step;
493921
+ this.thinkingEffort = metrics.thinkingEffort;
493922
+ this.attempt = metrics.attempt ?? 1;
493923
+ this.maxAttempts = metrics.maxAttempts ?? 1;
493924
+ this.completionBudget = metrics.completionBudget;
493925
+ this.lastHeartbeatAtMs = metrics.lastHeartbeatAtMs;
493926
+ this.activeToolName = metrics.activeToolName;
493927
+ }
493682
493928
  styled(text) {
493683
493929
  return currentTheme.italicFg("textDim", text);
493684
493930
  }
@@ -493690,6 +493936,7 @@ var ThinkingComponent = class {
493690
493936
  this.thinkElapsedMs = Date.now() - this.thinkStartMs;
493691
493937
  this.thinkStartMs = null;
493692
493938
  }
493939
+ this.finishedAtMs = Date.now();
493693
493940
  }
493694
493941
  dispose() {
493695
493942
  this.stopSpinner();
@@ -493713,12 +493960,24 @@ var ThinkingComponent = class {
493713
493960
  const abortMark = this.thinkAborted ? ` (${uiText("thinking.aborted")})` : "";
493714
493961
  const tokenKey = roundedTokenCount === 1 ? "thinking.tokens.one" : "thinking.tokens.other";
493715
493962
  const thinkingLabel = uiText("thinking.label", { name: this.persona });
493716
- const fullLabel = `${thinkingLabel}… (${elapsed} · ↓ ~${uiText(tokenKey, { count: tokenCount })} · ${startedAt})${abortMark}`;
493717
- const compactLabel = `${thinkingLabel}… (${elapsed} · ↓${tokenCount} · ${startedAt})${abortMark}`;
493963
+ const details = [];
493964
+ if (this.step !== void 0) details.push(uiText("thinking.step", { step: this.step }));
493965
+ if (this.thinkingEffort !== void 0) details.push(uiText("thinking.effort", { effort: this.thinkingEffort }));
493966
+ if (this.attempt > 1 || this.maxAttempts > 1) details.push(uiText("thinking.attempt", { attempt: this.attempt, maxAttempts: this.maxAttempts }));
493967
+ if (this.completionBudget !== void 0) details.push(uiText("thinking.budget", { budget: this.completionBudget.toLocaleString(locale) }));
493968
+ if (this.lastHeartbeatAtMs !== void 0) details.push(uiText("thinking.heartbeat", { seconds: Math.max(0, Math.floor((Date.now() - this.lastHeartbeatAtMs) / 1e3)) }));
493969
+ if (this.activeToolName !== void 0) details.push(this.activeToolName);
493970
+ const detailText = details.length === 0 ? "" : ` · ${details.join(" · ")}`;
493971
+ const fullLabel = `${thinkingLabel}… (${elapsed} · ↓ ~${uiText(tokenKey, { count: tokenCount })}${detailText} · ${startedAt})${abortMark}`;
493972
+ const compactLabel = `${thinkingLabel}… (${elapsed} · ↓${tokenCount}${this.step === void 0 ? "" : ` · #${this.step}`} · ${startedAt})${abortMark}`;
493718
493973
  const metricsOnly = `(${elapsed} · ${startedAt})${abortMark}`;
493719
493974
  const availableWidth = Math.max(1, width - visibleWidth(spinner));
493720
493975
  const label = visibleWidth(fullLabel) <= availableWidth ? fullLabel : visibleWidth(compactLabel) <= availableWidth ? compactLabel : metricsOnly;
493721
493976
  rendered = ["", spinner + currentTheme.fg("textDim", truncateToWidth(label, availableWidth))];
493977
+ } else if (this.thinkElapsedMs > 0) {
493978
+ const finishedAt = new Date(this.finishedAtMs ?? Date.now()).toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit" });
493979
+ const finalLabel = `${uiText("thinking.worked", { elapsed: formatLiveElapsed(this.formatElapsedSeconds()) })} · ${uiText("thinking.finished", { time: finishedAt })}`;
493980
+ rendered = ["", currentTheme.fg("textDim", truncateToWidth(finalLabel, Math.max(1, width)))];
493722
493981
  } else rendered = [""];
493723
493982
  if (isRenderCacheEnabled()) this.renderCache = {
493724
493983
  width,
@@ -508308,6 +508567,9 @@ var BottomPinnedTUI = class extends TUI {
508308
508567
  * page-up/down jumps without re-reading the live (possibly stale) value.
508309
508568
  */
508310
508569
  getTerminalRows() {
508570
+ return this.getRenderHeight();
508571
+ }
508572
+ getRenderHeight() {
508311
508573
  this.ensureResizeLatch();
508312
508574
  return this.latchedTerminalRows > 0 ? this.latchedTerminalRows : currentTerminalRows(this.terminal.rows);
508313
508575
  }
@@ -510438,7 +510700,7 @@ var SessionEventHandler = class {
510438
510700
  this.host.commitQueuedSteerAtStepStart(event.turnId);
510439
510701
  this.host.commitChannelPromptAtStepStart(event.turnId);
510440
510702
  this.host.streamingUI.flushNow();
510441
- this.host.streamingUI.setStep(event.step);
510703
+ this.host.streamingUI.beginStep(event);
510442
510704
  this.host.streamingUI.resetToolUi();
510443
510705
  this.host.streamingUI.finalizeLiveTextBuffers("waiting");
510444
510706
  this.host.patchLivePane({
@@ -510512,7 +510774,8 @@ var SessionEventHandler = class {
510512
510774
  handleStepRetrying(event) {
510513
510775
  this.turnWatchdog.recordProgress();
510514
510776
  const hint = formatModelRetryProgress(event);
510515
- if (event.outputMayHaveStarted === true) {
510777
+ const completionBudgetRetry = event.completionBudgetBefore !== void 0 && event.completionBudgetAfter !== void 0;
510778
+ if (event.outputMayHaveStarted === true || completionBudgetRetry) {
510516
510779
  const { streamingUI } = this.host;
510517
510780
  streamingUI.flushNow();
510518
510781
  streamingUI.discardUnfinishedToolUi();
@@ -510522,9 +510785,14 @@ var SessionEventHandler = class {
510522
510785
  kind: "status",
510523
510786
  turnId: String(event.turnId),
510524
510787
  renderMode: "plain",
510525
- content: uiText("sessionEvent.interrupted.reason", { reason: hint })
510788
+ content: completionBudgetRetry ? uiText("thinking.emptyRetry", {
510789
+ hint,
510790
+ before: event.completionBudgetBefore.toLocaleString(getCurrentUiLocale()),
510791
+ after: event.completionBudgetAfter.toLocaleString(getCurrentUiLocale())
510792
+ }) : uiText("sessionEvent.interrupted.reason", { reason: hint })
510526
510793
  });
510527
510794
  }
510795
+ this.host.streamingUI.noteStepRetry(event);
510528
510796
  this.modelRetryHint = hint;
510529
510797
  this.host.state.footer.setTransientHint(hint);
510530
510798
  this.host.state.ui.requestRender();
@@ -510540,6 +510808,7 @@ var SessionEventHandler = class {
510540
510808
  handleThinkingDelta(event) {
510541
510809
  const { state, streamingUI } = this.host;
510542
510810
  if (event.delta.length === 0 && !streamingUI.hasThinkingDraft()) return;
510811
+ if (event.delta.trim().length === 0) streamingUI.noteThinkingHeartbeat();
510543
510812
  if (event.delta.length > 0) this.turnWatchdog.recordProgress();
510544
510813
  if (event.delta.length > 0) this.clearModelRetryHint();
510545
510814
  streamingUI.appendThinkingDelta(event.delta);
@@ -513582,6 +513851,9 @@ var StreamingUIController = class {
513582
513851
  _remoteTurnActivity = { active: false };
513583
513852
  _remoteProcessStartedAt = new Date(Date.now() - process.uptime() * 1e3).toISOString();
513584
513853
  _liveTurnStartedAtMs = void 0;
513854
+ _liveStepStartedAtMs = void 0;
513855
+ _liveThinkingHeartbeatAtMs = void 0;
513856
+ _liveStepRequest = {};
513585
513857
  _liveOutputTokens = new LiveOutputTokenCounter();
513586
513858
  _countedToolCallIds = /* @__PURE__ */ new Set();
513587
513859
  _assistantDraft = "";
@@ -513612,6 +513884,32 @@ var StreamingUIController = class {
513612
513884
  this._currentStep = step;
513613
513885
  this.publishTelegramConsoleStatus();
513614
513886
  }
513887
+ beginStep(event) {
513888
+ this.setStep(event.step);
513889
+ this._liveStepStartedAtMs = Date.now();
513890
+ this._liveThinkingHeartbeatAtMs = void 0;
513891
+ this._liveOutputTokens.reset();
513892
+ this._countedToolCallIds.clear();
513893
+ this._liveStepRequest = {
513894
+ thinkingEffort: event.thinkingEffort,
513895
+ completionBudget: event.completionBudget,
513896
+ attempt: event.attempt ?? 1,
513897
+ maxAttempts: event.maxAttempts ?? 1
513898
+ };
513899
+ }
513900
+ noteStepRetry(event) {
513901
+ this._liveStepStartedAtMs = Date.now();
513902
+ this._liveThinkingHeartbeatAtMs = void 0;
513903
+ this._liveStepRequest = {
513904
+ ...this._liveStepRequest,
513905
+ attempt: event.nextAttempt,
513906
+ maxAttempts: event.maxAttempts,
513907
+ completionBudget: event.completionBudgetAfter ?? this._liveStepRequest.completionBudget
513908
+ };
513909
+ }
513910
+ noteThinkingHeartbeat() {
513911
+ this._liveThinkingHeartbeatAtMs = Date.now();
513912
+ }
513615
513913
  setRemoteTurnActivity(activity) {
513616
513914
  const previous = this._remoteTurnActivity;
513617
513915
  this._remoteTurnActivity = activity?.active === true ? activity : { active: false };
@@ -513640,14 +513938,25 @@ var StreamingUIController = class {
513640
513938
  }
513641
513939
  beginLiveTurn() {
513642
513940
  this._liveTurnStartedAtMs = Date.now();
513941
+ this._liveStepStartedAtMs = void 0;
513942
+ this._liveThinkingHeartbeatAtMs = void 0;
513943
+ this._liveStepRequest = {};
513643
513944
  this._liveOutputTokens.reset();
513644
513945
  this._countedToolCallIds.clear();
513645
513946
  this.lastFlushAt = void 0;
513646
513947
  }
513647
513948
  getLiveActivityMetrics() {
513949
+ const activeToolName = [...this._activeToolCalls.values()].at(-1)?.name ?? [...this._streamingToolCallArguments.values()].at(-1)?.name;
513648
513950
  return {
513649
- startedAtMs: this._liveTurnStartedAtMs,
513650
- estimatedOutputTokens: this._liveOutputTokens.estimatedOutputTokens()
513951
+ startedAtMs: this._liveStepStartedAtMs ?? this._liveTurnStartedAtMs,
513952
+ estimatedOutputTokens: this._liveOutputTokens.estimatedOutputTokens(),
513953
+ step: this._currentStep,
513954
+ thinkingEffort: this._liveStepRequest.thinkingEffort,
513955
+ completionBudget: this._liveStepRequest.completionBudget,
513956
+ attempt: this._liveStepRequest.attempt ?? 1,
513957
+ maxAttempts: this._liveStepRequest.maxAttempts ?? 1,
513958
+ lastHeartbeatAtMs: this._liveThinkingHeartbeatAtMs,
513959
+ activeToolName
513651
513960
  };
513652
513961
  }
513653
513962
  recordLiveOutput(fragment) {
@@ -513688,6 +513997,9 @@ var StreamingUIController = class {
513688
513997
  }
513689
513998
  resetLiveActivity() {
513690
513999
  this._liveTurnStartedAtMs = void 0;
514000
+ this._liveStepStartedAtMs = void 0;
514001
+ this._liveThinkingHeartbeatAtMs = void 0;
514002
+ this._liveStepRequest = {};
513691
514003
  this._liveOutputTokens.reset();
513692
514004
  this._countedToolCallIds.clear();
513693
514005
  }