blun-king-cli 9.1.536 → 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.
Files changed (129) hide show
  1. package/LIESMICH.txt +13 -869
  2. package/README.md +41 -833
  3. package/bin/assistant-message-offload-policy.cjs +3 -1
  4. package/bin/compaction-transaction-policy.cjs +122 -0
  5. package/bin/context-performance-policy.cjs +2 -5
  6. package/bin/context-pressure-policy.cjs +20 -0
  7. package/bin/cron-run-output.cjs +45 -0
  8. package/bin/cron-run-store.cjs +145 -0
  9. package/bin/default-model-output-budget-policy.cjs +28 -0
  10. package/bin/durable-task-resume-policy.cjs +130 -0
  11. package/bin/durable-task-resume-runtime.cjs +117 -0
  12. package/bin/durable-task-resume-store.cjs +88 -0
  13. package/bin/editable-tool-approval-policy.cjs +540 -0
  14. package/bin/editable-tool-approval-runtime.cjs +99 -0
  15. package/bin/file-observation-policy.cjs +133 -0
  16. package/bin/html-to-research-markdown.cjs +146 -0
  17. package/bin/launcher-runtime.js +0 -1
  18. package/bin/micro-compaction-policy.cjs +64 -0
  19. package/bin/mnemo-connect-heartbeat.cjs +1 -3
  20. package/bin/programmatic-tool-runtime.mjs +330 -4
  21. package/bin/read-continuation-policy.cjs +36 -5
  22. package/bin/retry-checkpoint-policy.cjs +13 -0
  23. package/bin/scoped-cron-run-policy.cjs +358 -0
  24. package/bin/session-checkpoint-policy.cjs +25 -0
  25. package/bin/startup-preferences.cjs +4 -3
  26. package/bin/structured-agent-swarm-output.cjs +325 -0
  27. package/bin/subagent-context-fork-policy.cjs +155 -0
  28. package/bin/subagent-skill-policy.cjs +204 -0
  29. package/bin/telegram-approval-relay.cjs +2 -1
  30. package/bin/tool-file-persistence.cjs +141 -0
  31. package/bin/tool-result-offload-policy.cjs +25 -33
  32. package/bin/turn-thinking-policy.cjs +2 -26
  33. package/bin/update-notice.js +30 -18
  34. package/bin/user-message-offload-policy.cjs +3 -1
  35. package/blun.mjs +1564 -640
  36. package/codebase-index/README.md +12 -0
  37. package/codebase-index/codebase_index.py +129 -18
  38. package/package.json +23 -58
  39. package/telegram-plugin/bin/telegram-mnemo-capture.cjs +1 -3
  40. package/telegram-plugin/bin/telegram-typing-keepalive.cjs +89 -0
  41. package/telegram-plugin/dist/bridge.mjs +8 -1
  42. package/CHANGELOG.md +0 -321
  43. package/agent-spine-plugin/CHANGELOG.md +0 -406
  44. package/agent-spine-plugin/CONTRIBUTING.md +0 -52
  45. package/agent-spine-plugin/README.md +0 -344
  46. package/agent-spine-plugin/SECURITY.md +0 -47
  47. package/agent-spine-plugin/docs/acceptance.md +0 -61
  48. package/agent-spine-plugin/docs/architecture.md +0 -183
  49. package/agent-spine-plugin/docs/attention.md +0 -121
  50. package/agent-spine-plugin/docs/automatic-continuity.md +0 -79
  51. package/agent-spine-plugin/docs/channel-runtime.md +0 -92
  52. package/agent-spine-plugin/docs/coordination.md +0 -138
  53. package/agent-spine-plugin/docs/feed-transport.md +0 -99
  54. package/agent-spine-plugin/docs/gateway-runtime.md +0 -116
  55. package/agent-spine-plugin/docs/harness-reference.md +0 -45
  56. package/agent-spine-plugin/docs/host-integration.md +0 -129
  57. package/agent-spine-plugin/docs/https-transport.md +0 -116
  58. package/agent-spine-plugin/docs/learning.md +0 -133
  59. package/agent-spine-plugin/docs/object-transport.md +0 -93
  60. package/agent-spine-plugin/docs/peer-transport.md +0 -88
  61. package/agent-spine-plugin/docs/preflight-recall.md +0 -69
  62. package/agent-spine-plugin/docs/preservation-contract.md +0 -53
  63. package/agent-spine-plugin/docs/quality-gates.md +0 -50
  64. package/agent-spine-plugin/docs/relationships.md +0 -73
  65. package/agent-spine-plugin/docs/releasing.md +0 -83
  66. package/agent-spine-plugin/docs/roadmap.md +0 -307
  67. package/agent-spine-plugin/docs/selfstarter.md +0 -88
  68. package/agent-spine-plugin/docs/session-briefing.md +0 -74
  69. package/agent-spine-plugin/docs/shared-memory.md +0 -259
  70. package/agent-spine-plugin/docs/source-roots.md +0 -86
  71. package/agent-spine-plugin/docs/sqlite-transport.md +0 -76
  72. package/agent-spine-plugin/scripts/check-hosts.js +0 -195
  73. package/agent-spine-plugin/scripts/check-install.js +0 -569
  74. package/agent-spine-plugin/scripts/check-syntax.js +0 -29
  75. package/agent-spine-plugin/scripts/github-actions.js +0 -11
  76. package/agent-spine-plugin/scripts/release-check.js +0 -128
  77. package/agent-spine-plugin/scripts/run-acceptance.js +0 -19
  78. package/agent-spine-plugin/scripts/run-checks.js +0 -46
  79. package/agent-spine-plugin/scripts/run-tests-hermetic.js +0 -73
  80. package/agent-spine-plugin/spine-example/1-identity.md +0 -12
  81. package/agent-spine-plugin/spine-example/2-voice.md +0 -6
  82. package/agent-spine-plugin/spine-example/3-conduct.md +0 -8
  83. package/agent-spine-plugin/spine-example/4-history.md +0 -4
  84. package/bin/empty-response-retry-policy.cjs +0 -29
  85. package/bin/fredrik-glm-provider.cjs +0 -256
  86. package/bin/package-regression-policy.cjs +0 -77
  87. package/fredrik-glm-profile.toml.example +0 -26
  88. package/release-planned-removals.json +0 -15
  89. package/scripts/check-active-profile-plugin-startup.js +0 -36
  90. package/scripts/check-active-work-steer-regression.js +0 -46
  91. package/scripts/check-approval-observability-regression.js +0 -111
  92. package/scripts/check-approval-queue-shortcuts-regression.js +0 -65
  93. package/scripts/check-bundled-agent-spine-regression.js +0 -48
  94. package/scripts/check-codebase-search-packaging-regression.js +0 -92
  95. package/scripts/check-copy-command-regression.js +0 -74
  96. package/scripts/check-current-turn-read-pin-mutation-regression.js +0 -72
  97. package/scripts/check-current-turn-read-pin-regression.js +0 -94
  98. package/scripts/check-deepseek-native-max-regression.js +0 -49
  99. package/scripts/check-empty-response-effort-downgrade-regression.js +0 -48
  100. package/scripts/check-fredrik-glm-mutation-regression.js +0 -18
  101. package/scripts/check-fredrik-glm-regression.js +0 -169
  102. package/scripts/check-historical-tool-result-preview-regression.js +0 -77
  103. package/scripts/check-history-pressure-offload-regression.js +0 -77
  104. package/scripts/check-mcp-startup-wait-budget.js +0 -48
  105. package/scripts/check-package-regression.js +0 -38
  106. package/scripts/check-plugin-startup-regression.js +0 -53
  107. package/scripts/check-programmatic-context-isolation-regression.js +0 -193
  108. package/scripts/check-programmatic-tool-regression.js +0 -294
  109. package/scripts/check-queue-controls-regression.js +0 -189
  110. package/scripts/check-release-metadata.js +0 -103
  111. package/scripts/check-reload-agent-spine-regression.js +0 -76
  112. package/scripts/check-resume-replay-regression.js +0 -102
  113. package/scripts/check-session-cancel-regression.js +0 -43
  114. package/scripts/check-session-picker-resume-metrics-regression.js +0 -97
  115. package/scripts/check-session-start-hook-context-regression.js +0 -228
  116. package/scripts/check-shell-terminal-isolation-regression.js +0 -81
  117. package/scripts/check-slash-escape-regression.js +0 -89
  118. package/scripts/check-startup-swarm-command-regression.js +0 -24
  119. package/scripts/check-structured-subagent-output-regression.js +0 -331
  120. package/scripts/check-telegram-bridge-watchdog.js +0 -60
  121. package/scripts/check-telegram-direct-work-resume-regression.js +0 -53
  122. package/scripts/check-telegram-loop-exactly-once-regression.js +0 -71
  123. package/scripts/check-todo-loop-regression.js +0 -78
  124. package/scripts/check-todo-progress-regression.js +0 -416
  125. package/scripts/check-todo-recovery-catalog-regression.js +0 -50
  126. package/scripts/check-tool-schema-capacity-regression.js +0 -40
  127. package/scripts/programmatic-tool-runtime.test.mjs +0 -365
  128. package/scripts/structured-subagent-output.test.cjs +0 -170
  129. /package/{scripts → bin}/fix-node-pty-perms.js +0 -0
package/blun.mjs CHANGED
@@ -1,10 +1,11 @@
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);
6
6
  const __dirname = __cjsShimDirname(__filename);
7
7
  import { createRequire } from "node:module";
8
+ const { htmlToResearchMarkdown } = createRequire(import.meta.url)("./bin/html-to-research-markdown.cjs");
8
9
  import telegramConsoleStatusPolicy from "./bin/telegram-console-status-policy.cjs";
9
10
  import cognitiveGoalAutostartPolicy from "./bin/cognitive-goal-autostart-policy.cjs";
10
11
  import cognitiveGoalTimeTriggerController from "./bin/cognitive-goal-time-trigger-controller.cjs";
@@ -16,7 +17,8 @@ import sessionScrollbackArchive from "./bin/session-scrollback-archive.cjs";
16
17
  import sessionReplayWindowPolicy from "./bin/session-replay-window-policy.cjs";
17
18
  import globPatternPolicy from "./bin/glob-pattern-policy.cjs";
18
19
  import userHomePathPolicy from "./bin/user-home-path-policy.cjs";
19
- import fredrikGlmProviderPolicy from "./bin/fredrik-glm-provider.cjs";
20
+ import editableToolApprovalPolicy from "./bin/editable-tool-approval-policy.cjs";
21
+ import editableToolApprovalRuntime from "./bin/editable-tool-approval-runtime.cjs";
20
22
  import crypto$1, { createHash, randomBytes, randomInt, randomUUID, timingSafeEqual } from "node:crypto";
21
23
  import * as fs$16 from "node:fs";
22
24
  import Kt, { accessSync, appendFileSync, chmodSync, closeSync, constants, copyFileSync, createReadStream, createWriteStream, existsSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, promises, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
@@ -58,17 +60,13 @@ const { replayWindowStartIndex, resolveReplayActiveTurnCount } = sessionReplayWi
58
60
  const { globPatternError } = globPatternPolicy;
59
61
  const { unsupportedUserHomePathError } = userHomePathPolicy;
60
62
  const {
61
- PROVIDER_ID: FREDRIK_GLM_PROVIDER_ID,
62
- PROVIDER_TYPE: FREDRIK_GLM_PROVIDER_TYPE,
63
- MODEL_EFFORTS: FREDRIK_GLM_EFFORTS,
64
- configuredModels: configuredFredrikGlmModels,
65
- configuredProvider: configuredFredrikGlmProvider,
66
- isAllowedRuntimeAlias: isAllowedFredrikRuntimeAlias,
67
- isConfiguredAlias: isConfiguredFredrikGlmAlias,
68
- normalizeEffort: normalizeFredrikGlmEffort,
69
- requestControls: fredrikGlmRequestControls,
70
- readApiKeyFile: readFredrikGlmApiKeyFile
71
- } = fredrikGlmProviderPolicy;
63
+ buildApprovalEditedEvent,
64
+ canonicalEditedToolInputJson,
65
+ isEditableToolApprovalEligible,
66
+ parseEditedToolInputJson,
67
+ validateEditedApprovalDecision
68
+ } = editableToolApprovalPolicy;
69
+ const { buildEditedToolCallPlan } = editableToolApprovalRuntime;
72
70
  import { EventEmitter as EventEmitter$1 } from "node:events";
73
71
  import { StringDecoder } from "node:string_decoder";
74
72
  import co from "node:assert";
@@ -2733,7 +2731,6 @@ var init_blun = __esmMin((() => {
2733
2731
  _defaultHeaders;
2734
2732
  _generationKwargs;
2735
2733
  _supportEfforts;
2736
- _openAICompatible;
2737
2734
  _client;
2738
2735
  _clientFactory;
2739
2736
  _files;
@@ -2747,7 +2744,6 @@ var init_blun = __esmMin((() => {
2747
2744
  this._stream = options.stream ?? true;
2748
2745
  this._generationKwargs = { ...options.generationKwargs };
2749
2746
  this._supportEfforts = options.supportEfforts ?? [];
2750
- this._openAICompatible = options.openAICompatible === true;
2751
2747
  this._client = this._apiKey === void 0 ? void 0 : createFetchHttpClient({
2752
2748
  apiKey: this._apiKey,
2753
2749
  baseUrl: this._baseUrl,
@@ -2802,8 +2798,6 @@ var init_blun = __esmMin((() => {
2802
2798
  }
2803
2799
  const kwargs = { ...this._generationKwargs };
2804
2800
  for (const key of Object.keys(kwargs)) if (kwargs[key] === void 0) delete kwargs[key];
2805
- if (kwargs["max_completion_tokens"] === void 0 && kwargs["max_tokens"] !== void 0) kwargs["max_completion_tokens"] = kwargs["max_tokens"];
2806
- delete kwargs["max_tokens"];
2807
2801
  const { extra_body: extraBody, ...requestKwargs } = kwargs;
2808
2802
  const extraBodyRecord = typeof extraBody === "object" && extraBody !== null ? { ...extraBody } : {};
2809
2803
  const thinking = sanitizeThinkingConfig(extraBodyRecord.thinking);
@@ -2859,17 +2853,8 @@ var init_blun = __esmMin((() => {
2859
2853
  delete requestExtraBody["model"];
2860
2854
  delete requestExtraBody["messages"];
2861
2855
  if (!thinkingDisabled && thinking?.keep !== void 0) requestExtraBody["thinking"] = { keep: thinking.keep };
2862
- let reasoningRequested;
2863
- if (this._openAICompatible) {
2864
- delete requestKwargs["chat_template_kwargs"];
2865
- const controls = fredrikGlmRequestControls(effectiveThinkingEffort ?? "max");
2866
- requestExtraBody["thinking"] = controls.thinking;
2867
- requestExtraBody["reasoning_effort"] = controls.reasoning_effort;
2868
- reasoningRequested = true;
2869
- } else {
2870
- const effectiveTemplateKwargs = requestKwargs["chat_template_kwargs"];
2871
- reasoningRequested = typeof effectiveTemplateKwargs === "object" && effectiveTemplateKwargs !== null && effectiveTemplateKwargs.thinking === true;
2872
- }
2856
+ const effectiveTemplateKwargs = requestKwargs["chat_template_kwargs"];
2857
+ const reasoningRequested = typeof effectiveTemplateKwargs === "object" && effectiveTemplateKwargs !== null && effectiveTemplateKwargs.thinking === true;
2873
2858
  const createParams = {
2874
2859
  model: this._model,
2875
2860
  messages,
@@ -2923,7 +2908,7 @@ var init_blun = __esmMin((() => {
2923
2908
  withMaxCompletionTokens(maxCompletionTokens, options) {
2924
2909
  let cap = maxCompletionTokens;
2925
2910
  if (options?.usedContextTokens !== void 0 && options?.maxContextTokens !== void 0 && options.maxContextTokens > 0) cap = Math.min(cap, options.maxContextTokens - options.usedContextTokens);
2926
- return this._withGenerationKwargs({ max_completion_tokens: Math.max(1, cap) });
2911
+ return this._withGenerationKwargs({ max_tokens: Math.max(1, cap) });
2927
2912
  }
2928
2913
  withExtraBody(extraBody) {
2929
2914
  const oldExtra = this._generationKwargs.extra_body ?? {};
@@ -10013,7 +9998,7 @@ var init_schema = __esmMin((() => {
10013
9998
  init_matches_rule();
10014
9999
  init_errors$8();
10015
10000
  init_zod$1();
10016
- ProviderTypeSchema = union([literal("blun"), literal("openai_compatible")]);
10001
+ ProviderTypeSchema = literal("blun");
10017
10002
  OAuthRefSchema = object({
10018
10003
  storage: _enum(["file", "keyring"]),
10019
10004
  key: string().min(1),
@@ -10023,7 +10008,6 @@ var init_schema = __esmMin((() => {
10023
10008
  ProviderConfigSchema = object({
10024
10009
  type: ProviderTypeSchema,
10025
10010
  apiKey: string().optional(),
10026
- apiKeyFile: string().optional(),
10027
10011
  baseUrl: string().optional(),
10028
10012
  defaultModel: string().optional(),
10029
10013
  oauth: OAuthRefSchema.optional(),
@@ -14687,7 +14671,7 @@ async function refreshProviderModels(host, options = {}) {
14687
14671
  var BLUN_LOCAL_PROVIDER_NAME;
14688
14672
  var init_refreshProviderModels = __esmMin((() => {
14689
14673
  init_managed_blun();
14690
- BLUN_LOCAL_PROVIDER_NAME = "king-blun";
14674
+ BLUN_LOCAL_PROVIDER_NAME = "blun";
14691
14675
  }));
14692
14676
  //#endregion
14693
14677
  //#region ../../packages/oauth/src/index.ts
@@ -15945,6 +15929,8 @@ function loadRuntimeConfigSafe(filePath, env = process.env) {
15945
15929
  } catch (error) {
15946
15930
  envWarnings.push(`Ignoring BLUN_MODEL_* environment overrides: ${describeUnknownError(error)}`);
15947
15931
  }
15932
+ const { applyDefaultModelOutputBudget } = createRequire(import.meta.url)("./bin/default-model-output-budget-policy.cjs");
15933
+ config = applyDefaultModelOutputBudget(config);
15948
15934
  return {
15949
15935
  config,
15950
15936
  fileWarnings,
@@ -21405,7 +21391,10 @@ var init_flags = __esmMin((() => {
21405
21391
  var RawSubagentProfileSchema, RawAgentProfileSchema;
21406
21392
  var init_types$13 = __esmMin((() => {
21407
21393
  init_zod$1();
21408
- RawSubagentProfileSchema = object({ description: string().optional() });
21394
+ RawSubagentProfileSchema = object({
21395
+ description: string().optional(),
21396
+ skills: array(string()).optional()
21397
+ });
21409
21398
  RawAgentProfileSchema = object({
21410
21399
  extends: string().optional(),
21411
21400
  name: string().min(1),
@@ -28499,10 +28488,13 @@ function linkResolvedSubagents(mergedProfiles, resolvedProfiles) {
28499
28488
  for (const [ownerName, owner] of mergedProfiles) {
28500
28489
  if (owner.subagents === void 0) continue;
28501
28490
  const subagents = {};
28502
- for (const subagentName of Object.keys(owner.subagents)) {
28491
+ for (const [subagentName, subagentBinding] of Object.entries(owner.subagents)) {
28503
28492
  const target = resolvedProfiles.get(subagentName);
28504
28493
  if (target === void 0) throwMissingSubagent(ownerName, subagentName);
28505
- subagents[subagentName] = target;
28494
+ subagents[subagentName] = subagentBinding.skills === void 0 ? target : {
28495
+ ...target,
28496
+ subagentSkills: [...subagentBinding.skills]
28497
+ };
28506
28498
  }
28507
28499
  const resolved = resolvedProfiles.get(ownerName);
28508
28500
  if (resolved !== void 0) resolved.subagents = subagents;
@@ -28568,10 +28560,12 @@ var init_load = __esmMin((() => {
28568
28560
  //#region ../../packages/agent-core/src/profile/default/agent.yaml?raw
28569
28561
  var agent_default$1;
28570
28562
  var init_agent$3 = __esmMin((() => {
28571
- agent_default$1 = "name: agent\ndescription: Default BLUN King agent\n\nsystemPromptPath: ./system.md\npromptVars:\n roleAdditional: ''\n\ntools:\n - Read\n - Write\n - Edit\n - Grep\n - Glob\n - Bash\n - TaskList\n - TaskOutput\n - TaskUpdate\n - TaskStop\n - CronCreate\n - CronList\n - CronDelete\n - ReadMediaFile\n - TodoList\n - Skill\n - WebSearch\n - Agent\n - AgentSwarm\n - FetchURL\n - GenerateImage\n - GenerateVideo\n - GenerateSpeech\n - UnderstandImage\n - UnderstandVideo\n - DubVideo\n - LipSyncMedia\n - GetMedia\n - AskUserQuestion\n - MistakeRecord\n - CodebaseSearch\n - EnterPlanMode\n - ExitPlanMode\n - CreateGoal\n - GetGoal\n - SetGoalBudget\n - UpdateGoal\n - mcp__*\n\nsubagents:\n coder:\n description: General software engineering agent — the only subagent type with file-editing tools; use it for any delegated task that must modify code.\n explore:\n description: Fast codebase exploration with prompt-enforced read-only behavior.\n plan:\n description: Read-only implementation planning and architecture design.\n";
28563
+ agent_default$1 = "name: agent\ndescription: Default BLUN King agent\n\nsystemPromptPath: ./system.md\npromptVars:\n roleAdditional: ''\n\ntools:\n - Read\n - Write\n - Edit\n - Grep\n - Glob\n - Bash\n - TaskList\n - TaskOutput\n - TaskUpdate\n - TaskResume\n - TaskStop\n - CronCreate\n - CronList\n - CronDelete\n - ReadMediaFile\n - TodoList\n - Skill\n - WebSearch\n - Agent\n - AgentSwarm\n - FetchURL\n - GenerateImage\n - GenerateVideo\n - GenerateSpeech\n - UnderstandImage\n - UnderstandVideo\n - DubVideo\n - LipSyncMedia\n - GetMedia\n - AskUserQuestion\n - MistakeRecord\n - CodebaseSearch\n - EnterPlanMode\n - ExitPlanMode\n - CreateGoal\n - GetGoal\n - SetGoalBudget\n - UpdateGoal\n - mcp__*\n\nsubagents:\n coder:\n description: General software engineering agent — the only subagent type with file-editing tools; use it for any delegated task that must modify code.\n explore:\n description: Fast codebase exploration with prompt-enforced read-only behavior.\n plan:\n description: Read-only implementation planning and architecture design.\n";
28564
+ agent_default$1 = agent_default$1.replace(" plan:\n", " research:\n description: Read-only web and source research with an explicit two-skill allowlist.\n skills:\n - web-lesen\n - premortem\n plan:\n");
28572
28565
  agent_default$1 = agent_default$1.replace(" - Read\n", " - Read\n - ReadBatch\n");
28573
28566
  agent_default$1 = agent_default$1.replace(" - TodoList\n", " - TodoList\n - CompactConversation\n");
28574
28567
  agent_default$1 = agent_default$1.replace(" - CodebaseSearch\n", " - CodebaseSearch\n - ProgrammaticTool\n");
28568
+ agent_default$1 = agent_default$1.replace(" - CronList\n", " - CronList\n - CronRunList\n - CronRunOutput\n");
28575
28569
  }));
28576
28570
  //#endregion
28577
28571
  //#region ../../packages/agent-core/src/profile/default/coder.yaml?raw
@@ -28590,6 +28584,13 @@ var init_explore = __esmMin((() => {
28590
28584
  explore_default = explore_default.replace(" - ReadBatch\n", " - ReadBatch\n - ProgrammaticTool\n");
28591
28585
  }));
28592
28586
  //#endregion
28587
+ //#region ../../packages/agent-core/src/profile/default/research.yaml?raw
28588
+ var research_default;
28589
+ var init_research = __esmMin((() => {
28590
+ init_explore();
28591
+ research_default = explore_default.replace("name: explore\n", "name: research\n").replace("Fast agent specialized for exploring codebases.", "Read-only agent specialized for source and web research with profile-scoped skills.");
28592
+ }));
28593
+ //#endregion
28593
28594
  //#region ../../packages/agent-core/src/profile/default/init.md?raw
28594
28595
  var init_default$2;
28595
28596
  var init_init = __esmMin((() => {
@@ -28620,6 +28621,7 @@ var init_default$1 = __esmMin((() => {
28620
28621
  coder_default = coder_default.replace("\nwhenToUse:", "\nexcludedTools:\n - mcp__plugin-telegram_telegram__reply\n - mcp__plugin-telegram_telegram__react\n - mcp__plugin-telegram_telegram__edit_message\n - mcp__plugin-telegram_telegram__download_attachment\n\nwhenToUse:");
28621
28622
  init_explore();
28622
28623
  explore_default = explore_default.replace("\nwhenToUse:", "\nexcludedTools:\n - mcp__plugin-telegram_telegram__reply\n - mcp__plugin-telegram_telegram__react\n - mcp__plugin-telegram_telegram__edit_message\n - mcp__plugin-telegram_telegram__download_attachment\n\nwhenToUse:");
28624
+ init_research();
28623
28625
  init_init();
28624
28626
  init_plan$1();
28625
28627
  plan_default = plan_default.replace("\nwhenToUse:", "\nexcludedTools:\n - mcp__plugin-telegram_telegram__reply\n - mcp__plugin-telegram_telegram__react\n - mcp__plugin-telegram_telegram__edit_message\n - mcp__plugin-telegram_telegram__download_attachment\n\nwhenToUse:");
@@ -28630,6 +28632,7 @@ var init_default$1 = __esmMin((() => {
28630
28632
  "profile/default/agent.yaml": agent_default$1,
28631
28633
  "profile/default/coder.yaml": coder_default,
28632
28634
  "profile/default/explore.yaml": explore_default,
28635
+ "profile/default/research.yaml": research_default,
28633
28636
  "profile/default/plan.yaml": plan_default,
28634
28637
  "profile/default/system.md": system_default
28635
28638
  };
@@ -28638,6 +28641,7 @@ var init_default$1 = __esmMin((() => {
28638
28641
  "agent.yaml",
28639
28642
  "coder.yaml",
28640
28643
  "explore.yaml",
28644
+ "research.yaml",
28641
28645
  "plan.yaml"
28642
28646
  ].map((file) => `profile/default/${file}`), PROFILE_SOURCES);
28643
28647
  }));
@@ -29132,6 +29136,9 @@ var init_agent_task = __esmMin((() => {
29132
29136
  runInBackground;
29133
29137
  parentToolCallId;
29134
29138
  responseFormat;
29139
+ resumed;
29140
+ replacesTaskId;
29141
+ resumeRootTaskId;
29135
29142
  kind = "agent";
29136
29143
  idPrefix = "agent";
29137
29144
  agentId;
@@ -29145,6 +29152,9 @@ var init_agent_task = __esmMin((() => {
29145
29152
  this.runInBackground = options.runInBackground;
29146
29153
  this.parentToolCallId = options.parentToolCallId;
29147
29154
  this.responseFormat = options.responseFormat;
29155
+ this.resumed = options.resumed;
29156
+ this.replacesTaskId = options.replacesTaskId;
29157
+ this.resumeRootTaskId = options.resumeRootTaskId;
29148
29158
  this.agentId = handle.agentId;
29149
29159
  this.subagentType = handle.profileName;
29150
29160
  }
@@ -29197,7 +29207,10 @@ var init_agent_task = __esmMin((() => {
29197
29207
  timeoutMs: this.continuationTimeoutMs,
29198
29208
  kind: "agent",
29199
29209
  agentId: this.agentId,
29200
- subagentType: this.subagentType
29210
+ subagentType: this.subagentType,
29211
+ resumed: this.resumed,
29212
+ replacesTaskId: this.replacesTaskId,
29213
+ resumeRootTaskId: this.resumeRootTaskId
29201
29214
  };
29202
29215
  }
29203
29216
  };
@@ -29470,6 +29483,11 @@ function buildBackgroundTaskNotificationBody(info) {
29470
29483
  if (info.status === "completed") return baseLine;
29471
29484
  const agentId = info.agentId;
29472
29485
  if (agentId === void 0 || agentId === info.taskId) return baseLine;
29486
+ if (info.status === "lost") return `${baseLine}${[
29487
+ "",
29488
+ `To recover this interrupted background run explicitly, call TaskResume(task_id="${info.taskId}", prompt="Inspect the preserved state and continue without repeating completed side effects.", description="Resume ${info.description}").`,
29489
+ `TaskResume keeps agent_id "${agentId}" and its context, creates a new linked task_id, and never runs automatically at startup.`
29490
+ ].join("\n")}`;
29473
29491
  return `${baseLine}${[
29474
29492
  "",
29475
29493
  `To recover or continue this subagent, call Agent(resume="${agentId}", prompt="Pick up where you left off; redo the last tool call if its result was never observed.").`,
@@ -29478,7 +29496,7 @@ function buildBackgroundTaskNotificationBody(info) {
29478
29496
  "The subagent retains its full prior context across the restart, but any in-flight tool call lost its result and may need to be redone."
29479
29497
  ].join("\n")}`;
29480
29498
  }
29481
- var MAX_OUTPUT_BYTES$2, NOTIFICATION_FALLBACK_PREVIEW_BYTES, MAX_FOREGROUND_CAPTURE_BYTES, captureForegroundOutputChunk, createAbortOutcome, SIGTERM_GRACE_MS$1, USER_INTERRUPT_REASON$1, _ALPHABET, BackgroundManager;
29499
+ var MAX_OUTPUT_BYTES$2, NOTIFICATION_FALLBACK_PREVIEW_BYTES, MAX_FOREGROUND_CAPTURE_BYTES, captureForegroundOutputChunk, createAbortOutcome, DurableTaskResumeStore$1, decorateTaskInfo$1, SIGTERM_GRACE_MS$1, USER_INTERRUPT_REASON$1, _ALPHABET, BackgroundManager;
29482
29500
  var init_background = __esmMin((() => {
29483
29501
  init_dist$4();
29484
29502
  init_errors$4();
@@ -29494,13 +29512,17 @@ var init_background = __esmMin((() => {
29494
29512
  NOTIFICATION_FALLBACK_PREVIEW_BYTES = 3e3;
29495
29513
  ({ MAX_FOREGROUND_CAPTURE_BYTES, captureForegroundOutputChunk } = createRequire(import.meta.url)("./bin/foreground-output-capture-policy.cjs"));
29496
29514
  ({ createAbortOutcome } = createRequire(import.meta.url)("./bin/abort-listener-policy.cjs"));
29515
+ ({ DurableTaskResumeStore: DurableTaskResumeStore$1 } = createRequire(import.meta.url)("./bin/durable-task-resume-store.cjs"));
29516
+ ({ decorateTaskInfo: decorateTaskInfo$1 } = createRequire(import.meta.url)("./bin/durable-task-resume-policy.cjs"));
29497
29517
  SIGTERM_GRACE_MS$1 = 5e3;
29498
29518
  USER_INTERRUPT_REASON$1 = "Interrupted by user";
29499
29519
  _ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz";
29500
29520
  BackgroundManager = class {
29501
29521
  agent;
29502
29522
  persistence;
29523
+ resumeStore;
29503
29524
  tasks = /* @__PURE__ */ new Map();
29525
+ reservedTaskIds = /* @__PURE__ */ new Set();
29504
29526
  /**
29505
29527
  * Ghosts: tasks loaded from disk during reconcile that have no live
29506
29528
  * KaosProcess. They appear in `list()` / `getTask()` with status
@@ -29512,6 +29534,7 @@ var init_background = __esmMin((() => {
29512
29534
  constructor(agent, persistence) {
29513
29535
  this.agent = agent;
29514
29536
  this.persistence = persistence;
29537
+ this.resumeStore = persistence?.sessionDir ? new DurableTaskResumeStore$1(persistence.sessionDir) : void 0;
29515
29538
  }
29516
29539
  fireTerminalEffects(entry) {
29517
29540
  if (!this.isDetached(entry)) return;
@@ -29555,6 +29578,13 @@ var init_background = __esmMin((() => {
29555
29578
  isDetached(entry) {
29556
29579
  return entry.foregroundRelease === void 0;
29557
29580
  }
29581
+ reserveTaskId(prefix) {
29582
+ let taskId;
29583
+ do taskId = generateTaskId(prefix);
29584
+ while (this.tasks.has(taskId) || this.ghosts.has(taskId) || this.reservedTaskIds.has(taskId) || this.resumeStore?.list().some((intent) => intent.replacementTaskId === taskId));
29585
+ this.reservedTaskIds.add(taskId);
29586
+ return taskId;
29587
+ }
29558
29588
  registerTask(task, options = {}) {
29559
29589
  const detached = options.detached ?? true;
29560
29590
  const entryOptions = {
@@ -29564,7 +29594,10 @@ var init_background = __esmMin((() => {
29564
29594
  signal: detached ? void 0 : options.signal
29565
29595
  };
29566
29596
  this.assertCanRegister(detached);
29567
- const taskId = generateTaskId(task.idPrefix);
29597
+ const taskId = options.taskId ?? this.reserveTaskId(task.idPrefix);
29598
+ if (!VALID_TASK_ID$1.test(taskId)) throw new Error(`Invalid task id: "${taskId}"`);
29599
+ if (this.tasks.has(taskId) || this.ghosts.has(taskId)) throw new Error(`Task id already exists: ${taskId}`);
29600
+ this.reservedTaskIds.delete(taskId);
29568
29601
  const entry = {
29569
29602
  taskId,
29570
29603
  task,
@@ -29598,8 +29631,8 @@ var init_background = __esmMin((() => {
29598
29631
  /** Get info about a specific task. Falls back to reconcile ghosts. */
29599
29632
  getTask(taskId) {
29600
29633
  const entry = this.tasks.get(taskId);
29601
- if (entry !== void 0) return this.toInfo(entry);
29602
- return this.ghosts.get(taskId);
29634
+ const info = entry !== void 0 ? this.toInfo(entry) : this.ghosts.get(taskId);
29635
+ return decorateTaskInfo$1(info, this.resumeStore?.getBySourceTaskId(taskId));
29603
29636
  }
29604
29637
  updateAgentTask(taskId, message) {
29605
29638
  const entry = this.tasks.get(taskId);
@@ -29622,12 +29655,13 @@ var init_background = __esmMin((() => {
29622
29655
  list(activeOnly = true, limit) {
29623
29656
  const result = [];
29624
29657
  for (const entry of this.tasks.values()) {
29625
- const info = this.toInfo(entry);
29658
+ const info = decorateTaskInfo$1(this.toInfo(entry), this.resumeStore?.getBySourceTaskId(entry.taskId));
29626
29659
  if (!this.shouldListTask(info, activeOnly)) continue;
29627
29660
  result.push(info);
29628
29661
  if (limit !== void 0 && result.length >= limit) return result;
29629
29662
  }
29630
- if (!activeOnly) for (const ghost of this.ghosts.values()) {
29663
+ if (!activeOnly) for (const storedGhost of this.ghosts.values()) {
29664
+ const ghost = decorateTaskInfo$1(storedGhost, this.resumeStore?.getBySourceTaskId(storedGhost.taskId));
29631
29665
  if (!this.shouldListTask(ghost, activeOnly)) continue;
29632
29666
  result.push(ghost);
29633
29667
  if (limit !== void 0 && result.length >= limit) return result;
@@ -29775,6 +29809,7 @@ var init_background = __esmMin((() => {
29775
29809
  async loadFromDisk() {
29776
29810
  const persistence = this.persistence;
29777
29811
  if (persistence === void 0) return;
29812
+ await this.resumeStore?.load();
29778
29813
  this.ghosts.clear();
29779
29814
  const persisted = await persistence.listTasks();
29780
29815
  for (const t of persisted) {
@@ -29820,6 +29855,11 @@ var init_background = __esmMin((() => {
29820
29855
  entry.persistWriteQueue = entry.persistWriteQueue.then(() => persistence.writeTask(info)).catch(() => {});
29821
29856
  return entry.persistWriteQueue;
29822
29857
  }
29858
+ async awaitTaskPersisted(taskId) {
29859
+ const entry = this.tasks.get(taskId);
29860
+ if (entry === void 0) throw new Error(`Task not found: ${taskId}`);
29861
+ await entry.persistWriteQueue;
29862
+ }
29823
29863
  appendOutput(entry, chunk) {
29824
29864
  const capture = this.isDetached(entry) ? {
29825
29865
  capturedText: chunk,
@@ -30307,7 +30347,6 @@ function resolveCompletionBudget(args) {
30307
30347
  const fromLegacy = parseEnvBudget(env["BLUN_MODEL_MAX_TOKENS"]);
30308
30348
  if (fromLegacy !== "absent") return fromLegacy === "disabled" ? void 0 : { hardCap: fromLegacy };
30309
30349
  if (args.maxOutputSize !== void 0 && args.maxOutputSize > 0) return { hardCap: args.maxOutputSize };
30310
- if (args.reservedContextSize !== void 0 && args.reservedContextSize > 0) return { fallback: args.reservedContextSize };
30311
30350
  return { fallback: DEFAULT_UNKNOWN_CONTEXT_FALLBACK };
30312
30351
  }
30313
30352
  function parseEnvBudget(raw) {
@@ -30360,13 +30399,12 @@ function applyCompletionBudgetWithDetails(args) {
30360
30399
  var MIN_FLOOR, DEFAULT_UNKNOWN_CONTEXT_FALLBACK, MIN_THINKING_COMPLETION_TOKENS, COMPLETION_CONTEXT_SAFETY_MARGIN;
30361
30400
  var init_completion_budget = __esmMin((() => {
30362
30401
  MIN_FLOOR = 1;
30363
- DEFAULT_UNKNOWN_CONTEXT_FALLBACK = 32e3;
30402
+ DEFAULT_UNKNOWN_CONTEXT_FALLBACK = 65536;
30364
30403
  MIN_THINKING_COMPLETION_TOKENS = 1024;
30365
30404
  COMPLETION_CONTEXT_SAFETY_MARGIN = 1e4;
30366
30405
  }));
30367
30406
  //#endregion
30368
30407
  //#region ../../packages/agent-core/src/loop/retry.ts
30369
- var { nextThinkingEffortForExhaustedEmpty } = createRequire(import.meta.url)("./bin/empty-response-retry-policy.cjs");
30370
30408
  async function chatWithRetry(input) {
30371
30409
  const maxAttempts = input.maxAttempts ?? 3;
30372
30410
  if (input.llm.isRetryableError === void 0 || maxAttempts <= 1) {
@@ -30380,10 +30418,9 @@ async function chatWithRetry(input) {
30380
30418
  }
30381
30419
  const delays = retryBackoffDelays(maxAttempts);
30382
30420
  let completionBudgetRetry;
30383
- let thinkingEffortRetry;
30384
30421
  let emptyRetryKind;
30385
30422
  for (let attempt = 1;; attempt += 1) try {
30386
- return await input.llm.chat(paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry, thinkingEffortRetry));
30423
+ return await input.llm.chat(paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry));
30387
30424
  } catch (error) {
30388
30425
  if (error instanceof APIEmptyResponseError && (emptyRetryKind !== void 0 || error.emptyResponseKind === "length" || error.emptyResponseKind === "stop")) {
30389
30426
  logEmptyResponse(input, error, attempt);
@@ -30393,24 +30430,24 @@ async function chatWithRetry(input) {
30393
30430
  throw terminal;
30394
30431
  }
30395
30432
  completionBudgetRetry = completionBudgetRetryForEmpty(error);
30396
- thinkingEffortRetry = nextThinkingEffortForExhaustedEmpty({
30397
- emptyResponseKind: error.emptyResponseKind,
30398
- maxCompletionTokens: error.maxCompletionTokens,
30399
- completionTokens: error.completionTokens,
30400
- thinkingEffort: input.llm.thinkingEffort
30401
- });
30402
30433
  emptyRetryKind = error.emptyResponseKind;
30403
30434
  input.params.signal.throwIfAborted();
30404
- input.dispatchEvent({
30405
- type: "step.retrying",
30406
- turnId: input.turnId,
30407
- step: input.currentStep,
30408
- stepUuid: input.stepUuid,
30409
- failedAttempt: attempt,
30410
- nextAttempt: attempt + 1,
30411
- maxAttempts,
30412
- delayMs: 0,
30413
- ...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
+ }
30414
30451
  });
30415
30452
  continue;
30416
30453
  }
@@ -30420,17 +30457,22 @@ async function chatWithRetry(input) {
30420
30457
  }
30421
30458
  const delayMs = retryDelayForError(error, delays[attempt - 1] ?? 0);
30422
30459
  input.params.signal.throwIfAborted();
30423
- input.dispatchEvent({
30424
- type: "step.retrying",
30425
- turnId: input.turnId,
30426
- step: input.currentStep,
30427
- stepUuid: input.stepUuid,
30428
- failedAttempt: attempt,
30429
- nextAttempt: attempt + 1,
30430
- maxAttempts,
30431
- delayMs,
30432
- outputMayHaveStarted: input.llm.didErrorEmitPartialOutput?.(error) === true,
30433
- ...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
+ }
30434
30476
  });
30435
30477
  await sleepForRetry(delayMs, input.params.signal);
30436
30478
  }
@@ -30442,6 +30484,14 @@ function completionBudgetRetryForEmpty(error) {
30442
30484
  multiplier: 2
30443
30485
  };
30444
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
+ }
30445
30495
  function retryDelayForError(error, fallbackDelayMs) {
30446
30496
  if (!(error instanceof APIProviderRateLimitError) || error.retryAfterMs === null) return fallbackDelayMs;
30447
30497
  return Math.max(fallbackDelayMs, error.retryAfterMs);
@@ -30455,12 +30505,11 @@ function logRequestFailure(input, error, attempt, maxAttempts) {
30455
30505
  ...retryErrorFields(error)
30456
30506
  });
30457
30507
  }
30458
- function paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry, thinkingEffortRetry) {
30508
+ function paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry) {
30459
30509
  const turnStep = `${input.turnId}.${String(input.currentStep)}`;
30460
30510
  return {
30461
30511
  ...input.params,
30462
30512
  completionBudgetRetry,
30463
- thinkingEffortRetry,
30464
30513
  requestLogFields: attempt === 1 ? { turnStep } : {
30465
30514
  turnStep,
30466
30515
  attempt: `${String(attempt)}/${String(maxAttempts)}`
@@ -30468,19 +30517,12 @@ function paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry, th
30468
30517
  };
30469
30518
  }
30470
30519
  function logEmptyResponse(input, error, attempt) {
30471
- const retryThinkingEffort = nextThinkingEffortForExhaustedEmpty({
30472
- emptyResponseKind: error.emptyResponseKind,
30473
- maxCompletionTokens: error.maxCompletionTokens,
30474
- completionTokens: error.completionTokens,
30475
- thinkingEffort: input.llm.thinkingEffort
30476
- });
30477
30520
  input.log?.warn(`[leer] fall=${error.emptyResponseKind}`, {
30478
30521
  turnStep: `${input.turnId}.${String(input.currentStep)}`,
30479
30522
  attempt,
30480
30523
  budget: error.maxCompletionTokens,
30481
30524
  completion: error.completionTokens,
30482
- reasoningLength: error.reasoningLength,
30483
- ...retryThinkingEffort === void 0 ? {} : { retryThinkingEffort }
30525
+ reasoningLength: error.reasoningLength
30484
30526
  });
30485
30527
  }
30486
30528
  function retryBackoffDelays(maxAttempts) {
@@ -30508,7 +30550,7 @@ function maybeStatusCode(error) {
30508
30550
  const statusCode = error.statusCode;
30509
30551
  return typeof statusCode === "number" ? statusCode : void 0;
30510
30552
  }
30511
- 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;
30512
30554
  var init_retry = __esmMin((() => {
30513
30555
  init_dist$4();
30514
30556
  init_src$4();
@@ -30516,6 +30558,7 @@ var init_retry = __esmMin((() => {
30516
30558
  init_abort();
30517
30559
  init_completion_budget();
30518
30560
  init_errors$4();
30561
+ ({ persistRetrySchedule } = createRequire(import.meta.url)("./bin/retry-checkpoint-policy.cjs"));
30519
30562
  RETRY_MIN_TIMEOUT_MS = 300;
30520
30563
  RETRY_MAX_TIMEOUT_MS = 5e3;
30521
30564
  RETRY_FACTOR = 2;
@@ -30653,7 +30696,7 @@ var init_programmatic_tool = __esmMin((() => {
30653
30696
  PROGRAMMATIC_TOOL_NAME = "ProgrammaticTool";
30654
30697
  ProgrammaticTool = class {
30655
30698
  name = PROGRAMMATIC_TOOL_NAME;
30656
- description = "Run bounded JavaScript in an isolated QuickJS interpreter to coordinate several sequential BLUN tool calls without returning every intermediate value to the model context. Declare every callable tool explicitly with its current BLUN name and a JavaScript alias. Calls still pass through the normal schema, hook, permission, scheduler, event, and result pipeline; denied or unavailable tools fail inside the program. The interpreter has no host filesystem, network, process, package loader, clock, or dynamic eval. Return a JSON-serializable result and use the JSON state object only for explicit continuation.";
30699
+ description = "Run bounded JavaScript in an isolated QuickJS interpreter to coordinate several sequential BLUN tool calls without returning every intermediate value to the model context. Declare every callable tool explicitly with its current BLUN name and a JavaScript alias. Calls still pass through the normal schema, hook, permission, scheduler, event, and result pipeline; denied or unavailable tools fail inside the program. The interpreter has no host filesystem, network, process, package loader, clock, or dynamic eval. Use bounded console.log, console.warn, or console.error diagnostics when needed. Return a JSON-serializable result and use the JSON state object only for explicit continuation.";
30657
30700
  parameters = {
30658
30701
  type: "object",
30659
30702
  properties: {
@@ -30724,8 +30767,13 @@ var init_programmatic_tool = __esmMin((() => {
30724
30767
  if (context.invokeTool.stopTurn === true) result.stopTurn = true;
30725
30768
  return result;
30726
30769
  } catch (error) {
30770
+ const message = error instanceof Error ? error.message : String(error);
30771
+ const programmaticConsole = error && typeof error === "object" ? error.programmaticConsole : void 0;
30727
30772
  const result = {
30728
- output: error instanceof Error ? error.message : String(error),
30773
+ output: programmaticConsole ? JSON.stringify({
30774
+ error: message,
30775
+ console: programmaticConsole
30776
+ }) : message,
30729
30777
  isError: true
30730
30778
  };
30731
30779
  if (context.invokeTool.stopTurn === true) result.stopTurn = true;
@@ -74888,6 +74936,25 @@ var init_kosong_llm = __esmMin((() => {
74888
74936
  get thinkingEffort() {
74889
74937
  return this.provider.thinkingEffort;
74890
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
+ }
74891
74958
  notifyMediaDropped(dropped) {
74892
74959
  if (this.onMediaDropped === void 0) return;
74893
74960
  const fresh = dropped.filter((part) => {
@@ -74930,25 +74997,12 @@ var init_kosong_llm = __esmMin((() => {
74930
74997
  let result;
74931
74998
  let completionBudget;
74932
74999
  try {
74933
- const requestProvider = params.thinkingEffortRetry === void 0 ? this.provider : this.provider.withThinking(params.thinkingEffortRetry);
74934
75000
  const enrichedMessages = this.visionReader === void 0 ? params.messages : await enrichMessagesWithVision(params.messages, this.visionReader, params.signal, this.onVisionUsage);
74935
75001
  const tools = [...params.tools];
74936
75002
  const outgoingMessages = downgradeUnsupportedMedia(enrichedMessages, this.capability, (dropped) => {
74937
75003
  this.notifyMediaDropped(dropped);
74938
75004
  });
74939
- const outgoingRequestTokens = estimateSystemPromptTokens(this.systemPrompt) + estimateTokensForTools(tools) + estimateTokensForMessages(outgoingMessages);
74940
- const reportedContextTokens = this.reportedContextTokens?.() ?? 0;
74941
- const usedContextTokens = Math.max(outgoingRequestTokens, reportedContextTokens);
74942
- completionBudget = applyCompletionBudgetWithDetails({
74943
- provider: requestProvider,
74944
- budget: this.completionBudgetConfig,
74945
- capability: this.capability,
74946
- usedContextTokens,
74947
- retry: params.completionBudgetRetry ?? (thinkingEnabled(requestProvider.thinkingEffort) ? {
74948
- minimumCompletionTokens: 1024,
74949
- multiplier: 1
74950
- } : void 0)
74951
- });
75005
+ completionBudget = this.describeRequest(outgoingMessages, tools, params.completionBudgetRetry).details;
74952
75006
  result = await this.generate(completionBudget.provider, this.systemPrompt, tools, outgoingMessages, callbacks, options);
74953
75007
  } catch (error) {
74954
75008
  if (error instanceof APIEmptyResponseError) throw error.withMetadata({ maxCompletionTokens: completionBudget === void 0 ? null : completionBudget.maxCompletionTokens ?? null });
@@ -75471,12 +75525,13 @@ function extractCompactionSummary(response) {
75471
75525
  if (summary.trim().length === 0) throw new APIEmptyResponseError("The compaction response did not contain a non-empty summary.");
75472
75526
  return summary;
75473
75527
  }
75474
- 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;
75475
75529
  var init_full = __esmMin((() => {
75476
75530
  ({ archiveCompactionHistory, buildCompactionArchiveNotice } = createRequire(import.meta.url)("./bin/compaction-history-archive.cjs"));
75477
75531
  ({ waitForAbortableCompletion } = createRequire(import.meta.url)("./bin/abort-listener-policy.cjs"));
75478
75532
  ({ capCompactionCompletionTokens, capCompactionStageTarget } = createRequire(import.meta.url)("./bin/compaction-stage-policy.cjs"));
75479
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"));
75480
75535
  init_errors$8();
75481
75536
  init_src$4();
75482
75537
  init_errors$4();
@@ -75563,23 +75618,27 @@ var init_full = __esmMin((() => {
75563
75618
  const budget = this.strategy.compactionBudgetTokens;
75564
75619
  return budget !== void 0 && Number.isFinite(budget) && budget > 0 ? Math.floor(budget) : void 0;
75565
75620
  }
75566
- proactiveCompactionStatus() {
75567
- return proactiveCompactionEligibility({
75568
- usedTokens: this.estimateCurrentRequestTokens(),
75569
- budgetTokens: this.getCompactionBudgetTokens(),
75570
- hasShrinkableHistory: this.hasShrinkableHistory(this.agent.context.history),
75571
- isCompacting: this.isCompacting
75572
- });
75621
+ proactiveCompactionStatus(context = {}) {
75622
+ const usedTokens = this.estimateCurrentRequestTokens(context);
75623
+ return {
75624
+ ...proactiveCompactionEligibility({
75625
+ usedTokens,
75626
+ budgetTokens: this.getCompactionBudgetTokens(),
75627
+ hasShrinkableHistory: this.hasShrinkableHistory(this.agent.context.history),
75628
+ isCompacting: this.isCompacting
75629
+ }),
75630
+ usedTokens
75631
+ };
75573
75632
  }
75574
75633
  isProactiveCompactionEligible() {
75575
75634
  return this.proactiveCompactionStatus().eligible;
75576
75635
  }
75577
- requestProactiveCompaction() {
75578
- const status = this.proactiveCompactionStatus();
75636
+ requestProactiveCompaction(context = {}) {
75637
+ const status = this.proactiveCompactionStatus(context);
75579
75638
  if (!status.eligible) return status;
75580
75639
  this.proactiveCompactionRequested = true;
75581
75640
  this.agent.telemetry.track("proactive_compaction_requested", {
75582
- used_tokens: this.estimateCurrentRequestTokens(),
75641
+ used_tokens: status.usedTokens,
75583
75642
  threshold_tokens: status.thresholdTokens
75584
75643
  });
75585
75644
  return status;
@@ -75623,6 +75682,15 @@ var init_full = __esmMin((() => {
75623
75682
  }
75624
75683
  if (this.agent.context.history.length === 0) throw new BlunError(ErrorCodes.COMPACTION_UNABLE, "No messages to compact in current history.");
75625
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);
75626
75694
  this.agent.records.logRecord({
75627
75695
  type: "full_compaction.begin",
75628
75696
  ...data
@@ -75635,20 +75703,32 @@ var init_full = __esmMin((() => {
75635
75703
  const abortController = new AbortController();
75636
75704
  this.compacting = {
75637
75705
  abortController,
75638
- promise: this.compactionWorker(abortController.signal, data),
75706
+ promise: this.compactionWorker(abortController.signal, data, transaction),
75707
+ transaction,
75639
75708
  blockedByTurn: false
75640
75709
  };
75641
75710
  }
75642
- 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) {
75643
75721
  this.agent.replayBuilder.patchLast("compaction", { result: "cancelled" });
75644
75722
  if (!this.compacting) return;
75645
75723
  this.agent.records.logRecord({ type: "full_compaction.cancel" });
75724
+ this.closeTransaction(error === void 0 ? "cancelled" : "failed", error);
75646
75725
  this.compacting.abortController.abort();
75647
75726
  this.compacting = null;
75648
75727
  this.agent.emitEvent({ type: "compaction.cancelled" });
75649
75728
  }
75650
75729
  markCompleted() {
75651
75730
  this.agent.records.logRecord({ type: "full_compaction.complete" });
75731
+ this.closeTransaction("success");
75652
75732
  this.compacting = null;
75653
75733
  }
75654
75734
  get tokenCountWithPending() {
@@ -75675,9 +75755,19 @@ var init_full = __esmMin((() => {
75675
75755
  const requestMessages = requestContext.messages ?? this.agent.context.messages;
75676
75756
  const projectedMessages = requestContext.additionalMessages === void 0 ? requestMessages : [...requestMessages, ...requestContext.additionalMessages];
75677
75757
  const requestTokens = this.estimateCurrentRequestTokens(requestContext);
75678
- const proactiveStatus = this.requestProactiveCompaction();
75758
+ const proactiveStatus = this.requestProactiveCompaction(requestContext);
75679
75759
  if (proactiveStatus.eligible) {
75680
75760
  this.proactiveCompactionRequested = false;
75761
+ this.agent.records.logRecord({
75762
+ type: "policy.intervention",
75763
+ policy: "proactive_compaction_trigger",
75764
+ location: "FullCompaction.beforeStep",
75765
+ size_before: this.estimateCurrentRequestTokens(),
75766
+ size_after: proactiveStatus.usedTokens,
75767
+ unit: "tokens",
75768
+ threshold_tokens: proactiveStatus.thresholdTokens,
75769
+ selected_tool_count: requestContext.tools?.length ?? 0
75770
+ });
75681
75771
  if (!this.compacting) this.beginAutoCompaction();
75682
75772
  await this.block(signal);
75683
75773
  }
@@ -75747,9 +75837,9 @@ var init_full = __esmMin((() => {
75747
75837
  await waitForAbortableCompletion(signal, active.promise, onAbort);
75748
75838
  }
75749
75839
  }
75750
- async compactionWorker(signal, data) {
75840
+ async compactionWorker(signal, data, transaction) {
75751
75841
  try {
75752
- const output = await this.compactionRound(signal, data);
75842
+ const output = await this.compactionRound(signal, data, transaction);
75753
75843
  if (!output) return;
75754
75844
  const { result, stageCount } = output;
75755
75845
  try {
@@ -75774,9 +75864,12 @@ var init_full = __esmMin((() => {
75774
75864
  });
75775
75865
  this.triggerPostCompactHook(data, result);
75776
75866
  } catch (error) {
75777
- if (isAbortError$4(error)) return;
75867
+ if (isAbortError$4(error)) {
75868
+ if (this.compacting?.transaction === transaction) this.cancel();
75869
+ return;
75870
+ }
75778
75871
  const blockedByTurn = this.compacting?.blockedByTurn === true;
75779
- this.cancel();
75872
+ this.cancel(error);
75780
75873
  this.agent.log.error("compaction failed", { error });
75781
75874
  if (blockedByTurn) throw error;
75782
75875
  this.agent.emitEvent({
@@ -75796,7 +75889,7 @@ var init_full = __esmMin((() => {
75796
75889
  const todoMarkdown = renderTodoList(todos, "## TODO List");
75797
75890
  return `${summary.trim()}\n\n${todoMarkdown}`;
75798
75891
  }
75799
- async compactionRound(signal, data) {
75892
+ async compactionRound(signal, data, transaction) {
75800
75893
  const startedAt = Date.now();
75801
75894
  const originalHistory = [...this.agent.context.history];
75802
75895
  const tokensBefore = estimateTokensForMessages(originalHistory);
@@ -76072,7 +76165,9 @@ var init_full = __esmMin((() => {
76072
76165
  contextSummary,
76073
76166
  compactedCount: originalHistory.length,
76074
76167
  tokensBefore,
76075
- droppedCount: droppedCount === 0 ? void 0 : droppedCount
76168
+ droppedCount: droppedCount === 0 ? void 0 : droppedCount,
76169
+ transaction,
76170
+ historyBefore: originalHistory
76076
76171
  });
76077
76172
  this.agent.telemetry.track("compaction_finished", {
76078
76173
  source: data.source,
@@ -76183,10 +76278,18 @@ var init_full = __esmMin((() => {
76183
76278
  }));
76184
76279
  //#endregion
76185
76280
  //#region ../../packages/agent-core/src/agent/compaction/micro.ts
76186
- 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;
76187
76290
  var init_micro = __esmMin((() => {
76188
76291
  ({ isWireOnlyProgrammaticEvent } = createRequire(import.meta.url)("./bin/programmatic-context-isolation.cjs"));
76189
- ({ 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"));
76190
76293
  ({ isPersistedToolResultReference, freshToolResultIds } = createRequire(import.meta.url)("./bin/tool-result-offload-policy.cjs"));
76191
76294
  ({ projectHistoricalUnaddressedTelegramMessages } = createRequire(import.meta.url)("./bin/telegram-context-projection-policy.cjs"));
76192
76295
  ({ dedupeRepeatedUserMessages } = createRequire(import.meta.url)("./bin/repeated-user-message-projection.cjs"));
@@ -76201,7 +76304,7 @@ var init_micro = __esmMin((() => {
76201
76304
  compactToolArguments: MICRO_COMPACTION_TOOL_ARGUMENTS_ENABLED,
76202
76305
  minToolArgumentTokens: MICRO_COMPACTION_TOOL_ARGUMENT_MIN_TOKENS,
76203
76306
  cacheMissedThresholdMs: 3600 * 1e3,
76204
- truncatedMarker: "[Old tool result content cleared]",
76307
+ truncatedMarker: "[Repeated tool result omitted]",
76205
76308
  truncatedArgumentsMarker: "[Old tool call arguments cleared]",
76206
76309
  minContextUsageRatio: .5
76207
76310
  };
@@ -76249,10 +76352,18 @@ var init_micro = __esmMin((() => {
76249
76352
  const effect = this.measureEffect(history, selection.cutoff);
76250
76353
  const previousEffect = this.measureEffect(history, previousCutoff);
76251
76354
  if (effect.truncatedToolResultCount <= previousEffect.truncatedToolResultCount && effect.truncatedToolArgumentCount <= previousEffect.truncatedToolArgumentCount) return;
76252
- this.apply(selection.cutoff);
76253
76355
  const rawContextTokens = estimateTokensForMessages(history);
76254
76356
  const tokensBefore = rawContextTokens - previousEffect.truncatedToolResultTokensBefore + previousEffect.truncatedToolResultTokensAfter - previousEffect.truncatedToolArgumentTokensBefore + previousEffect.truncatedToolArgumentTokensAfter;
76255
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
+ });
76256
76367
  this.agent.telemetry.track("micro_compaction_finished", {
76257
76368
  trigger: selection.trigger,
76258
76369
  keep_recent_messages: config.keepRecentMessages,
@@ -76284,15 +76395,16 @@ var init_micro = __esmMin((() => {
76284
76395
  const historicalArgumentCutoff = Math.max(this.cutoff, messages.length - config.keepRecentMessages);
76285
76396
  const completedToolCallIds = new Set(messages.filter((message) => message?.role === "tool" && message.toolCallId !== void 0).map((message) => message.toolCallId));
76286
76397
  const protectedToolResultIds = freshToolResultIds(messages);
76398
+ const reducibleToolResultIds = redundantHistoricalToolResultReferences(messages, this.cutoff);
76287
76399
  const serializedArgumentsMarker = JSON.stringify({ _blun_compacted: config.truncatedArgumentsMarker });
76288
76400
  const result = [];
76289
76401
  let i = 0;
76290
76402
  for (const msg of messages) {
76291
- 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({
76292
76404
  ...msg,
76293
76405
  content: [{
76294
76406
  type: "text",
76295
- text: config.truncatedMarker
76407
+ text: repeatedToolResultReference(config.truncatedMarker, reducibleToolResultIds.get(msg.toolCallId))
76296
76408
  }]
76297
76409
  });
76298
76410
  else if (config.compactToolArguments && i < historicalArgumentCutoff && msg.role === "assistant" && Array.isArray(msg.toolCalls)) {
@@ -76321,7 +76433,6 @@ var init_micro = __esmMin((() => {
76321
76433
  return result;
76322
76434
  }
76323
76435
  measureEffect(messages, cutoff) {
76324
- let markerTokenCount;
76325
76436
  let argumentsMarkerTokenCount;
76326
76437
  let truncatedToolResultCount = 0;
76327
76438
  let truncatedToolResultTokensBefore = 0;
@@ -76331,19 +76442,20 @@ var init_micro = __esmMin((() => {
76331
76442
  let truncatedToolArgumentTokensAfter = 0;
76332
76443
  const completedToolCallIds = new Set(messages.filter((message) => message?.role === "tool" && message.toolCallId !== void 0).map((message) => message.toolCallId));
76333
76444
  const protectedToolResultIds = freshToolResultIds(messages);
76445
+ const reducibleToolResultIds = redundantHistoricalToolResultReferences(messages, cutoff);
76334
76446
  const serializedArgumentsMarker = JSON.stringify({ _blun_compacted: this.config.truncatedArgumentsMarker });
76335
76447
  for (let i = 0; i < messages.length && i < cutoff; i++) {
76336
76448
  const message = messages[i];
76337
- 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)) {
76338
76450
  const contentTokens = estimateTokensForContentParts(message.content);
76339
76451
  if (contentTokens >= this.config.minContentTokens) {
76340
- markerTokenCount ??= estimateTokensForContentParts([{
76341
- type: "text",
76342
- text: this.config.truncatedMarker
76343
- }]);
76344
76452
  truncatedToolResultCount += 1;
76345
76453
  truncatedToolResultTokensBefore += contentTokens;
76346
- truncatedToolResultTokensAfter += markerTokenCount;
76454
+ const replacement = repeatedToolResultReference(this.config.truncatedMarker, reducibleToolResultIds.get(message.toolCallId));
76455
+ truncatedToolResultTokensAfter += estimateTokensForContentParts([{
76456
+ type: "text",
76457
+ text: replacement
76458
+ }]);
76347
76459
  }
76348
76460
  }
76349
76461
  if (!this.config.compactToolArguments || message?.role !== "assistant" || !Array.isArray(message.toolCalls)) continue;
@@ -76556,6 +76668,9 @@ function isValidCronTask(obj) {
76556
76668
  if (o["paused"] !== void 0 && typeof o["paused"] !== "boolean") return false;
76557
76669
  if (o["autoExpire"] !== void 0 && typeof o["autoExpire"] !== "boolean") return false;
76558
76670
  if (o["scheduleFromAt"] !== void 0 && (typeof o["scheduleFromAt"] !== "number" || !Number.isFinite(o["scheduleFromAt"]))) return false;
76671
+ if (o["allowedTools"] !== void 0 && (!Array.isArray(o["allowedTools"]) || !o["allowedTools"].every((name) => typeof name === "string"))) return false;
76672
+ if (o["allowedTools"] !== void 0 && typeof o["toolScopeDigest"] !== "string") return false;
76673
+ if (o["allowedTools"] === void 0 && o["toolScopeDigest"] !== void 0) return false;
76559
76674
  if (o["owner"] === "session-loop" && (typeof o["loopInterval"] !== "string" || o["loopInterval"].length === 0 || o["recurring"] === false || o["autoExpire"] !== false)) return false;
76560
76675
  return true;
76561
76676
  }
@@ -77333,7 +77448,7 @@ function hasUnfinishedTodoWork(agent) {
77333
77448
  const todos = agent.tools.storeData()["todo"];
77334
77449
  return Array.isArray(todos) && todos.some((todo) => todo?.status === "in_progress" || todo?.status === "pending");
77335
77450
  }
77336
- var STALE_THRESHOLD_MS, CronManager;
77451
+ var STALE_THRESHOLD_MS, normalizeCronAllowedTools, cronToolScopeForTask, filterToolsForCronScope, inheritedCronToolScope, createCronRunReceipt, buildCronFileCandidate, publicCronRunList, createCronRunStore, createMemoryCronRunStore, readCronFinalMessage, CronManager;
77337
77452
  var init_manager$3 = __esmMin((() => {
77338
77453
  init_clock();
77339
77454
  init_cron_fire_xml();
@@ -77341,6 +77456,17 @@ var init_manager$3 = __esmMin((() => {
77341
77456
  init_session_store$2();
77342
77457
  init_scheduler();
77343
77458
  init_telemetry_events();
77459
+ ({
77460
+ normalizeCronAllowedTools,
77461
+ cronToolScopeForTask,
77462
+ filterToolsForCronScope,
77463
+ inheritedCronToolScope,
77464
+ createCronRunReceipt,
77465
+ buildCronFileCandidate,
77466
+ publicCronRunList
77467
+ } = createRequire(import.meta.url)("./bin/scoped-cron-run-policy.cjs"));
77468
+ ({ createCronRunStore, createMemoryCronRunStore } = createRequire(import.meta.url)("./bin/cron-run-store.cjs"));
77469
+ ({ readCronFinalMessage } = createRequire(import.meta.url)("./bin/cron-run-output.cjs"));
77344
77470
  STALE_THRESHOLD_MS = 10080 * 60 * 1e3;
77345
77471
  CronManager = class {
77346
77472
  /** In-memory task store. Empty at construction; populated by
@@ -77376,6 +77502,11 @@ var init_manager$3 = __esmMin((() => {
77376
77502
  * later `blun resume` can reload via {@link loadFromDisk}.
77377
77503
  */
77378
77504
  persistStore;
77505
+ runStore;
77506
+ bufferedRuns = [];
77507
+ runByTurnId = /* @__PURE__ */ new Map();
77508
+ runAccumulators = /* @__PURE__ */ new Map();
77509
+ drainTimer = null;
77379
77510
  /**
77380
77511
  * Per-id serializer for persistence writes. Prevents a fast
77381
77512
  * `add` → `remove` sequence on the same id from racing each other on
@@ -77389,6 +77520,7 @@ var init_manager$3 = __esmMin((() => {
77389
77520
  this.store = new SessionCronStore();
77390
77521
  this.clocks = opts.clocks ?? resolveClockSources(process.env["BLUN_CRON_CLOCK"]) ?? SYSTEM_CLOCKS;
77391
77522
  this.persistStore = agent.homedir === void 0 ? void 0 : createCronPersistStore(agent.homedir);
77523
+ this.runStore = agent.homedir === void 0 ? createMemoryCronRunStore() : createCronRunStore(agent.homedir, { now: () => this.clocks.wallNow() });
77392
77524
  this.scheduler = createCronScheduler({
77393
77525
  clocks: this.clocks,
77394
77526
  source: () => this.store.list(),
@@ -77440,7 +77572,10 @@ var init_manager$3 = __esmMin((() => {
77440
77572
  */
77441
77573
  removeTasks(ids) {
77442
77574
  const removed = this.store.remove(ids);
77443
- for (const id of removed) this.persistEnqueue(id, () => this.persistStore.remove(id));
77575
+ for (const id of removed) {
77576
+ this.persistEnqueue(id, () => this.persistStore.remove(id));
77577
+ this.runStore.markJobDeletedById(id);
77578
+ }
77444
77579
  return removed;
77445
77580
  }
77446
77581
  updateTask(id, patch) {
@@ -77480,6 +77615,11 @@ var init_manager$3 = __esmMin((() => {
77480
77615
  * input, so a regenerated value would corrupt both.
77481
77616
  */
77482
77617
  async loadFromDisk() {
77618
+ const loadedRuns = this.runStore.load();
77619
+ for (const runId of loadedRuns.lostRunIds ?? []) {
77620
+ const receipt = this.runStore.get(runId);
77621
+ if (receipt !== void 0) this.emitRunTerminal(receipt);
77622
+ }
77483
77623
  if (this.persistStore === void 0) return;
77484
77624
  const tasks = await this.persistStore.list();
77485
77625
  this.store.clear();
@@ -77547,6 +77687,8 @@ var init_manager$3 = __esmMin((() => {
77547
77687
  * would be missing from the resume's `loadFromDisk()`.
77548
77688
  */
77549
77689
  async stop() {
77690
+ if (this.drainTimer !== null) clearTimeout(this.drainTimer);
77691
+ this.drainTimer = null;
77550
77692
  this.unbindSigusr1();
77551
77693
  await this.scheduler.stop();
77552
77694
  await this.flushPersist();
@@ -77612,24 +77754,49 @@ var init_manager$3 = __esmMin((() => {
77612
77754
  */
77613
77755
  handleFire(task, ctx) {
77614
77756
  const stale = this.isStale(task);
77757
+ const toolScope = cronToolScopeForTask(task);
77758
+ const runId = randomBytes(8).toString("hex");
77615
77759
  const origin = {
77616
77760
  kind: "cron_job",
77617
77761
  jobId: task.id,
77762
+ runId,
77618
77763
  cron: task.cron,
77619
77764
  recurring: task.recurring !== false,
77620
77765
  coalescedCount: ctx.coalescedCount,
77621
- stale
77766
+ stale,
77767
+ ...(toolScope.mode === "scoped" ? { toolScope } : {})
77622
77768
  };
77623
77769
  const content = [{
77624
77770
  type: "text",
77625
77771
  text: task.owner === "session-loop" ? renderSessionLoopWakeupXml(origin, task.prompt, task.loopInterval ?? "auto") : renderCronFireXml(origin, task.prompt)
77626
77772
  }];
77773
+ const receipt = createCronRunReceipt({
77774
+ runId,
77775
+ jobId: task.id,
77776
+ cron: task.cron,
77777
+ recurring: task.recurring !== false,
77778
+ stale,
77779
+ coalescedCount: ctx.coalescedCount,
77780
+ toolScopeDigest: toolScope.digest,
77781
+ firedAt: new Date(this.clocks.wallNow()).toISOString()
77782
+ });
77783
+ this.runStore.create(receipt);
77784
+ this.bufferedRuns.push({ runId, content, origin });
77785
+ this.runAccumulators.set(runId, {
77786
+ toolCalls: /* @__PURE__ */ new Map(),
77787
+ fileCandidates: /* @__PURE__ */ new Map(),
77788
+ outputs: [],
77789
+ finalStepId: null
77790
+ });
77791
+ this.agent.emitEvent({ type: "cron.fired", origin });
77627
77792
  this.agent.emitEvent({
77628
- type: "cron.fired",
77629
- origin,
77630
- prompt: task.prompt
77793
+ type: "cron.run.created",
77794
+ runId,
77795
+ jobId: task.id,
77796
+ coalescedCount: ctx.coalescedCount,
77797
+ toolScopeDigest: toolScope.digest
77631
77798
  });
77632
- const turnId = this.agent.turn.steer(content, origin);
77799
+ const turnId = this.launchBufferedRuns();
77633
77800
  this.agent.telemetry.track(CRON_FIRED, {
77634
77801
  recurring: task.recurring !== false,
77635
77802
  coalesced_count: ctx.coalescedCount,
@@ -77641,6 +77808,137 @@ var init_manager$3 = __esmMin((() => {
77641
77808
  this.emitDeleted(task.id);
77642
77809
  }
77643
77810
  }
77811
+ launchBufferedRuns() {
77812
+ if (this.bufferedRuns.length === 0) return null;
77813
+ if (this.agent.turn.hasActiveTurn || this.agent.fullCompaction.isCompacting) {
77814
+ this.scheduleBufferedRunDrain();
77815
+ return null;
77816
+ }
77817
+ const next = this.bufferedRuns.shift();
77818
+ const acceptance = this.agent.turn.promptWithAcceptance(next.content, next.origin);
77819
+ if (acceptance.accepted !== true || acceptance.turnId === null) {
77820
+ this.bufferedRuns.unshift(next);
77821
+ this.scheduleBufferedRunDrain();
77822
+ return null;
77823
+ }
77824
+ return acceptance.turnId;
77825
+ }
77826
+ scheduleBufferedRunDrain() {
77827
+ if (this.drainTimer !== null || this.bufferedRuns.length === 0) return;
77828
+ this.drainTimer = setTimeout(() => {
77829
+ this.drainTimer = null;
77830
+ this.launchBufferedRuns();
77831
+ }, 250);
77832
+ this.drainTimer.unref?.();
77833
+ }
77834
+ observeLoopEvent(turnId, event) {
77835
+ const runId = this.runByTurnId.get(turnId);
77836
+ if (runId === void 0) return;
77837
+ const accumulator = this.runAccumulators.get(runId);
77838
+ if (accumulator === void 0) return;
77839
+ if (event.type === "step.begin" && typeof event.uuid === "string") accumulator.finalStepId = event.uuid;
77840
+ if (event.type === "tool.call") {
77841
+ accumulator.toolCalls.set(event.toolCallId, { name: event.name, isError: false });
77842
+ const candidate = buildCronFileCandidate({
77843
+ toolName: event.name,
77844
+ toolCallId: event.toolCallId,
77845
+ display: event.display,
77846
+ workspaceRoot: this.agent.config.cwd,
77847
+ additionalRoots: this.agent.getAdditionalDirs(),
77848
+ pathExists: typeof event.display?.path === "string" && existsSync(event.display.path)
77849
+ });
77850
+ if (candidate !== null) accumulator.fileCandidates.set(event.toolCallId, candidate);
77851
+ }
77852
+ if (event.type === "tool.result") {
77853
+ const call = accumulator.toolCalls.get(event.toolCallId);
77854
+ if (call !== void 0) call.isError = event.result.isError === true;
77855
+ const candidate = accumulator.fileCandidates.get(event.toolCallId);
77856
+ if (candidate !== void 0 && event.result.isError !== true) accumulator.outputs.push(candidate);
77857
+ accumulator.fileCandidates.delete(event.toolCallId);
77858
+ }
77859
+ }
77860
+ observeAgentEvent(event) {
77861
+ if (event.type === "turn.started") {
77862
+ const runId = event.origin?.kind === "cron_job" && typeof event.origin.runId === "string" ? event.origin.runId : event.origin?.kind === "system_trigger" && typeof event.origin.cronRunId === "string" ? event.origin.cronRunId : void 0;
77863
+ if (runId === void 0) return;
77864
+ const receipt = this.runStore.get(runId);
77865
+ if (receipt?.status !== "buffered" && receipt?.status !== "running") return;
77866
+ this.runByTurnId.set(event.turnId, runId);
77867
+ if (receipt.status === "buffered") {
77868
+ const running = this.runStore.transition(runId, "running", {
77869
+ turnId: event.turnId,
77870
+ startedAt: new Date(this.clocks.wallNow()).toISOString()
77871
+ });
77872
+ this.agent.emitEvent({
77873
+ type: "cron.run.started",
77874
+ runId: running.runId,
77875
+ jobId: running.jobId,
77876
+ turnId: event.turnId
77877
+ });
77878
+ }
77879
+ return;
77880
+ }
77881
+ if (event.type !== "turn.ended") return;
77882
+ const runId = this.runByTurnId.get(event.turnId);
77883
+ if (runId === void 0) return;
77884
+ const accumulator = this.runAccumulators.get(runId);
77885
+ if (accumulator !== void 0) accumulator.lastTurnEnd = event;
77886
+ this.runByTurnId.delete(event.turnId);
77887
+ }
77888
+ observeRunWorkerEnded(runId, event) {
77889
+ const current = this.runStore.get(runId);
77890
+ if (current?.status !== "running" && current?.status !== "buffered") return;
77891
+ const accumulator = this.runAccumulators.get(runId) ?? {
77892
+ toolCalls: /* @__PURE__ */ new Map(),
77893
+ outputs: [],
77894
+ finalStepId: null
77895
+ };
77896
+ const status = event.reason === "cancelled" ? "cancelled" : event.reason === "failed" || event.reason === "filtered" ? "failed" : "completed";
77897
+ const terminal = this.runStore.transition(runId, status, {
77898
+ endedAt: new Date(this.clocks.wallNow()).toISOString(),
77899
+ toolCalls: [...accumulator.toolCalls.values()],
77900
+ outputs: accumulator.outputs,
77901
+ finalStepId: accumulator.finalStepId,
77902
+ error: status === "failed" ? {
77903
+ category: event.reason === "filtered" ? "policy" : "executor",
77904
+ code: event.error?.code ?? (event.reason === "filtered" ? "PROVIDER_FILTERED" : "TURN_FAILED")
77905
+ } : void 0
77906
+ });
77907
+ this.emitRunTerminal(terminal);
77908
+ this.runAccumulators.delete(runId);
77909
+ this.scheduleBufferedRunDrain();
77910
+ }
77911
+ observeRunWorkerFailed(runId) {
77912
+ this.observeRunWorkerEnded(runId, {
77913
+ reason: "failed",
77914
+ error: { code: "TURN_WORKER_FAILED" }
77915
+ });
77916
+ }
77917
+ emitRunTerminal(receipt) {
77918
+ const durationMs = receipt.startedAt === null || receipt.endedAt === null ? void 0 : Math.max(0, Date.parse(receipt.endedAt) - Date.parse(receipt.startedAt));
77919
+ this.agent.emitEvent({
77920
+ type: `cron.run.${receipt.status}`,
77921
+ runId: receipt.runId,
77922
+ jobId: receipt.jobId,
77923
+ durationMs,
77924
+ toolCalls: receipt.toolSummary.calls,
77925
+ toolErrors: receipt.toolSummary.errors,
77926
+ outputCount: receipt.outputs.length,
77927
+ errorCategory: receipt.error?.category
77928
+ });
77929
+ }
77930
+ listRuns(filters) {
77931
+ return publicCronRunList(this.runStore.list(), filters);
77932
+ }
77933
+ readRunOutput(runId) {
77934
+ const receipt = this.runStore.get(runId);
77935
+ if (receipt === void 0) return null;
77936
+ let finalMessage = null;
77937
+ if (receipt.finalMessageRef !== null && this.agent.homedir !== void 0) try {
77938
+ finalMessage = readCronFinalMessage(join$4(this.agent.homedir, "wire.jsonl"), receipt.finalMessageRef.stepId);
77939
+ } catch {}
77940
+ return { receipt, finalMessage };
77941
+ }
77644
77942
  /**
77645
77943
  * Reserved hook for an explicit "you missed N fires while offline"
77646
77944
  * banner. Today the scheduler's `coalescedCount` semantics already
@@ -78105,7 +78403,8 @@ var init_cron_create = __esmMin((() => {
78105
78403
  CronCreateInputSchema = object({
78106
78404
  cron: string().describe("5-field cron expression in local time: \"M H DoM Mon DoW\" (e.g. \"*/5 * * * *\" = every 5 minutes; \"30 14 28 2 *\" = Feb 28 at 2:30pm local — a pinned date like this repeats yearly unless you also pass recurring: false)."),
78107
78405
  prompt: string().min(1).max(MAX_PROMPT_BYTES).describe("The prompt to enqueue at each fire time. Limited to 8 KiB (UTF-8)."),
78108
- recurring: boolean$1().optional().default(true).describe("true (default) = fire on every cron match until deleted or auto-expired after 7 days. false = fire once at the next match, then auto-delete. Use false for \"remind me at X\" one-shot requests with pinned minute/hour/dom/month.")
78406
+ recurring: boolean$1().optional().default(true).describe("true (default) = fire on every cron match until deleted or auto-expired after 7 days. false = fire once at the next match, then auto-delete. Use false for \"remind me at X\" one-shot requests with pinned minute/hour/dom/month."),
78407
+ allowed_tools: array(string()).max(64).optional().describe("Optional exact tool names allowed in each isolated run. Omit for legacy behavior; an empty array allows no tools. Wildcards and unknown tools are rejected.")
78109
78408
  });
78110
78409
  CronCreateTool = class {
78111
78410
  manager;
@@ -78145,6 +78444,15 @@ var init_cron_create = __esmMin((() => {
78145
78444
  output: `Prompt exceeds ${String(MAX_PROMPT_BYTES)} bytes (got ${String(byteLen)}).`
78146
78445
  };
78147
78446
  const recurring = args.recurring !== false;
78447
+ let toolScope;
78448
+ try {
78449
+ toolScope = normalizeCronAllowedTools(args.allowed_tools, this.manager.agent.tools.loopTools);
78450
+ } catch (error) {
78451
+ return {
78452
+ isError: true,
78453
+ output: error instanceof Error ? error.message : String(error)
78454
+ };
78455
+ }
78148
78456
  if (!recurring) {
78149
78457
  const firstFire = computeNextCronRun(parsed, nowAtPrepare);
78150
78458
  if (firstFire !== null && firstFire - nowAtPrepare > ONE_SHOT_MAX_FUTURE_MS) return {
@@ -78157,7 +78465,8 @@ var init_cron_create = __esmMin((() => {
78157
78465
  approvalRule: literalRulePattern(this.name, JSON.stringify({
78158
78466
  cron: normalizedCron,
78159
78467
  prompt: args.prompt,
78160
- recurring
78468
+ recurring,
78469
+ ...(args.allowed_tools === void 0 ? {} : { allowed_tools: toolScope.names })
78161
78470
  })),
78162
78471
  execute: async () => {
78163
78472
  const nowMs = this.manager.clocks.wallNow();
@@ -78168,7 +78477,11 @@ var init_cron_create = __esmMin((() => {
78168
78477
  const task = this.manager.addTask({
78169
78478
  cron: normalizedCron,
78170
78479
  prompt: args.prompt,
78171
- recurring
78480
+ recurring,
78481
+ ...(toolScope.mode === "scoped" ? {
78482
+ allowedTools: toolScope.names,
78483
+ toolScopeDigest: toolScope.digest
78484
+ } : {})
78172
78485
  });
78173
78486
  const ideal = computeNextCronRun(parsed, nowMs);
78174
78487
  const nextFireAt = ideal === null ? null : recurring ? jitteredNextCronRunMs(task, parsed, ideal) : oneShotJitteredNextCronRunMs(task, ideal);
@@ -79135,6 +79448,32 @@ var init_context$2 = __esmMin((() => {
79135
79448
  keptHeadUserMessageCount,
79136
79449
  droppedCount: input.droppedCount
79137
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
+ }));
79469
+ this.agent.records.logRecord({
79470
+ type: "policy.intervention",
79471
+ policy: "full_context_compaction",
79472
+ location: "AgentContext.applyCompaction",
79473
+ size_before: result.tokensBefore,
79474
+ size_after: result.tokensAfter,
79475
+ unit: "tokens"
79476
+ });
79138
79477
  this.agent.records.logRecord({
79139
79478
  type: "context.apply_compaction",
79140
79479
  ...result
@@ -79149,17 +79488,7 @@ var init_context$2 = __esmMin((() => {
79149
79488
  keptHeadUserMessageCount: result.keptHeadUserMessageCount,
79150
79489
  droppedCount: result.droppedCount
79151
79490
  } });
79152
- const summaryMessage = {
79153
- role: "user",
79154
- content: [{
79155
- type: "text",
79156
- text: contextSummary
79157
- }],
79158
- toolCalls: [],
79159
- origin: { kind: "compaction_summary" }
79160
- };
79161
- const isLegacyRestore = this.agent.records.restoring !== null && input.keptUserMessageCount === void 0 && input.compactedCount < this._history.length;
79162
- this._history = isLegacyRestore ? [summaryMessage, ...this._history.slice(input.compactedCount)] : [...keptMessages, summaryMessage];
79491
+ this._history = nextHistory;
79163
79492
  this.markPendingTokenEstimateDirty();
79164
79493
  this.openSteps.clear();
79165
79494
  this.pendingToolResultIds.clear();
@@ -79195,6 +79524,7 @@ var init_context$2 = __esmMin((() => {
79195
79524
  }
79196
79525
  project(messages, options) {
79197
79526
  const anomalies = [];
79527
+ const underPressure = toolResultOffloadPressureForAgent(this.agent);
79198
79528
  const userOffloaded = this.agent.userMessageOffload.compact(messages);
79199
79529
  const historicalMediaProjected = projectHistoricalMediaParts(userOffloaded);
79200
79530
  const historicalUserReferencesProjected = compactHistoricalPersistedUserMessageReferences(historicalMediaProjected);
@@ -79202,7 +79532,9 @@ var init_context$2 = __esmMin((() => {
79202
79532
  const historicalTelegramProjected = projectHistoricalUnaddressedTelegramMessages(duplicateUserMessagesProjected);
79203
79533
  const assistantOffloaded = this.agent.assistantMessageOffload.compact(historicalTelegramProjected);
79204
79534
  const repeatedAssistantProjected = projectRepeatedAssistantResponses(assistantOffloaded);
79205
- const result = project(this.agent.microCompaction.compact(compactHistoricalSuccessfulToolResults(dedupeRepeatedSuccessfulToolResults(repeatedAssistantProjected, this.agent.toolResultBatchOffload.compact(dedupeRecurringCronWakeups(dedupeRepeatedInjections(compactHistoricalSkillActivations(compactBaselineSkillInjections(repeatedAssistantProjected)))))))), {
79535
+ const batchProjected = this.agent.toolResultBatchOffload.compact(dedupeRecurringCronWakeups(dedupeRepeatedInjections(compactHistoricalSkillActivations(compactBaselineSkillInjections(repeatedAssistantProjected)))));
79536
+ const toolResultsProjected = compactHistoricalSuccessfulToolResults(dedupeRepeatedSuccessfulToolResults(repeatedAssistantProjected, batchProjected), { underPressure });
79537
+ const result = project(this.agent.microCompaction.compact(toolResultsProjected), {
79206
79538
  ...options,
79207
79539
  onAnomaly: (anomaly) => {
79208
79540
  anomalies.push(anomaly);
@@ -233897,9 +234229,9 @@ var init_plan_mode_guard_deny = __esmMin((() => {
233897
234229
  message: planModeWriteDeniedMessage(planFilePath)
233898
234230
  };
233899
234231
  }
233900
- if (toolName === "TaskStop") return {
234232
+ if (toolName === "TaskStop" || toolName === "TaskResume") return {
233901
234233
  kind: "deny",
233902
- message: "TaskStop is not available in plan mode. Call ExitPlanMode to exit plan mode before stopping a background task."
234234
+ message: `${toolName} is not available in plan mode. Call ExitPlanMode before changing background task execution.`
233903
234235
  };
233904
234236
  if (toolName === "CronCreate" || toolName === "CronDelete") return {
233905
234237
  kind: "deny",
@@ -234265,6 +234597,16 @@ var init_permission = __esmMin((() => {
234265
234597
  if (pattern === void 0) return;
234266
234598
  this.localSessionApprovalRulePatterns.add(pattern);
234267
234599
  }
234600
+ recordApprovalEdited(context, editedArgs) {
234601
+ const event = buildApprovalEditedEvent({
234602
+ turnId: Number(context.turnId),
234603
+ toolCallId: context.toolCall.id,
234604
+ toolName: context.toolCall.name,
234605
+ originalArgs: context.args,
234606
+ editedArgs
234607
+ });
234608
+ this.agent.records.logRecord(event);
234609
+ }
234268
234610
  get sessionApprovalRulePatterns() {
234269
234611
  return [...this.localSessionApprovalRulePatterns, ...this.parent?.sessionApprovalRulePatterns ?? []];
234270
234612
  }
@@ -234284,6 +234626,8 @@ var init_permission = __esmMin((() => {
234284
234626
  const { signal } = context;
234285
234627
  const id = context.toolCall.id;
234286
234628
  const name = context.toolCall.name;
234629
+ const approvalEditCount = Number.isSafeInteger(context.approvalEditCount) ? context.approvalEditCount : 0;
234630
+ const allowEdit = approvalEditCount === 0 && isEditableToolApprovalEligible(name);
234287
234631
  const display = context.execution.display ?? {
234288
234632
  kind: "generic",
234289
234633
  summary: context.execution.description ?? `Approve ${name}`,
@@ -234321,7 +234665,10 @@ var init_permission = __esmMin((() => {
234321
234665
  toolCallId: id,
234322
234666
  toolName: name,
234323
234667
  action,
234324
- display
234668
+ display,
234669
+ allowEdit,
234670
+ approvalEditCount,
234671
+ editableToolInput: allowEdit ? context.args : void 0
234325
234672
  }, { signal });
234326
234673
  } catch (error) {
234327
234674
  this.agent.telemetry.track("permission_approval_result", {
@@ -234349,6 +234696,19 @@ var init_permission = __esmMin((() => {
234349
234696
  return resolved === void 0 ? Promise.reject(error) : this.permissionPolicyResolutionToPrepare(resolved, context, policyName);
234350
234697
  }
234351
234698
  } else response = { decision: "approved" };
234699
+ let editedDecision;
234700
+ if (response.decision === "edited") try {
234701
+ editedDecision = validateEditedApprovalDecision({
234702
+ response,
234703
+ toolName: name,
234704
+ editCount: approvalEditCount
234705
+ });
234706
+ } catch (error) {
234707
+ response = {
234708
+ decision: "rejected",
234709
+ feedback: `Edited approval was rejected before tool preparation: ${error instanceof Error ? error.message : String(error)}`
234710
+ };
234711
+ }
234352
234712
  const sessionApprovalRule = response.decision === "approved" && response.scope === "session" ? context.execution.approvalRule : void 0;
234353
234713
  if (requestedApproval) this.agent.hooks?.fireAndForgetTrigger?.("PermissionResult", {
234354
234714
  matcherValue: name,
@@ -234363,13 +234723,14 @@ var init_permission = __esmMin((() => {
234363
234723
  selectedLabel: response.selectedLabel
234364
234724
  }
234365
234725
  });
234726
+ const approvalRecordResponse = response.decision === "edited" ? { decision: "edited" } : response;
234366
234727
  this.recordApprovalResult({
234367
234728
  turnId: Number(context.turnId),
234368
234729
  toolCallId: id,
234369
234730
  toolName: name,
234370
234731
  action,
234371
234732
  sessionApprovalRule,
234372
- result: response
234733
+ result: approvalRecordResponse
234373
234734
  });
234374
234735
  this.agent.telemetry.track("permission_approval_result", {
234375
234736
  policy_name: policyName ?? null,
@@ -234381,6 +234742,17 @@ var init_permission = __esmMin((() => {
234381
234742
  session_cache_written: sessionApprovalRule !== void 0,
234382
234743
  has_feedback: response.feedback !== void 0 && response.feedback.length > 0
234383
234744
  });
234745
+ if (response.decision === "edited" && editedDecision !== void 0) {
234746
+ let recorded = false;
234747
+ return { approvalEdit: {
234748
+ args: editedDecision.editedToolInput,
234749
+ record: (validatedArgs) => {
234750
+ if (recorded) throw new Error("Edited approval Wire event was already recorded");
234751
+ recorded = true;
234752
+ this.recordApprovalEdited(context, validatedArgs);
234753
+ }
234754
+ } };
234755
+ }
234384
234756
  const resolved = result.resolveApproval?.(response);
234385
234757
  if (resolved !== void 0) return this.permissionPolicyResolutionToPrepare(resolved, context, policyName);
234386
234758
  if (response.decision === "approved") return;
@@ -244234,6 +244606,7 @@ function createNestedToolInvoker(step, parentToolCall) {
244234
244606
  ...step,
244235
244607
  signal: nestedSignal,
244236
244608
  toolCalls: [nestedToolCall],
244609
+ checkpointBeforeToolExecution: void 0,
244237
244610
  dispatchEvent: (event) => step.dispatchEvent(markProgrammaticNestedEvent(event))
244238
244611
  };
244239
244612
  const preflight = preflightToolCall(nestedStep, nestedToolCall);
@@ -244306,7 +244679,7 @@ function validateExecutableToolArgs(tool, args) {
244306
244679
  }
244307
244680
  return validateToolArgs(validator, args);
244308
244681
  }
244309
- async function prepareToolCall(step, call) {
244682
+ async function prepareToolCall(step, call, approvalEditCount = 0) {
244310
244683
  const settleError = async (args, output, displayFields) => {
244311
244684
  await dispatchToolCall(step, call, args, displayFields);
244312
244685
  return { task: makeResolvedToolCallTask(makeErrorToolResult(call, args, output)) };
@@ -244341,12 +244714,43 @@ async function prepareToolCall(step, call) {
244341
244714
  const settleAborted = () => settleError(effectiveArgs, abortedToolOutput(call.toolName, step.signal), displayFields);
244342
244715
  if (step.signal.aborted) return settleAborted();
244343
244716
  if (execution.isError === true) return settleSynthetic(effectiveArgs, execution, displayFields);
244344
- const authorization = await runAuthorizeToolExecutionHook(step, call, effectiveArgs, execution);
244717
+ const authorization = await runAuthorizeToolExecutionHook(step, call, effectiveArgs, execution, approvalEditCount);
244345
244718
  if (step.signal.aborted) return settleAborted();
244346
244719
  if (authorization?.block === true) return settleError(effectiveArgs, authorization.reason ?? `Tool call "${call.toolName}" was blocked`, displayFields);
244347
244720
  if (authorization?.syntheticResult !== void 0) return settleSynthetic(effectiveArgs, authorization.syntheticResult, displayFields);
244721
+ if (authorization?.approvalEdit !== void 0) {
244722
+ let plan;
244723
+ try {
244724
+ plan = buildEditedToolCallPlan({
244725
+ step,
244726
+ call,
244727
+ editedArgs: authorization.approvalEdit.args,
244728
+ editCount: approvalEditCount,
244729
+ preflightToolCall
244730
+ });
244731
+ } catch (error) {
244732
+ return settleError(authorization.approvalEdit.args, `Edited approval could not be re-prepared: ${errorMessage$12(error)}`, displayFields);
244733
+ }
244734
+ if (plan.kind === "rejected") return settleError(plan.call.args, plan.output ?? `Edited args for tool "${call.toolName}" were rejected`, displayFields);
244735
+ try {
244736
+ authorization.approvalEdit.record(plan.call.args);
244737
+ } catch (error) {
244738
+ return settleError(plan.call.args, `Edited approval evidence could not be recorded: ${errorMessage$12(error)}`, displayFields);
244739
+ }
244740
+ return prepareToolCall(plan.step, plan.call, plan.editCount);
244741
+ }
244348
244742
  const executionMetadata = authorization?.executionMetadata ?? decision.metadata;
244349
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
+ }
244350
244754
  return {
244351
244755
  task: {
244352
244756
  accesses: execution.accesses ?? ToolAccesses.all(),
@@ -244418,7 +244822,7 @@ async function runPrepareToolExecutionHook(step, call) {
244418
244822
  metadata: hookResult?.executionMetadata
244419
244823
  };
244420
244824
  }
244421
- async function runAuthorizeToolExecutionHook(step, call, args, execution) {
244825
+ async function runAuthorizeToolExecutionHook(step, call, args, execution, approvalEditCount = 0) {
244422
244826
  const { hooks, signal, turnId, currentStep, llm } = step;
244423
244827
  if (hooks?.authorizeToolExecution === void 0) return void 0;
244424
244828
  try {
@@ -244428,6 +244832,7 @@ async function runAuthorizeToolExecutionHook(step, call, args, execution) {
244428
244832
  tool: call.tool,
244429
244833
  args,
244430
244834
  execution,
244835
+ approvalEditCount,
244431
244836
  turnId,
244432
244837
  stepNumber: currentStep,
244433
244838
  signal,
@@ -244652,9 +245057,10 @@ async function dispatchToolCall(step, call, args, displayFields) {
244652
245057
  display: displayFields?.display
244653
245058
  });
244654
245059
  }
244655
- 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;
244656
245061
  var init_tool_call = __esmMin((() => {
244657
245062
  ({ markProgrammaticNestedEvent } = createRequire(import.meta.url)("./bin/programmatic-context-isolation.cjs"));
245063
+ ({ checkpointBeforeExternalSideEffect } = createRequire(import.meta.url)("./bin/session-checkpoint-policy.cjs"));
244658
245064
  init_args_validator();
244659
245065
  init_path_access();
244660
245066
  init_abort();
@@ -244678,7 +245084,7 @@ var init_tool_call = __esmMin((() => {
244678
245084
  * does not lose model usage that was already spent.
244679
245085
  */
244680
245086
  async function executeLoopStep(deps) {
244681
- 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;
244682
245088
  const beforeStep = hooks?.beforeStep === void 0 ? void 0 : await hooks.beforeStep({
244683
245089
  turnId,
244684
245090
  stepNumber: currentStep,
@@ -244694,12 +245100,15 @@ async function executeLoopStep(deps) {
244694
245100
  const messages = await stepBuildMessages();
244695
245101
  signal.throwIfAborted();
244696
245102
  const stepUuid = randomUUID();
245103
+ const requestMetadata = stepLLM.describeRequest?.(messages, stepTools ?? []);
244697
245104
  const stepEvents = createStepEventGate({
244698
245105
  dispatchEvent,
244699
245106
  turnId,
244700
245107
  currentStep,
244701
245108
  stepUuid,
244702
- onStepStarted
245109
+ onStepStarted,
245110
+ requestMetadata,
245111
+ maxAttempts: maxRetryAttempts
244703
245112
  });
244704
245113
  const prepareRequestBoundary = stepLLM.prepareRequestBoundary?.bind(stepLLM);
244705
245114
  const step = {
@@ -244711,7 +245120,8 @@ async function executeLoopStep(deps) {
244711
245120
  signal,
244712
245121
  turnId,
244713
245122
  currentStep,
244714
- stepUuid
245123
+ stepUuid,
245124
+ checkpointBeforeToolExecution
244715
245125
  };
244716
245126
  let chatParams = {
244717
245127
  messages,
@@ -244724,9 +245134,8 @@ async function executeLoopStep(deps) {
244724
245134
  signal.throwIfAborted();
244725
245135
  const retryInput = {
244726
245136
  llm: stepLLM,
244727
- dispatchEvent: (event) => {
244728
- stepEvents.dispatchRetrying(event);
244729
- },
245137
+ dispatchEvent: (event) => stepEvents.dispatchRetrying(event),
245138
+ checkpointBeforeRetryWait,
244730
245139
  turnId,
244731
245140
  currentStep,
244732
245141
  stepUuid,
@@ -244886,29 +245295,33 @@ async function chatWithLiveResponseRepetitionRecovery(deps) {
244886
245295
  occurrences: repetition.count,
244887
245296
  wordCount: repetition.wordCount
244888
245297
  });
244889
- await stepEvents.dispatchRetrying({
244890
- type: "step.retrying",
244891
- turnId: retryInput.turnId,
244892
- step: retryInput.currentStep,
244893
- stepUuid: retryInput.stepUuid,
244894
- failedAttempt: 1,
244895
- nextAttempt: 2,
244896
- maxAttempts: 2,
244897
- delayMs: 0,
244898
- outputMayHaveStarted: true,
244899
- errorName: "LiveResponseRepetitionError",
244900
- 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
+ }
244901
245315
  });
244902
245316
  }
244903
245317
  }
244904
245318
  throw new Error("Live response repetition recovery exhausted");
244905
245319
  }
244906
245320
  function createStepEventGate(deps) {
244907
- const { dispatchEvent, turnId, currentStep, stepUuid, onStepStarted } = deps;
245321
+ const { dispatchEvent, turnId, currentStep, stepUuid, onStepStarted, requestMetadata, maxAttempts } = deps;
244908
245322
  let startPromise;
244909
245323
  let eventQueue = Promise.resolve();
244910
245324
  let hasOutput = false;
244911
- const pendingBeforeStart = [];
244912
245325
  let liveRepetitionGuard;
244913
245326
  let liveRepetitionController;
244914
245327
  let liveRepetitionResult = null;
@@ -244918,10 +245331,13 @@ function createStepEventGate(deps) {
244918
245331
  type: "step.begin",
244919
245332
  uuid: stepUuid,
244920
245333
  turnId,
244921
- step: currentStep
245334
+ step: currentStep,
245335
+ thinkingEffort: requestMetadata?.thinkingEffort,
245336
+ completionBudget: requestMetadata?.completionBudget,
245337
+ attempt: 1,
245338
+ maxAttempts
244922
245339
  });
244923
245340
  onStepStarted?.();
244924
- for (const dispatch of pendingBeforeStart.splice(0)) await dispatch();
244925
245341
  })();
244926
245342
  return startPromise;
244927
245343
  };
@@ -244956,14 +245372,9 @@ function createStepEventGate(deps) {
244956
245372
  return AbortSignal.any([signal, liveRepetitionController.signal]);
244957
245373
  },
244958
245374
  dispatchRetrying: async (event) => {
244959
- if (startPromise === void 0) {
244960
- pendingBeforeStart.push(() => {
244961
- dispatchEvent(event);
244962
- });
244963
- return;
244964
- }
244965
- const queued = eventQueue.then(() => {
244966
- dispatchEvent(event);
245375
+ const queued = eventQueue.then(async () => {
245376
+ await start();
245377
+ await dispatchEvent(event);
244967
245378
  });
244968
245379
  eventQueue = queued;
244969
245380
  await queued;
@@ -245027,7 +245438,7 @@ var init_turn_step = __esmMin((() => {
245027
245438
  //#endregion
245028
245439
  //#region ../../packages/agent-core/src/loop/run-turn.ts
245029
245440
  async function runTurn(input) {
245030
- 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;
245031
245442
  let usage = emptyUsage();
245032
245443
  let steps = 0;
245033
245444
  let stopReason = "end_turn";
@@ -245057,6 +245468,8 @@ async function runTurn(input) {
245057
245468
  log,
245058
245469
  currentStep: stepNumber,
245059
245470
  maxRetryAttempts,
245471
+ checkpointBeforeToolExecution,
245472
+ checkpointBeforeRetryWait,
245060
245473
  recordUsage: recordStepUsage,
245061
245474
  onStepStarted: setActiveStep.bind(void 0, stepNumber)
245062
245475
  });
@@ -245955,7 +246368,7 @@ var init_modelCatalog$2 = __esmMin((() => {
245955
246368
  function isVolatileEventType(type) {
245956
246369
  return volatileEventTypeSet.has(type);
245957
246370
  }
245958
- var MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE, tokenUsageSchema, finishReasonSchema, usageStatusSchema, permissionModeSchema, skillSourceSchema, userPromptOriginSchema, skillActivationOriginSchema, pluginCommandOriginSchema, injectionOriginSchema, shellCommandOriginSchema, compactionSummaryOriginSchema, systemTriggerOriginSchema, agentCoreBackgroundTaskStatusSchema, backgroundTaskOriginSchema, cronJobOriginSchema, cronMissedOriginSchema, hookResultOriginSchema, retryOriginSchema, promptOriginSchema, goalStatusSchema, goalActorSchema, goalBudgetReportSchema, goalSnapshotSchema, goalChangeStatsSchema, goalChangeKindSchema, goalChangeSchema, blunErrorCodeSchema, blunErrorPayloadSchema, backgroundTaskInfoBaseSchema, processBackgroundTaskInfoSchema, agentBackgroundTaskInfoSchema, questionBackgroundTaskInfoSchema, backgroundTaskInfoSchema, compactionResultSchema, toolUpdateSchema, turnEndReasonSchema, agentStatusUpdatedEventSchema, sessionMetaUpdatedEventSchema, sessionCreatedEventSchema, workspaceCreatedEventSchema, workspaceUpdatedEventSchema, workspaceDeletedEventSchema, sessionStatusChangedEventSchema, modelCatalogChangedEventSchema, goalUpdatedEventSchema, skillActivatedEventSchema, pluginCommandActivatedEventSchema, errorEventSchema, warningEventSchema, turnStartedEventSchema, turnEndedEventSchema, turnStepStartedEventSchema, turnStepCompletedEventSchema, turnStepRetryingEventSchema, turnStepInterruptedEventSchema, assistantDeltaEventSchema, hookResultEventSchema, thinkingDeltaEventSchema, toolCallDeltaEventSchema, toolCallStartedEventSchema, toolProgressEventSchema, shellOutputEventSchema, shellStartedEventSchema, toolResultEventSchema, subagentSpawnedEventSchema, subagentStartedEventSchema, subagentSuspendedEventSchema, subagentCompletedEventSchema, subagentFailedEventSchema, compactionStartedEventSchema, compactionBlockedEventSchema, compactionCancelledEventSchema, compactionProgressEventSchema, compactionCompletedEventSchema, backgroundTaskStartedEventSchema, backgroundTaskTerminatedEventSchema, cronFiredEventSchema, attentionIntentSchema, attentionAuthorizedEventSchema, promptSubmittedEventSchema, toolListUpdatedReasonSchema, toolListUpdatedEventSchema, mcpServerStatusPayloadSchema, mcpServerStatusEventSchema, mediaDroppedEventSchema, agentEventSchema, eventSchema, VOLATILE_EVENT_TYPES, volatileEventTypeSet;
246371
+ var MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE, tokenUsageSchema, finishReasonSchema, usageStatusSchema, permissionModeSchema, skillSourceSchema, userPromptOriginSchema, skillActivationOriginSchema, pluginCommandOriginSchema, injectionOriginSchema, shellCommandOriginSchema, compactionSummaryOriginSchema, cronToolScopeSchema, systemTriggerOriginSchema, agentCoreBackgroundTaskStatusSchema, backgroundTaskOriginSchema, cronJobOriginSchema, cronMissedOriginSchema, hookResultOriginSchema, retryOriginSchema, promptOriginSchema, goalStatusSchema, goalActorSchema, goalBudgetReportSchema, goalSnapshotSchema, goalChangeStatsSchema, goalChangeKindSchema, goalChangeSchema, blunErrorCodeSchema, blunErrorPayloadSchema, backgroundTaskInfoBaseSchema, processBackgroundTaskInfoSchema, agentBackgroundTaskInfoSchema, questionBackgroundTaskInfoSchema, backgroundTaskInfoSchema, compactionResultSchema, toolUpdateSchema, turnEndReasonSchema, agentStatusUpdatedEventSchema, sessionMetaUpdatedEventSchema, sessionCreatedEventSchema, workspaceCreatedEventSchema, workspaceUpdatedEventSchema, workspaceDeletedEventSchema, sessionStatusChangedEventSchema, modelCatalogChangedEventSchema, goalUpdatedEventSchema, skillActivatedEventSchema, pluginCommandActivatedEventSchema, errorEventSchema, warningEventSchema, turnStartedEventSchema, turnEndedEventSchema, turnStepStartedEventSchema, turnStepCompletedEventSchema, turnStepRetryingEventSchema, turnStepInterruptedEventSchema, assistantDeltaEventSchema, hookResultEventSchema, thinkingDeltaEventSchema, toolCallDeltaEventSchema, toolCallStartedEventSchema, toolProgressEventSchema, shellOutputEventSchema, shellStartedEventSchema, toolResultEventSchema, subagentSpawnedEventSchema, subagentStartedEventSchema, subagentSuspendedEventSchema, subagentCompletedEventSchema, subagentFailedEventSchema, compactionStartedEventSchema, compactionBlockedEventSchema, compactionCancelledEventSchema, compactionProgressEventSchema, compactionCompletedEventSchema, backgroundTaskStartedEventSchema, backgroundTaskTerminatedEventSchema, cronFiredEventSchema, cronRunCreatedEventSchema, cronRunStartedEventSchema, cronRunTerminalEventSchema, attentionIntentSchema, attentionAuthorizedEventSchema, promptSubmittedEventSchema, toolListUpdatedReasonSchema, toolListUpdatedEventSchema, mcpServerStatusPayloadSchema, mcpServerStatusEventSchema, mediaDroppedEventSchema, agentEventSchema, eventSchema, VOLATILE_EVENT_TYPES, volatileEventTypeSet;
245959
246372
  var init_events$1 = __esmMin((() => {
245960
246373
  init_zod$1();
245961
246374
  init_display();
@@ -246029,9 +246442,16 @@ var init_events$1 = __esmMin((() => {
246029
246442
  isError: boolean$1().optional()
246030
246443
  });
246031
246444
  compactionSummaryOriginSchema = object({ kind: literal("compaction_summary") });
246445
+ cronToolScopeSchema = object({
246446
+ mode: literal("scoped"),
246447
+ names: array(string()).max(64),
246448
+ digest: string()
246449
+ });
246032
246450
  systemTriggerOriginSchema = object({
246033
246451
  kind: literal("system_trigger"),
246034
- name: string()
246452
+ name: string(),
246453
+ cronRunId: string().optional(),
246454
+ toolScope: cronToolScopeSchema.optional()
246035
246455
  });
246036
246456
  agentCoreBackgroundTaskStatusSchema = _enum([
246037
246457
  "running",
@@ -246050,10 +246470,12 @@ var init_events$1 = __esmMin((() => {
246050
246470
  cronJobOriginSchema = object({
246051
246471
  kind: literal("cron_job"),
246052
246472
  jobId: string(),
246473
+ runId: string().optional(),
246053
246474
  cron: string(),
246054
246475
  recurring: boolean$1(),
246055
246476
  coalescedCount: number$1(),
246056
- stale: boolean$1()
246477
+ stale: boolean$1(),
246478
+ toolScope: cronToolScopeSchema.optional()
246057
246479
  });
246058
246480
  cronMissedOriginSchema = object({
246059
246481
  kind: literal("cron_missed"),
@@ -246066,7 +246488,8 @@ var init_events$1 = __esmMin((() => {
246066
246488
  });
246067
246489
  retryOriginSchema = object({
246068
246490
  kind: literal("retry"),
246069
- trigger: string().optional()
246491
+ trigger: string().optional(),
246492
+ toolScope: cronToolScopeSchema.optional()
246070
246493
  });
246071
246494
  promptOriginSchema = discriminatedUnion("kind", [
246072
246495
  userPromptOriginSchema,
@@ -246419,7 +246842,11 @@ var init_events$1 = __esmMin((() => {
246419
246842
  type: literal("turn.step.started"),
246420
246843
  turnId: number$1(),
246421
246844
  step: number$1(),
246422
- 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()
246423
246850
  });
246424
246851
  turnStepCompletedEventSchema = object({
246425
246852
  type: literal("turn.step.completed"),
@@ -246449,7 +246876,9 @@ var init_events$1 = __esmMin((() => {
246449
246876
  outputMayHaveStarted: boolean$1().optional(),
246450
246877
  errorName: string(),
246451
246878
  errorMessage: string(),
246452
- statusCode: number$1().optional()
246879
+ statusCode: number$1().optional(),
246880
+ completionBudgetBefore: number$1().int().positive().optional(),
246881
+ completionBudgetAfter: number$1().int().positive().optional()
246453
246882
  });
246454
246883
  turnStepInterruptedEventSchema = object({
246455
246884
  type: literal("turn.step.interrupted"),
@@ -246586,8 +247015,30 @@ var init_events$1 = __esmMin((() => {
246586
247015
  });
246587
247016
  cronFiredEventSchema = object({
246588
247017
  type: literal("cron.fired"),
246589
- origin: cronJobOriginSchema,
246590
- prompt: string()
247018
+ origin: cronJobOriginSchema
247019
+ });
247020
+ cronRunCreatedEventSchema = object({
247021
+ type: literal("cron.run.created"),
247022
+ runId: string(),
247023
+ jobId: string(),
247024
+ coalescedCount: number$1(),
247025
+ toolScopeDigest: string().nullable()
247026
+ });
247027
+ cronRunStartedEventSchema = object({
247028
+ type: literal("cron.run.started"),
247029
+ runId: string(),
247030
+ jobId: string(),
247031
+ turnId: number$1()
247032
+ });
247033
+ cronRunTerminalEventSchema = object({
247034
+ type: _enum(["cron.run.completed", "cron.run.failed", "cron.run.cancelled", "cron.run.lost"]),
247035
+ runId: string(),
247036
+ jobId: string(),
247037
+ durationMs: number$1().optional(),
247038
+ toolCalls: number$1(),
247039
+ toolErrors: number$1(),
247040
+ outputCount: number$1(),
247041
+ errorCategory: string().optional()
246591
247042
  });
246592
247043
  attentionIntentSchema = object({
246593
247044
  accepted: literal(true),
@@ -246701,6 +247152,9 @@ var init_events$1 = __esmMin((() => {
246701
247152
  backgroundTaskStartedEventSchema,
246702
247153
  backgroundTaskTerminatedEventSchema,
246703
247154
  cronFiredEventSchema,
247155
+ cronRunCreatedEventSchema,
247156
+ cronRunStartedEventSchema,
247157
+ cronRunTerminalEventSchema,
246704
247158
  attentionAuthorizedEventSchema,
246705
247159
  promptSubmittedEventSchema
246706
247160
  ]);
@@ -247246,7 +247700,8 @@ var init_approval$2 = __esmMin((() => {
247246
247700
  approvalDecisionSchema = _enum([
247247
247701
  "approved",
247248
247702
  "rejected",
247249
- "cancelled"
247703
+ "cancelled",
247704
+ "edited"
247250
247705
  ]);
247251
247706
  approvalScopeSchema = _enum(["session"]);
247252
247707
  approvalRequestSchema = object({
@@ -247257,6 +247712,7 @@ var init_approval$2 = __esmMin((() => {
247257
247712
  tool_name: string().min(1),
247258
247713
  action: string(),
247259
247714
  tool_input_display: unknown(),
247715
+ allow_edit: boolean$1().optional(),
247260
247716
  created_at: isoDateTimeSchema,
247261
247717
  expires_at: isoDateTimeSchema
247262
247718
  });
@@ -247264,7 +247720,8 @@ var init_approval$2 = __esmMin((() => {
247264
247720
  decision: approvalDecisionSchema,
247265
247721
  scope: approvalScopeSchema.optional(),
247266
247722
  feedback: string().optional(),
247267
- selected_label: string().optional()
247723
+ selected_label: string().optional(),
247724
+ edited_tool_input: unknown().optional()
247268
247725
  });
247269
247726
  }));
247270
247727
  //#endregion
@@ -251720,6 +252177,89 @@ var init_task_update = __esmMin((() => {
251720
252177
  };
251721
252178
  }));
251722
252179
  //#endregion
252180
+ //#region ../../packages/agent-core/src/tools/background/task-resume.ts
252181
+ var DurableTaskResumeRuntime$1, TaskResumeInputSchema, TaskResumeTool;
252182
+ var init_task_resume = __esmMin((() => {
252183
+ init_zod$1();
252184
+ init_input_schema();
252185
+ init_rule_match();
252186
+ init_agent_task();
252187
+ ({ DurableTaskResumeRuntime: DurableTaskResumeRuntime$1 } = createRequire(import.meta.url)("./bin/durable-task-resume-runtime.cjs"));
252188
+ TaskResumeInputSchema = object({
252189
+ task_id: string().trim().min(1).describe("The lost agent task ID, or completed TaskResume successor, to continue."),
252190
+ prompt: string().trim().min(1).max(32768).describe("New instructions for the preserved agent context."),
252191
+ description: string().trim().min(1).max(1024).describe("Short description for the replacement background task."),
252192
+ timeout_minutes: number$1().int().min(0).max(10080).optional().describe("Wall-clock continuation interval for the replacement run. Defaults to 240 minutes; 0 disables it for this run.")
252193
+ });
252194
+ TaskResumeTool = class {
252195
+ manager;
252196
+ subagentHost;
252197
+ runtime;
252198
+ name = "TaskResume";
252199
+ description = "Explicitly continue a recoverable background agent task after a process loss. This resumes the same agent and preserved context, but creates a new background task ID linked to the terminal source task. Only lost agent tasks and completed TaskResume successors are accepted. It never resumes automatically at startup.";
252200
+ parameters = toInputJsonSchema(TaskResumeInputSchema);
252201
+ constructor(manager, subagentHost) {
252202
+ this.manager = manager;
252203
+ this.subagentHost = subagentHost;
252204
+ this.runtime = new DurableTaskResumeRuntime$1({
252205
+ getTask: (taskId) => manager.getTask(taskId),
252206
+ getIntent: (taskId) => manager.resumeStore?.getBySourceTaskId(taskId),
252207
+ writeIntent: (intent) => manager.resumeStore.write(intent),
252208
+ markIntentStarted: (taskId, startedAt) => manager.resumeStore.markStarted(taskId, startedAt),
252209
+ reserveTaskId: (prefix) => manager.reserveTaskId(prefix),
252210
+ resumeAgent: (agentId, options) => subagentHost.resume(agentId, options),
252211
+ createTask: (handle, description, metadata) => new AgentBackgroundTask(handle, description, subagentHost, metadata.controller ?? new AbortController(), {
252212
+ timeoutMs: resolveSubagentTimeoutMs({ perRunMinutes: metadata.timeoutMinutes }),
252213
+ runInBackground: true,
252214
+ parentToolCallId: metadata.parentToolCallId,
252215
+ responseFormat: void 0,
252216
+ resumed: true,
252217
+ replacesTaskId: metadata.replacesTaskId,
252218
+ resumeRootTaskId: metadata.resumeRootTaskId
252219
+ }),
252220
+ registerTask: (task, options) => manager.registerTask(task, options),
252221
+ awaitTaskPersisted: (taskId) => manager.awaitTaskPersisted(taskId),
252222
+ emitEvent: (event) => manager.agent.emitEvent(event),
252223
+ now: () => Date.now()
252224
+ });
252225
+ }
252226
+ resolveExecution(args) {
252227
+ return {
252228
+ description: `Resuming agent task ${args.task_id}`,
252229
+ approvalRule: this.name,
252230
+ matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.task_id),
252231
+ execute: (ctx) => this.execute(args, ctx)
252232
+ };
252233
+ }
252234
+ async execute(args, { toolCallId, signal, turnId }) {
252235
+ const controller = new AbortController();
252236
+ try {
252237
+ signal.throwIfAborted();
252238
+ const result = await this.runtime.resume({
252239
+ taskId: args.task_id,
252240
+ prompt: args.prompt,
252241
+ description: args.description,
252242
+ timeoutMinutes: args.timeout_minutes,
252243
+ parentToolCallId: toolCallId,
252244
+ toolScope: this.subagentHost.toolScopeForTurn(Number(turnId)),
252245
+ controller,
252246
+ signal
252247
+ });
252248
+ return {
252249
+ output: `task_id: ${result.taskId}\nstatus: ${result.status}\nagent_id: ${result.agentId}\nreplaces_task_id: ${result.replacesTaskId}\nresume_root_task_id: ${result.resumeRootTaskId}\nresumed: true`,
252250
+ isError: false
252251
+ };
252252
+ } catch (error) {
252253
+ controller.abort();
252254
+ return {
252255
+ output: error instanceof Error ? error.message : String(error),
252256
+ isError: true
252257
+ };
252258
+ }
252259
+ }
252260
+ };
252261
+ }));
252262
+ //#endregion
251723
252263
  //#region ../../packages/agent-core/src/tools/background/task-stop.md?raw
251724
252264
  var task_stop_default;
251725
252265
  var init_task_stop$1 = __esmMin((() => {
@@ -251907,6 +252447,67 @@ var init_cron_list = __esmMin((() => {
251907
252447
  };
251908
252448
  }));
251909
252449
  //#endregion
252450
+ //#region ../../packages/agent-core/src/tools/cron/cron-runs.ts
252451
+ var CronRunListInputSchema, CronRunOutputInputSchema, CronRunListTool, CronRunOutputTool;
252452
+ var init_cron_runs = __esmMin((() => {
252453
+ init_zod$1();
252454
+ init_input_schema();
252455
+ CronRunListInputSchema = object({
252456
+ job_id: string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u).optional().describe("Optional cron job id filter."),
252457
+ status: string().regex(/^(buffered|running|completed|failed|cancelled|lost)$/u).optional().describe("Optional run status filter."),
252458
+ limit: number$1().int().min(1).max(100).optional().default(20).describe("Maximum number of newest run receipts.")
252459
+ }).strict();
252460
+ CronRunOutputInputSchema = object({
252461
+ run_id: string().regex(/^[0-9a-f]{16}$/u).describe("The 16-hex run id returned by CronRunList.")
252462
+ }).strict();
252463
+ CronRunListTool = class {
252464
+ manager;
252465
+ name = "CronRunList";
252466
+ description = "List bounded private receipts for cron runs in this session. Receipts contain lifecycle, tool counts, and output references, never prompts, thoughts, raw tool arguments, results, headers, or approval feedback.";
252467
+ parameters = toInputJsonSchema(CronRunListInputSchema);
252468
+ constructor(manager) {
252469
+ this.manager = manager;
252470
+ }
252471
+ resolveExecution(args) {
252472
+ return {
252473
+ description: "Listing private cron run receipts",
252474
+ approvalRule: this.name,
252475
+ execute: async () => {
252476
+ const runs = this.manager.listRuns({
252477
+ jobId: args.job_id,
252478
+ status: args.status,
252479
+ limit: args.limit
252480
+ });
252481
+ return { output: JSON.stringify({ runs }, null, 2), isError: false };
252482
+ }
252483
+ };
252484
+ }
252485
+ };
252486
+ CronRunOutputTool = class {
252487
+ manager;
252488
+ name = "CronRunOutput";
252489
+ description = "Read one private cron run receipt and its bounded final assistant message. Raw prompts, thoughts, tool arguments, tool results, headers, approvals, and Bash-inferred files are never returned.";
252490
+ parameters = toInputJsonSchema(CronRunOutputInputSchema);
252491
+ constructor(manager) {
252492
+ this.manager = manager;
252493
+ }
252494
+ resolveExecution(args) {
252495
+ return {
252496
+ description: `Reading private cron run ${args.run_id}`,
252497
+ approvalRule: this.name,
252498
+ execute: async () => {
252499
+ const run = this.manager.readRunOutput(args.run_id);
252500
+ if (run === null) return {
252501
+ output: `No cron run with id ${args.run_id} exists in this session.`,
252502
+ isError: true
252503
+ };
252504
+ return { output: JSON.stringify(run, null, 2), isError: false };
252505
+ }
252506
+ };
252507
+ }
252508
+ };
252509
+ }));
252510
+ //#endregion
251910
252511
  //#region ../../packages/agent-core/src/agent/permission/policies/deny-all.ts
251911
252512
  var DenyAllPermissionPolicy;
251912
252513
  var init_deny_all = __esmMin((() => {
@@ -252318,6 +252919,7 @@ var init_subagent_batch = __esmMin((() => {
252318
252919
  description: task.description,
252319
252920
  swarmIndex: task.swarmIndex,
252320
252921
  runInBackground: task.runInBackground,
252922
+ responseFormat: task.responseFormat,
252321
252923
  compactBeforeRetry: attempt.state.retryCount > 0,
252322
252924
  signal: attempt.controller.signal,
252323
252925
  onReady: () => {
@@ -252342,11 +252944,13 @@ var init_subagent_batch = __esmMin((() => {
252342
252944
  return this.failedAttemptOutcome(attempt, error);
252343
252945
  }
252344
252946
  attempt.state.agentId = handle.agentId;
252947
+ attempt.state.profileName = handle.profileName;
252345
252948
  try {
252346
252949
  const completion = await handle.completion;
252347
252950
  return {
252348
252951
  task,
252349
252952
  agentId: handle.agentId,
252953
+ profileName: handle.profileName,
252350
252954
  status: "completed",
252351
252955
  result: completion.result,
252352
252956
  usage: completion.usage
@@ -252370,6 +252974,7 @@ var init_subagent_batch = __esmMin((() => {
252370
252974
  return {
252371
252975
  task: attempt.state.task,
252372
252976
  agentId: attempt.state.agentId,
252977
+ profileName: attempt.state.profileName,
252373
252978
  status,
252374
252979
  state: attempt.state.agentId === void 0 ? "not_started" : "started",
252375
252980
  error: this.attemptErrorMessage(attempt, error, status)
@@ -252633,7 +253238,7 @@ async function runChildTurnToCompletion(child, signal) {
252633
253238
  }
252634
253239
  return completion.stopReason;
252635
253240
  }
252636
- async function completeChildTurnWithMaxTokensHandoff(child, signal) {
253241
+ async function completeChildTurnWithMaxTokensHandoff(child, signal, promptOrigin = SUBAGENT_PROMPT_ORIGIN) {
252637
253242
  let stopReason = await runChildTurnToCompletion(child, signal);
252638
253243
  let handoffAttempts = 0;
252639
253244
  while (shouldRequestSubagentHandoff(stopReason, handoffAttempts)) {
@@ -252642,7 +253247,7 @@ async function completeChildTurnWithMaxTokensHandoff(child, signal) {
252642
253247
  if (child.turn.prompt([{
252643
253248
  type: "text",
252644
253249
  text: SUBAGENT_MAX_TOKENS_HANDOFF_PROMPT
252645
- }], SUBAGENT_PROMPT_ORIGIN) === null) throw new Error("Subagent could not start its max_tokens recovery handoff.");
253250
+ }], promptOrigin) === null) throw new Error("Subagent could not start its max_tokens recovery handoff.");
252646
253251
  stopReason = await runChildTurnToCompletion(child, signal);
252647
253252
  }
252648
253253
  if (stopReason === "max_tokens") throw new Error(buildSubagentMaxTokensFailure(lastAssistantText(child)));
@@ -252659,7 +253264,7 @@ function lastAssistantText(agent) {
252659
253264
  }
252660
253265
  return "";
252661
253266
  }
252662
- async function completeStructuredSubagentResult(child, childId, profileName, responseFormat, signal) {
253267
+ async function completeStructuredSubagentResult(child, childId, profileName, responseFormat, signal, promptOrigin = SUBAGENT_PROMPT_ORIGIN) {
252663
253268
  let validation = validateStructuredSubagentOutput(lastAssistantText(child), responseFormat);
252664
253269
  if (validation.validatorException === true) throw new Error(validation.error);
252665
253270
  if (!validation.ok) {
@@ -252667,8 +253272,8 @@ async function completeStructuredSubagentResult(child, childId, profileName, res
252667
253272
  if (child.turn.prompt([{
252668
253273
  type: "text",
252669
253274
  text: buildStructuredResponseRepairPrompt(responseFormat, validation.error)
252670
- }], SUBAGENT_PROMPT_ORIGIN) === null) throw new Error("Subagent could not start its structured-output repair turn.");
252671
- await completeChildTurnWithMaxTokensHandoff(child, signal);
253275
+ }], promptOrigin) === null) throw new Error("Subagent could not start its structured-output repair turn.");
253276
+ await completeChildTurnWithMaxTokensHandoff(child, signal, promptOrigin);
252672
253277
  signal.throwIfAborted();
252673
253278
  validation = validateStructuredSubagentOutput(lastAssistantText(child), responseFormat);
252674
253279
  if (validation.validatorException === true) throw new Error(validation.error);
@@ -252681,7 +253286,7 @@ function shouldSuppressQueuedAttemptFailureEvent(options, error) {
252681
253286
  if (isProviderRateLimitError(error)) return true;
252682
253287
  return isAbortError$4(error) || options.signal.aborted;
252683
253288
  }
252684
- var DEFAULT_SUBAGENT_TIMEOUT_MS, resolveSubagentTimeoutMs, runAgentWithTimeoutContinuation, buildSubagentUsageDelta, inheritSubagentAllowedTools, inheritSubagentLifecycleTools, STRUCTURED_SUBAGENT_OUTPUT_ERROR, prepareStructuredResponseFormat, validateStructuredSubagentOutput, buildStructuredResponseFormatReminder, buildStructuredResponseRepairPrompt, buildStructuredSubagentEnvelope, SUBAGENT_MAX_TOKENS_ERROR, SUBAGENT_MAX_TOKENS_HANDOFF_PROMPT, buildSubagentMaxTokensFailure, isSubagentMaxTokensTurnError, shouldRequestSubagentHandoff, SUMMARY_MIN_LENGTH, SUMMARY_CONTINUATION_ATTEMPTS, HOOK_TEXT_PREVIEW_LENGTH, TOOL_CALL_DISABLED_MESSAGE, SUBAGENT_PROMPT_ORIGIN, SIDE_QUESTION_SYSTEM_REMINDER, SessionSubagentHost;
253289
+ var DEFAULT_SUBAGENT_TIMEOUT_MS, resolveSubagentTimeoutMs, runAgentWithTimeoutContinuation, buildSubagentUsageDelta, inheritSubagentAllowedTools, inheritSubagentLifecycleTools, prepareSubagentSkillPolicy, profileWithSubagentSkillTools, restoreSubagentSkillPolicy, STRUCTURED_SUBAGENT_OUTPUT_ERROR, prepareStructuredResponseFormat, validateStructuredSubagentOutput, buildStructuredResponseFormatReminder, buildStructuredResponseRepairPrompt, buildStructuredSubagentEnvelope, SUBAGENT_MAX_TOKENS_ERROR, SUBAGENT_MAX_TOKENS_HANDOFF_PROMPT, buildSubagentMaxTokensFailure, isSubagentMaxTokensTurnError, shouldRequestSubagentHandoff, SUBAGENT_FORK_REMINDER, projectSubagentForkContext, resolveSubagentContextMode, SUMMARY_MIN_LENGTH, SUMMARY_CONTINUATION_ATTEMPTS, HOOK_TEXT_PREVIEW_LENGTH, TOOL_CALL_DISABLED_MESSAGE, SUBAGENT_PROMPT_ORIGIN, SIDE_QUESTION_SYSTEM_REMINDER, SessionSubagentHost;
252685
253290
  var init_subagent_host = __esmMin((() => {
252686
253291
  init_src$4();
252687
253292
  init_errors$8();
@@ -252696,6 +253301,8 @@ var init_subagent_host = __esmMin((() => {
252696
253301
  ({ DEFAULT_SUBAGENT_TIMEOUT_MS, resolveSubagentTimeoutMs, runAgentWithTimeoutContinuation } = createRequire(import.meta.url)("./bin/subagent-timeout-policy.cjs"));
252697
253302
  ({ buildSubagentUsageDelta } = createRequire(import.meta.url)("./bin/subagent-usage-rollup-policy.cjs"));
252698
253303
  ({ inheritSubagentAllowedTools, inheritSubagentLifecycleTools } = createRequire(import.meta.url)("./bin/subagent-tool-policy.cjs"));
253304
+ ({ prepareSubagentSkillPolicy, profileWithSubagentSkillTools, restoreSubagentSkillPolicy } = createRequire(import.meta.url)("./bin/subagent-skill-policy.cjs"));
253305
+ ({ SUBAGENT_FORK_REMINDER, projectSubagentForkContext, resolveSubagentContextMode } = createRequire(import.meta.url)("./bin/subagent-context-fork-policy.cjs"));
252699
253306
  ({
252700
253307
  STRUCTURED_SUBAGENT_OUTPUT_ERROR,
252701
253308
  prepareStructuredResponseFormat,
@@ -252719,6 +253326,12 @@ var init_subagent_host = __esmMin((() => {
252719
253326
  kind: "system_trigger",
252720
253327
  name: "subagent"
252721
253328
  };
253329
+ function subagentPromptOrigin(toolScope) {
253330
+ return toolScope === void 0 ? SUBAGENT_PROMPT_ORIGIN : {
253331
+ ...SUBAGENT_PROMPT_ORIGIN,
253332
+ toolScope
253333
+ };
253334
+ }
252722
253335
  SIDE_QUESTION_SYSTEM_REMINDER = `
252723
253336
  This is a side-channel conversation with the user. You should answer user questions directly based on what you already know.
252724
253337
 
@@ -252757,21 +253370,37 @@ IMPORTANT:
252757
253370
  }
252758
253371
  return this.session.getReadyAgent(currentId);
252759
253372
  }
253373
+ toolScopeForTurn(turnId) {
253374
+ return inheritedCronToolScope(this.session.getReadyAgent(this.ownerAgentId)?.turn.toolScopeForTurn(turnId));
253375
+ }
253376
+ isRootAgent() {
253377
+ return this.session.metadata.agents[this.ownerAgentId]?.parentAgentId == null;
253378
+ }
252760
253379
  async spawn(options) {
252761
253380
  options.signal.throwIfAborted();
252762
253381
  const parent = await this.session.ensureAgentResumed(this.ownerAgentId);
253382
+ const contextMode = resolveSubagentContextMode({
253383
+ requested: options.contextMode,
253384
+ isRoot: this.isRootAgent()
253385
+ });
252763
253386
  const profile = this.resolveProfile(parent, options.profileName);
253387
+ const skillPolicy = prepareSubagentSkillPolicy(profile.subagentSkills, this.session.skills);
253388
+ const effectiveProfile = profileWithSubagentSkillTools(profile, skillPolicy);
252764
253389
  const { id, agent } = await this.session.createAgent({
252765
253390
  type: "sub",
252766
- generate: parent.rawGenerate
253391
+ generate: parent.rawGenerate,
253392
+ skillRegistry: skillPolicy.registry
252767
253393
  }, {
252768
253394
  parentAgentId: this.ownerAgentId,
252769
- swarmItem: options.swarmItem
253395
+ swarmItem: options.swarmItem,
253396
+ profileName: profile.name,
253397
+ skillPolicy: skillPolicy.metadata
252770
253398
  });
252771
253399
  const completion = this.runWithTrackedChildUsage(parent, agent, id, options, async (runOptions) => {
252772
253400
  this.emitSubagentSpawned(parent, id, profile.name, runOptions);
252773
253401
  try {
252774
- await this.configureChild(parent, agent, profile);
253402
+ await this.configureChild(parent, agent, effectiveProfile);
253403
+ if (contextMode === "fork") this.seedForkedContext(parent, agent);
252775
253404
  return await this.runPromptTurn(parent, id, agent, profile.name, runOptions);
252776
253405
  } catch (error) {
252777
253406
  this.emitSubagentFailed(parent, id, runOptions, error);
@@ -252845,7 +253474,7 @@ IMPORTANT:
252845
253474
  await child.fullCompaction.block(runOptions.signal);
252846
253475
  }
252847
253476
  this.emitSubagentStarted(parent, agentId);
252848
- if (child.turn.retry("agent-host") === null) throw new Error(`Agent instance "${agentId}" could not start a retry turn`);
253477
+ if (child.turn.retry("agent-host", runOptions.toolScope) === null) throw new Error(`Agent instance "${agentId}" could not start a retry turn`);
252849
253478
  this.observeFirstRequest(child, runOptions);
252850
253479
  return await this.waitForChildCompletion(parent, agentId, child, profileName, runOptions);
252851
253480
  } catch (error) {
@@ -252968,23 +253597,29 @@ IMPORTANT:
252968
253597
  const gitContext = await collectGitContext(child.kaos, child.config.cwd);
252969
253598
  if (gitContext) childPrompt = `${gitContext}\n\n${childPrompt}`;
252970
253599
  }
253600
+ if (options.systemReminder !== void 0) child.context.appendSystemReminder(options.systemReminder, {
253601
+ kind: "system_trigger",
253602
+ name: "durable_task_resume"
253603
+ });
252971
253604
  if (options.responseFormat !== void 0) child.context.appendSystemReminder(buildStructuredResponseFormatReminder(options.responseFormat), {
252972
253605
  kind: "system_trigger",
252973
253606
  name: "subagent_response_format"
252974
253607
  });
252975
253608
  this.emitSubagentStarted(parent, childId);
253609
+ const childOrigin = subagentPromptOrigin(options.toolScope);
252976
253610
  if (child.turn.prompt([{
252977
253611
  type: "text",
252978
253612
  text: childPrompt
252979
- }], SUBAGENT_PROMPT_ORIGIN) === null) throw new Error(`Agent instance "${childId}" could not start a turn`);
253613
+ }], childOrigin) === null) throw new Error(`Agent instance "${childId}" could not start a turn`);
252980
253614
  this.observeFirstRequest(child, options);
252981
253615
  return this.waitForChildCompletion(parent, childId, child, profileName, options);
252982
253616
  }
252983
253617
  async waitForChildCompletion(parent, childId, child, profileName, options) {
252984
- await completeChildTurnWithMaxTokensHandoff(child, options.signal);
253618
+ const childOrigin = subagentPromptOrigin(options.toolScope);
253619
+ await completeChildTurnWithMaxTokensHandoff(child, options.signal, childOrigin);
252985
253620
  let result;
252986
253621
  if (options.responseFormat !== void 0) {
252987
- const structuredResult = await completeStructuredSubagentResult(child, childId, profileName, options.responseFormat, options.signal);
253622
+ const structuredResult = await completeStructuredSubagentResult(child, childId, profileName, options.responseFormat, options.signal, childOrigin);
252988
253623
  result = buildStructuredSubagentEnvelope({
252989
253624
  agentId: childId,
252990
253625
  profileName,
@@ -253001,8 +253636,8 @@ IMPORTANT:
253001
253636
  child.turn.prompt([{
253002
253637
  type: "text",
253003
253638
  text: summary_continuation_default
253004
- }], SUBAGENT_PROMPT_ORIGIN);
253005
- await completeChildTurnWithMaxTokensHandoff(child, options.signal);
253639
+ }], childOrigin);
253640
+ await completeChildTurnWithMaxTokensHandoff(child, options.signal, childOrigin);
253006
253641
  result = lastAssistantText(child);
253007
253642
  }
253008
253643
  }
@@ -253029,10 +253664,22 @@ IMPORTANT:
253029
253664
  });
253030
253665
  const context = await prepareSystemPromptContext(this.session.systemContextKaos(child.kaos.getcwd()), this.session.options.blunHomeDir, { additionalDirs: child.getAdditionalDirs() });
253031
253666
  child.useProfile(profile, context, this.session.options.blunHomeDir);
253032
- child.tools.inheritUserTools(parent.tools);
253667
+ child.tools.inheritUserTools(parent.tools, /* @__PURE__ */ new Set(["Skill"]));
253033
253668
  inheritSubagentLifecycleTools(parent.tools, child.tools);
253034
253669
  inheritSubagentAllowedTools(parent.tools, child.tools);
253035
253670
  }
253671
+ seedForkedContext(parent, child) {
253672
+ const projection = projectSubagentForkContext(parent.context.history);
253673
+ child.context.useProjectedHistoryFrom({
253674
+ history: projection.messages,
253675
+ project: (history) => history
253676
+ });
253677
+ child.context.appendSystemReminder(SUBAGENT_FORK_REMINDER, {
253678
+ kind: "system_trigger",
253679
+ name: "subagent_context_fork"
253680
+ });
253681
+ return projection;
253682
+ }
253036
253683
  async triggerSubagentStart(parent, profileName, prompt, signal) {
253037
253684
  await parent.hooks?.trigger("SubagentStart", {
253038
253685
  matcherValue: profileName,
@@ -253064,10 +253711,11 @@ IMPORTANT:
253064
253711
  subagentId: childId,
253065
253712
  subagentName: profileName,
253066
253713
  parentToolCallId: options.parentToolCallId,
253067
- parentToolCallUuid: options.parentToolCallUuid,
253068
- parentAgentId: this.ownerAgentId,
253069
- description: options.description,
253070
- swarmIndex: options.swarmIndex,
253714
+ parentToolCallUuid: options.parentToolCallUuid,
253715
+ parentAgentId: this.ownerAgentId,
253716
+ description: options.description,
253717
+ contextMode: options.contextMode === "fork" ? "fork" : "isolated",
253718
+ swarmIndex: options.swarmIndex,
253071
253719
  runInBackground: options.runInBackground
253072
253720
  });
253073
253721
  parent.telemetry.track("subagent_created", {
@@ -253160,7 +253808,7 @@ function buildSubagentDescriptions(subagents) {
253160
253808
  return `${header}\n Tools: ${subagent.tools.join(", ")}`;
253161
253809
  }).join("\n");
253162
253810
  }
253163
- var AgentToolInputSchema, BACKGROUND_AGENT_UNAVAILABLE, AgentTool, USER_INTERRUPTED_SUBAGENT_MESSAGE, resolveSubagentRunMode;
253811
+ var AgentToolInputSchema, BACKGROUND_AGENT_UNAVAILABLE, SUBAGENT_CONTEXT_FORK_TOOL_DESCRIPTION, AgentTool, USER_INTERRUPTED_SUBAGENT_MESSAGE, resolveSubagentRunMode;
253164
253812
  var init_agent$1 = __esmMin((() => {
253165
253813
  init_zod$1();
253166
253814
  init_tool_access();
@@ -253174,6 +253822,7 @@ var init_agent$1 = __esmMin((() => {
253174
253822
  init_agent_background_enabled();
253175
253823
  init_agent$2();
253176
253824
  ({ resolveSubagentRunMode } = createRequire(import.meta.url)("./bin/subagent-parent-responsiveness.cjs"));
253825
+ SUBAGENT_CONTEXT_FORK_TOOL_DESCRIPTION = "The default context_mode=isolated starts with zero conversation context. For a new root-level subagent whose work genuinely depends on this exact conversation, context_mode=fork passes only a bounded, redacted projection of direct local user text and completed text-only assistant replies. It never passes private channel messages, system injections, attachments, tool calls, arguments, or results. The delegated prompt remains required and authoritative. Fork is unavailable when resuming and unavailable to nested subagents.";
253177
253826
  AgentToolInputSchema = preprocess((input) => {
253178
253827
  if (typeof input !== "object" || input === null || Array.isArray(input)) return input;
253179
253828
  const normalized = { ...input };
@@ -253186,6 +253835,7 @@ var init_agent$1 = __esmMin((() => {
253186
253835
  prompt: string().describe("Full task prompt for the subagent"),
253187
253836
  description: string().describe("Short task description (3-5 words) for UI display"),
253188
253837
  subagent_type: string().optional().describe("One of the available agent types (see \"Available agent types\" in this tool description). Defaults to \"coder\" when omitted."),
253838
+ context_mode: _enum(["isolated", "fork"]).optional().describe("Context boundary for a new subagent. Defaults to isolated. fork is root-only and passes a bounded redacted user/assistant projection without tools, private channels, system injections, attachments, or tool results."),
253189
253839
  resume: string().optional().describe("Optional agent ID to resume instead of creating a new instance. When set, do not also pass subagent_type — the resumed agent keeps its own type, and supplying both is rejected."),
253190
253840
  run_in_background: boolean$1().optional().describe("Compatibility option. Normal subagents run detached when task management is available. A response_format call requires this to be false or omitted and runs in the foreground for validation."),
253191
253841
  timeout_minutes: number$1().int().min(0).max(10080).optional().describe("Wall-clock interval before the same agent is continued automatically. Defaults to 240 minutes. Set 0 to disable the interval for this run."),
@@ -253217,7 +253867,7 @@ var init_agent$1 = __esmMin((() => {
253217
253867
  const log = options?.log;
253218
253868
  this.allowBackground = options?.allowBackground ?? true;
253219
253869
  const typeLines = buildSubagentDescriptions(subagents);
253220
- const baseDescription = `${agent_default}\n\n${this.allowBackground ? agent_background_enabled_default : agent_background_disabled_default}`;
253870
+ const baseDescription = `${agent_default}\n\n${SUBAGENT_CONTEXT_FORK_TOOL_DESCRIPTION}\n\n${this.allowBackground ? agent_background_enabled_default : agent_background_disabled_default}`;
253221
253871
  this.description = typeLines ? `${baseDescription}\n\nAvailable agent types (pass via subagent_type):\n${typeLines}` : baseDescription;
253222
253872
  this.log = log;
253223
253873
  }
@@ -253246,7 +253896,7 @@ var init_agent$1 = __esmMin((() => {
253246
253896
  execute: (ctx) => this.execution(args, ctx)
253247
253897
  };
253248
253898
  }
253249
- async execution(args, { toolCallId, signal }) {
253899
+ async execution(args, { toolCallId, signal, turnId }) {
253250
253900
  try {
253251
253901
  signal.throwIfAborted();
253252
253902
  if (args.response_format !== void 0 && args.run_in_background === true) return {
@@ -253269,6 +253919,19 @@ var init_agent$1 = __esmMin((() => {
253269
253919
  const runInBackground = responseFormat === void 0 ? resolvedRunMode.runInBackground : false;
253270
253920
  const requestedProfileName = args.subagent_type?.length ? args.subagent_type : void 0;
253271
253921
  const resumeAgentId = args.resume?.trim();
253922
+ let contextMode;
253923
+ try {
253924
+ contextMode = resolveSubagentContextMode({
253925
+ requested: args.context_mode,
253926
+ resume: resumeAgentId !== void 0 && resumeAgentId.length > 0,
253927
+ isRoot: this.subagentHost.isRootAgent()
253928
+ });
253929
+ } catch (error) {
253930
+ return {
253931
+ output: error instanceof Error ? error.message : String(error),
253932
+ isError: true
253933
+ };
253934
+ }
253272
253935
  if (resumeAgentId !== void 0 && resumeAgentId.length > 0 && requestedProfileName !== void 0) return {
253273
253936
  output: "Cannot set subagent_type when resuming an existing agent. Resume by agent id only.",
253274
253937
  isError: true
@@ -253289,6 +253952,8 @@ var init_agent$1 = __esmMin((() => {
253289
253952
  description: args.description,
253290
253953
  runInBackground,
253291
253954
  responseFormat,
253955
+ contextMode,
253956
+ toolScope: this.subagentHost.toolScopeForTurn(Number(turnId)),
253292
253957
  signal: controller.signal
253293
253958
  };
253294
253959
  let handle;
@@ -253365,7 +254030,7 @@ var init_agent$1 = __esmMin((() => {
253365
254030
  //#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-swarm.md?raw
253366
254031
  var agent_swarm_default;
253367
254032
  var init_agent_swarm$1 = __esmMin((() => {
253368
- agent_swarm_default = "Launch multiple subagents from one prompt template, existing agent resumes, or both.\n\nUse AgentSwarm when many subagents should run the same kind of task over different inputs. The placeholder is exactly `{{item}}`. For example, with `prompt_template` set to `Review {{item}} for likely regressions.` and `items` set to `[\"src/a.ts\", \"src/b.ts\"]`, AgentSwarm launches two new subagents with those two concrete prompts. For a few differently-shaped tasks, make separate `Agent` calls in one message instead.\n\nUse `resume_agent_ids` to continue subagents that already exist from earlier work, such as ones that failed or timed out: map each agent id to the prompt for that resumed subagent (usually `continue` if no extra information is needed). You may combine `resume_agent_ids` with `items` in the same call to resume existing subagents and launch new ones. Do not duplicate resumed work in `items`.\n\nEach of these is enforced — a violation is rejected before any subagent starts: provide at least 2 `items` unless you pass `resume_agent_ids`; whenever `items` are present, `prompt_template` is required and must contain `{{item}}`; and the filled-in prompts must be distinct (two items that expand to the same prompt are rejected).\n\nUse enough subagents to keep the work focused and parallel. AgentSwarm supports up to 128 subagents, and launches are queued automatically, so it is safe to split large tasks into many clear, independent items.\n\nIf `AgentSwarm` is called, that call must be the only tool call in the response.\n";
254033
+ agent_swarm_default = "Launch multiple subagents from one prompt template, existing agent resumes, or both.\n\nUse AgentSwarm when many subagents should run the same kind of task over different inputs. The placeholder is exactly `{{item}}`. For example, with `prompt_template` set to `Review {{item}} for likely regressions.` and `items` set to `[\"src/a.ts\", \"src/b.ts\"]`, AgentSwarm launches two new subagents with those two concrete prompts. For a few differently-shaped tasks, make separate `Agent` calls in one message instead.\n\nUse `resume_agent_ids` to continue subagents that already exist from earlier work, such as ones that failed or timed out: map each agent id to the prompt for that resumed subagent (usually `continue` if no extra information is needed). You may combine `resume_agent_ids` with `items` in the same call to resume existing subagents and launch new ones. Do not duplicate resumed work in `items`.\n\nEach of these is enforced — a violation is rejected before any subagent starts: provide at least 2 `items` unless you pass `resume_agent_ids`; whenever `items` are present, `prompt_template` is required and must contain `{{item}}`; and the filled-in prompts must be distinct (two items that expand to the same prompt are rejected).\n\nUse enough subagents to keep the work focused and parallel. AgentSwarm supports up to 128 subagents, and launches are queued automatically, so it is safe to split large tasks into many clear, independent items.\n\nUse `response_format` when all children must return one shared bounded JSON shape. Each child is validated and repaired independently, and the final result is canonical task-order JSON. Omit it to retain the existing XML result format unchanged.\n\nIf `AgentSwarm` is called, that call must be the only tool call in the response.\n";
253369
254034
  }));
253370
254035
  //#endregion
253371
254036
  //#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-swarm.ts
@@ -253448,13 +254113,14 @@ function renderSwarmSummary(completed, failed, aborted = 0) {
253448
254113
  function escapeXmlAttribute(value) {
253449
254114
  return value.replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
253450
254115
  }
253451
- var DEFAULT_SUBAGENT_TYPE, PROMPT_TEMPLATE_PLACEHOLDER, MAX_AGENT_SWARM_SUBAGENTS, AgentSwarmToolInputSchema, AgentSwarmTool;
254116
+ var DEFAULT_SUBAGENT_TYPE, PROMPT_TEMPLATE_PLACEHOLDER, MAX_AGENT_SWARM_SUBAGENTS, renderStructuredSwarmResults, parseStructuredSwarmDisplay, structuredSwarmToolResult, AgentSwarmToolInputSchema, AgentSwarmTool;
253452
254117
  var init_agent_swarm = __esmMin((() => {
253453
254118
  init_zod$1();
253454
254119
  init_subagent_host();
253455
254120
  init_tool_access();
253456
254121
  init_input_schema();
253457
254122
  init_agent_swarm$1();
254123
+ ({ renderStructuredSwarmResults, parseStructuredSwarmDisplay, structuredSwarmToolResult } = createRequire(import.meta.url)("./bin/structured-agent-swarm-output.cjs"));
253458
254124
  DEFAULT_SUBAGENT_TYPE = "coder";
253459
254125
  PROMPT_TEMPLATE_PLACEHOLDER = "{{item}}";
253460
254126
  MAX_AGENT_SWARM_SUBAGENTS = 128;
@@ -253464,7 +254130,11 @@ var init_agent_swarm = __esmMin((() => {
253464
254130
  prompt_template: string().trim().min(1).optional().describe(`Prompt template for each subagent. The ${PROMPT_TEMPLATE_PLACEHOLDER} placeholder is replaced with each item value.`),
253465
254131
  items: array(string().trim().min(1)).max(MAX_AGENT_SWARM_SUBAGENTS).optional().describe(`Values used to fill ${PROMPT_TEMPLATE_PLACEHOLDER}. Each item launches one new subagent.`),
253466
254132
  resume_agent_ids: record(string().trim().min(1), string().trim().min(1)).optional().describe("Map of existing subagent agent_id to the prompt used to resume that subagent. These resumed subagents are launched before new item-based subagents."),
253467
- timeout_minutes: number$1().int().min(0).max(10080).optional().describe("Wall-clock interval before each same swarm agent is continued automatically. Defaults to 240 minutes. Set 0 to disable the interval for this run.")
254133
+ timeout_minutes: number$1().int().min(0).max(10080).optional().describe("Wall-clock interval before each same swarm agent is continued automatically. Defaults to 240 minutes. Set 0 to disable the interval for this run."),
254134
+ response_format: object({
254135
+ name: string().min(1).max(64).describe("Stable name for the shared structured result"),
254136
+ schema: record(string(), unknown()).describe("Restricted JSON Schema applied to every child result")
254137
+ }).optional().describe("Require one shared validated JSON object shape from every spawned or resumed swarm child.")
253468
254138
  }).strict();
253469
254139
  AgentSwarmTool = class {
253470
254140
  subagentHost;
@@ -253492,8 +254162,17 @@ var init_agent_swarm = __esmMin((() => {
253492
254162
  }
253493
254163
  async execution(args, context) {
253494
254164
  try {
254165
+ let responseFormat;
254166
+ if (args.response_format !== void 0) try {
254167
+ responseFormat = prepareStructuredResponseFormat(args.response_format, compileToolArgsValidator);
254168
+ } catch (error) {
254169
+ return {
254170
+ output: `Invalid response_format: ${error instanceof Error ? error.message : String(error)}`,
254171
+ isError: true
254172
+ };
254173
+ }
253495
254174
  this.swarmMode.enter("tool");
253496
- return { output: await this.runSwarm(args, context.signal, context.toolCallId) };
254175
+ return structuredSwarmToolResult(await this.runSwarm(args, context.signal, context.toolCallId, responseFormat, context.turnId));
253497
254176
  } catch (error) {
253498
254177
  return {
253499
254178
  output: error instanceof Error ? error.message : String(error),
@@ -253501,7 +254180,7 @@ var init_agent_swarm = __esmMin((() => {
253501
254180
  };
253502
254181
  }
253503
254182
  }
253504
- async runSwarm(args, signal, toolCallId) {
254183
+ async runSwarm(args, signal, toolCallId, responseFormat, turnId) {
253505
254184
  const profileName = normalizeOptionalString$2(args.subagent_type) ?? DEFAULT_SUBAGENT_TYPE;
253506
254185
  const tasks = createAgentSwarmSpecs(args, (agentId) => this.subagentHost.getSwarmItem(agentId)).map((spec) => {
253507
254186
  const descriptionName = spec.kind === "resume" ? "resume" : profileName;
@@ -253513,6 +254192,8 @@ var init_agent_swarm = __esmMin((() => {
253513
254192
  description: childDescription(args.description, spec.index, descriptionName),
253514
254193
  swarmIndex: spec.index,
253515
254194
  runInBackground: false,
254195
+ responseFormat,
254196
+ toolScope: this.subagentHost.toolScopeForTurn(Number(turnId)),
253516
254197
  swarmItem: spec.item,
253517
254198
  signal,
253518
254199
  timeout: resolveSubagentTimeoutMs({ perRunMinutes: args.timeout_minutes })
@@ -253527,10 +254208,11 @@ var init_agent_swarm = __esmMin((() => {
253527
254208
  kind: "spawn"
253528
254209
  };
253529
254210
  });
253530
- return renderSwarmResults((await this.subagentHost.runQueued(tasks)).map(({ task, ...result }) => ({
254211
+ const results = (await this.subagentHost.runQueued(tasks)).map(({ task, ...result }) => ({
253531
254212
  spec: task.data,
253532
254213
  ...result
253533
- })));
254214
+ }));
254215
+ return responseFormat === void 0 ? renderSwarmResults(results) : renderStructuredSwarmResults(results, responseFormat);
253534
254216
  }
253535
254217
  };
253536
254218
  }));
@@ -254011,7 +254693,15 @@ function replaceOnceLiteral(content, oldString, newString) {
254011
254693
  if (index === -1) return content;
254012
254694
  return content.slice(0, index) + newString + content.slice(index + oldString.length);
254013
254695
  }
254014
- 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;
254015
254705
  var init_edit = __esmMin((() => {
254016
254706
  init_zod$1();
254017
254707
  init_tool_access();
@@ -254023,6 +254713,7 @@ var init_edit = __esmMin((() => {
254023
254713
  init_edit$1();
254024
254714
  init_lsp_diagnostics();
254025
254715
  ({ findDegenerateGeneratedStatementRun } = createRequire(import.meta.url)("./bin/generated-source-health.cjs"));
254716
+ ({ writeToolTextAtomic } = createRequire(import.meta.url)("./bin/tool-file-persistence.cjs"));
254026
254717
  EditInputSchema = object({
254027
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."),
254028
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."),
@@ -254036,14 +254727,16 @@ var init_edit = __esmMin((() => {
254036
254727
  workspace;
254037
254728
  history;
254038
254729
  lsp;
254730
+ fileObservation;
254039
254731
  name = "Edit";
254040
254732
  description = edit_default;
254041
254733
  parameters = toInputJsonSchema(EditInputSchema);
254042
- constructor(kaos, workspace, history, lsp) {
254734
+ constructor(kaos, workspace, history, lsp, fileObservation) {
254043
254735
  this.kaos = kaos;
254044
254736
  this.workspace = workspace;
254045
254737
  this.history = history;
254046
254738
  this.lsp = lsp;
254739
+ this.fileObservation = fileObservation;
254047
254740
  }
254048
254741
  resolveExecution(args) {
254049
254742
  const path = resolvePathAccessPath(args.path, {
@@ -254081,6 +254774,12 @@ var init_edit = __esmMin((() => {
254081
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.`
254082
254775
  };
254083
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
+ };
254084
254783
  const raw = await this.kaos.readText(safePath);
254085
254784
  const modelView = toModelTextView(raw);
254086
254785
  const content = modelView.text;
@@ -254103,7 +254802,7 @@ var init_edit = __esmMin((() => {
254103
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.`
254104
254803
  };
254105
254804
  const newContent = replaceOnceLiteral(content, args.old_string, args.new_string);
254106
- return this.writeReplacement(args, safePath, raw, newContent, modelView.lineEndingStyle, 1);
254805
+ return this.writeReplacement(args, safePath, raw, newContent, modelView.lineEndingStyle, 1, authorization.version);
254107
254806
  }
254108
254807
  const parts = content.split(args.old_string);
254109
254808
  const replacementCount = parts.length - 1;
@@ -254113,7 +254812,7 @@ var init_edit = __esmMin((() => {
254113
254812
  `
254114
254813
  };
254115
254814
  const newContent = parts.join(args.new_string);
254116
- return this.writeReplacement(args, safePath, raw, newContent, modelView.lineEndingStyle, replacementCount);
254815
+ return this.writeReplacement(args, safePath, raw, newContent, modelView.lineEndingStyle, replacementCount, authorization.version);
254117
254816
  } catch (error) {
254118
254817
  if (error?.code === "EISDIR") return {
254119
254818
  isError: true,
@@ -254125,7 +254824,7 @@ var init_edit = __esmMin((() => {
254125
254824
  };
254126
254825
  }
254127
254826
  }
254128
- async writeReplacement(args, safePath, currentContent, nextContent, lineEndingStyle, replacementCount) {
254827
+ async writeReplacement(args, safePath, currentContent, nextContent, lineEndingStyle, replacementCount, observedVersion) {
254129
254828
  const materialized = materializeModelText(nextContent, lineEndingStyle);
254130
254829
  const lineLimit = evaluateSourceFileLineLimit(safePath, materialized, {
254131
254830
  currentContent,
@@ -254136,7 +254835,14 @@ var init_edit = __esmMin((() => {
254136
254835
  isError: true,
254137
254836
  output: lineLimit.error
254138
254837
  };
254139
- 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));
254140
254846
  const occurrence = replacementCount === 1 ? "occurrence" : "occurrences";
254141
254847
  const notice = lineLimit.notice === void 0 ? "" : ` ${lineLimit.notice}`;
254142
254848
  return appendLspDiagnostics({ output: `Replaced ${String(replacementCount)} ${occurrence} in ${args.path}.` + notice }, safePath, this.lsp);
@@ -259646,7 +260352,7 @@ function renderLine(entry, lineEndingStyle) {
259646
260352
  function renderedLineBytes(renderedLine, isFirst) {
259647
260353
  return (isFirst ? 0 : 1) + Buffer.byteLength(renderedLine, "utf8");
259648
260354
  }
259649
- function renderEntries(entries, lineEndingStyle) {
260355
+ function renderEntries(entries, lineEndingStyle, maxBytes) {
259650
260356
  const renderedLines = [];
259651
260357
  const truncatedLineNumbers = [];
259652
260358
  let bytes = 0;
@@ -259654,14 +260360,14 @@ function renderEntries(entries, lineEndingStyle) {
259654
260360
  for (const entry of entries) {
259655
260361
  const rendered = renderLine(entry, lineEndingStyle);
259656
260362
  const lineBytes = renderedLineBytes(rendered.line, renderedLines.length === 0);
259657
- if (renderedLines.length > 0 && bytes + lineBytes > MAX_BYTES) {
260363
+ if (renderedLines.length > 0 && bytes + lineBytes > maxBytes) {
259658
260364
  maxBytesReached = true;
259659
260365
  break;
259660
260366
  }
259661
260367
  if (rendered.wasTruncated) truncatedLineNumbers.push(entry.lineNo);
259662
260368
  renderedLines.push(rendered.line);
259663
260369
  bytes += lineBytes;
259664
- if (bytes >= MAX_BYTES) {
260370
+ if (bytes >= maxBytes) {
259665
260371
  maxBytesReached = true;
259666
260372
  break;
259667
260373
  }
@@ -259692,7 +260398,7 @@ function containsNulByte(text) {
259692
260398
  function notReadableFileOutput(path) {
259693
260399
  return `"${path}" is not readable as UTF-8 text. If it is an image or video, use ReadMediaFile. For other binary formats, use Bash or an MCP tool if available.`;
259694
260400
  }
259695
- var MAX_LINES$1, MAX_LINE_LENGTH, MAX_BYTES, S_IFMT$1, S_IFREG, PositiveLineOffsetSchema, TailLineOffsetSchema, ReadInputSchema, ReadBatchInputSchema, READ_DESCRIPTION, READ_BATCH_DESCRIPTION, ReadTool, ReadBatchTool, readContinuationNotice, READ_MODEL_VISIBLE_BYTES, MAX_READ_BATCH_REQUESTS, readBatchAllFailed, renderReadBatchOutput;
260401
+ var MAX_LINES$1, MAX_LINE_LENGTH, S_IFMT$1, S_IFREG, PositiveLineOffsetSchema, TailLineOffsetSchema, ReadInputSchema, ReadBatchInputSchema, READ_DESCRIPTION, READ_BATCH_DESCRIPTION, ReadTool, ReadBatchTool, readContinuationNotice, readModelVisibleBytes, readModelVisibleLines, MAX_READ_BATCH_REQUESTS, readBatchAllFailed, renderReadBatchOutput;
259696
260402
  var init_read = __esmMin((() => {
259697
260403
  init_zod$1();
259698
260404
  init_tool_access();
@@ -259703,46 +260409,49 @@ var init_read = __esmMin((() => {
259703
260409
  init_rule_match();
259704
260410
  init_line_endings();
259705
260411
  init_read$1();
259706
- ({ readContinuationNotice, READ_MODEL_VISIBLE_BYTES } = createRequire(import.meta.url)("./bin/read-continuation-policy.cjs"));
260412
+ ({ readContinuationNotice, readModelVisibleBytes, readModelVisibleLines } = createRequire(import.meta.url)("./bin/read-continuation-policy.cjs"));
259707
260413
  ({ MAX_READ_BATCH_REQUESTS, readBatchAllFailed, renderReadBatchOutput } = createRequire(import.meta.url)("./bin/read-batch-policy.cjs"));
259708
260414
  MAX_LINES$1 = 1e3;
259709
260415
  MAX_LINE_LENGTH = 2e3;
259710
- MAX_BYTES = READ_MODEL_VISIBLE_BYTES;
259711
260416
  S_IFMT$1 = 61440;
259712
260417
  S_IFREG = 32768;
259713
260418
  PositiveLineOffsetSchema = number$1().int().min(1);
259714
- TailLineOffsetSchema = number$1().int().min(-MAX_LINES$1).max(-1);
260419
+ TailLineOffsetSchema = number$1().int().max(-1);
259715
260420
  ReadInputSchema = object({
259716
260421
  path: string().describe("Path to a text file. Relative paths resolve against the working directory; a path outside the working directory must be absolute. Directories are not supported; use `ls` via Bash for a known directory, or Glob for pattern search."),
259717
- line_offset: union([PositiveLineOffsetSchema, TailLineOffsetSchema]).optional().describe(`The line number to start reading from. Omit to start at line 1. Negative values read from the end of the file; the absolute value cannot exceed ${String(MAX_LINES$1)}.`),
259718
- n_lines: number$1().int().positive().optional().describe(`The number of lines to read; the tool also applies its internal cap. Omit to read up to the internal cap of ${String(MAX_LINES$1)} lines.`)
260422
+ line_offset: union([PositiveLineOffsetSchema, TailLineOffsetSchema]).optional().describe("The line number to start reading from. Omit to start at line 1. Negative values read backward from the end within the active context budget."),
260423
+ n_lines: number$1().int().positive().optional().describe("The number of lines for an explicit targeted range. Omit to read the complete file whenever the active context has room.")
259719
260424
  });
259720
260425
  ReadBatchInputSchema = object({ requests: array(ReadInputSchema).min(2).max(MAX_READ_BATCH_REQUESTS).describe(`Two to ${String(MAX_READ_BATCH_REQUESTS)} independent known text-file reads. Do not batch a read whose path or range depends on an earlier result.`) });
259721
260426
  object({
259722
260427
  content: string(),
259723
260428
  lineCount: number$1().int().nonnegative()
259724
260429
  });
260430
+ read_default = "Read a known UTF-8 text file. Invalid paths error; directories are unsupported. Relative paths use the working directory; outside paths must be absolute. Use Glob for unknown names, Grep for content, and ReadMediaFile for media.\n\nOmit `line_offset` and `n_lines` to read the complete file whenever the active context has room. Explicit ranges remain available for targeted inspection. Under real context pressure, a result is capped and names the exact next `line_offset`; continue from that line without gaps. Individual lines beyond {{ MAX_LINE_LENGTH }} characters are truncated. Negative `line_offset` reads from the end, up to {{ MAX_LINES }} lines. Issue independent Read calls together in one response when several files or ranges may be useful. Prefer ReadBatch when two or more independent paths or ranges are already known.\n\nSensitive files such as `.env` and credential stores are refused; templates and public keys remain readable. Only UTF-8 text without NUL bytes is accepted; use Bash or an MCP tool for other binaries.\n\nOutput is `<line-number>\\t<content>` per line. The trailing `<system>...</system>` block is status, not file content. Pure CRLF appears as LF and is preserved by Edit. Mixed or lone carriage returns appear as `\\r` and require exact `Edit.old_string` escapes.";
259725
260431
  READ_DESCRIPTION = renderPrompt(read_default, {
259726
260432
  MAX_LINES: MAX_LINES$1,
259727
- MAX_BYTES_KB: MAX_BYTES / 1024,
259728
- MAX_LINE_LENGTH
259729
- });
259730
- read_default = "Read a known UTF-8 text file. Invalid paths error; directories are unsupported. Relative paths use the working directory; outside paths must be absolute. Use Glob for unknown names, Grep for content, and ReadMediaFile for media.\n\nEach call returns at most {{ MAX_LINES }} lines or {{ MAX_BYTES_KB }} KB and truncates lines beyond {{ MAX_LINE_LENGTH }} characters. Page large files with 1-based `line_offset` and `n_lines`; omit `n_lines` for the cap. Negative `line_offset` reads from the end, up to {{ MAX_LINES }} lines. A capped result names the exact next `line_offset`. Issue independent Read calls together in one response when several files or ranges may be useful. Prefer ReadBatch when two or more independent paths or ranges are already known.\n\nSensitive files such as `.env` and credential stores are refused; templates and public keys remain readable. Only UTF-8 text without NUL bytes is accepted; use Bash or an MCP tool for other binaries.\n\nOutput is `<line-number>\\t<content>` per line. The trailing `<system>...</system>` block is status, not file content. Pure CRLF appears as LF and is preserved by Edit. Mixed or lone carriage returns appear as `\\r` and require exact `Edit.old_string` escapes.";
259731
- READ_DESCRIPTION = renderPrompt(read_default, {
259732
- MAX_LINES: MAX_LINES$1,
259733
- MAX_BYTES_KB: MAX_BYTES / 1024,
259734
260433
  MAX_LINE_LENGTH
259735
260434
  });
259736
260435
  READ_BATCH_DESCRIPTION = `Read ${String(MAX_READ_BATCH_REQUESTS)} or fewer independent known UTF-8 text files or ranges concurrently in one tool call. Use this instead of serial Read calls only when every path and range is already known and no later request depends on an earlier result. Each request uses the same path, sensitive-file, UTF-8, line, and byte rules as Read. Results remain in request order and identify partial failures individually.`;
259737
260436
  ReadTool = class {
259738
260437
  kaos;
259739
260438
  workspace;
260439
+ contextWindowState;
260440
+ fileObservation;
259740
260441
  name = "Read";
259741
260442
  description = READ_DESCRIPTION;
259742
260443
  parameters = toInputJsonSchema(ReadInputSchema);
259743
- constructor(kaos, workspace) {
260444
+ constructor(kaos, workspace, contextWindowState = () => ({}), fileObservation) {
259744
260445
  this.kaos = kaos;
259745
260446
  this.workspace = workspace;
260447
+ this.contextWindowState = contextWindowState;
260448
+ this.fileObservation = fileObservation;
260449
+ }
260450
+ modelVisibleBytes() {
260451
+ return readModelVisibleBytes(this.contextWindowState());
260452
+ }
260453
+ modelVisibleLines() {
260454
+ return readModelVisibleLines(this.contextWindowState());
259746
260455
  }
259747
260456
  resolveExecution(args) {
259748
260457
  const path = resolvePathAccessPath(args.path, {
@@ -259773,10 +260482,13 @@ var init_read = __esmMin((() => {
259773
260482
  try {
259774
260483
  stat = await this.kaos.stat(safePath);
259775
260484
  } catch (error) {
259776
- if (isFileNotFoundError(error)) return {
259777
- isError: true,
259778
- output: `"${args.path}" does not exist.`
259779
- };
260485
+ if (isFileNotFoundError(error)) {
260486
+ this.fileObservation.recordAbsent(safePath);
260487
+ return {
260488
+ isError: true,
260489
+ output: `"${args.path}" does not exist.`
260490
+ };
260491
+ }
259780
260492
  throw error;
259781
260493
  }
259782
260494
  if (!isRegularFileMode(stat.stMode)) return {
@@ -259793,10 +260505,21 @@ var init_read = __esmMin((() => {
259793
260505
  output: notReadableFileOutput(args.path)
259794
260506
  };
259795
260507
  const lineOffset = args.line_offset ?? 1;
259796
- const requestedLines = args.n_lines ?? 1e3;
259797
- const effectiveLimit = Math.min(requestedLines, MAX_LINES$1);
259798
- if (lineOffset < 0) return await this.readTail(safePath, args.path, lineOffset, effectiveLimit, requestedLines);
259799
- return await this.readForward(safePath, args.path, lineOffset, effectiveLimit, requestedLines);
260508
+ const maxLines = this.modelVisibleLines();
260509
+ const requestedLines = args.n_lines ?? maxLines;
260510
+ const effectiveLimit = Math.min(requestedLines, maxLines);
260511
+ const maxBytes = this.modelVisibleBytes();
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;
259800
260523
  } catch (error) {
259801
260524
  if (isTextDecodeError(error)) return {
259802
260525
  isError: true,
@@ -259808,7 +260531,7 @@ var init_read = __esmMin((() => {
259808
260531
  };
259809
260532
  }
259810
260533
  }
259811
- async readForward(safePath, displayPath, lineOffset, effectiveLimit, requestedLines) {
260534
+ async readForward(safePath, displayPath, lineOffset, effectiveLimit, requestedLines, maxBytes, maxLines) {
259812
260535
  const rangeKaos = this.kaos;
259813
260536
  if (rangeKaos.scanTextFile !== void 0 && rangeKaos.readLineRange !== void 0) {
259814
260537
  const scan = await rangeKaos.scanTextFile(safePath);
@@ -259817,31 +260540,47 @@ var init_read = __esmMin((() => {
259817
260540
  output: notReadableFileOutput(displayPath)
259818
260541
  };
259819
260542
  const selectedEntries = [];
260543
+ const lineEndingStyle = lineEndingStyleFromFlags(scan.lineEndingFlags);
260544
+ let selectedBytes = 0;
260545
+ let maxBytesReached = false;
259820
260546
  let lineNo = lineOffset;
259821
260547
  for await (const rawLine of rangeKaos.readLineRange(safePath, {
259822
260548
  startLine: lineOffset,
259823
260549
  maxLines: effectiveLimit,
259824
260550
  errors: "strict"
259825
260551
  })) {
259826
- selectedEntries.push({
260552
+ const entry = {
259827
260553
  lineNo,
259828
260554
  rawContent: stripTrailingLf(rawLine)
259829
- });
260555
+ };
260556
+ const rendered = renderLine(entry, lineEndingStyle);
260557
+ const lineBytes = renderedLineBytes(rendered.line, selectedEntries.length === 0);
260558
+ if (selectedEntries.length > 0 && selectedBytes + lineBytes > maxBytes) {
260559
+ maxBytesReached = true;
260560
+ break;
260561
+ }
260562
+ selectedEntries.push(entry);
260563
+ selectedBytes += lineBytes;
259830
260564
  lineNo += 1;
260565
+ if (selectedBytes >= maxBytes) {
260566
+ maxBytesReached = true;
260567
+ break;
260568
+ }
259831
260569
  }
259832
- const lineEndingStyle = lineEndingStyleFromFlags(scan.lineEndingFlags);
259833
- const rendered = renderEntries(selectedEntries, lineEndingStyle);
260570
+ const rendered = renderEntries(selectedEntries, lineEndingStyle, maxBytes);
259834
260571
  return this.finishReadResult({
259835
260572
  renderedLines: rendered.renderedLines,
259836
260573
  truncatedLineNumbers: rendered.truncatedLineNumbers,
259837
- maxLinesReached: effectiveLimit >= 1e3 && lineOffset + 1e3 <= scan.totalLines,
259838
- maxBytesReached: rendered.maxBytesReached,
260574
+ maxLinesReached: effectiveLimit >= maxLines && lineOffset + maxLines <= scan.totalLines,
260575
+ maxBytesReached: maxBytesReached || rendered.maxBytesReached,
259839
260576
  lineEndingStyle,
259840
260577
  startLine: selectedEntries.length > 0 ? lineOffset : 0,
259841
260578
  totalLines: scan.totalLines,
259842
260579
  requestedLines,
259843
260580
  lineOffset,
259844
- effectiveLimit
260581
+ effectiveLimit,
260582
+ maxBytes,
260583
+ maxLines
259845
260584
  });
259846
260585
  }
259847
260586
  const selectedEntries = [];
@@ -259852,7 +260591,10 @@ var init_read = __esmMin((() => {
259852
260591
  };
259853
260592
  let currentLineNo = 0;
259854
260593
  let maxLinesReached = false;
260594
+ let maxBytesReached = false;
260595
+ let selectedBytes = 0;
259855
260596
  let collectionClosed = false;
260597
+ let closedByLines = false;
259856
260598
  for await (const rawLine of this.kaos.readLines(safePath, { errors: "strict" })) {
259857
260599
  if (containsNulByte(rawLine)) return {
259858
260600
  isError: true,
@@ -259861,38 +260603,56 @@ var init_read = __esmMin((() => {
259861
260603
  currentLineNo += 1;
259862
260604
  updateLineEndingFlags(flags, rawLine);
259863
260605
  if (collectionClosed) {
259864
- if (effectiveLimit >= 1e3 && currentLineNo >= lineOffset) maxLinesReached = true;
260606
+ if (closedByLines && effectiveLimit >= maxLines && currentLineNo >= lineOffset) maxLinesReached = true;
259865
260607
  continue;
259866
260608
  }
259867
260609
  if (currentLineNo < lineOffset) continue;
259868
260610
  if (selectedEntries.length >= effectiveLimit) {
259869
- if (effectiveLimit >= 1e3) maxLinesReached = true;
260611
+ if (effectiveLimit >= maxLines) maxLinesReached = true;
259870
260612
  collectionClosed = true;
260613
+ closedByLines = true;
259871
260614
  continue;
259872
260615
  }
259873
- selectedEntries.push({
260616
+ const entry = {
259874
260617
  lineNo: currentLineNo,
259875
260618
  rawContent: stripTrailingLf(rawLine)
259876
- });
259877
- if (selectedEntries.length >= effectiveLimit) collectionClosed = true;
260619
+ };
260620
+ const conservative = renderLine(entry, "mixed");
260621
+ const lineBytes = renderedLineBytes(conservative.line, selectedEntries.length === 0);
260622
+ if (selectedEntries.length > 0 && selectedBytes + lineBytes > maxBytes) {
260623
+ maxBytesReached = true;
260624
+ collectionClosed = true;
260625
+ continue;
260626
+ }
260627
+ selectedEntries.push(entry);
260628
+ selectedBytes += lineBytes;
260629
+ if (selectedEntries.length >= effectiveLimit) {
260630
+ collectionClosed = true;
260631
+ closedByLines = true;
260632
+ } else if (selectedBytes >= maxBytes) {
260633
+ maxBytesReached = true;
260634
+ collectionClosed = true;
260635
+ }
259878
260636
  }
259879
260637
  const lineEndingStyle = lineEndingStyleFromFlags(flags);
259880
- const rendered = renderEntries(selectedEntries, lineEndingStyle);
260638
+ const rendered = renderEntries(selectedEntries, lineEndingStyle, maxBytes);
259881
260639
  return this.finishReadResult({
259882
260640
  renderedLines: rendered.renderedLines,
259883
260641
  truncatedLineNumbers: rendered.truncatedLineNumbers,
259884
260642
  maxLinesReached,
259885
- maxBytesReached: rendered.maxBytesReached,
260643
+ maxBytesReached: maxBytesReached || rendered.maxBytesReached,
259886
260644
  lineEndingStyle,
259887
260645
  startLine: selectedEntries.length > 0 ? lineOffset : 0,
259888
260646
  totalLines: currentLineNo,
259889
260647
  requestedLines,
259890
260648
  lineOffset,
259891
- effectiveLimit
260649
+ effectiveLimit,
260650
+ maxBytes,
260651
+ maxLines
259892
260652
  });
259893
260653
  }
259894
- async readTail(safePath, displayPath, lineOffset, effectiveLimit, requestedLines) {
259895
- const tailCount = Math.abs(lineOffset);
260654
+ async readTail(safePath, displayPath, lineOffset, effectiveLimit, requestedLines, maxBytes, maxLines) {
260655
+ const tailCount = Math.min(Math.abs(lineOffset), maxLines);
259896
260656
  const rangeKaos = this.kaos;
259897
260657
  if (rangeKaos.scanTextFile !== void 0 && rangeKaos.readTailLines !== void 0) {
259898
260658
  const scan = await rangeKaos.scanTextFile(safePath);
@@ -259915,7 +260675,9 @@ var init_read = __esmMin((() => {
259915
260675
  lineEndingFlags: scan.lineEndingFlags,
259916
260676
  effectiveLimit,
259917
260677
  totalLines: scan.totalLines,
259918
- requestedLines
260678
+ requestedLines,
260679
+ maxBytes,
260680
+ maxLines
259919
260681
  });
259920
260682
  }
259921
260683
  const entries = [];
@@ -259943,7 +260705,9 @@ var init_read = __esmMin((() => {
259943
260705
  lineEndingFlags: flags,
259944
260706
  effectiveLimit,
259945
260707
  totalLines: currentLineNo,
259946
- requestedLines
260708
+ requestedLines,
260709
+ maxBytes,
260710
+ maxLines
259947
260711
  });
259948
260712
  }
259949
260713
  finishTailEntries(input) {
@@ -259957,7 +260721,7 @@ var init_read = __esmMin((() => {
259957
260721
  let totalBytes = 0;
259958
260722
  for (const [index, candidate] of renderedCandidates.entries()) totalBytes += renderedLineBytes(candidate.rendered.line, index === 0);
259959
260723
  let maxBytesReached = false;
259960
- if (totalBytes > MAX_BYTES) {
260724
+ if (totalBytes > input.maxBytes) {
259961
260725
  maxBytesReached = true;
259962
260726
  const kept = [];
259963
260727
  let bytes = 0;
@@ -259965,7 +260729,7 @@ var init_read = __esmMin((() => {
259965
260729
  const candidate = renderedCandidates[i];
259966
260730
  if (candidate === void 0) continue;
259967
260731
  const lineBytes = renderedLineBytes(candidate.rendered.line, kept.length === 0);
259968
- if (bytes + lineBytes > MAX_BYTES) break;
260732
+ if (bytes + lineBytes > input.maxBytes) break;
259969
260733
  kept.unshift(candidate);
259970
260734
  bytes += lineBytes;
259971
260735
  }
@@ -259985,7 +260749,9 @@ var init_read = __esmMin((() => {
259985
260749
  lineEndingStyle,
259986
260750
  startLine: renderedCandidates[0]?.entry.lineNo ?? 0,
259987
260751
  totalLines: input.totalLines,
259988
- requestedLines: input.requestedLines
260752
+ requestedLines: input.requestedLines,
260753
+ maxBytes: input.maxBytes,
260754
+ maxLines: input.maxLines
259989
260755
  });
259990
260756
  }
259991
260757
  finishReadResult(input) {
@@ -260000,8 +260766,8 @@ var init_read = __esmMin((() => {
260000
260766
  const lineCount = input.renderedLines.length;
260001
260767
  const parts = lineCount > 0 ? [`${String(lineCount)} ${lineCount === 1 ? "line" : "lines"} read from file starting from line ${String(input.startLine)}.`] : ["No lines read from file."];
260002
260768
  parts.push(`Total lines in file: ${String(input.totalLines)}.`);
260003
- if (input.maxLinesReached) parts.push(`Max ${String(MAX_LINES$1)} lines reached.`);
260004
- else if (input.maxBytesReached) parts.push(`Max ${String(MAX_BYTES)} bytes reached.`);
260769
+ if (input.maxLinesReached) parts.push(`Max ${String(input.maxLines)} lines reached.`);
260770
+ else if (input.maxBytesReached) parts.push(`Max ${String(input.maxBytes)} bytes reached.`);
260005
260771
  else if (lineCount < input.requestedLines) parts.push("End of file reached.");
260006
260772
  const continuationNotice = readContinuationNotice({
260007
260773
  ...input,
@@ -260020,10 +260786,10 @@ var init_read = __esmMin((() => {
260020
260786
  name = "ReadBatch";
260021
260787
  description = READ_BATCH_DESCRIPTION;
260022
260788
  parameters = toInputJsonSchema(ReadBatchInputSchema);
260023
- constructor(kaos, workspace) {
260789
+ constructor(kaos, workspace, contextWindowState, fileObservation) {
260024
260790
  this.kaos = kaos;
260025
260791
  this.workspace = workspace;
260026
- this.reader = new ReadTool(kaos, workspace);
260792
+ this.reader = new ReadTool(kaos, workspace, contextWindowState, fileObservation);
260027
260793
  }
260028
260794
  resolveExecution(args) {
260029
260795
  const items = args.requests.map((request) => ({
@@ -260448,7 +261214,7 @@ function countCompletedLines(content) {
260448
261214
  for (const character of content) if (character === "\n") count += 1;
260449
261215
  return count;
260450
261216
  }
260451
- 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;
260452
261218
  var init_write = __esmMin((() => {
260453
261219
  init_dist$6();
260454
261220
  init_zod$1();
@@ -260462,6 +261228,7 @@ var init_write = __esmMin((() => {
260462
261228
  init_lsp_diagnostics();
260463
261229
  ({ resolveWriteContinuationContract, resolvePlainWriteContract, splitNativeWriteBytes } = createRequire(import.meta.url)("./bin/write-continuation-policy.cjs"));
260464
261230
  ({ writeNativeLargeContentOnDisk } = createRequire(import.meta.url)("./bin/native-large-file-io.cjs"));
261231
+ ({ writeToolTextAtomic } = createRequire(import.meta.url)("./bin/tool-file-persistence.cjs"));
260465
261232
  S_IFMT = 61440;
260466
261233
  S_IFDIR = 16384;
260467
261234
  DEFAULT_CONTINUATION_CHUNK_BYTES = 2048;
@@ -260491,17 +261258,19 @@ bytesWritten: number$1().int().nonnegative() });
260491
261258
  workspace;
260492
261259
  history;
260493
261260
  lsp;
261261
+ fileObservation;
260494
261262
  maxContinuationChunkBytes;
260495
261263
  name = "Write";
260496
261264
  description = write_default;
260497
261265
  parameters = toInputJsonSchema(WriteInputSchema);
260498
261266
  pendingContinuations = /* @__PURE__ */ new Map();
260499
261267
  continuationRequiredPaths = /* @__PURE__ */ new Set();
260500
- constructor(kaos, workspace, history, lsp, maxContinuationChunkBytes = resolveWriteContinuationChunkBytes()) {
261268
+ constructor(kaos, workspace, history, lsp, fileObservation, maxContinuationChunkBytes = resolveWriteContinuationChunkBytes()) {
260501
261269
  this.kaos = kaos;
260502
261270
  this.workspace = workspace;
260503
261271
  this.history = history;
260504
261272
  this.lsp = lsp;
261273
+ this.fileObservation = fileObservation;
260505
261274
  this.maxContinuationChunkBytes = maxContinuationChunkBytes;
260506
261275
  }
260507
261276
  resolveExecution(args) {
@@ -260670,6 +261439,12 @@ bytesWritten: number$1().int().nonnegative() });
260670
261439
  isError: true,
260671
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.`
260672
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
+ };
260673
261448
  let currentContent;
260674
261449
  if (isSourceFilePath(safePath)) try {
260675
261450
  currentContent = await this.kaos.readText(safePath);
@@ -260697,9 +261472,16 @@ bytesWritten: number$1().int().nonnegative() });
260697
261472
  continuationRequired: this.continuationRequiredPaths.has(safePath)
260698
261473
  });
260699
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
+ };
260700
261481
  const chunks = splitNativeWriteBytes(args.content, this.maxContinuationChunkBytes);
260701
261482
  const nativeResult = await this.writeNativeLargeContent(safePath, chunks, mode);
260702
261483
  if (nativeResult.isError === true) return nativeResult;
261484
+ this.fileObservation.recordPresent(safePath, await this.kaos.stat(safePath));
260703
261485
  this.continuationRequiredPaths.delete(safePath);
260704
261486
  const notice = lineLimit.notice === void 0 ? "" : ` ${lineLimit.notice}`;
260705
261487
  return appendLspDiagnostics({
@@ -260712,8 +261494,15 @@ bytesWritten: number$1().int().nonnegative() });
260712
261494
  output: parentError
260713
261495
  };
260714
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
+ };
260715
261503
  if (mode === "append") await this.kaos.writeText(safePath, args.content, { mode: "a" });
260716
- 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));
260717
261506
  const bytesWritten = Buffer.byteLength(args.content, "utf8");
260718
261507
  const notice = lineLimit.notice === void 0 ? "" : ` ${lineLimit.notice}`;
260719
261508
  return appendLspDiagnostics({ output: `${mode === "append" ? "Appended" : "Wrote"} ${String(bytesWritten)} bytes to ${args.path}.${notice}` }, safePath, this.lsp);
@@ -261262,7 +262051,8 @@ var init_tool_dedup = __esmMin((() => {
261262
262051
  //#region ../../packages/agent-core/src/agent/turn/tool-result-budget.ts
261263
262052
  async function budgetToolResultForModel(options) {
261264
262053
  const text = persistableToolResultText(options.result.output);
261265
- 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;
261266
262056
  const readSourcePath = reusableReadSourcePath(options);
261267
262057
  if (readSourcePath !== void 0) return referenceReadSourceForModel(options, text, readSourcePath);
261268
262058
  return persistToolResultForModel(options, text);
@@ -261418,7 +262208,7 @@ function renderHistoricalToolResultReference(toolName, toolCallId, text, outputP
261418
262208
  function safeToolResultFileStem(toolName, toolCallId) {
261419
262209
  return `${toolName}-${toolCallId}`.replace(/[^a-zA-Z0-9._-]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 80) || "tool-result";
261420
262210
  }
261421
- var TOOL_RESULT_MAX_CHARS, TOOL_RESULT_PREVIEW_CHARS, TOOL_RESULT_HISTORICAL_PREVIEW_CHARS, TOOL_RESULT_RECOVERY_PAGE_LINES, TOOL_RESULT_OFFLOAD_MARKER, TOOL_RESULT_HISTORICAL_KEEP_RECENT_MESSAGES, shouldKeepFreshToolResult, shouldOffloadToolResult, createToolResultPreview, compactPersistedToolResultReference, compactHistoricalSuccessfulToolResults, currentTurnReadToolResultIds, currentUserTurnStartIndex, dedupeRepeatedSuccessfulToolResults, readContinuationLineOffset, selectToolResultBatchOffloads, selectHistoricalToolResultOffloads, buildToolResultOffloadTelemetry;
262211
+ var TOOL_RESULT_MAX_CHARS, TOOL_RESULT_PREVIEW_CHARS, TOOL_RESULT_HISTORICAL_PREVIEW_CHARS, TOOL_RESULT_RECOVERY_PAGE_LINES, TOOL_RESULT_OFFLOAD_MARKER, TOOL_RESULT_HISTORICAL_KEEP_RECENT_MESSAGES, shouldKeepFreshToolResult, shouldOffloadToolResult, createToolResultPreview, compactPersistedToolResultReference, compactHistoricalSuccessfulToolResults, currentTurnReadToolResultIds, currentUserTurnStartIndex, dedupeRepeatedSuccessfulToolResults, hasToolResultOffloadPressure, readContinuationLineOffset, selectToolResultBatchOffloads, selectHistoricalToolResultOffloads, buildToolResultOffloadTelemetry;
261422
262212
  var init_tool_result_budget = __esmMin((() => {
261423
262213
  init_dist$6();
261424
262214
  const toolResultOffloadPolicy = createRequire(import.meta.url)("./bin/tool-result-offload-policy.cjs");
@@ -261438,6 +262228,7 @@ var init_tool_result_budget = __esmMin((() => {
261438
262228
  currentUserTurnStartIndex = toolResultOffloadPolicy.currentUserTurnStartIndex;
261439
262229
  dedupeRepeatedSuccessfulToolResults = toolResultOffloadPolicy.dedupeRepeatedSuccessfulToolResults;
261440
262230
  freshToolResultIds = toolResultOffloadPolicy.freshToolResultIds;
262231
+ hasToolResultOffloadPressure = toolResultOffloadPolicy.hasToolResultOffloadPressure;
261441
262232
  readContinuationLineOffset = toolResultOffloadPolicy.readContinuationLineOffset;
261442
262233
  selectToolResultBatchOffloads = toolResultOffloadPolicy.selectToolResultBatchOffloads;
261443
262234
  selectHistoricalToolResultOffloads = toolResultOffloadPolicy.selectHistoricalToolResultOffloads;
@@ -261452,6 +262243,7 @@ var ToolResultBatchOffload = class {
261452
262243
  }
261453
262244
  async detect() {
261454
262245
  const history = this.agent.context.history;
262246
+ if (!toolResultOffloadPressureForAgent(this.agent)) return 0;
261455
262247
  const tailIds = freshToolResultIds(history);
261456
262248
  const pinnedReadIds = currentTurnReadToolResultIds(history);
261457
262249
  const recentStart = Math.max(0, history.length - TOOL_RESULT_HISTORICAL_KEEP_RECENT_MESSAGES);
@@ -261534,6 +262326,7 @@ var ToolResultBatchOffload = class {
261534
262326
  });
261535
262327
  }
261536
262328
  compact(messages) {
262329
+ if (!toolResultOffloadPressureForAgent(this.agent)) return messages;
261537
262330
  const recentStart = Math.max(0, messages.length - TOOL_RESULT_HISTORICAL_KEEP_RECENT_MESSAGES);
261538
262331
  let changed = false;
261539
262332
  const projected = messages.map((message, index) => {
@@ -261584,6 +262377,13 @@ var ToolResultBatchOffload = class {
261584
262377
  }
261585
262378
  }
261586
262379
  };
262380
+ function toolResultOffloadPressureForAgent(agent) {
262381
+ return hasToolResultOffloadPressure({ contextUsageRatio: contextUsageRatioForAgent(agent) });
262382
+ }
262383
+ function contextUsageRatioForAgent(agent) {
262384
+ const maxContextTokens = agent.fullCompaction.getEffectiveMaxContextTokens();
262385
+ return maxContextTokens > 0 ? agent.context.tokenCountWithPending / maxContextTokens : 1;
262386
+ }
261587
262387
  //#endregion
261588
262388
  //#region ../../packages/agent-core/src/agent/turn/user-message-offload.ts
261589
262389
  function persistableUserMessageText(message) {
@@ -261652,6 +262452,7 @@ var UserMessageOffload = class {
261652
262452
  if (this.agent.homedir === void 0) return 0;
261653
262453
  const currentTurnStart = currentUserTurnStartIndex(history);
261654
262454
  const totalHistoryChars = historyTextChars(history);
262455
+ const contextUsageRatio = contextUsageRatioForAgent(this.agent);
261655
262456
  let offloaded = 0;
261656
262457
  for (let historyIndex = 0; historyIndex < history.length; historyIndex++) {
261657
262458
  if (historyIndex === currentTurnStart) continue;
@@ -261663,7 +262464,8 @@ var UserMessageOffload = class {
261663
262464
  historyIndex,
261664
262465
  historyLength: history.length,
261665
262466
  historyChars: totalHistoryChars,
261666
- textChars: text.length
262467
+ textChars: text.length,
262468
+ contextUsageRatio
261667
262469
  });
261668
262470
  if (!immediateOversize && !historicalOversize) continue;
261669
262471
  const messageHash = userMessageOffloadHash(message, text);
@@ -261675,6 +262477,14 @@ var UserMessageOffload = class {
261675
262477
  type: "text",
261676
262478
  text: replacementText
261677
262479
  }, ...message.content.filter((part) => part.type !== "text")];
262480
+ this.agent.records.logRecord({
262481
+ type: "policy.intervention",
262482
+ policy: "user_message_offload",
262483
+ location: "UserMessageOffload.detect",
262484
+ size_before: text.length,
262485
+ size_after: replacementText.length,
262486
+ unit: "chars"
262487
+ });
261678
262488
  this.apply({
261679
262489
  messageHash,
261680
262490
  content,
@@ -261699,7 +262509,7 @@ var UserMessageOffload = class {
261699
262509
  });
261700
262510
  }
261701
262511
  compact(messages) {
261702
- if (this.replacements.size === 0) return messages;
262512
+ if (this.replacements.size === 0 || !toolResultOffloadPressureForAgent(this.agent)) return messages;
261703
262513
  return messages.map((message) => {
261704
262514
  const text = persistableUserMessageText(message);
261705
262515
  if (text === void 0) return message;
@@ -261786,6 +262596,7 @@ var AssistantMessageOffload = class {
261786
262596
  const history = this.agent.context.history;
261787
262597
  if (this.agent.homedir === void 0) return 0;
261788
262598
  const totalHistoryChars = historyTextChars(history);
262599
+ const contextUsageRatio = contextUsageRatioForAgent(this.agent);
261789
262600
  let offloaded = 0;
261790
262601
  for (let historyIndex = 0; historyIndex < history.length; historyIndex++) {
261791
262602
  const message = history[historyIndex];
@@ -261794,7 +262605,8 @@ var AssistantMessageOffload = class {
261794
262605
  historyIndex,
261795
262606
  historyLength: history.length,
261796
262607
  historyChars: totalHistoryChars,
261797
- textChars: text.length
262608
+ textChars: text.length,
262609
+ contextUsageRatio
261798
262610
  })) continue;
261799
262611
  const messageHash = assistantMessageOffloadHash(message, text);
261800
262612
  if (this.replacements.has(messageHash)) continue;
@@ -261805,6 +262617,14 @@ var AssistantMessageOffload = class {
261805
262617
  type: "text",
261806
262618
  text: replacementText
261807
262619
  }, ...message.content.filter((part) => part.type !== "text")];
262620
+ this.agent.records.logRecord({
262621
+ type: "policy.intervention",
262622
+ policy: "assistant_message_offload",
262623
+ location: "AssistantMessageOffload.detect",
262624
+ size_before: text.length,
262625
+ size_after: replacementText.length,
262626
+ unit: "chars"
262627
+ });
261808
262628
  this.apply({
261809
262629
  messageHash,
261810
262630
  content,
@@ -261829,6 +262649,7 @@ var AssistantMessageOffload = class {
261829
262649
  });
261830
262650
  }
261831
262651
  compact(messages) {
262652
+ const underPressure = toolResultOffloadPressureForAgent(this.agent);
261832
262653
  const completedToolCallIds = new Set(messages.filter((message) => message?.role === "tool" && message.toolCallId !== void 0).map((message) => message.toolCallId));
261833
262654
  const totalHistoryChars = historyTextChars(messages);
261834
262655
  let changed = false;
@@ -261858,7 +262679,7 @@ var AssistantMessageOffload = class {
261858
262679
  }
261859
262680
  const text = persistableAssistantMessageText(message);
261860
262681
  if (text === void 0) return message;
261861
- const replacement = this.replacements.get(assistantMessageOffloadHash(message, text));
262682
+ const replacement = underPressure ? this.replacements.get(assistantMessageOffloadHash(message, text)) : void 0;
261862
262683
  if (replacement === void 0) return message;
261863
262684
  changed = true;
261864
262685
  return { ...message, content: replacement.content };
@@ -261885,6 +262706,17 @@ function blunExtractText(content) {
261885
262706
  if (Array.isArray(content)) return content.map((c) => typeof c === "string" ? c : c && typeof c === "object" && "text" in c && typeof c.text === "string" ? c.text : "").join(" ");
261886
262707
  return "";
261887
262708
  }
262709
+ function blunRepeatActiveTurnPrompt(history, input, stepNumber) {
262710
+ if (stepNumber <= 1) return history;
262711
+ const prompt = blunExtractText(input);
262712
+ if (prompt.length === 0) return history;
262713
+ return [...history, {
262714
+ role: "user",
262715
+ content: [{ type: "text", text: `<active-task-reminder>\nThe active user task is repeated verbatim below. Continue from the current work state; do not restart completed work.\n\n${prompt}\n</active-task-reminder>` }],
262716
+ toolCalls: [],
262717
+ origin: { kind: "injection", variant: "active_turn_prompt" }
262718
+ }];
262719
+ }
261888
262720
  /**
261889
262721
  * BLUN: decide whether a turn should carry the full tool set. Small-context models
261890
262722
  * (e.g. King on an 8k window) lose their identity/language when all tool schemas
@@ -262004,7 +262836,11 @@ function mapLoopEvent(event, turnId) {
262004
262836
  type: "turn.step.started",
262005
262837
  turnId,
262006
262838
  step: event.step,
262007
- stepId: event.uuid
262839
+ stepId: event.uuid,
262840
+ thinkingEffort: event.thinkingEffort,
262841
+ completionBudget: event.completionBudget,
262842
+ attempt: event.attempt,
262843
+ maxAttempts: event.maxAttempts
262008
262844
  };
262009
262845
  case "step.end": return {
262010
262846
  type: "turn.step.completed",
@@ -262034,7 +262870,9 @@ function mapLoopEvent(event, turnId) {
262034
262870
  outputMayHaveStarted: event.outputMayHaveStarted,
262035
262871
  errorName: event.errorName,
262036
262872
  errorMessage: event.errorMessage,
262037
- statusCode: event.statusCode
262873
+ statusCode: event.statusCode,
262874
+ completionBudgetBefore: event.completionBudgetBefore,
262875
+ completionBudgetAfter: event.completionBudgetAfter
262038
262876
  };
262039
262877
  case "content.part": return;
262040
262878
  case "tool.call": return {
@@ -262263,6 +263101,15 @@ var init_turn = __esmMin((() => {
262263
263101
  kind: "system_trigger",
262264
263102
  name: "goal_continuation"
262265
263103
  };
263104
+ function goalContinuationOrigin(origin) {
263105
+ const cronRunId = origin?.kind === "cron_job" ? origin.runId : origin?.cronRunId;
263106
+ if (cronRunId === void 0 && origin?.toolScope === void 0) return GOAL_CONTINUATION_ORIGIN;
263107
+ return {
263108
+ ...GOAL_CONTINUATION_ORIGIN,
263109
+ ...(cronRunId === void 0 ? {} : { cronRunId }),
263110
+ ...(origin?.toolScope === void 0 ? {} : { toolScope: origin.toolScope })
263111
+ };
263112
+ }
262266
263113
  GOAL_COMPLETION_REMINDER_NAME = "goal_completion";
262267
263114
  GOAL_BLOCKED_REMINDER_NAME = "goal_blocked";
262268
263115
  GOAL_RATE_LIMIT_PAUSE_REASON = "Paused after provider rate limit";
@@ -262310,8 +263157,10 @@ var init_turn = __esmMin((() => {
262310
263157
  stepToolCallKeys = /* @__PURE__ */ new Map();
262311
263158
  telemetryModeByTurn = /* @__PURE__ */ new Map();
262312
263159
  currentStepByTurn = /* @__PURE__ */ new Map();
263160
+ toolScopeByTurn = /* @__PURE__ */ new Map();
262313
263161
  interruptedTelemetryTurnIds = /* @__PURE__ */ new Set();
262314
263162
  stepFailureByTurn = /* @__PURE__ */ new Map();
263163
+ stepRequestStateByTurn = /* @__PURE__ */ new Map();
262315
263164
  currentStep = 0;
262316
263165
  cognitiveLifecycle;
262317
263166
  cognitiveLifecycleUnavailable = false;
@@ -262576,10 +263425,11 @@ var init_turn = __esmMin((() => {
262576
263425
  duplicate: false
262577
263426
  };
262578
263427
  }
262579
- retry(trigger) {
263428
+ retry(trigger, toolScope) {
262580
263429
  return this.prompt([], {
262581
263430
  kind: "retry",
262582
- trigger
263431
+ trigger,
263432
+ ...(toolScope === void 0 ? {} : { toolScope })
262583
263433
  });
262584
263434
  }
262585
263435
  launch(input, origin) {
@@ -262657,6 +263507,9 @@ var init_turn = __esmMin((() => {
262657
263507
  get hasActiveTurn() {
262658
263508
  return this.activeTurn !== null && this.activeTurn !== "resuming";
262659
263509
  }
263510
+ toolScopeForTurn(turnId) {
263511
+ return this.toolScopeByTurn.get(turnId);
263512
+ }
262660
263513
  ensureActiveTurn() {
262661
263514
  if (this.activeTurn === null || this.activeTurn === "resuming") throw new Error("No active turn");
262662
263515
  return this.activeTurn;
@@ -262768,15 +263621,23 @@ var init_turn = __esmMin((() => {
262768
263621
  */
262769
263622
  async turnWorker(firstTurnId, input, origin, signal) {
262770
263623
  const ownsActiveTurn = () => this.activeTurn !== null && this.activeTurn !== "resuming" && this.activeTurn.controller.signal === signal;
263624
+ let result;
262771
263625
  try {
262772
- if (this.agent.goal.getGoal().goal?.status === "active") return await this.driveGoal(firstTurnId, input, origin, signal);
262773
- const end = await this.runOneTurn(firstTurnId, input, origin, signal, true);
262774
- if (this.agent.goal.getGoal().goal?.status === "active" && end.event.reason !== "cancelled" && end.event.reason !== "failed" && end.event.reason !== "filtered") return await this.driveGoal(this.allocateTurnId(), [{
262775
- type: "text",
262776
- text: GOAL_CONTINUATION_PROMPT
262777
- }], GOAL_CONTINUATION_ORIGIN, signal);
262778
- return end;
263626
+ if (this.agent.goal.getGoal().goal?.status === "active") result = await this.driveGoal(firstTurnId, input, origin, signal);
263627
+ else {
263628
+ const end = await this.runOneTurn(firstTurnId, input, origin, signal, true);
263629
+ if (this.agent.goal.getGoal().goal?.status === "active" && end.event.reason !== "cancelled" && end.event.reason !== "failed" && end.event.reason !== "filtered") result = await this.driveGoal(this.allocateTurnId(), [{
263630
+ type: "text",
263631
+ text: GOAL_CONTINUATION_PROMPT
263632
+ }], goalContinuationOrigin(origin), signal);
263633
+ else result = end;
263634
+ }
263635
+ return result;
263636
+ } catch (error) {
263637
+ if (origin.kind === "cron_job" && typeof origin.runId === "string") this.agent.cron?.observeRunWorkerFailed(origin.runId);
263638
+ throw error;
262779
263639
  } finally {
263640
+ if (result !== void 0 && origin.kind === "cron_job" && typeof origin.runId === "string") this.agent.cron?.observeRunWorkerEnded(origin.runId, result.event);
262780
263641
  if (ownsActiveTurn()) this.activeTurn = null;
262781
263642
  }
262782
263643
  }
@@ -262830,7 +263691,7 @@ var init_turn = __esmMin((() => {
262830
263691
  type: "text",
262831
263692
  text: GOAL_CONTINUATION_PROMPT
262832
263693
  }];
262833
- turnOrigin = GOAL_CONTINUATION_ORIGIN;
263694
+ turnOrigin = goalContinuationOrigin(origin);
262834
263695
  }
262835
263696
  }
262836
263697
  async endGoalTurnWithoutModel(turnId, input, origin) {
@@ -262878,6 +263739,7 @@ var init_turn = __esmMin((() => {
262878
263739
  this.currentStepByTurn.set(turnId, 0);
262879
263740
  this.recordExternalReportSources(turnId, origin);
262880
263741
  const persistedOrigin = durablePromptOrigin(origin);
263742
+ if (persistedOrigin.toolScope !== void 0) this.toolScopeByTurn.set(turnId, persistedOrigin.toolScope);
262881
263743
  this.agent.telemetry.track("turn_started", {
262882
263744
  mode: telemetryMode,
262883
263745
  ...this.requestProviderProps()
@@ -262985,11 +263847,13 @@ var init_turn = __esmMin((() => {
262985
263847
  if (ended.reason !== "completed") this.trackTurnInterrupted(turnId, this.currentStepByTurn.get(turnId) ?? this.currentStep);
262986
263848
  this.telemetryModeByTurn.delete(turnId);
262987
263849
  this.currentStepByTurn.delete(turnId);
263850
+ this.toolScopeByTurn.delete(turnId);
262988
263851
  this.interruptedTelemetryTurnIds.delete(turnId);
262989
263852
  this.cognitiveActionEvidenceByTurn.delete(turnId);
262990
263853
  this.cognitiveExternalReportsByTurn.delete(turnId);
262991
263854
  this.cognitiveLocalClaimsByTurn.delete(turnId);
262992
263855
  this.stepFailureByTurn.delete(turnId);
263856
+ this.stepRequestStateByTurn.delete(turnId);
262993
263857
  await this.agent.records.flush();
262994
263858
  await this.agent.records.writeResumeCheckpoint();
262995
263859
  return {
@@ -263082,13 +263946,14 @@ var init_turn = __esmMin((() => {
263082
263946
  let previousStepToolOutcome = "initial";
263083
263947
  let currentStepHadTool = false;
263084
263948
  let currentStepHadFailure = false;
263949
+ let currentLoopStep = 0;
263085
263950
  while (true) {
263086
263951
  signal.throwIfAborted();
263087
263952
  const model = this.agent.config.model;
263088
263953
  const loopControl = this.agent.blunConfig?.loopControl;
263089
263954
  let stopForGoalBudget = false;
263090
263955
  try {
263091
- const originTools = blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, this.agent.tools.loopTools), origin);
263956
+ const originTools = filterToolsForCronScope(blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, this.agent.tools.loopTools), origin), origin.toolScope);
263092
263957
  const compactConversationTool = originTools.find((tool) => tool.name === "CompactConversation");
263093
263958
  const eligibleTools = originTools.filter((tool) => tool.name !== "CompactConversation" || this.agent.fullCompaction.isProactiveCompactionEligible());
263094
263959
  const turnRequiredToolNames = new Set(requiredToolNames);
@@ -263114,12 +263979,13 @@ var init_turn = __esmMin((() => {
263114
263979
  eligibleToolSchemaTokens: estimateTokensForTools(eligibleTools),
263115
263980
  selectedToolSchemaTokens: estimateTokensForTools(selectedTools)
263116
263981
  });
263982
+ const turnHistory = () => fastConversation ? turnThinkingEffort === "off" ? blunStandaloneConversationHistory(this.agent.context.history) : blunFastConversationHistory(this.agent.context.history) : origin.kind === "cron_job" && origin.recurring === true ? projectRecurringCronHistory(this.agent.context.history, origin.jobId) : personalMemoryRecall === void 0 ? this.agent.context.history : [...this.agent.context.history, personalMemoryRecall];
263117
263983
  return (await runTurn({
263118
263984
  turnId: String(turnId),
263119
263985
  signal,
263120
263986
  llm: turnLLM,
263121
- buildMessages: () => this.agent.context.project(fastConversation ? turnThinkingEffort === "off" ? blunStandaloneConversationHistory(this.agent.context.history) : blunFastConversationHistory(this.agent.context.history) : origin.kind === "cron_job" && origin.recurring === true ? projectRecurringCronHistory(this.agent.context.history, origin.jobId) : personalMemoryRecall === void 0 ? this.agent.context.history : [...this.agent.context.history, personalMemoryRecall], { dropOrphanResults: true }),
263122
- buildMessagesStrict: () => this.agent.context.project(fastConversation ? turnThinkingEffort === "off" ? blunStandaloneConversationHistory(this.agent.context.history) : blunFastConversationHistory(this.agent.context.history) : origin.kind === "cron_job" && origin.recurring === true ? projectRecurringCronHistory(this.agent.context.history, origin.jobId) : personalMemoryRecall === void 0 ? this.agent.context.history : [...this.agent.context.history, personalMemoryRecall], {
263987
+ buildMessages: () => this.agent.context.project(blunRepeatActiveTurnPrompt(turnHistory(), input, currentLoopStep), { dropOrphanResults: true }),
263988
+ buildMessagesStrict: () => this.agent.context.project(blunRepeatActiveTurnPrompt(turnHistory(), input, currentLoopStep), {
263123
263989
  synthesizeMissing: true,
263124
263990
  dropOrphanResults: true,
263125
263991
  dedupeDuplicateToolCalls: true,
@@ -263131,6 +263997,8 @@ var init_turn = __esmMin((() => {
263131
263997
  log: this.agent.log,
263132
263998
  maxSteps: loopControl?.maxStepsPerTurn,
263133
263999
  maxRetryAttempts: loopControl?.maxRetriesPerStep,
264000
+ checkpointBeforeToolExecution: () => this.agent.records.flush(),
264001
+ checkpointBeforeRetryWait: () => this.agent.records.flush(),
263134
264002
  recordStepUsage: async (usage) => {
263135
264003
  try {
263136
264004
  stopForGoalBudget = (await this.agent.goal.recordTokenUsage(grandTotal(usage)))?.budget.overBudget === true;
@@ -263140,6 +264008,7 @@ var init_turn = __esmMin((() => {
263140
264008
  },
263141
264009
  hooks: {
263142
264010
  beforeStep: async ({ signal: stepSignal, stepNumber }) => {
264011
+ currentLoopStep = stepNumber;
263143
264012
  await this.agent.records.flush();
263144
264013
  await this.agent.toolResultBatchOffload.detect();
263145
264014
  this.agent.microCompaction.detect();
@@ -263327,14 +264196,25 @@ var init_turn = __esmMin((() => {
263327
264196
  toolOutput: isError === true ? void 0 : toolOutputText(output).slice(0, 2e3)
263328
264197
  }
263329
264198
  });
263330
- return budgetToolResultForModel({
264199
+ const budgetedResult = await budgetToolResultForModel({
263331
264200
  homedir: this.agent.homedir,
263332
264201
  toolName: ctx.toolCall.name,
263333
264202
  toolCallId: ctx.toolCall.id,
263334
264203
  toolArgs: ctx.args,
263335
264204
  result: finalResult,
264205
+ contextTokens: this.agent.context.tokenCountWithPending,
264206
+ maxContextTokens: this.agent.config.modelCapabilities.max_context_tokens,
263336
264207
  telemetry: this.agent.telemetry
263337
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;
263338
264218
  }
263339
264219
  }
263340
264220
  })).stopReason;
@@ -263377,11 +264257,32 @@ var init_turn = __esmMin((() => {
263377
264257
  buildDispatchEvent(turnId) {
263378
264258
  return createLoopEventDispatcher({
263379
264259
  appendTranscriptRecord: async (event) => {
264260
+ this.agent.cron?.observeLoopEvent(turnId, event);
263380
264261
  this.agent.context.appendLoopEvent(event);
263381
264262
  },
263382
264263
  emitLiveEvent: (event) => {
263383
264264
  this.noteFirstRequestEvent(event);
263384
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
+ });
263385
264286
  const mapped = mapLoopEvent(event, turnId);
263386
264287
  if (mapped !== void 0) return this.agent.emitEvent(mapped);
263387
264288
  }
@@ -263405,9 +264306,18 @@ var init_turn = __esmMin((() => {
263405
264306
  }
263406
264307
  trackLoopTelemetry(event, turnId) {
263407
264308
  if (event.type === "step.begin") {
263408
- this.beginTrackedStep(turnId, event.step);
264309
+ this.beginTrackedStep(turnId, event.step, event);
263409
264310
  return;
263410
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
+ }
263411
264321
  if (event.type === "turn.interrupted") {
263412
264322
  if (event.reason === "error" && event.activeStep !== void 0) this.stepFailureByTurn.set(turnId, event);
263413
264323
  this.trackTurnInterrupted(turnId, interruptedStep(event));
@@ -263415,9 +264325,15 @@ var init_turn = __esmMin((() => {
263415
264325
  }
263416
264326
  this.trackToolLifecycle(event, turnId);
263417
264327
  }
263418
- beginTrackedStep(turnId, step) {
264328
+ beginTrackedStep(turnId, step, event) {
263419
264329
  this.currentStepByTurn.set(turnId, step);
263420
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
+ });
263421
264337
  if (!this.stepToolCallKeys.has(step)) this.stepToolCallKeys.set(step, /* @__PURE__ */ new Set());
263422
264338
  }
263423
264339
  trackToolLifecycle(event, turnId) {
@@ -264434,7 +265350,7 @@ var init_codebase_search = __esmMin((() => {
264434
265350
  description: `Semantic search: ${args.query.length > 50 ? `${args.query.slice(0, 50)}…` : args.query}`,
264435
265351
  display: {
264436
265352
  kind: "command",
264437
- command: `python codebase_index.py query . "${args.query}" --top ${String(args.top)}`,
265353
+ command: `python codebase_index.py query . "${args.query}" --top ${String(args.top)} --model auto`,
264438
265354
  cwd: this.cwd,
264439
265355
  description: `Codebase semantic search`,
264440
265356
  language: "bash"
@@ -264454,7 +265370,9 @@ var init_codebase_search = __esmMin((() => {
264454
265370
  this.cwd,
264455
265371
  args.query,
264456
265372
  "--top",
264457
- String(args.top)
265373
+ String(args.top),
265374
+ "--model",
265375
+ "auto"
264458
265376
  ], {
264459
265377
  cwd: this.cwd,
264460
265378
  timeout: SCRIPT_TIMEOUT_MS,
@@ -265087,10 +266005,12 @@ var init_builtin = __esmMin((() => {
265087
266005
  init_task_list();
265088
266006
  init_task_output();
265089
266007
  init_task_update();
266008
+ init_task_resume();
265090
266009
  init_task_stop();
265091
266010
  init_cron_create();
265092
266011
  init_cron_delete();
265093
266012
  init_cron_list();
266013
+ init_cron_runs();
265094
266014
  init_agent$1();
265095
266015
  init_agent_swarm();
265096
266016
  init_ask_user();
@@ -265122,7 +266042,7 @@ var init_builtin = __esmMin((() => {
265122
266042
  var init_types$3 = __esmMin((() => {}));
265123
266043
  //#endregion
265124
266044
  //#region ../../packages/agent-core/src/agent/tool/index.ts
265125
- var import_picomatch, profileToolExclusionPolicy, applyProfileToolExclusions, shouldRecordUserToolUnregister, SHELL_FOREGROUND_TIMEOUT_S, ToolManager;
266045
+ var import_picomatch, profileToolExclusionPolicy, applyProfileToolExclusions, shouldRecordUserToolUnregister, createFileObservationPolicy, SHELL_FOREGROUND_TIMEOUT_S, ToolManager;
265126
266046
  var init_tool$1 = __esmMin((() => {
265127
266047
  init_dist$4();
265128
266048
  import_picomatch = /* @__PURE__ */ __toESM(require_picomatch(), 1);
@@ -265138,6 +266058,7 @@ var init_tool$1 = __esmMin((() => {
265138
266058
  profileToolExclusionPolicy = createRequire(import.meta.url)("./bin/profile-tool-exclusion-policy.cjs");
265139
266059
  applyProfileToolExclusions = profileToolExclusionPolicy.applyProfileToolExclusions;
265140
266060
  ({ shouldRecordUserToolUnregister } = createRequire(import.meta.url)("./bin/user-tool-record-policy.cjs"));
266061
+ ({ createFileObservationPolicy } = createRequire(import.meta.url)("./bin/file-observation-policy.cjs"));
265141
266062
  SHELL_FOREGROUND_TIMEOUT_S = 120;
265142
266063
  ToolManager = class {
265143
266064
  agent;
@@ -265320,9 +266241,10 @@ var init_tool$1 = __esmMin((() => {
265320
266241
  hasUserTool(name) {
265321
266242
  return this.userTools.has(name);
265322
266243
  }
265323
- inheritUserTools(parent) {
266244
+ inheritUserTools(parent, excludedNames = /* @__PURE__ */ new Set()) {
265324
266245
  for (const tool of parent.userTools.values()) {
265325
266246
  if (!parent.enabledTools.has(tool.name)) continue;
266247
+ if (excludedNames.has(tool.name)) continue;
265326
266248
  this.registerUserTool({
265327
266249
  name: tool.name,
265328
266250
  description: tool.description,
@@ -265537,11 +266459,16 @@ var init_tool$1 = __esmMin((() => {
265537
266459
  }, this.agent.skills?.registry.getSkillRoots() ?? []);
265538
266460
  const allowBackground = this.enabledTools.has("TaskList") && this.enabledTools.has("TaskOutput") && this.enabledTools.has("TaskStop");
265539
266461
  const goalToolsEnabled = this.agent.type === "main";
266462
+ const readBudget = () => ({
266463
+ contextTokens: this.agent.context.tokenCountWithPending,
266464
+ maxContextTokens: this.agent.fullCompaction.getEffectiveMaxContextTokens()
266465
+ });
266466
+ const fileObservation = createFileObservationPolicy({ pathClass: kaos.pathClass() });
265540
266467
  this.builtinTools = new Map([
265541
- new ReadTool(kaos, workspace),
265542
- new ReadBatchTool(kaos, workspace),
265543
- new WriteTool(kaos, workspace, () => this.agent.context.history, toolServices?.lsp),
265544
- 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),
265545
266472
  new GrepTool(kaos, workspace, this.agent.telemetry),
265546
266473
  new GlobTool(kaos, workspace, this.agent.telemetry),
265547
266474
  new BashTool(kaos, cwd, background, { allowBackground }),
@@ -265559,9 +266486,12 @@ var init_tool$1 = __esmMin((() => {
265559
266486
  new TaskListTool(background),
265560
266487
  new TaskOutputTool(background),
265561
266488
  new TaskUpdateTool(background),
266489
+ this.agent.subagentHost && allowBackground && background.resumeStore && new TaskResumeTool(background, this.agent.subagentHost),
265562
266490
  new TaskStopTool(background),
265563
266491
  this.agent.cron && new CronCreateTool(this.agent.cron),
265564
266492
  this.agent.cron && new CronListTool(this.agent.cron),
266493
+ this.agent.cron && new CronRunListTool(this.agent.cron),
266494
+ this.agent.cron && new CronRunOutputTool(this.agent.cron),
265565
266495
  this.agent.cron && new CronDeleteTool(this.agent.cron),
265566
266496
  this.agent.skills?.registry.listInvocableSkills().length && new SkillTool(this.agent),
265567
266497
  this.agent.subagentHost && new AgentTool(this.agent.subagentHost, background, DEFAULT_AGENT_PROFILES["agent"]?.subagents, {
@@ -265968,7 +266898,7 @@ var init_llm_request_logger = __esmMin((() => {
265968
266898
  function normalizeRuntimeSystemPromptAppend(value) {
265969
266899
  return value?.trim().slice(0, 16e3) ?? "";
265970
266900
  }
265971
- 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;
265972
266902
  var init_agent = __esmMin((() => {
265973
266903
  init_dist$6();
265974
266904
  init_config$4();
@@ -266007,8 +266937,8 @@ var init_agent = __esmMin((() => {
266007
266937
  init_error_memory();
266008
266938
  ({ createEffectiveSystemPromptResolver } = createRequire(import.meta.url)("./bin/effective-system-prompt-cache-policy.cjs"));
266009
266939
  ({ resolveProviderIdleTimeoutMs } = createRequire(import.meta.url)("./bin/provider-idle-timeout-policy.cjs"));
266010
- ({ capCompletionBudgetForAdaptiveEffort, capTurnCompletionTokens, selectThinkingEffortForBufferedSteer, selectThinkingEffortForWorkStep, selectThinkingEffortForTurn } = createRequire(import.meta.url)("./bin/turn-thinking-policy.cjs"));
266011
- PINNED_MODEL_ALIASES = new Set(["king-blun", "pruefstand"]);
266940
+ ({ capCompletionBudgetForAdaptiveEffort, selectThinkingEffortForBufferedSteer, selectThinkingEffortForWorkStep, selectThinkingEffortForTurn } = createRequire(import.meta.url)("./bin/turn-thinking-policy.cjs"));
266941
+ PINNED_MODEL_ALIASES = new Set(["blun/king"]);
266012
266942
  Agent$1 = class {
266013
266943
  type;
266014
266944
  _kaos;
@@ -266202,7 +267132,7 @@ var init_agent = __esmMin((() => {
266202
267132
  const provider = thinkingEffort === void 0 ? runtimeModel.provider : runtimeModel.provider.withThinking(thinkingEffort);
266203
267133
  const loopControl = this.blunConfig?.loopControl;
266204
267134
  const completionBudgetConfig = resolveCompletionBudget({
266205
- maxOutputSize: capTurnCompletionTokens(runtimeModel.maxOutputSize),
267135
+ maxOutputSize: runtimeModel.maxOutputSize,
266206
267136
  reservedContextSize: loopControl?.reservedContextSize
266207
267137
  });
266208
267138
  return new KosongLLM({
@@ -266550,6 +267480,7 @@ var init_agent = __esmMin((() => {
266550
267480
  }
266551
267481
  emitEvent(event) {
266552
267482
  if (this.records.restoring) return;
267483
+ this.cron?.observeAgentEvent(event);
266553
267484
  return this.rpc?.emitEvent?.(event);
266554
267485
  }
266555
267486
  emitStatusUpdated() {
@@ -298410,7 +299341,9 @@ var init_session$1 = __esmMin((() => {
298410
299341
  homedir,
298411
299342
  type,
298412
299343
  parentAgentId,
298413
- swarmItem: options.swarmItem
299344
+ swarmItem: options.swarmItem,
299345
+ profileName: options.profileName,
299346
+ skillPolicy: options.skillPolicy
298414
299347
  };
298415
299348
  this.writeMetadata();
298416
299349
  }
@@ -298686,7 +299619,7 @@ var init_session$1 = __esmMin((() => {
298686
299619
  missingCapability: part.missingCapability
298687
299620
  });
298688
299621
  },
298689
- skills: this.skills,
299622
+ skills: config.skillRegistry === void 0 ? this.skills : config.skillRegistry,
298690
299623
  rpc: proxyWithExtraPayload(this.rpc, { agentId: id }),
298691
299624
  modelProvider: this.options.providerManager,
298692
299625
  hookEngine: config.hookEngine ?? this.hookEngine,
@@ -298751,9 +299684,16 @@ var init_session$1 = __esmMin((() => {
298751
299684
  const parentAgentId = meta.parentAgentId ?? null;
298752
299685
  const parent = parentAgentId === null ? void 0 : await this.resumeAgent(parentAgentId, [...stack, id]);
298753
299686
  try {
298754
- const agent = this.instantiateAgent(id, meta.homedir, meta.type, {}, parentAgentId);
299687
+ let restoredSkillPolicy;
299688
+ if (meta.type === "sub" && meta.skillPolicy !== void 0) {
299689
+ if (meta.profileName === void 0) throw new Error("SUBAGENT_SKILL_POLICY_CHANGED: persisted subagent profile is unavailable; spawn a new subagent");
299690
+ const persistedProfile = DEFAULT_AGENT_PROFILES[parent?.agent.config.profileName ?? "agent"]?.subagents?.[meta.profileName] ?? DEFAULT_AGENT_PROFILES["agent"]?.subagents?.[meta.profileName];
299691
+ if (persistedProfile === void 0) throw new Error("SUBAGENT_SKILL_POLICY_CHANGED: persisted subagent profile was not found; spawn a new subagent");
299692
+ restoredSkillPolicy = restoreSubagentSkillPolicy(persistedProfile.subagentSkills, meta.skillPolicy, this.skills);
299693
+ }
299694
+ const agent = this.instantiateAgent(id, meta.homedir, meta.type, restoredSkillPolicy === void 0 ? {} : { skillRegistry: restoredSkillPolicy.registry }, parentAgentId);
298755
299695
  const result = await agent.resume();
298756
- await this.restoreAgentProfileHandle(agent, meta, parent?.agent);
299696
+ await this.restoreAgentProfileHandle(agent, meta, parent?.agent, restoredSkillPolicy);
298757
299697
  this.ensureBaselineSkill(agent);
298758
299698
  agent.setRuntimeSystemPromptAppend(this.accountMemoryContext);
298759
299699
  this.agents.set(id, agent);
@@ -298766,18 +299706,33 @@ var init_session$1 = __esmMin((() => {
298766
299706
  throw error;
298767
299707
  }
298768
299708
  }
298769
- async restoreAgentProfileHandle(agent, meta, parentAgent) {
299709
+ async restoreAgentProfileHandle(agent, meta, parentAgent, restoredSkillPolicy) {
298770
299710
  if (agent.config.systemPrompt === "") return;
298771
- const profile = this.resolvePersistedProfile(agent, meta, parentAgent);
299711
+ let profile = this.resolvePersistedProfile(agent, meta, parentAgent);
298772
299712
  if (profile === void 0) return;
299713
+ if (restoredSkillPolicy !== void 0) profile = profileWithSubagentSkillTools(profile, restoredSkillPolicy);
298773
299714
  agent.setActiveProfile(profile, this.options.blunHomeDir);
298774
299715
  await agent.refreshSystemPrompt();
298775
299716
  }
298776
299717
  ensureBaselineSkill(agent) {
298777
- if (agent.skills?.ensureBaseline(BASELINE_SKILL_NAME) !== true) this.log.warn("baseline skill is unavailable", { skill: BASELINE_SKILL_NAME });
299718
+ const skill = this.skills.getSkill(BASELINE_SKILL_NAME);
299719
+ if (skill === void 0) {
299720
+ this.log.warn("baseline skill is unavailable", { skill: BASELINE_SKILL_NAME });
299721
+ return;
299722
+ }
299723
+ const variant = `${BASELINE_SKILL_ORIGIN_PREFIX}${skill.name}`;
299724
+ if (agent.context.history.some((message) => message.origin?.kind === "injection" && message.origin.variant === variant)) return;
299725
+ agent.context.appendSystemReminder(renderBaselineSkillPrompt({
299726
+ skillName: skill.name,
299727
+ skillSource: skill.source,
299728
+ skillDir: skill.dir
299729
+ }), {
299730
+ kind: "injection",
299731
+ variant
299732
+ });
298778
299733
  }
298779
299734
  resolvePersistedProfile(agent, meta, parentAgent) {
298780
- const profileName = agent.config.profileName;
299735
+ const profileName = meta.profileName ?? agent.config.profileName;
298781
299736
  if (profileName === void 0) return void 0;
298782
299737
  if (meta.type === "sub") return DEFAULT_AGENT_PROFILES[parentAgent?.config.profileName ?? "agent"]?.subagents?.[profileName] ?? DEFAULT_AGENT_PROFILES["agent"]?.subagents?.[profileName];
298783
299738
  return DEFAULT_AGENT_PROFILES[profileName];
@@ -313566,27 +314521,14 @@ var init_local_fetch_url = __esmMin((() => {
313566
314521
  kind: "passthrough"
313567
314522
  };
313568
314523
  return {
313569
- content: this.extractMainContent(body),
314524
+ content: this.extractMainContent(body, url),
313570
314525
  kind: "extracted"
313571
314526
  };
313572
314527
  }
313573
- extractMainContent(html) {
313574
- const primary = parseHTML(html);
313575
- try {
313576
- const article = new import_readability.Readability(primary.document, { charThreshold: 0 }).parse();
313577
- if (article !== null) {
313578
- const text = (article.textContent ?? "").trim();
313579
- if (text.length > 0) {
313580
- const title = (article.title ?? "").trim();
313581
- return title.length > 0 ? `# ${title}\n\n${text}` : text;
313582
- }
313583
- }
313584
- } catch {}
313585
- const { document } = parseHTML(html);
313586
- const titleText = (document.querySelector("title")?.textContent ?? "").trim();
313587
- const fallbackText = ((document.querySelector("article") ?? document.querySelector("main") ?? document.querySelector("body"))?.textContent ?? "").trim();
313588
- if (fallbackText.length === 0) throw new Error("Failed to extract meaningful content from the page. The page may require JavaScript to render.");
313589
- return titleText.length > 0 ? `# ${titleText}\n\n${fallbackText}` : fallbackText;
314528
+ extractMainContent(html, baseUrl) {
314529
+ const content = htmlToResearchMarkdown(html, baseUrl);
314530
+ if (content.length === 0) throw new Error("Failed to extract meaningful content from the page. The page may require JavaScript to render.");
314531
+ return content;
313590
314532
  }
313591
314533
  };
313592
314534
  }));
@@ -315079,17 +316021,7 @@ function resolveModelCapabilities(alias, provider) {
315079
316021
  };
315080
316022
  }
315081
316023
  function toKosongProviderConfig(provider, model, blunRequestHeaders, promptCacheKey, supportEfforts) {
315082
- assertSupportedProviderType(provider);
315083
- if (provider.type === FREDRIK_GLM_PROVIDER_TYPE) return {
315084
- type: "blun",
315085
- model,
315086
- baseUrl: provider.baseUrl,
315087
- apiKey: readFredrikGlmApiKeyFile(provider),
315088
- generationKwargs: { prompt_cache_key: promptCacheKey },
315089
- supportEfforts: [...FREDRIK_GLM_EFFORTS],
315090
- openAICompatible: true,
315091
- defaultHeaders: { "User-Agent": "BLUN-King/Fredrik-GLM" }
315092
- };
316024
+ assertBlunProviderType(provider);
315093
316025
  const envCustomHeaders = parseBlunCodeCustomHeaders();
315094
316026
  return {
315095
316027
  type: "blun",
@@ -315110,12 +316042,11 @@ function defaultHeadersField(headers) {
315110
316042
  return { defaultHeaders: { ...headers } };
315111
316043
  }
315112
316044
  function providerApiKey(provider) {
315113
- assertSupportedProviderType(provider);
315114
- if (provider.type === FREDRIK_GLM_PROVIDER_TYPE) return readFredrikGlmApiKeyFile(provider);
316045
+ assertBlunProviderType(provider);
315115
316046
  return providerValue(provider.apiKey, provider.env, "BLUN_API_KEY");
315116
316047
  }
315117
- function assertSupportedProviderType(provider) {
315118
- if (provider.type !== "blun" && provider.type !== FREDRIK_GLM_PROVIDER_TYPE) throw new BlunError(ErrorCodes.MODEL_CONFIG_INVALID, "Only approved BLUN Code provider types are supported.");
316048
+ function assertBlunProviderType(provider) {
316049
+ if (provider.type !== "blun") throw new BlunError(ErrorCodes.MODEL_CONFIG_INVALID, "Only the BLUN provider type is supported.");
315119
316050
  }
315120
316051
  function providerValue(configured, env, envKey) {
315121
316052
  return nonEmptyString$2(configured) ?? envValue(env, envKey);
@@ -315134,7 +316065,7 @@ var init_provider_manager = __esmMin((() => {
315134
316065
  init_config$4();
315135
316066
  init_errors$8();
315136
316067
  MANAGED_PROVIDER_NAME$2 = "managed:blun";
315137
- MANAGED_BLUN_MODEL_ALIASES$1 = new Set(["blun/king", "king-blun"]);
316068
+ MANAGED_BLUN_MODEL_ALIASES$1 = new Set(["blun/king"]);
315138
316069
  ProviderManager = class {
315139
316070
  options;
315140
316071
  runtimeModelContexts = /* @__PURE__ */ new Map();
@@ -315153,9 +316084,7 @@ var init_provider_manager = __esmMin((() => {
315153
316084
  if (providerName === void 0) throw new BlunError(ErrorCodes.CONFIG_INVALID, `Model "${model}" must define a provider in config.toml.`);
315154
316085
  const providerConfig = this.config.providers[providerName];
315155
316086
  if (providerConfig === void 0) throw new BlunError(ErrorCodes.CONFIG_INVALID, `Provider "${providerName}" for model "${model}" is not configured.`);
315156
- assertSupportedProviderType(providerConfig);
315157
- if (providerConfig.type === FREDRIK_GLM_PROVIDER_TYPE && (providerName !== FREDRIK_GLM_PROVIDER_ID || !isConfiguredFredrikGlmAlias(model, alias))) throw new BlunError(ErrorCodes.CONFIG_INVALID, "Fredrik GLM provider aliases must match the approved profile-local model catalog.");
315158
- if (providerConfig.type !== FREDRIK_GLM_PROVIDER_TYPE && isConfiguredFredrikGlmAlias(model, alias)) throw new BlunError(ErrorCodes.CONFIG_INVALID, "Fredrik GLM aliases require the approved profile-local provider.");
316087
+ assertBlunProviderType(providerConfig);
315159
316088
  const runtimeContext = this.runtimeModelContexts.get(model);
315160
316089
  const maxContextSize = runtimeContext?.providerName === providerName && runtimeContext.model === alias.model ? runtimeContext.maxContextTokens : effectiveAlias.maxContextSize;
315161
316090
  if (!Number.isInteger(maxContextSize) || maxContextSize <= 0) throw new BlunError(ErrorCodes.CONFIG_INVALID, `Model "${model}" must define a positive max_context_size in config.toml.`);
@@ -315169,7 +316098,7 @@ var init_provider_manager = __esmMin((() => {
315169
316098
  }, provider),
315170
316099
  alwaysThinking: (effectiveAlias.capabilities ?? []).some((c) => c.trim().toLowerCase() === "always_thinking"),
315171
316100
  maxOutputSize: effectiveAlias.maxOutputSize,
315172
- type: providerConfig.type
316101
+ type: "blun"
315173
316102
  };
315174
316103
  }
315175
316104
  setRuntimeModelContext(input) {
@@ -315177,7 +316106,7 @@ var init_provider_manager = __esmMin((() => {
315177
316106
  if (!Number.isSafeInteger(input.maxContextTokens) || input.maxContextTokens <= 0) throw new BlunError(ErrorCodes.CONFIG_INVALID, "Runtime model context must be a positive integer.");
315178
316107
  const alias = this.config.models?.[input.modelAlias];
315179
316108
  const providerName = alias?.provider ?? this.config.defaultProvider;
315180
- if (alias === void 0 || providerName !== input.providerName || alias.model !== input.model || providerName !== "managed:blun" && providerName !== "king-blun") throw new BlunError(ErrorCodes.CONFIG_INVALID, "Runtime model context does not match the configured internal BLUN model.");
316109
+ if (alias === void 0 || providerName !== input.providerName || alias.model !== input.model || providerName !== "managed:blun") throw new BlunError(ErrorCodes.CONFIG_INVALID, "Runtime model context does not match the configured BLUN model.");
315181
316110
  const previous = this.runtimeModelContexts.get(input.modelAlias);
315182
316111
  this.runtimeModelContexts.set(input.modelAlias, {
315183
316112
  providerName: input.providerName,
@@ -315189,7 +316118,7 @@ var init_provider_manager = __esmMin((() => {
315189
316118
  resolveAuth(model, options) {
315190
316119
  const { providerName } = this.resolveProviderConfig(model);
315191
316120
  const providerConfig = this.config.providers[providerName];
315192
- const apiKey = providerConfig?.type === "blun" ? providerApiKey(providerConfig) : void 0;
316121
+ const apiKey = providerConfig === void 0 ? void 0 : providerApiKey(providerConfig);
315193
316122
  const revocationStore = this.options.managedApiKeyRevocationStore;
315194
316123
  if (providerName === MANAGED_PROVIDER_NAME$2 && providerConfig?.oauth === void 0 && apiKey !== void 0 && revocationStore !== void 0) return this.resolveManagedApiKeyAuth(providerName, apiKey, revocationStore, options?.log);
315195
316124
  if (providerConfig?.oauth === void 0) return void 0;
@@ -319412,6 +320341,7 @@ function toBrokerRequest$1(req, params) {
319412
320341
  tool_name: req.toolName,
319413
320342
  action: req.action,
319414
320343
  tool_input_display: req.display,
320344
+ allow_edit: req.allowEdit === true ? true : void 0,
319415
320345
  created_at: params.createdAt,
319416
320346
  expires_at: params.expiresAt
319417
320347
  };
@@ -319426,7 +320356,8 @@ function toAgentCoreResponse$1(resp) {
319426
320356
  decision: resp.decision,
319427
320357
  scope: resp.scope,
319428
320358
  feedback: resp.feedback,
319429
- selectedLabel: resp.selected_label
320359
+ selectedLabel: resp.selected_label,
320360
+ edited_tool_input: resp.edited_tool_input
319430
320361
  };
319431
320362
  }
319432
320363
  var IApprovalService;
@@ -343030,7 +343961,7 @@ const DEFAULT_NOTIFICATIONS_CONFIG = {
343030
343961
  enabled: true,
343031
343962
  condition: "unfocused"
343032
343963
  };
343033
- const DEFAULT_UPGRADE_PREFERENCES = { autoInstall: true };
343964
+ const DEFAULT_UPGRADE_PREFERENCES = { autoInstall: false };
343034
343965
  /**
343035
343966
  * F2 Tippen-mit-Vorschlag: Code-Sprachen standardmäßig an, md/plain aus.
343036
343967
  * Unbekannte Sprachen fallen auf "an" zurück (Opt-out über tui.toml).
@@ -373133,16 +374064,18 @@ var PendingApproval = class {
373133
374064
  createdAt;
373134
374065
  expiresAt;
373135
374066
  protocolRequest;
374067
+ editContext;
373136
374068
  _resolveFn;
373137
374069
  _rejectFn;
373138
374070
  _settled = false;
373139
- constructor(approvalId, sessionId, toolCallId, createdAt, expiresAt, protocolRequest, _resolveFn, _rejectFn) {
374071
+ constructor(approvalId, sessionId, toolCallId, createdAt, expiresAt, protocolRequest, editContext, _resolveFn, _rejectFn) {
373140
374072
  this.approvalId = approvalId;
373141
374073
  this.sessionId = sessionId;
373142
374074
  this.toolCallId = toolCallId;
373143
374075
  this.createdAt = createdAt;
373144
374076
  this.expiresAt = expiresAt;
373145
374077
  this.protocolRequest = protocolRequest;
374078
+ this.editContext = editContext;
373146
374079
  this._resolveFn = _resolveFn;
373147
374080
  this._rejectFn = _rejectFn;
373148
374081
  }
@@ -373216,7 +374149,10 @@ let ApprovalService = class ApprovalService extends Disposable {
373216
374149
  toolCallId: req.toolCallId
373217
374150
  }, "approval requested");
373218
374151
  return new Promise((resolve, reject) => {
373219
- this._pending.set(approvalId, new PendingApproval(approvalId, req.sessionId, req.toolCallId, createdAt, expiresAt, protocolRequest, resolve, reject));
374152
+ this._pending.set(approvalId, new PendingApproval(approvalId, req.sessionId, req.toolCallId, createdAt, expiresAt, protocolRequest, {
374153
+ toolName: req.toolName,
374154
+ editCount: Number.isSafeInteger(req.approvalEditCount) ? req.approvalEditCount : 0
374155
+ }, resolve, reject));
373220
374156
  this._byToolCallId.set(req.toolCallId, approvalId);
373221
374157
  });
373222
374158
  }
@@ -373245,6 +374181,14 @@ let ApprovalService = class ApprovalService extends Disposable {
373245
374181
  isPending(approvalId) {
373246
374182
  return this._pending.has(approvalId);
373247
374183
  }
374184
+ getEditContext(approvalId) {
374185
+ const pending = this._pending.get(approvalId);
374186
+ if (!pending) return void 0;
374187
+ return {
374188
+ toolName: pending.editContext.toolName,
374189
+ editCount: pending.editContext.editCount
374190
+ };
374191
+ }
373248
374192
  listPending(sessionId) {
373249
374193
  return Array.from(this._pending.values()).filter((p) => p.sessionId === sessionId).map((p) => p.protocolRequest);
373250
374194
  }
@@ -373287,6 +374231,24 @@ const approvalParamsSchema = object({
373287
374231
  session_id: string().min(1),
373288
374232
  approval_id: string().min(1)
373289
374233
  });
374234
+ const EDITABLE_APPROVAL_RAW_BODY_LIMIT = 65536;
374235
+ async function captureEditableApprovalRawBody(req, reply, payload) {
374236
+ const chunks = [];
374237
+ let totalBytes = 0;
374238
+ for await (const chunk of payload) {
374239
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
374240
+ totalBytes += bytes.length;
374241
+ if (totalBytes > EDITABLE_APPROVAL_RAW_BODY_LIMIT) {
374242
+ const error = new Error("Approval response body exceeds the editable-input limit");
374243
+ error.statusCode = 413;
374244
+ throw error;
374245
+ }
374246
+ chunks.push(bytes);
374247
+ }
374248
+ const rawBody = Buffer.concat(chunks, totalBytes);
374249
+ req.editableApprovalRawBody = rawBody.toString("utf8");
374250
+ return Readable.from([rawBody]);
374251
+ }
373290
374252
  function registerApprovalsRoutes(app, ix) {
373291
374253
  const listRoute = defineRoute({
373292
374254
  method: "GET",
@@ -373331,7 +374293,27 @@ function registerApprovalsRoutes(app, ix) {
373331
374293
  reply.send(errEnvelope(ErrorCode$1.APPROVAL_NOT_FOUND, `approval ${approval_id} not found`, req.id));
373332
374294
  return;
373333
374295
  }
373334
- const inProc = toAgentCoreResponse$1(body);
374296
+ const editContext = broker.getEditContext(approval_id);
374297
+ if (editContext === void 0 || typeof req.editableApprovalRawBody !== "string") {
374298
+ reply.send(errEnvelope(ErrorCode$1.VALIDATION_FAILED, "approval response could not be validated from its raw JSON body", req.id));
374299
+ return;
374300
+ }
374301
+ let inProc;
374302
+ try {
374303
+ const rawResponse = parseEditedToolInputJson(req.editableApprovalRawBody);
374304
+ const normalized = validateEditedApprovalDecision({
374305
+ response: rawResponse,
374306
+ toolName: editContext.toolName,
374307
+ editCount: editContext.editCount
374308
+ });
374309
+ inProc = normalized.decision === "edited" ? {
374310
+ decision: "edited",
374311
+ edited_tool_input: normalized.editedToolInput
374312
+ } : normalized;
374313
+ } catch (error) {
374314
+ reply.send(errEnvelope(ErrorCode$1.VALIDATION_FAILED, error instanceof Error ? error.message : String(error), req.id));
374315
+ return;
374316
+ }
373335
374317
  broker.resolve(approval_id, inProc);
373336
374318
  broker.markResolved(approval_id);
373337
374319
  const result = {
@@ -373340,6 +374322,7 @@ function registerApprovalsRoutes(app, ix) {
373340
374322
  };
373341
374323
  reply.send(okEnvelope(result, req.id));
373342
374324
  });
374325
+ route.options.preParsing = captureEditableApprovalRawBody;
373343
374326
  app.post(route.path, route.options, route.handler);
373344
374327
  }
373345
374328
  //#endregion
@@ -404208,13 +405191,6 @@ const BUILTIN_SLASH_COMMAND_DEFINITIONS = [
404208
405191
  completeArgs: swarmArgumentCompletions,
404209
405192
  availability: "idle-only"
404210
405193
  },
404211
- {
404212
- name: "model",
404213
- aliases: [],
404214
- descriptionKey: "command.model.description",
404215
- priority: 96,
404216
- availability: "always"
404217
- },
404218
405194
  {
404219
405195
  name: "effort",
404220
405196
  aliases: ["thinking"],
@@ -404666,6 +405642,7 @@ registerUiCatalogFragment({
404666
405642
  //#endregion
404667
405643
  //#region src/tui/commands/resolve.ts
404668
405644
  const LEGACY_EFFORT_COMMANDS = new Set([
405645
+ "model",
404669
405646
  "automodel",
404670
405647
  "router"
404671
405648
  ]);
@@ -408495,6 +409472,9 @@ var TUI = class TUI extends Container {
408495
409472
  setClearOnShrink(enabled) {
408496
409473
  this.clearOnShrink = enabled;
408497
409474
  }
409475
+ getRenderHeight() {
409476
+ return this.terminal.rows;
409477
+ }
408498
409478
  setFocus(component) {
408499
409479
  this.setFocusInternal({
408500
409480
  component,
@@ -409103,7 +410083,7 @@ var TUI = class TUI extends Container {
409103
410083
  doRender() {
409104
410084
  if (this.stopped) return;
409105
410085
  const width = this.terminal.columns;
409106
- const height = this.terminal.rows;
410086
+ const height = this.getRenderHeight();
409107
410087
  const widthChanged = this.previousWidth !== 0 && this.previousWidth !== width;
409108
410088
  const heightChanged = this.previousHeight !== 0 && this.previousHeight !== height;
409109
410089
  const previousBufferLength = this.previousHeight > 0 ? this.previousViewportTop + this.previousHeight : height;
@@ -417702,168 +418682,6 @@ function segmentsFor(model) {
417702
418682
  if (availability === "unsupported") return ["off"];
417703
418683
  return ["off", "on"];
417704
418684
  }
417705
- function fredrikSelectableModels(models) {
417706
- return Object.fromEntries(Object.entries(models).filter(([alias]) => isAllowedFredrikRuntimeAlias(alias, models)));
417707
- }
417708
- function fredrikProviderDisplayName(provider) {
417709
- if (provider === "managed:blun") return PRODUCT_NAME;
417710
- if (provider.startsWith("managed:")) return provider.slice(8);
417711
- return provider;
417712
- }
417713
- function fredrikCreateModelChoices(models) {
417714
- return Object.entries(fredrikSelectableModels(models)).map(([alias, configured]) => {
417715
- const model = effectiveModelAlias(configured);
417716
- const name = modelDisplayName$1(alias, model);
417717
- const provider = fredrikProviderDisplayName(model.provider);
417718
- return {
417719
- alias,
417720
- model,
417721
- name,
417722
- provider,
417723
- label: `${name} (${provider})`
417724
- };
417725
- });
417726
- }
417727
- function fredrikEffortLabel(effort) {
417728
- const label = effortDisplayLabel(effort);
417729
- if (label !== effort || effort.length === 0) return label;
417730
- return effort.charAt(0).toUpperCase() + effort.slice(1);
417731
- }
417732
- function fredrikDefaultThinkingEffort(model) {
417733
- if (thinkingAvailability(model) === "unsupported") return "off";
417734
- const efforts = effortsOf(model);
417735
- if (efforts.length > 0) return model.defaultEffort ?? efforts[Math.floor(efforts.length / 2)];
417736
- return "on";
417737
- }
417738
- function fredrikCommitEffort(choice, draft) {
417739
- if (draft === "on") return fredrikDefaultThinkingEffort(choice.model);
417740
- return draft;
417741
- }
417742
- var FredrikModelSelectorComponent = class extends Container {
417743
- focused = false;
417744
- opts;
417745
- list;
417746
- thinkingOverrides = /* @__PURE__ */ new Map();
417747
- ignoreSubmitTailUntil = Date.now() + 250;
417748
- constructor(opts) {
417749
- super();
417750
- this.opts = opts;
417751
- const choices = fredrikCreateModelChoices(opts.models);
417752
- const selectedIndex = choices.findIndex((choice) => choice.alias === (opts.selectedValue ?? opts.currentValue));
417753
- this.list = new SearchableList({
417754
- items: choices,
417755
- toSearchText: (choice) => choice.label,
417756
- initialIndex: Math.max(selectedIndex, 0),
417757
- searchable: opts.searchable === true
417758
- });
417759
- }
417760
- draftFor(choice) {
417761
- const override = this.thinkingOverrides.get(choice.alias);
417762
- if (override !== void 0) return override;
417763
- if (choice.alias === this.opts.currentValue) return this.opts.currentThinkingEffort;
417764
- const efforts = effortsOf(choice.model);
417765
- if (efforts.length > 0) {
417766
- const fallback = choice.model.defaultEffort ?? efforts[Math.floor(efforts.length / 2)];
417767
- if (fallback !== void 0 && efforts.includes(fallback)) return fallback;
417768
- return efforts[0];
417769
- }
417770
- return thinkingAvailability(choice.model) !== "unsupported" ? "on" : "off";
417771
- }
417772
- effectiveEffort(choice) {
417773
- const draft = this.draftFor(choice);
417774
- const segments = segmentsFor(choice.model);
417775
- return segments.includes(draft) ? draft : segments[0];
417776
- }
417777
- handleInput(data) {
417778
- if (isKeyRelease(data)) return;
417779
- if (Date.now() <= this.ignoreSubmitTailUntil && /^[\r\n]+$/.test(data)) return;
417780
- this.ignoreSubmitTailUntil = 0;
417781
- if (matchesKey(data, Key.escape)) {
417782
- if (this.list.clearQuery()) return;
417783
- this.opts.onCancel();
417784
- return;
417785
- }
417786
- if (this.list.handleKey(data)) return;
417787
- if (matchesKey(data, Key.left) || matchesKey(data, Key.right)) {
417788
- const selected = this.selectedChoice();
417789
- if (selected !== void 0) {
417790
- const segments = segmentsFor(selected.model);
417791
- if (segments.length > 1) {
417792
- const current = this.effectiveEffort(selected);
417793
- const index = segments.indexOf(current);
417794
- const delta = matchesKey(data, Key.left) ? -1 : 1;
417795
- const next = Math.max(0, Math.min(segments.length - 1, index + delta));
417796
- if (next !== index) this.thinkingOverrides.set(selected.alias, segments[next]);
417797
- }
417798
- }
417799
- return;
417800
- }
417801
- if (matchesKey(data, Key.enter)) {
417802
- const selected = this.selectedChoice();
417803
- if (selected === void 0) return;
417804
- this.opts.onSelect({
417805
- alias: selected.alias,
417806
- thinking: fredrikCommitEffort(selected, this.effectiveEffort(selected))
417807
- });
417808
- return;
417809
- }
417810
- if (matchesKey(data, Key.alt("s")) && this.opts.onSessionOnlySelect !== void 0) {
417811
- const selected = this.selectedChoice();
417812
- if (selected === void 0) return;
417813
- this.opts.onSessionOnlySelect({
417814
- alias: selected.alias,
417815
- thinking: fredrikCommitEffort(selected, this.effectiveEffort(selected))
417816
- });
417817
- }
417818
- }
417819
- render(width) {
417820
- const view = this.list.view();
417821
- const totalCount = Object.keys(fredrikSelectableModels(this.opts.models)).length;
417822
- const titleSuffix = this.opts.searchable === true && view.query.length === 0 ? currentTheme.fg("textMuted", ` (${uiText("model.typeToSearch")})`) : "";
417823
- const lines = [
417824
- currentTheme.fg("primary", "-".repeat(width)),
417825
- currentTheme.boldFg("primary", ` ${uiText("model.title")}`) + titleSuffix,
417826
- currentTheme.fg("textMuted", ` ${uiText("model.navigate")} | ${uiText("model.thinking")} (Left/Right) | Enter ${uiText("model.select")} | Esc ${uiText("model.cancel")}`),
417827
- ""
417828
- ];
417829
- if (view.query.length > 0) lines.push(currentTheme.fg("primary", ` ${uiText("model.search")}: `) + currentTheme.fg("text", view.query));
417830
- if (view.items.length === 0) lines.push(currentTheme.fg("textMuted", ` ${uiText("model.noMatches")}`));
417831
- for (let index = view.page.start; index < view.page.end; index++) {
417832
- const choice = view.items[index];
417833
- if (choice === void 0) continue;
417834
- const selected = index === view.selectedIndex;
417835
- const current = choice.alias === this.opts.currentValue;
417836
- const pointer = selected ? ">" : " ";
417837
- let line = currentTheme.fg(selected ? "primary" : "textDim", ` ${pointer} `);
417838
- line += selected ? currentTheme.boldFg("primary", choice.name) : currentTheme.fg("text", choice.name);
417839
- line += " " + currentTheme.fg("textMuted", choice.provider);
417840
- if (current) line += " " + currentTheme.fg("success", currentMark());
417841
- lines.push(line);
417842
- }
417843
- if (view.query.length > 0) lines.push("", currentTheme.fg("textMuted", ` ${String(view.items.length)} / ${String(totalCount)}`));
417844
- lines.push("");
417845
- const selected = this.selectedChoice();
417846
- if (selected !== void 0) {
417847
- lines.push(currentTheme.fg("textMuted", ` ${uiText("model.thinking")} (Left/Right ${uiText("model.toSwitch")})`));
417848
- lines.push(this.renderThinkingControl(selected));
417849
- }
417850
- lines.push("", currentTheme.fg("primary", "-".repeat(width)));
417851
- return lines.map((line) => truncateToWidth(line, width));
417852
- }
417853
- selectedChoice() {
417854
- return this.list.selected();
417855
- }
417856
- renderThinkingControl(choice) {
417857
- const segment = (label, active) => active ? currentTheme.boldFg("primary", `[ ${label} ]`) : currentTheme.fg("text", ` ${label} `);
417858
- const unavailable = (label) => currentTheme.fg("textMuted", ` ${label} (${uiText("model.unsupported")}) `);
417859
- const efforts = effortsOf(choice.model);
417860
- const availability = thinkingAvailability(choice.model);
417861
- if (efforts.length === 0 && availability === "always-on") return ` ${segment(uiText("model.on"), true)} ${unavailable(uiText("model.off"))}`;
417862
- if (efforts.length === 0 && availability === "unsupported") return ` ${unavailable(uiText("model.on"))} ${segment(uiText("model.off"), true)}`;
417863
- const active = this.effectiveEffort(choice);
417864
- return ` ${segmentsFor(choice.model).map((effort) => segment(fredrikEffortLabel(effort), effort === active)).join(" ")}`;
417865
- }
417866
- };
417867
418685
  //#endregion
417868
418686
  //#region src/tui/components/dialogs/permission-selector.ts
417869
418687
  function permissionOptions() {
@@ -421669,47 +422487,6 @@ async function handleThemeCommand(host, args) {
421669
422487
  }
421670
422488
  await applyThemeChoice(host, theme);
421671
422489
  }
421672
- function resolveFredrikModelArgument(models, raw) {
421673
- const query = raw.trim().toLowerCase();
421674
- if (query.length === 0) return void 0;
421675
- return Object.entries(models).filter(([alias]) => isAllowedFredrikRuntimeAlias(alias, models)).find(([alias, model]) => [alias, model.model, model.displayName].filter((value) => typeof value === "string").some((value) => value.toLowerCase() === query))?.[0];
421676
- }
421677
- function showFredrikModelPicker(host, selectedValue = host.state.appState.model) {
421678
- const models = fredrikSelectableModels(host.state.appState.availableModels);
421679
- host.mountEditorReplacement(new FredrikModelSelectorComponent({
421680
- models,
421681
- currentValue: host.state.appState.model,
421682
- selectedValue,
421683
- currentThinkingEffort: host.state.appState.thinkingEffort,
421684
- searchable: true,
421685
- onSelect: (selection) => {
421686
- host.restoreEditorAfter(() => performModelSwitch(host, selection.alias, selection.thinking, false));
421687
- },
421688
- onSessionOnlySelect: (selection) => {
421689
- host.restoreEditorAfter(() => performModelSwitch(host, selection.alias, selection.thinking, false));
421690
- },
421691
- onCancel: () => {
421692
- host.restoreEditor();
421693
- }
421694
- }));
421695
- }
421696
- async function handleModelCommand(host, args) {
421697
- if (host.session === void 0) {
421698
- host.showError(noActiveSessionMessage());
421699
- return;
421700
- }
421701
- const raw = args.trim();
421702
- if (raw.length === 0) {
421703
- showFredrikModelPicker(host);
421704
- return;
421705
- }
421706
- const alias = resolveFredrikModelArgument(host.state.appState.availableModels, raw);
421707
- if (alias === void 0) {
421708
- host.showError(uiText("config.model.unknownAlias", { alias: raw }));
421709
- return;
421710
- }
421711
- showFredrikModelPicker(host, alias);
421712
- }
421713
422490
  async function handleEffortCommand(host, args) {
421714
422491
  const alias = host.state.appState.model;
421715
422492
  const model = host.state.appState.availableModels[alias];
@@ -421741,7 +422518,7 @@ async function handleEffortCommand(host, args) {
421741
422518
  }));
421742
422519
  return;
421743
422520
  }
421744
- await performEffortSelection(host, alias, arg, !isConfiguredFredrikGlmAlias(alias, model));
422521
+ await performEffortSelection(host, alias, arg, true);
421745
422522
  }
421746
422523
  function showEffortPicker(host, model, segments) {
421747
422524
  const liveEffort = host.state.appState.thinkingEffort;
@@ -421752,7 +422529,7 @@ function showEffortPicker(host, model, segments) {
421752
422529
  currentValue,
421753
422530
  currentBlunSwarm: host.state.appState.swarmMode && host.state.appState.swarmModeEntry === "effort",
421754
422531
  onSelect: (effort) => {
421755
- host.restoreEditorAfter(() => performEffortSelection(host, alias, effort, !isConfiguredFredrikGlmAlias(alias, host.state.appState.availableModels[alias])));
422532
+ host.restoreEditorAfter(() => performEffortSelection(host, alias, effort, true));
421756
422533
  },
421757
422534
  onSessionOnlySelect: (effort) => {
421758
422535
  host.restoreEditorAfter(() => performEffortSelection(host, alias, effort, false));
@@ -432550,6 +433327,11 @@ function agentSwarmResultSummaryFromOutput(output) {
432550
433327
  };
432551
433328
  }
432552
433329
  function parseAgentSwarmResultStatuses(output) {
433330
+ const structured = parseStructuredSwarmDisplay(output);
433331
+ if (structured.recognized) return structured.statuses.map((entry) => ({
433332
+ ...entry,
433333
+ status: entry.status === "aborted" ? "cancelled" : entry.status
433334
+ }));
432553
433335
  const xmlStatuses = parseAgentSwarmXmlResultStatuses(output);
432554
433336
  if (xmlStatuses.length > 0) return xmlStatuses;
432555
433337
  return parseAgentSwarmLegacyResultStatuses(output);
@@ -493011,12 +493793,28 @@ registerUiCatalogFragment({
493011
493793
  en: {
493012
493794
  "thinking.label": "{name} thinking",
493013
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}",
493014
493804
  "thinking.tokens.one": "{count} Token",
493015
493805
  "thinking.tokens.other": "{count} Tokens"
493016
493806
  },
493017
493807
  de: {
493018
493808
  "thinking.label": "{name} denkt",
493019
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}",
493020
493818
  "thinking.tokens.one": "{count} Token",
493021
493819
  "thinking.tokens.other": "{count} Tokens"
493022
493820
  },
@@ -493070,6 +493868,14 @@ var ThinkingComponent = class {
493070
493868
  thinkElapsedMs = 0;
493071
493869
  thinkAborted = false;
493072
493870
  estimatedOutputTokens = 0;
493871
+ step;
493872
+ thinkingEffort;
493873
+ attempt = 1;
493874
+ maxAttempts = 1;
493875
+ completionBudget;
493876
+ lastHeartbeatAtMs;
493877
+ activeToolName;
493878
+ finishedAtMs;
493073
493879
  textComponent;
493074
493880
  renderCache;
493075
493881
  constructor(text, showMarker = true, mode = "finalized", ui, metrics) {
@@ -493084,6 +493890,7 @@ var ThinkingComponent = class {
493084
493890
  this.thinkStartMs = metrics?.startedAtMs ?? Date.now();
493085
493891
  this.thinkAborted = false;
493086
493892
  this.estimatedOutputTokens = metrics?.estimatedOutputTokens ?? 0;
493893
+ this.applyLiveMetrics(metrics ?? {});
493087
493894
  }
493088
493895
  }
493089
493896
  markRenderDirty() {
@@ -493102,10 +493909,22 @@ var ThinkingComponent = class {
493102
493909
  }
493103
493910
  setLiveMetrics(metrics) {
493104
493911
  if (this.mode === "live" && !this.thinkAborted && metrics.startedAtMs !== void 0) this.thinkStartMs = metrics.startedAtMs;
493105
- 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]);
493106
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;
493107
493917
  this.markRenderDirty();
493108
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
+ }
493109
493928
  styled(text) {
493110
493929
  return currentTheme.italicFg("textDim", text);
493111
493930
  }
@@ -493117,6 +493936,7 @@ var ThinkingComponent = class {
493117
493936
  this.thinkElapsedMs = Date.now() - this.thinkStartMs;
493118
493937
  this.thinkStartMs = null;
493119
493938
  }
493939
+ this.finishedAtMs = Date.now();
493120
493940
  }
493121
493941
  dispose() {
493122
493942
  this.stopSpinner();
@@ -493140,12 +493960,24 @@ var ThinkingComponent = class {
493140
493960
  const abortMark = this.thinkAborted ? ` (${uiText("thinking.aborted")})` : "";
493141
493961
  const tokenKey = roundedTokenCount === 1 ? "thinking.tokens.one" : "thinking.tokens.other";
493142
493962
  const thinkingLabel = uiText("thinking.label", { name: this.persona });
493143
- const fullLabel = `${thinkingLabel}… (${elapsed} · ↓ ~${uiText(tokenKey, { count: tokenCount })} · ${startedAt})${abortMark}`;
493144
- 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}`;
493145
493973
  const metricsOnly = `(${elapsed} · ${startedAt})${abortMark}`;
493146
493974
  const availableWidth = Math.max(1, width - visibleWidth(spinner));
493147
493975
  const label = visibleWidth(fullLabel) <= availableWidth ? fullLabel : visibleWidth(compactLabel) <= availableWidth ? compactLabel : metricsOnly;
493148
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)))];
493149
493981
  } else rendered = [""];
493150
493982
  if (isRenderCacheEnabled()) this.renderCache = {
493151
493983
  width,
@@ -497454,9 +498286,6 @@ async function handleBuiltInSlashCommand(host, name, args) {
497454
498286
  case "theme":
497455
498287
  await handleThemeCommand(host, args);
497456
498288
  return;
497457
- case "model":
497458
- await handleModelCommand(host, args);
497459
- return;
497460
498289
  case "effort":
497461
498290
  await handleEffortCommand(host, args);
497462
498291
  return;
@@ -499539,9 +500368,11 @@ registerUiCatalogFragment({
499539
500368
  "approval.search.scope": "scope: {scope}",
499540
500369
  "approval.backgroundTask": "{status} {kind} task {taskId}: {description}",
499541
500370
  "approval.hint.feedback": "Type feedback · ↵ submit.",
500371
+ "approval.hint.editArguments": "Enter the complete replacement JSON object · ↵ submit.",
499542
500372
  "approval.hint.main": "↑/↓ select · {numbers} choose · ↵ confirm{preview}",
499543
500373
  "approval.hint.preview": " · ctrl+e preview",
499544
500374
  "approval.choice.approveOnce": "Approve once",
500375
+ "approval.choice.editArguments": "Edit arguments (JSON)",
499545
500376
  "approval.choice.approveSession": "Approve for this session",
499546
500377
  "approval.choice.reject": "Reject",
499547
500378
  "approval.choice.rejectFeedback": "Reject with feedback",
@@ -499551,6 +500382,7 @@ registerUiCatalogFragment({
499551
500382
  "approval.transcript.approvedSession": "Approved for session",
499552
500383
  "approval.transcript.rejected": "Rejected",
499553
500384
  "approval.transcript.cancelled": "Cancelled",
500385
+ "approval.transcript.edited": "Arguments edited",
499554
500386
  "approval.transcript.action": "{decision}: {action}",
499555
500387
  "approval.transcript.actionWithFeedback": "{decision}: {action} — \"{feedback}\""
499556
500388
  },
@@ -499570,9 +500402,11 @@ registerUiCatalogFragment({
499570
500402
  "approval.search.scope": "Bereich: {scope}",
499571
500403
  "approval.backgroundTask": "Aufgabe {taskId} ({status}, {kind}): {description}",
499572
500404
  "approval.hint.feedback": "Feedback eingeben · ↵ absenden.",
500405
+ "approval.hint.editArguments": "Vollständiges Ersatz-JSON-Objekt eingeben · ↵ absenden.",
499573
500406
  "approval.hint.main": "↑/↓ auswählen · {numbers} wählen · ↵ bestätigen{preview}",
499574
500407
  "approval.hint.preview": " · ctrl+e Vorschau",
499575
500408
  "approval.choice.approveOnce": "Einmal genehmigen",
500409
+ "approval.choice.editArguments": "Argumente bearbeiten (JSON)",
499576
500410
  "approval.choice.approveSession": "Für diese Sitzung genehmigen",
499577
500411
  "approval.choice.reject": "Ablehnen",
499578
500412
  "approval.choice.rejectFeedback": "Ablehnen und Feedback geben",
@@ -499582,6 +500416,7 @@ registerUiCatalogFragment({
499582
500416
  "approval.transcript.approvedSession": "Für diese Sitzung genehmigt",
499583
500417
  "approval.transcript.rejected": "Abgelehnt",
499584
500418
  "approval.transcript.cancelled": "Abgebrochen",
500419
+ "approval.transcript.edited": "Argumente bearbeitet",
499585
500420
  "approval.transcript.action": "{decision}: {action}",
499586
500421
  "approval.transcript.actionWithFeedback": "{decision}: {action} – „{feedback}“"
499587
500422
  },
@@ -499601,9 +500436,11 @@ registerUiCatalogFragment({
499601
500436
  "approval.search.scope": "Ámbito: {scope}",
499602
500437
  "approval.backgroundTask": "Tarea {taskId} ({status}, {kind}): {description}",
499603
500438
  "approval.hint.feedback": "Escribe tus comentarios · ↵ enviar.",
500439
+ "approval.hint.editArguments": "Introduce el objeto JSON completo de sustitución · ↵ enviar.",
499604
500440
  "approval.hint.main": "↑/↓ seleccionar · {numbers} elegir · ↵ confirmar{preview}",
499605
500441
  "approval.hint.preview": " · ctrl+e vista previa",
499606
500442
  "approval.choice.approveOnce": "Aprobar una vez",
500443
+ "approval.choice.editArguments": "Editar argumentos (JSON)",
499607
500444
  "approval.choice.approveSession": "Aprobar durante esta sesión",
499608
500445
  "approval.choice.reject": "Rechazar",
499609
500446
  "approval.choice.rejectFeedback": "Rechazar y enviar comentarios",
@@ -499613,6 +500450,7 @@ registerUiCatalogFragment({
499613
500450
  "approval.transcript.approvedSession": "Aprobado durante esta sesión",
499614
500451
  "approval.transcript.rejected": "Rechazado",
499615
500452
  "approval.transcript.cancelled": "Cancelado",
500453
+ "approval.transcript.edited": "Argumentos modificados",
499616
500454
  "approval.transcript.action": "{decision}: {action}",
499617
500455
  "approval.transcript.actionWithFeedback": "{decision}: {action} — «{feedback}»"
499618
500456
  },
@@ -499632,9 +500470,11 @@ registerUiCatalogFragment({
499632
500470
  "approval.search.scope": "Portée : {scope}",
499633
500471
  "approval.backgroundTask": "Tâche {taskId} ({status}, {kind}) : {description}",
499634
500472
  "approval.hint.feedback": "Saisissez un commentaire · ↵ envoyer.",
500473
+ "approval.hint.editArguments": "Saisissez l’objet JSON de remplacement complet · ↵ envoyer.",
499635
500474
  "approval.hint.main": "↑/↓ sélectionner · {numbers} choisir · ↵ confirmer{preview}",
499636
500475
  "approval.hint.preview": " · ctrl+e aperçu",
499637
500476
  "approval.choice.approveOnce": "Approuver une fois",
500477
+ "approval.choice.editArguments": "Modifier les arguments (JSON)",
499638
500478
  "approval.choice.approveSession": "Approuver pour cette session",
499639
500479
  "approval.choice.reject": "Refuser",
499640
500480
  "approval.choice.rejectFeedback": "Refuser et ajouter un commentaire",
@@ -499644,6 +500484,7 @@ registerUiCatalogFragment({
499644
500484
  "approval.transcript.approvedSession": "Approuvé pour cette session",
499645
500485
  "approval.transcript.rejected": "Refusé",
499646
500486
  "approval.transcript.cancelled": "Annulé",
500487
+ "approval.transcript.edited": "Arguments modifiés",
499647
500488
  "approval.transcript.action": "{decision} : {action}",
499648
500489
  "approval.transcript.actionWithFeedback": "{decision} : {action} — « {feedback} »"
499649
500490
  },
@@ -499663,9 +500504,11 @@ registerUiCatalogFragment({
499663
500504
  "approval.search.scope": "Omfattning: {scope}",
499664
500505
  "approval.backgroundTask": "Uppgift {taskId} ({status}, {kind}): {description}",
499665
500506
  "approval.hint.feedback": "Skriv återkoppling · ↵ skicka.",
500507
+ "approval.hint.editArguments": "Ange hela JSON-objektet som ska ersätta det befintliga · ↵ skicka.",
499666
500508
  "approval.hint.main": "↑/↓ markera · {numbers} välj · ↵ bekräfta{preview}",
499667
500509
  "approval.hint.preview": " · ctrl+e förhandsgranska",
499668
500510
  "approval.choice.approveOnce": "Godkänn en gång",
500511
+ "approval.choice.editArguments": "Redigera argument (JSON)",
499669
500512
  "approval.choice.approveSession": "Godkänn för den här sessionen",
499670
500513
  "approval.choice.reject": "Avvisa",
499671
500514
  "approval.choice.rejectFeedback": "Avvisa och lämna återkoppling",
@@ -499675,6 +500518,7 @@ registerUiCatalogFragment({
499675
500518
  "approval.transcript.approvedSession": "Godkänt för den här sessionen",
499676
500519
  "approval.transcript.rejected": "Avvisat",
499677
500520
  "approval.transcript.cancelled": "Avbrutet",
500521
+ "approval.transcript.edited": "Argument redigerade",
499678
500522
  "approval.transcript.action": "{decision}: {action}",
499679
500523
  "approval.transcript.actionWithFeedback": "{decision}: {action} – ”{feedback}”"
499680
500524
  },
@@ -499858,7 +500702,7 @@ var ApprovalPanelComponent = class extends Container {
499858
500702
  if (!option) return;
499859
500703
  this.onResponse({
499860
500704
  response: option.response,
499861
- feedback: feedback || void 0,
500705
+ ...(option.input_kind === "edited_tool_input_json" ? { edited_tool_input_json: feedback } : { feedback: feedback || void 0 }),
499862
500706
  selected_label: option.selected_label
499863
500707
  });
499864
500708
  }
@@ -499868,6 +500712,7 @@ var ApprovalPanelComponent = class extends Container {
499868
500712
  if (option.requires_feedback === true) {
499869
500713
  this.selectedIndex = index;
499870
500714
  this.feedbackMode = true;
500715
+ if (option.input_kind === "edited_tool_input_json") this.feedbackInput.setValue(this.request.data.editable_tool_input_json ?? "{}");
499871
500716
  } else this.submit(index);
499872
500717
  }
499873
500718
  handleInput(data) {
@@ -499964,7 +500809,7 @@ var ApprovalPanelComponent = class extends Container {
499964
500809
  if (option.description !== void 0 && option.description.length > 0 && !(this.feedbackMode && option.requires_feedback === true && isSelected)) for (const descLine of wrapTextWithAnsi(option.description, Math.max(20, width - 7))) lines.push(indent(` ${dim(descLine)}`));
499965
500810
  }
499966
500811
  lines.push("");
499967
- if (this.feedbackMode) lines.push(indent(dim(uiText("approval.hint.feedback"))));
500812
+ if (this.feedbackMode) lines.push(indent(dim(uiText(this.choiceAt(this.selectedIndex)?.input_kind === "edited_tool_input_json" ? "approval.hint.editArguments" : "approval.hint.feedback"))));
499968
500813
  else {
499969
500814
  const expandHint = hasPreviewable ? uiText("approval.hint.preview") : "";
499970
500815
  lines.push(indent(dim(uiText("approval.hint.main", {
@@ -503221,12 +504066,18 @@ async function refreshAllProviderModels(host, options = {}) {
503221
504066
  }
503222
504067
  //#endregion
503223
504068
  //#region src/tui/reverse-rpc/approval/adapter.ts
503224
- function defaultApprovalChoices() {
504069
+ function defaultApprovalChoices(allowEdit = false) {
503225
504070
  return [
503226
504071
  {
503227
504072
  label: uiText("approval.choice.approveOnce"),
503228
504073
  response: "approved"
503229
504074
  },
504075
+ ...allowEdit ? [{
504076
+ label: uiText("approval.choice.editArguments"),
504077
+ response: "edited",
504078
+ requires_feedback: true,
504079
+ input_kind: "edited_tool_input_json"
504080
+ }] : [],
503230
504081
  {
503231
504082
  label: uiText("approval.choice.approveSession"),
503232
504083
  response: "approved_for_session"
@@ -503263,7 +504114,8 @@ function adaptApprovalRequest(event) {
503263
504114
  action: resolved.action ?? event.action,
503264
504115
  description: resolved.description,
503265
504116
  display: resolved.blocks,
503266
- choices: adaptChoices(event.toolName, event.display)
504117
+ choices: adaptChoices(event.toolName, event.display, event.allowEdit === true),
504118
+ editable_tool_input_json: event.allowEdit === true ? canonicalEditedToolInputJson(event.editableToolInput) : void 0
503267
504119
  };
503268
504120
  }
503269
504121
  function resolveDisplay(toolName, display, action) {
@@ -503367,6 +504219,10 @@ function inferFileOp(toolName) {
503367
504219
  return "read";
503368
504220
  }
503369
504221
  function adaptPanelResponse(response) {
504222
+ if (response.response === "edited") return {
504223
+ decision: "edited",
504224
+ edited_tool_input_json: response.edited_tool_input_json
504225
+ };
503370
504226
  if (response.response === "approved_for_session") return {
503371
504227
  decision: "approved",
503372
504228
  scope: "session",
@@ -503530,10 +504386,10 @@ function adaptDisplay(display) {
503530
504386
  default: return [];
503531
504387
  }
503532
504388
  }
503533
- function adaptChoices(toolName, display) {
504389
+ function adaptChoices(toolName, display, allowEdit = false) {
503534
504390
  if (toolName === "ExitPlanMode" || display.kind === "plan_review") return adaptPlanReviewChoices(display);
503535
504391
  if (display.kind === "goal_start") return adaptGoalStartChoices(display);
503536
- return defaultApprovalChoices();
504392
+ return defaultApprovalChoices(allowEdit);
503537
504393
  }
503538
504394
  function adaptGoalStartChoices(display) {
503539
504395
  return goalStartOptions(display.mode).map((option) => option.value === "cancel" ? {
@@ -503629,7 +504485,7 @@ function createApprovalRequestHandler(controller, onResponse, options = {}) {
503629
504485
  }).catch(() => {});
503630
504486
  }
503631
504487
  const response = await pending;
503632
- relay?.complete(response);
504488
+ relay?.complete(response.decision === "edited" ? { decision: "edited" } : response);
503633
504489
  onResponse?.(event, response);
503634
504490
  return response;
503635
504491
  } catch {
@@ -503676,10 +504532,7 @@ function applyManagedAccountContext(models, maxContextTokens) {
503676
504532
  maxContextSize: maxContextTokens
503677
504533
  } }
503678
504534
  };
503679
- return {
503680
- [BLUN_KING_MODEL_ALIAS]: king,
503681
- ...configuredFredrikGlmModels(models)
503682
- };
504535
+ return { [BLUN_KING_MODEL_ALIAS]: king };
503683
504536
  }
503684
504537
  function normalizeKingProductEffort(value) {
503685
504538
  if (value === "none" || value === "minimal" || value === "off") return "low";
@@ -503735,11 +504588,7 @@ function nextManagedQuotaWarning(windows, highestShown) {
503735
504588
  //#region src/tui/controllers/auth-flow.ts
503736
504589
  function managedProviderOnly(providers) {
503737
504590
  const managed = providers[DEFAULT_OAUTH_PROVIDER_NAME];
503738
- const fredrikGlm = configuredFredrikGlmProvider(providers);
503739
- return {
503740
- ...managed === void 0 ? {} : { [DEFAULT_OAUTH_PROVIDER_NAME]: managed },
503741
- ...fredrikGlm === void 0 ? {} : { [FREDRIK_GLM_PROVIDER_ID]: fredrikGlm }
503742
- };
504591
+ return managed === void 0 ? {} : { [DEFAULT_OAUTH_PROVIDER_NAME]: managed };
503743
504592
  }
503744
504593
  var AuthFlowController = class {
503745
504594
  host;
@@ -507718,6 +508567,9 @@ var BottomPinnedTUI = class extends TUI {
507718
508567
  * page-up/down jumps without re-reading the live (possibly stale) value.
507719
508568
  */
507720
508569
  getTerminalRows() {
508570
+ return this.getRenderHeight();
508571
+ }
508572
+ getRenderHeight() {
507721
508573
  this.ensureResizeLatch();
507722
508574
  return this.latchedTerminalRows > 0 ? this.latchedTerminalRows : currentTerminalRows(this.terminal.rows);
507723
508575
  }
@@ -509848,7 +510700,7 @@ var SessionEventHandler = class {
509848
510700
  this.host.commitQueuedSteerAtStepStart(event.turnId);
509849
510701
  this.host.commitChannelPromptAtStepStart(event.turnId);
509850
510702
  this.host.streamingUI.flushNow();
509851
- this.host.streamingUI.setStep(event.step);
510703
+ this.host.streamingUI.beginStep(event);
509852
510704
  this.host.streamingUI.resetToolUi();
509853
510705
  this.host.streamingUI.finalizeLiveTextBuffers("waiting");
509854
510706
  this.host.patchLivePane({
@@ -509922,7 +510774,8 @@ var SessionEventHandler = class {
509922
510774
  handleStepRetrying(event) {
509923
510775
  this.turnWatchdog.recordProgress();
509924
510776
  const hint = formatModelRetryProgress(event);
509925
- if (event.outputMayHaveStarted === true) {
510777
+ const completionBudgetRetry = event.completionBudgetBefore !== void 0 && event.completionBudgetAfter !== void 0;
510778
+ if (event.outputMayHaveStarted === true || completionBudgetRetry) {
509926
510779
  const { streamingUI } = this.host;
509927
510780
  streamingUI.flushNow();
509928
510781
  streamingUI.discardUnfinishedToolUi();
@@ -509932,9 +510785,14 @@ var SessionEventHandler = class {
509932
510785
  kind: "status",
509933
510786
  turnId: String(event.turnId),
509934
510787
  renderMode: "plain",
509935
- 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 })
509936
510793
  });
509937
510794
  }
510795
+ this.host.streamingUI.noteStepRetry(event);
509938
510796
  this.modelRetryHint = hint;
509939
510797
  this.host.state.footer.setTransientHint(hint);
509940
510798
  this.host.state.ui.requestRender();
@@ -509950,6 +510808,7 @@ var SessionEventHandler = class {
509950
510808
  handleThinkingDelta(event) {
509951
510809
  const { state, streamingUI } = this.host;
509952
510810
  if (event.delta.length === 0 && !streamingUI.hasThinkingDraft()) return;
510811
+ if (event.delta.trim().length === 0) streamingUI.noteThinkingHeartbeat();
509953
510812
  if (event.delta.length > 0) this.turnWatchdog.recordProgress();
509954
510813
  if (event.delta.length > 0) this.clearModelRetryHint();
509955
510814
  streamingUI.appendThinkingDelta(event.delta);
@@ -512992,6 +513851,9 @@ var StreamingUIController = class {
512992
513851
  _remoteTurnActivity = { active: false };
512993
513852
  _remoteProcessStartedAt = new Date(Date.now() - process.uptime() * 1e3).toISOString();
512994
513853
  _liveTurnStartedAtMs = void 0;
513854
+ _liveStepStartedAtMs = void 0;
513855
+ _liveThinkingHeartbeatAtMs = void 0;
513856
+ _liveStepRequest = {};
512995
513857
  _liveOutputTokens = new LiveOutputTokenCounter();
512996
513858
  _countedToolCallIds = /* @__PURE__ */ new Set();
512997
513859
  _assistantDraft = "";
@@ -513022,6 +513884,32 @@ var StreamingUIController = class {
513022
513884
  this._currentStep = step;
513023
513885
  this.publishTelegramConsoleStatus();
513024
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
+ }
513025
513913
  setRemoteTurnActivity(activity) {
513026
513914
  const previous = this._remoteTurnActivity;
513027
513915
  this._remoteTurnActivity = activity?.active === true ? activity : { active: false };
@@ -513050,14 +513938,25 @@ var StreamingUIController = class {
513050
513938
  }
513051
513939
  beginLiveTurn() {
513052
513940
  this._liveTurnStartedAtMs = Date.now();
513941
+ this._liveStepStartedAtMs = void 0;
513942
+ this._liveThinkingHeartbeatAtMs = void 0;
513943
+ this._liveStepRequest = {};
513053
513944
  this._liveOutputTokens.reset();
513054
513945
  this._countedToolCallIds.clear();
513055
513946
  this.lastFlushAt = void 0;
513056
513947
  }
513057
513948
  getLiveActivityMetrics() {
513949
+ const activeToolName = [...this._activeToolCalls.values()].at(-1)?.name ?? [...this._streamingToolCallArguments.values()].at(-1)?.name;
513058
513950
  return {
513059
- startedAtMs: this._liveTurnStartedAtMs,
513060
- 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
513061
513960
  };
513062
513961
  }
513063
513962
  recordLiveOutput(fragment) {
@@ -513098,6 +513997,9 @@ var StreamingUIController = class {
513098
513997
  }
513099
513998
  resetLiveActivity() {
513100
513999
  this._liveTurnStartedAtMs = void 0;
514000
+ this._liveStepStartedAtMs = void 0;
514001
+ this._liveThinkingHeartbeatAtMs = void 0;
514002
+ this._liveStepRequest = {};
513101
514003
  this._liveOutputTokens.reset();
513102
514004
  this._countedToolCallIds.clear();
513103
514005
  }
@@ -518668,6 +519570,10 @@ var BlunTUI = class {
518668
519570
  const sessionId = session.id;
518669
519571
  const autostartPrompt = autostart.observation === void 0 ? GOAL_CONTINUATION_PROMPT : `${GOAL_CONTINUATION_PROMPT}\n\n${autostart.observation}`;
518670
519572
  this.beginSessionRequest();
519573
+ this.setAppState({
519574
+ model: BLUN_KING_MODEL_ALIAS,
519575
+ modelFallbackAllowed: false
519576
+ });
518671
519577
  try {
518672
519578
  const result = await session.promptAccepted(autostartPrompt);
518673
519579
  if (!result.accepted && this.session?.id === sessionId) {
@@ -519704,6 +520610,10 @@ var BlunTUI = class {
519704
520610
  contextOnly: false
519705
520611
  };
519706
520612
  this.pendingChannelReplyGuard = installedGuard;
520613
+ this.setAppState({
520614
+ model: BLUN_KING_MODEL_ALIAS,
520615
+ modelFallbackAllowed: false
520616
+ });
519707
520617
  session.promptAccepted(options?.parts ?? input).then((result) => {
519708
520618
  if (result.duplicate === true) {
519709
520619
  this.traceTelegramDelivery?.({ stage: "committed", ...context.item.channelDeliveryTrace, route: "channel_command_prompt", reason: "duplicate" });
@@ -519767,6 +520677,10 @@ var BlunTUI = class {
519767
520677
  type: "text",
519768
520678
  text: focusedModelInput
519769
520679
  }, imagePart] : focusedModelInput;
520680
+ this.setAppState({
520681
+ model: BLUN_KING_MODEL_ALIAS,
520682
+ modelFallbackAllowed: false
520683
+ });
519770
520684
  session.promptAccepted(promptInput, channelPromptOrigin(channelReportSources)).then((result) => {
519771
520685
  if (result.duplicate === true) {
519772
520686
  this.traceTelegramDelivery?.({ stage: "committed", ...channelDeliveryTrace, route: "prompt", reason: "duplicate" });
@@ -519961,6 +520875,10 @@ var BlunTUI = class {
519961
520875
  return;
519962
520876
  }
519963
520877
  this.beginSessionRequest();
520878
+ this.setAppState({
520879
+ model: BLUN_KING_MODEL_ALIAS,
520880
+ modelFallbackAllowed: false
520881
+ });
519964
520882
  session.promptAccepted(TRUNCATED_REPLY_CONTINUATION_PROMPT).then((result) => {
519965
520883
  if (!result.accepted) this.failTruncatedChannelReplyRecovery(new Error("continuation prompt rejected"));
519966
520884
  }).catch((error) => {
@@ -520231,6 +521149,10 @@ var BlunTUI = class {
520231
521149
  });
520232
521150
  this.beginSessionRequest();
520233
521151
  const sdkInput = options?.parts ?? input;
521152
+ this.setAppState({
521153
+ model: BLUN_KING_MODEL_ALIAS,
521154
+ modelFallbackAllowed: false
521155
+ });
520234
521156
  session.promptAccepted(sdkInput).catch((error) => {
520235
521157
  finishPersonalMemoryRememberIntentTurn(session.id);
520236
521158
  const message = formatErrorMessage$2(error);
@@ -520345,19 +521267,18 @@ var BlunTUI = class {
520345
521267
  }
520346
521268
  }
520347
521269
  setAppState(patch) {
520348
- const managedAccountContextTokens = "managedAccountContextTokens" in patch ? patch.managedAccountContextTokens : this.state.appState.managedAccountContextTokens;
520349
- const availableModels = applyManagedAccountContext(patch.availableModels ?? this.state.appState.availableModels, isValidManagedContextTokens(managedAccountContextTokens) ? managedAccountContextTokens : void 0);
520350
- const allowedModel = (candidate) => typeof candidate === "string" && isAllowedFredrikRuntimeAlias(candidate, availableModels) ? candidate : BLUN_KING_MODEL_ALIAS;
520351
521270
  let effectivePatch = {
520352
521271
  ...patch,
520353
521272
  modelFallbackAllowed: false,
520354
- ..."model" in patch && patch.model?.trim().length ? { model: allowedModel(patch.model) } : {},
520355
- ..."activeResponderModel" in patch && patch.activeResponderModel != null ? { activeResponderModel: allowedModel(patch.activeResponderModel) } : {}
521273
+ ..."model" in patch && patch.model?.trim().length ? { model: BLUN_KING_MODEL_ALIAS } : {},
521274
+ ..."activeResponderModel" in patch && patch.activeResponderModel != null ? { activeResponderModel: BLUN_KING_MODEL_ALIAS } : {}
520356
521275
  };
520357
521276
  if ("availableModels" in patch || "managedAccountContextTokens" in patch) {
520358
- if (availableModels !== patch.availableModels) effectivePatch = {
521277
+ const managedAccountContextTokens = "managedAccountContextTokens" in patch ? patch.managedAccountContextTokens : this.state.appState.managedAccountContextTokens;
521278
+ const effectiveModels = applyManagedAccountContext(patch.availableModels ?? this.state.appState.availableModels, isValidManagedContextTokens(managedAccountContextTokens) ? managedAccountContextTokens : void 0);
521279
+ if (effectiveModels !== patch.availableModels) effectivePatch = {
520359
521280
  ...effectivePatch,
520360
- availableModels
521281
+ availableModels: effectiveModels
520361
521282
  };
520362
521283
  }
520363
521284
  if (!hasPatchChanges(this.state.appState, effectivePatch)) return;
@@ -520434,11 +521355,7 @@ var BlunTUI = class {
520434
521355
  return this.harness.createSession(options);
520435
521356
  }
520436
521357
  async setSession(session, options = {}) {
520437
- const resumedStatus = await session.getStatus();
520438
- if (!isAllowedFredrikRuntimeAlias(resumedStatus.model ?? BLUN_KING_MODEL_ALIAS, this.state.appState.availableModels)) {
520439
- await session.setModel(BLUN_KING_MODEL_ALIAS, { allowFallback: false });
520440
- this.showStatus(uiText("config.model.unknownAlias", { alias: resumedStatus.model ?? "" }), "warning");
520441
- }
521358
+ await session.setModel(BLUN_KING_MODEL_ALIAS, { allowFallback: false });
520442
521359
  await this.personalMemoryController.clear(this.session);
520443
521360
  const previous = this.unloadCurrentSession(approvalCancellationFeedback("switching_session"));
520444
521361
  await this.managedQuotaWarningPersistence;
@@ -520446,7 +521363,10 @@ var BlunTUI = class {
520446
521363
  resetChannelPreambleState(this.channelPreamble);
520447
521364
  this.session = session;
520448
521365
  this.managedQuotaWarningController.restore(session.id, managedQuotaWarningThresholdFromMetadata(session.getResumeState()?.sessionMetadata?.custom));
520449
- this.setAppState({ modelFallbackAllowed: false });
521366
+ this.setAppState({
521367
+ model: BLUN_KING_MODEL_ALIAS,
521368
+ modelFallbackAllowed: false
521369
+ });
520450
521370
  this.harness.setTelemetryContext({ sessionId: session.id });
520451
521371
  this.registerSessionHandlers(session);
520452
521372
  this.syncAdditionalDirs(session);
@@ -520458,7 +521378,7 @@ var BlunTUI = class {
520458
521378
  const [status, goalResult, loopResult] = await Promise.all([session.getStatus(), session.getGoal(), session.getLoop()]);
520459
521379
  this.setAppState({
520460
521380
  sessionId: session.id,
520461
- model: status.model ?? BLUN_KING_MODEL_ALIAS,
521381
+ model: BLUN_KING_MODEL_ALIAS,
520462
521382
  modelFallbackAllowed: false,
520463
521383
  activeResponderModel: null,
520464
521384
  thinkingEffort: status.thinkingEffort,
@@ -520678,6 +521598,7 @@ var BlunTUI = class {
520678
521598
  this.approvalController.cancelAll(approvalCancellationFeedback("reloading_session"));
520679
521599
  this.questionController.cancelAll("");
520680
521600
  this.resetSessionRuntime();
521601
+ await session.setModel(BLUN_KING_MODEL_ALIAS, { allowFallback: false });
520681
521602
  this.session = session;
520682
521603
  this.harness.setTelemetryContext({ sessionId: session.id });
520683
521604
  this.registerSessionHandlers(session);
@@ -520815,6 +521736,9 @@ var BlunTUI = class {
520815
521736
  case "cancelled":
520816
521737
  decision = uiText("approval.transcript.cancelled");
520817
521738
  break;
521739
+ case "edited":
521740
+ decision = uiText("approval.transcript.edited");
521741
+ break;
520818
521742
  }
520819
521743
  const content = response.feedback !== void 0 && response.feedback.length > 0 ? uiText("approval.transcript.actionWithFeedback", {
520820
521744
  decision,