blun-king-cli 9.1.527 → 9.1.550

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 (108) hide show
  1. package/LIESMICH.txt +13 -834
  2. package/README.md +41 -799
  3. package/bin/agent-resume-snapshot.cjs +31 -0
  4. package/bin/assistant-message-offload-policy.cjs +23 -2
  5. package/bin/codebase-search-runtime.cjs +23 -0
  6. package/bin/context-performance-policy.cjs +2 -5
  7. package/bin/context-pressure-policy.cjs +20 -0
  8. package/bin/cron-run-output.cjs +45 -0
  9. package/bin/cron-run-store.cjs +145 -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/empty-response-retry-policy.cjs +29 -0
  16. package/bin/history-offload-pressure-policy.cjs +33 -0
  17. package/bin/html-to-research-markdown.cjs +146 -0
  18. package/bin/programmatic-context-isolation.cjs +25 -0
  19. package/bin/programmatic-tool-runtime.mjs +627 -0
  20. package/bin/read-continuation-policy.cjs +36 -5
  21. package/bin/scoped-cron-run-policy.cjs +358 -0
  22. package/bin/skill-activation-performance-policy.cjs +9 -0
  23. package/bin/startup-preferences.cjs +3 -3
  24. package/bin/structured-agent-swarm-output.cjs +325 -0
  25. package/bin/structured-subagent-output.cjs +252 -0
  26. package/bin/subagent-context-fork-policy.cjs +155 -0
  27. package/bin/subagent-skill-policy.cjs +204 -0
  28. package/bin/telegram-approval-relay.cjs +2 -1
  29. package/bin/telegram-direct-focus-policy.cjs +25 -1
  30. package/bin/todo-list-turn-policy.cjs +111 -1
  31. package/bin/tool-result-offload-policy.cjs +43 -1
  32. package/bin/turn-thinking-policy.cjs +6 -15
  33. package/bin/turn-tool-performance-policy.cjs +5 -4
  34. package/bin/update-notice.js +14 -18
  35. package/bin/user-message-offload-policy.cjs +12 -1
  36. package/blun.mjs +1406 -265
  37. package/codebase-index/README.md +82 -0
  38. package/codebase-index/codebase_index.py +469 -0
  39. package/package.json +24 -38
  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 -260
  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/package-regression-policy.cjs +0 -77
  85. package/release-planned-removals.json +0 -15
  86. package/scripts/check-active-profile-plugin-startup.js +0 -36
  87. package/scripts/check-approval-observability-regression.js +0 -111
  88. package/scripts/check-approval-queue-shortcuts-regression.js +0 -65
  89. package/scripts/check-bundled-agent-spine-regression.js +0 -48
  90. package/scripts/check-copy-command-regression.js +0 -74
  91. package/scripts/check-historical-tool-result-preview-regression.js +0 -77
  92. package/scripts/check-mcp-startup-wait-budget.js +0 -48
  93. package/scripts/check-package-regression.js +0 -38
  94. package/scripts/check-plugin-startup-regression.js +0 -53
  95. package/scripts/check-queue-controls-regression.js +0 -189
  96. package/scripts/check-release-metadata.js +0 -103
  97. package/scripts/check-reload-agent-spine-regression.js +0 -76
  98. package/scripts/check-resume-replay-regression.js +0 -100
  99. package/scripts/check-session-cancel-regression.js +0 -43
  100. package/scripts/check-session-picker-resume-metrics-regression.js +0 -97
  101. package/scripts/check-session-start-hook-context-regression.js +0 -228
  102. package/scripts/check-shell-terminal-isolation-regression.js +0 -81
  103. package/scripts/check-slash-escape-regression.js +0 -89
  104. package/scripts/check-telegram-bridge-watchdog.js +0 -60
  105. package/scripts/check-telegram-loop-exactly-once-regression.js +0 -71
  106. package/scripts/check-todo-loop-regression.js +0 -78
  107. package/scripts/check-todo-recovery-catalog-regression.js +0 -50
  108. /package/{scripts → bin}/fix-node-pty-perms.js +0 -0
package/blun.mjs CHANGED
@@ -5,6 +5,7 @@ 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,6 +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";
20
+ import editableToolApprovalPolicy from "./bin/editable-tool-approval-policy.cjs";
21
+ import editableToolApprovalRuntime from "./bin/editable-tool-approval-runtime.cjs";
19
22
  import crypto$1, { createHash, randomBytes, randomInt, randomUUID, timingSafeEqual } from "node:crypto";
20
23
  import * as fs$16 from "node:fs";
21
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";
@@ -56,6 +59,14 @@ const { SessionScrollbackArchive, sessionScrollbackArchiveDirectory } = sessionS
56
59
  const { replayWindowStartIndex, resolveReplayActiveTurnCount } = sessionReplayWindowPolicy;
57
60
  const { globPatternError } = globPatternPolicy;
58
61
  const { unsupportedUserHomePathError } = userHomePathPolicy;
62
+ const {
63
+ buildApprovalEditedEvent,
64
+ canonicalEditedToolInputJson,
65
+ isEditableToolApprovalEligible,
66
+ parseEditedToolInputJson,
67
+ validateEditedApprovalDecision
68
+ } = editableToolApprovalPolicy;
69
+ const { buildEditedToolCallPlan } = editableToolApprovalRuntime;
59
70
  import { EventEmitter as EventEmitter$1 } from "node:events";
60
71
  import { StringDecoder } from "node:string_decoder";
61
72
  import co from "node:assert";
@@ -14662,7 +14673,7 @@ async function refreshProviderModels(host, options = {}) {
14662
14673
  var BLUN_LOCAL_PROVIDER_NAME;
14663
14674
  var init_refreshProviderModels = __esmMin((() => {
14664
14675
  init_managed_blun();
14665
- BLUN_LOCAL_PROVIDER_NAME = "king-blun";
14676
+ BLUN_LOCAL_PROVIDER_NAME = "blun";
14666
14677
  }));
14667
14678
  //#endregion
14668
14679
  //#region ../../packages/oauth/src/index.ts
@@ -21380,7 +21391,10 @@ var init_flags = __esmMin((() => {
21380
21391
  var RawSubagentProfileSchema, RawAgentProfileSchema;
21381
21392
  var init_types$13 = __esmMin((() => {
21382
21393
  init_zod$1();
21383
- RawSubagentProfileSchema = object({ description: string().optional() });
21394
+ RawSubagentProfileSchema = object({
21395
+ description: string().optional(),
21396
+ skills: array(string()).optional()
21397
+ });
21384
21398
  RawAgentProfileSchema = object({
21385
21399
  extends: string().optional(),
21386
21400
  name: string().min(1),
@@ -28474,10 +28488,13 @@ function linkResolvedSubagents(mergedProfiles, resolvedProfiles) {
28474
28488
  for (const [ownerName, owner] of mergedProfiles) {
28475
28489
  if (owner.subagents === void 0) continue;
28476
28490
  const subagents = {};
28477
- for (const subagentName of Object.keys(owner.subagents)) {
28491
+ for (const [subagentName, subagentBinding] of Object.entries(owner.subagents)) {
28478
28492
  const target = resolvedProfiles.get(subagentName);
28479
28493
  if (target === void 0) throwMissingSubagent(ownerName, subagentName);
28480
- subagents[subagentName] = target;
28494
+ subagents[subagentName] = subagentBinding.skills === void 0 ? target : {
28495
+ ...target,
28496
+ subagentSkills: [...subagentBinding.skills]
28497
+ };
28481
28498
  }
28482
28499
  const resolved = resolvedProfiles.get(ownerName);
28483
28500
  if (resolved !== void 0) resolved.subagents = subagents;
@@ -28543,9 +28560,12 @@ var init_load = __esmMin((() => {
28543
28560
  //#region ../../packages/agent-core/src/profile/default/agent.yaml?raw
28544
28561
  var agent_default$1;
28545
28562
  var init_agent$3 = __esmMin((() => {
28546
- 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");
28547
28565
  agent_default$1 = agent_default$1.replace(" - Read\n", " - Read\n - ReadBatch\n");
28548
28566
  agent_default$1 = agent_default$1.replace(" - TodoList\n", " - TodoList\n - CompactConversation\n");
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");
28549
28569
  }));
28550
28570
  //#endregion
28551
28571
  //#region ../../packages/agent-core/src/profile/default/coder.yaml?raw
@@ -28553,6 +28573,7 @@ var coder_default;
28553
28573
  var init_coder = __esmMin((() => {
28554
28574
  coder_default = "extends: agent\nname: coder\npromptVars:\n roleAdditional: |\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\n\n Your final message is the entire handoff — the parent sees nothing else from your run. Make it technically complete: what you changed and why, the path of every file you touched, how you verified the change (tests or commands run, with results), and anything left undone or worth follow-up. A final message of only a sentence or two is treated as too brief and sent back to you for expansion, costing an extra turn.\nwhenToUse: |\n Use this agent for non-trivial software engineering work that may require reading files, editing code, running commands, and returning a compact but technically complete summary to the parent agent.\ntools:\n - Bash\n - Read\n - ReadMediaFile\n - Glob\n - Grep\n - Write\n - Edit\n - MistakeRecord\n - WebSearch\n - FetchURL\n - mcp__*\n";
28555
28575
  coder_default = coder_default.replace(" - Read\n", " - Read\n - ReadBatch\n");
28576
+ coder_default = coder_default.replace(" - ReadBatch\n", " - ReadBatch\n - ProgrammaticTool\n");
28556
28577
  }));
28557
28578
  //#endregion
28558
28579
  //#region ../../packages/agent-core/src/profile/default/explore.yaml?raw
@@ -28560,6 +28581,14 @@ var explore_default;
28560
28581
  var init_explore = __esmMin((() => {
28561
28582
  explore_default = "extends: agent\nname: explore\npromptVars:\n roleAdditional: |\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\n\n You are a codebase exploration specialist. Your role is EXCLUSIVELY to search, read, and analyze existing code and resources. You do NOT have access to project file editing tools. MistakeRecord is the sole write-capable exception: it may record a concrete refutation in shared BLUN learning memory, never modify project files.\n\n Your strengths:\n - Rapidly finding files using glob patterns\n - Searching code and text with powerful regex patterns\n - Reading and analyzing file contents\n - Running read-only shell commands (git log, git diff, ls, find, etc.)\n\n Guidelines:\n - Use Glob for broad file pattern matching. Prefer patterns with a literal anchor (extension or subdirectory); pure wildcards like `*` or `**/*` are allowed but usually truncate at the match cap.\n - Use Grep for searching file contents with regex\n - Use Read when you know the specific file path\n - Use Bash ONLY for read-only operations (ls, git status, git log, git diff, find)\n - NEVER use Bash for any file creation or modification commands\n - Use WebSearch or FetchURL when a question needs external context (library documentation, error messages, upstream APIs); the local codebase remains your primary domain\n - Adapt your search depth based on the thoroughness level specified by the caller\n - Wherever possible, spawn multiple parallel tool calls for grepping and reading files to maximize speed\n\n If the prompt includes a <git-context> block, use it to orient yourself about the repository state before starting your investigation.\n\n You are meant to be a fast agent. Complete the search request efficiently and report your findings clearly in a structured format.\nwhenToUse: |\n Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (e.g. \"src/**/*.yaml\"), search code for keywords (e.g. \"database connection\"), or answer questions about the codebase (e.g. \"how does the auth module work?\"). When calling this agent, specify the desired thoroughness level: \"quick\" for basic searches, \"medium\" for moderate exploration, or \"thorough\" for comprehensive analysis across multiple locations and naming conventions. Use this agent for any read-only exploration that will clearly require more than 3 search queries. Prefer launching multiple explore agents concurrently when investigating independent questions.\ntools:\n - Bash\n - Read\n - ReadMediaFile\n - Glob\n - Grep\n - MistakeRecord\n - WebSearch\n - FetchURL\n";
28562
28583
  explore_default = explore_default.replace(" - Read\n", " - Read\n - ReadBatch\n");
28584
+ explore_default = explore_default.replace(" - ReadBatch\n", " - ReadBatch\n - ProgrammaticTool\n");
28585
+ }));
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.");
28563
28592
  }));
28564
28593
  //#endregion
28565
28594
  //#region ../../packages/agent-core/src/profile/default/init.md?raw
@@ -28573,6 +28602,7 @@ var plan_default;
28573
28602
  var init_plan$1 = __esmMin((() => {
28574
28603
  plan_default = "extends: agent\nname: plan\npromptVars:\n roleAdditional: |\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\n\n Before designing your implementation plan, consider whether you fully understand the codebase areas relevant to the task. If not, recommend the parent agent to use the explore agent (subagent_type=\"explore\") to investigate key questions first. In your response, clearly state:\n 1. What you already know from the information provided\n 2. What questions remain unanswered that would benefit from explore agent investigation\n 3. Your implementation plan (either preliminary if questions remain, or final if sufficient context exists)\n\n You are a read-only planning agent: you can read and search files (Read, Glob, Grep, ReadMediaFile) and consult the web (WebSearch, FetchURL), but you have no shell and no project file-editing tools. MistakeRecord is the sole write-capable exception: it may record a concrete refutation in shared BLUN learning memory, never modify project files. Where the general instructions tell you to make changes with tools, that does not apply to you — do not attempt to run commands or modify project files. Your deliverable is the plan itself, returned as your final message.\nwhenToUse: |\n Use this agent when the parent agent needs a step-by-step implementation plan, key file identification, and architectural trade-off analysis before code changes are made.\ntools:\n - Read\n - ReadMediaFile\n - Glob\n - Grep\n - MistakeRecord\n - WebSearch\n - FetchURL\n";
28575
28604
  plan_default = plan_default.replace(" - Read\n", " - Read\n - ReadBatch\n");
28605
+ plan_default = plan_default.replace(" - ReadBatch\n", " - ReadBatch\n - ProgrammaticTool\n");
28576
28606
  }));
28577
28607
  //#endregion
28578
28608
  //#region ../../packages/agent-core/src/profile/default/system.md?raw
@@ -28591,6 +28621,7 @@ var init_default$1 = __esmMin((() => {
28591
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:");
28592
28622
  init_explore();
28593
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();
28594
28625
  init_init();
28595
28626
  init_plan$1();
28596
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:");
@@ -28601,6 +28632,7 @@ var init_default$1 = __esmMin((() => {
28601
28632
  "profile/default/agent.yaml": agent_default$1,
28602
28633
  "profile/default/coder.yaml": coder_default,
28603
28634
  "profile/default/explore.yaml": explore_default,
28635
+ "profile/default/research.yaml": research_default,
28604
28636
  "profile/default/plan.yaml": plan_default,
28605
28637
  "profile/default/system.md": system_default
28606
28638
  };
@@ -28609,6 +28641,7 @@ var init_default$1 = __esmMin((() => {
28609
28641
  "agent.yaml",
28610
28642
  "coder.yaml",
28611
28643
  "explore.yaml",
28644
+ "research.yaml",
28612
28645
  "plan.yaml"
28613
28646
  ].map((file) => `profile/default/${file}`), PROFILE_SOURCES);
28614
28647
  }));
@@ -29102,6 +29135,10 @@ var init_agent_task = __esmMin((() => {
29102
29135
  continuationTimeoutMs;
29103
29136
  runInBackground;
29104
29137
  parentToolCallId;
29138
+ responseFormat;
29139
+ resumed;
29140
+ replacesTaskId;
29141
+ resumeRootTaskId;
29105
29142
  kind = "agent";
29106
29143
  idPrefix = "agent";
29107
29144
  agentId;
@@ -29114,6 +29151,10 @@ var init_agent_task = __esmMin((() => {
29114
29151
  this.continuationTimeoutMs = options.timeoutMs;
29115
29152
  this.runInBackground = options.runInBackground;
29116
29153
  this.parentToolCallId = options.parentToolCallId;
29154
+ this.responseFormat = options.responseFormat;
29155
+ this.resumed = options.resumed;
29156
+ this.replacesTaskId = options.replacesTaskId;
29157
+ this.resumeRootTaskId = options.resumeRootTaskId;
29117
29158
  this.agentId = handle.agentId;
29118
29159
  this.subagentType = handle.profileName;
29119
29160
  }
@@ -29133,6 +29174,7 @@ var init_agent_task = __esmMin((() => {
29133
29174
  prompt: continuation.kind === "transient_provider" ? "Continue from the preserved context after a transient provider interruption. Do not repeat completed work; inspect the preserved wire and continue from the last durable boundary." : "Continue from the preserved context after the wall-clock interval.",
29134
29175
  description: this.description,
29135
29176
  runInBackground: this.runInBackground,
29177
+ responseFormat: this.responseFormat,
29136
29178
  signal: this.abortController.signal
29137
29179
  });
29138
29180
  return this.handle;
@@ -29165,7 +29207,10 @@ var init_agent_task = __esmMin((() => {
29165
29207
  timeoutMs: this.continuationTimeoutMs,
29166
29208
  kind: "agent",
29167
29209
  agentId: this.agentId,
29168
- subagentType: this.subagentType
29210
+ subagentType: this.subagentType,
29211
+ resumed: this.resumed,
29212
+ replacesTaskId: this.replacesTaskId,
29213
+ resumeRootTaskId: this.resumeRootTaskId
29169
29214
  };
29170
29215
  }
29171
29216
  };
@@ -29438,6 +29483,11 @@ function buildBackgroundTaskNotificationBody(info) {
29438
29483
  if (info.status === "completed") return baseLine;
29439
29484
  const agentId = info.agentId;
29440
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")}`;
29441
29491
  return `${baseLine}${[
29442
29492
  "",
29443
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.").`,
@@ -29446,7 +29496,7 @@ function buildBackgroundTaskNotificationBody(info) {
29446
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."
29447
29497
  ].join("\n")}`;
29448
29498
  }
29449
- 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;
29450
29500
  var init_background = __esmMin((() => {
29451
29501
  init_dist$4();
29452
29502
  init_errors$4();
@@ -29462,13 +29512,17 @@ var init_background = __esmMin((() => {
29462
29512
  NOTIFICATION_FALLBACK_PREVIEW_BYTES = 3e3;
29463
29513
  ({ MAX_FOREGROUND_CAPTURE_BYTES, captureForegroundOutputChunk } = createRequire(import.meta.url)("./bin/foreground-output-capture-policy.cjs"));
29464
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"));
29465
29517
  SIGTERM_GRACE_MS$1 = 5e3;
29466
29518
  USER_INTERRUPT_REASON$1 = "Interrupted by user";
29467
29519
  _ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz";
29468
29520
  BackgroundManager = class {
29469
29521
  agent;
29470
29522
  persistence;
29523
+ resumeStore;
29471
29524
  tasks = /* @__PURE__ */ new Map();
29525
+ reservedTaskIds = /* @__PURE__ */ new Set();
29472
29526
  /**
29473
29527
  * Ghosts: tasks loaded from disk during reconcile that have no live
29474
29528
  * KaosProcess. They appear in `list()` / `getTask()` with status
@@ -29480,6 +29534,7 @@ var init_background = __esmMin((() => {
29480
29534
  constructor(agent, persistence) {
29481
29535
  this.agent = agent;
29482
29536
  this.persistence = persistence;
29537
+ this.resumeStore = persistence?.sessionDir ? new DurableTaskResumeStore$1(persistence.sessionDir) : void 0;
29483
29538
  }
29484
29539
  fireTerminalEffects(entry) {
29485
29540
  if (!this.isDetached(entry)) return;
@@ -29523,6 +29578,13 @@ var init_background = __esmMin((() => {
29523
29578
  isDetached(entry) {
29524
29579
  return entry.foregroundRelease === void 0;
29525
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
+ }
29526
29588
  registerTask(task, options = {}) {
29527
29589
  const detached = options.detached ?? true;
29528
29590
  const entryOptions = {
@@ -29532,7 +29594,10 @@ var init_background = __esmMin((() => {
29532
29594
  signal: detached ? void 0 : options.signal
29533
29595
  };
29534
29596
  this.assertCanRegister(detached);
29535
- 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);
29536
29601
  const entry = {
29537
29602
  taskId,
29538
29603
  task,
@@ -29566,8 +29631,8 @@ var init_background = __esmMin((() => {
29566
29631
  /** Get info about a specific task. Falls back to reconcile ghosts. */
29567
29632
  getTask(taskId) {
29568
29633
  const entry = this.tasks.get(taskId);
29569
- if (entry !== void 0) return this.toInfo(entry);
29570
- 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));
29571
29636
  }
29572
29637
  updateAgentTask(taskId, message) {
29573
29638
  const entry = this.tasks.get(taskId);
@@ -29590,12 +29655,13 @@ var init_background = __esmMin((() => {
29590
29655
  list(activeOnly = true, limit) {
29591
29656
  const result = [];
29592
29657
  for (const entry of this.tasks.values()) {
29593
- const info = this.toInfo(entry);
29658
+ const info = decorateTaskInfo$1(this.toInfo(entry), this.resumeStore?.getBySourceTaskId(entry.taskId));
29594
29659
  if (!this.shouldListTask(info, activeOnly)) continue;
29595
29660
  result.push(info);
29596
29661
  if (limit !== void 0 && result.length >= limit) return result;
29597
29662
  }
29598
- 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));
29599
29665
  if (!this.shouldListTask(ghost, activeOnly)) continue;
29600
29666
  result.push(ghost);
29601
29667
  if (limit !== void 0 && result.length >= limit) return result;
@@ -29743,6 +29809,7 @@ var init_background = __esmMin((() => {
29743
29809
  async loadFromDisk() {
29744
29810
  const persistence = this.persistence;
29745
29811
  if (persistence === void 0) return;
29812
+ await this.resumeStore?.load();
29746
29813
  this.ghosts.clear();
29747
29814
  const persisted = await persistence.listTasks();
29748
29815
  for (const t of persisted) {
@@ -29788,6 +29855,11 @@ var init_background = __esmMin((() => {
29788
29855
  entry.persistWriteQueue = entry.persistWriteQueue.then(() => persistence.writeTask(info)).catch(() => {});
29789
29856
  return entry.persistWriteQueue;
29790
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
+ }
29791
29863
  appendOutput(entry, chunk) {
29792
29864
  const capture = this.isDetached(entry) ? {
29793
29865
  capturedText: chunk,
@@ -30334,6 +30406,7 @@ var init_completion_budget = __esmMin((() => {
30334
30406
  }));
30335
30407
  //#endregion
30336
30408
  //#region ../../packages/agent-core/src/loop/retry.ts
30409
+ var { nextThinkingEffortForExhaustedEmpty } = createRequire(import.meta.url)("./bin/empty-response-retry-policy.cjs");
30337
30410
  async function chatWithRetry(input) {
30338
30411
  const maxAttempts = input.maxAttempts ?? 3;
30339
30412
  if (input.llm.isRetryableError === void 0 || maxAttempts <= 1) {
@@ -30347,9 +30420,10 @@ async function chatWithRetry(input) {
30347
30420
  }
30348
30421
  const delays = retryBackoffDelays(maxAttempts);
30349
30422
  let completionBudgetRetry;
30423
+ let thinkingEffortRetry;
30350
30424
  let emptyRetryKind;
30351
30425
  for (let attempt = 1;; attempt += 1) try {
30352
- return await input.llm.chat(paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry));
30426
+ return await input.llm.chat(paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry, thinkingEffortRetry));
30353
30427
  } catch (error) {
30354
30428
  if (error instanceof APIEmptyResponseError && (emptyRetryKind !== void 0 || error.emptyResponseKind === "length" || error.emptyResponseKind === "stop")) {
30355
30429
  logEmptyResponse(input, error, attempt);
@@ -30359,6 +30433,12 @@ async function chatWithRetry(input) {
30359
30433
  throw terminal;
30360
30434
  }
30361
30435
  completionBudgetRetry = completionBudgetRetryForEmpty(error);
30436
+ thinkingEffortRetry = nextThinkingEffortForExhaustedEmpty({
30437
+ emptyResponseKind: error.emptyResponseKind,
30438
+ maxCompletionTokens: error.maxCompletionTokens,
30439
+ completionTokens: error.completionTokens,
30440
+ thinkingEffort: input.llm.thinkingEffort
30441
+ });
30362
30442
  emptyRetryKind = error.emptyResponseKind;
30363
30443
  input.params.signal.throwIfAborted();
30364
30444
  input.dispatchEvent({
@@ -30415,11 +30495,12 @@ function logRequestFailure(input, error, attempt, maxAttempts) {
30415
30495
  ...retryErrorFields(error)
30416
30496
  });
30417
30497
  }
30418
- function paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry) {
30498
+ function paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry, thinkingEffortRetry) {
30419
30499
  const turnStep = `${input.turnId}.${String(input.currentStep)}`;
30420
30500
  return {
30421
30501
  ...input.params,
30422
30502
  completionBudgetRetry,
30503
+ thinkingEffortRetry,
30423
30504
  requestLogFields: attempt === 1 ? { turnStep } : {
30424
30505
  turnStep,
30425
30506
  attempt: `${String(attempt)}/${String(maxAttempts)}`
@@ -30427,12 +30508,19 @@ function paramsForAttempt(input, attempt, maxAttempts, completionBudgetRetry) {
30427
30508
  };
30428
30509
  }
30429
30510
  function logEmptyResponse(input, error, attempt) {
30511
+ const retryThinkingEffort = nextThinkingEffortForExhaustedEmpty({
30512
+ emptyResponseKind: error.emptyResponseKind,
30513
+ maxCompletionTokens: error.maxCompletionTokens,
30514
+ completionTokens: error.completionTokens,
30515
+ thinkingEffort: input.llm.thinkingEffort
30516
+ });
30430
30517
  input.log?.warn(`[leer] fall=${error.emptyResponseKind}`, {
30431
30518
  turnStep: `${input.turnId}.${String(input.currentStep)}`,
30432
30519
  attempt,
30433
30520
  budget: error.maxCompletionTokens,
30434
30521
  completion: error.completionTokens,
30435
- reasoningLength: error.reasoningLength
30522
+ reasoningLength: error.reasoningLength,
30523
+ ...retryThinkingEffort === void 0 ? {} : { retryThinkingEffort }
30436
30524
  });
30437
30525
  }
30438
30526
  function retryBackoffDelays(maxAttempts) {
@@ -30599,6 +30687,101 @@ var init_todo_list = __esmMin((() => {
30599
30687
  };
30600
30688
  }));
30601
30689
  //#endregion
30690
+ //#region ../../packages/agent-core/src/tools/builtin/state/programmatic-tool.ts
30691
+ var PROGRAMMATIC_TOOL_NAME, ProgrammaticTool;
30692
+ var init_programmatic_tool = __esmMin((() => {
30693
+ PROGRAMMATIC_TOOL_NAME = "ProgrammaticTool";
30694
+ ProgrammaticTool = class {
30695
+ name = PROGRAMMATIC_TOOL_NAME;
30696
+ 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.";
30697
+ parameters = {
30698
+ type: "object",
30699
+ properties: {
30700
+ code: {
30701
+ type: "string",
30702
+ maxLength: 32e3,
30703
+ description: "JavaScript function body. Use state for explicit JSON state and tools.<alias>(args) for declared sequential tool calls."
30704
+ },
30705
+ state: {
30706
+ type: "object",
30707
+ description: "Optional JSON-only state snapshot from a previous run."
30708
+ },
30709
+ tools: {
30710
+ type: "array",
30711
+ maxItems: 16,
30712
+ description: "Explicit allowlist for this program. Each name must be a tool available in the current turn.",
30713
+ items: {
30714
+ type: "object",
30715
+ properties: {
30716
+ name: {
30717
+ type: "string",
30718
+ minLength: 1,
30719
+ description: "Exact current BLUN tool name."
30720
+ },
30721
+ alias: {
30722
+ type: "string",
30723
+ pattern: "^[A-Za-z_$][A-Za-z0-9_$]*$",
30724
+ description: "JavaScript identifier exposed under tools."
30725
+ }
30726
+ },
30727
+ required: ["name", "alias"],
30728
+ additionalProperties: false
30729
+ }
30730
+ }
30731
+ },
30732
+ required: ["code"],
30733
+ additionalProperties: false
30734
+ };
30735
+ resolveExecution(args) {
30736
+ const declaredTools = Array.isArray(args.tools) ? args.tools : [];
30737
+ return {
30738
+ description: `Running bounded programmatic tool plan (${declaredTools.length} allowed tool${declaredTools.length === 1 ? "" : "s"})`,
30739
+ approvalRule: this.name,
30740
+ execute: async (context) => {
30741
+ if (typeof context.invokeTool !== "function") return {
30742
+ output: "Programmatic tool invocation boundary is unavailable.",
30743
+ isError: true
30744
+ };
30745
+ try {
30746
+ const { createProgrammaticToolRuntime } = await import(new URL("./bin/programmatic-tool-runtime.mjs", import.meta.url).href);
30747
+ const runtime = createProgrammaticToolRuntime({
30748
+ allowedTools: declaredTools,
30749
+ invokeTool: context.invokeTool,
30750
+ onEvent: (event) => context.onUpdate({
30751
+ kind: "programmatic_tool",
30752
+ event
30753
+ })
30754
+ });
30755
+ const outcome = await runtime.run({
30756
+ code: args.code,
30757
+ state: args.state ?? {},
30758
+ signal: context.signal
30759
+ });
30760
+ const result = {
30761
+ output: JSON.stringify(outcome),
30762
+ isError: false
30763
+ };
30764
+ if (context.invokeTool.stopTurn === true) result.stopTurn = true;
30765
+ return result;
30766
+ } catch (error) {
30767
+ const message = error instanceof Error ? error.message : String(error);
30768
+ const programmaticConsole = error && typeof error === "object" ? error.programmaticConsole : void 0;
30769
+ const result = {
30770
+ output: programmaticConsole ? JSON.stringify({
30771
+ error: message,
30772
+ console: programmaticConsole
30773
+ }) : message,
30774
+ isError: true
30775
+ };
30776
+ if (context.invokeTool.stopTurn === true) result.stopTurn = true;
30777
+ return result;
30778
+ }
30779
+ }
30780
+ };
30781
+ }
30782
+ };
30783
+ }));
30784
+ //#endregion
30602
30785
  //#region ../../packages/agent-core/src/tools/support/file-type.ts
30603
30786
  function toBuffer$2(data) {
30604
30787
  return Buffer.isBuffer(data) ? data : Buffer.from(data.buffer, data.byteOffset, data.byteLength);
@@ -74747,6 +74930,9 @@ var init_kosong_llm = __esmMin((() => {
74747
74930
  this.visionReader = config.visionReader;
74748
74931
  this.onVisionUsage = config.onVisionUsage;
74749
74932
  }
74933
+ get thinkingEffort() {
74934
+ return this.provider.thinkingEffort;
74935
+ }
74750
74936
  notifyMediaDropped(dropped) {
74751
74937
  if (this.onMediaDropped === void 0) return;
74752
74938
  const fresh = dropped.filter((part) => {
@@ -74789,6 +74975,7 @@ var init_kosong_llm = __esmMin((() => {
74789
74975
  let result;
74790
74976
  let completionBudget;
74791
74977
  try {
74978
+ const requestProvider = params.thinkingEffortRetry === void 0 ? this.provider : this.provider.withThinking(params.thinkingEffortRetry);
74792
74979
  const enrichedMessages = this.visionReader === void 0 ? params.messages : await enrichMessagesWithVision(params.messages, this.visionReader, params.signal, this.onVisionUsage);
74793
74980
  const tools = [...params.tools];
74794
74981
  const outgoingMessages = downgradeUnsupportedMedia(enrichedMessages, this.capability, (dropped) => {
@@ -74798,11 +74985,11 @@ var init_kosong_llm = __esmMin((() => {
74798
74985
  const reportedContextTokens = this.reportedContextTokens?.() ?? 0;
74799
74986
  const usedContextTokens = Math.max(outgoingRequestTokens, reportedContextTokens);
74800
74987
  completionBudget = applyCompletionBudgetWithDetails({
74801
- provider: this.provider,
74988
+ provider: requestProvider,
74802
74989
  budget: this.completionBudgetConfig,
74803
74990
  capability: this.capability,
74804
74991
  usedContextTokens,
74805
- retry: params.completionBudgetRetry ?? (thinkingEnabled(this.provider.thinkingEffort) ? {
74992
+ retry: params.completionBudgetRetry ?? (thinkingEnabled(requestProvider.thinkingEffort) ? {
74806
74993
  minimumCompletionTokens: 1024,
74807
74994
  multiplier: 1
74808
74995
  } : void 0)
@@ -75421,23 +75608,27 @@ var init_full = __esmMin((() => {
75421
75608
  const budget = this.strategy.compactionBudgetTokens;
75422
75609
  return budget !== void 0 && Number.isFinite(budget) && budget > 0 ? Math.floor(budget) : void 0;
75423
75610
  }
75424
- proactiveCompactionStatus() {
75425
- return proactiveCompactionEligibility({
75426
- usedTokens: this.estimateCurrentRequestTokens(),
75427
- budgetTokens: this.getCompactionBudgetTokens(),
75428
- hasShrinkableHistory: this.hasShrinkableHistory(this.agent.context.history),
75429
- isCompacting: this.isCompacting
75430
- });
75611
+ proactiveCompactionStatus(context = {}) {
75612
+ const usedTokens = this.estimateCurrentRequestTokens(context);
75613
+ return {
75614
+ ...proactiveCompactionEligibility({
75615
+ usedTokens,
75616
+ budgetTokens: this.getCompactionBudgetTokens(),
75617
+ hasShrinkableHistory: this.hasShrinkableHistory(this.agent.context.history),
75618
+ isCompacting: this.isCompacting
75619
+ }),
75620
+ usedTokens
75621
+ };
75431
75622
  }
75432
75623
  isProactiveCompactionEligible() {
75433
75624
  return this.proactiveCompactionStatus().eligible;
75434
75625
  }
75435
- requestProactiveCompaction() {
75436
- const status = this.proactiveCompactionStatus();
75626
+ requestProactiveCompaction(context = {}) {
75627
+ const status = this.proactiveCompactionStatus(context);
75437
75628
  if (!status.eligible) return status;
75438
75629
  this.proactiveCompactionRequested = true;
75439
75630
  this.agent.telemetry.track("proactive_compaction_requested", {
75440
- used_tokens: this.estimateCurrentRequestTokens(),
75631
+ used_tokens: status.usedTokens,
75441
75632
  threshold_tokens: status.thresholdTokens
75442
75633
  });
75443
75634
  return status;
@@ -75533,9 +75724,19 @@ var init_full = __esmMin((() => {
75533
75724
  const requestMessages = requestContext.messages ?? this.agent.context.messages;
75534
75725
  const projectedMessages = requestContext.additionalMessages === void 0 ? requestMessages : [...requestMessages, ...requestContext.additionalMessages];
75535
75726
  const requestTokens = this.estimateCurrentRequestTokens(requestContext);
75536
- const proactiveStatus = this.requestProactiveCompaction();
75727
+ const proactiveStatus = this.requestProactiveCompaction(requestContext);
75537
75728
  if (proactiveStatus.eligible) {
75538
75729
  this.proactiveCompactionRequested = false;
75730
+ this.agent.records.logRecord({
75731
+ type: "policy.intervention",
75732
+ policy: "proactive_compaction_trigger",
75733
+ location: "FullCompaction.beforeStep",
75734
+ size_before: this.estimateCurrentRequestTokens(),
75735
+ size_after: proactiveStatus.usedTokens,
75736
+ unit: "tokens",
75737
+ threshold_tokens: proactiveStatus.thresholdTokens,
75738
+ selected_tool_count: requestContext.tools?.length ?? 0
75739
+ });
75539
75740
  if (!this.compacting) this.beginAutoCompaction();
75540
75741
  await this.block(signal);
75541
75742
  }
@@ -76041,8 +76242,9 @@ var init_full = __esmMin((() => {
76041
76242
  }));
76042
76243
  //#endregion
76043
76244
  //#region ../../packages/agent-core/src/agent/compaction/micro.ts
76044
- 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, DEFAULT_CONFIG, MicroCompaction;
76245
+ var selectMicroCompactionCutoff, MICRO_COMPACTION_RECENT_MESSAGES, MICRO_COMPACTION_TOOL_ARGUMENTS_ENABLED, MICRO_COMPACTION_TOOL_ARGUMENT_MIN_TOKENS, isPersistedToolResultReference, freshToolResultIds, projectHistoricalUnaddressedTelegramMessages, dedupeRepeatedUserMessages, projectRepeatedAssistantResponses, compactHistoricalSkillActivations, dedupeRecurringCronWakeups, dedupeRepeatedInjections, projectLoopEventForRecord, projectUsageModelForRecord, projectUsageForRecord, resolveCompletedStepUuid, resolveStepEventUuid, restoreUsageFromRecord, restoreUsageModelFromRecord, isWireOnlyProgrammaticEvent, DEFAULT_CONFIG, MicroCompaction;
76045
76246
  var init_micro = __esmMin((() => {
76247
+ ({ isWireOnlyProgrammaticEvent } = createRequire(import.meta.url)("./bin/programmatic-context-isolation.cjs"));
76046
76248
  ({ selectMicroCompactionCutoff, MICRO_COMPACTION_RECENT_MESSAGES, MICRO_COMPACTION_TOOL_ARGUMENTS_ENABLED, MICRO_COMPACTION_TOOL_ARGUMENT_MIN_TOKENS } = createRequire(import.meta.url)("./bin/micro-compaction-policy.cjs"));
76047
76249
  ({ isPersistedToolResultReference, freshToolResultIds } = createRequire(import.meta.url)("./bin/tool-result-offload-policy.cjs"));
76048
76250
  ({ projectHistoricalUnaddressedTelegramMessages } = createRequire(import.meta.url)("./bin/telegram-context-projection-policy.cjs"));
@@ -76413,6 +76615,9 @@ function isValidCronTask(obj) {
76413
76615
  if (o["paused"] !== void 0 && typeof o["paused"] !== "boolean") return false;
76414
76616
  if (o["autoExpire"] !== void 0 && typeof o["autoExpire"] !== "boolean") return false;
76415
76617
  if (o["scheduleFromAt"] !== void 0 && (typeof o["scheduleFromAt"] !== "number" || !Number.isFinite(o["scheduleFromAt"]))) return false;
76618
+ if (o["allowedTools"] !== void 0 && (!Array.isArray(o["allowedTools"]) || !o["allowedTools"].every((name) => typeof name === "string"))) return false;
76619
+ if (o["allowedTools"] !== void 0 && typeof o["toolScopeDigest"] !== "string") return false;
76620
+ if (o["allowedTools"] === void 0 && o["toolScopeDigest"] !== void 0) return false;
76416
76621
  if (o["owner"] === "session-loop" && (typeof o["loopInterval"] !== "string" || o["loopInterval"].length === 0 || o["recurring"] === false || o["autoExpire"] !== false)) return false;
76417
76622
  return true;
76418
76623
  }
@@ -77190,7 +77395,7 @@ function hasUnfinishedTodoWork(agent) {
77190
77395
  const todos = agent.tools.storeData()["todo"];
77191
77396
  return Array.isArray(todos) && todos.some((todo) => todo?.status === "in_progress" || todo?.status === "pending");
77192
77397
  }
77193
- var STALE_THRESHOLD_MS, CronManager;
77398
+ var STALE_THRESHOLD_MS, normalizeCronAllowedTools, cronToolScopeForTask, filterToolsForCronScope, inheritedCronToolScope, createCronRunReceipt, buildCronFileCandidate, publicCronRunList, createCronRunStore, createMemoryCronRunStore, readCronFinalMessage, CronManager;
77194
77399
  var init_manager$3 = __esmMin((() => {
77195
77400
  init_clock();
77196
77401
  init_cron_fire_xml();
@@ -77198,6 +77403,17 @@ var init_manager$3 = __esmMin((() => {
77198
77403
  init_session_store$2();
77199
77404
  init_scheduler();
77200
77405
  init_telemetry_events();
77406
+ ({
77407
+ normalizeCronAllowedTools,
77408
+ cronToolScopeForTask,
77409
+ filterToolsForCronScope,
77410
+ inheritedCronToolScope,
77411
+ createCronRunReceipt,
77412
+ buildCronFileCandidate,
77413
+ publicCronRunList
77414
+ } = createRequire(import.meta.url)("./bin/scoped-cron-run-policy.cjs"));
77415
+ ({ createCronRunStore, createMemoryCronRunStore } = createRequire(import.meta.url)("./bin/cron-run-store.cjs"));
77416
+ ({ readCronFinalMessage } = createRequire(import.meta.url)("./bin/cron-run-output.cjs"));
77201
77417
  STALE_THRESHOLD_MS = 10080 * 60 * 1e3;
77202
77418
  CronManager = class {
77203
77419
  /** In-memory task store. Empty at construction; populated by
@@ -77233,6 +77449,11 @@ var init_manager$3 = __esmMin((() => {
77233
77449
  * later `blun resume` can reload via {@link loadFromDisk}.
77234
77450
  */
77235
77451
  persistStore;
77452
+ runStore;
77453
+ bufferedRuns = [];
77454
+ runByTurnId = /* @__PURE__ */ new Map();
77455
+ runAccumulators = /* @__PURE__ */ new Map();
77456
+ drainTimer = null;
77236
77457
  /**
77237
77458
  * Per-id serializer for persistence writes. Prevents a fast
77238
77459
  * `add` → `remove` sequence on the same id from racing each other on
@@ -77246,6 +77467,7 @@ var init_manager$3 = __esmMin((() => {
77246
77467
  this.store = new SessionCronStore();
77247
77468
  this.clocks = opts.clocks ?? resolveClockSources(process.env["BLUN_CRON_CLOCK"]) ?? SYSTEM_CLOCKS;
77248
77469
  this.persistStore = agent.homedir === void 0 ? void 0 : createCronPersistStore(agent.homedir);
77470
+ this.runStore = agent.homedir === void 0 ? createMemoryCronRunStore() : createCronRunStore(agent.homedir, { now: () => this.clocks.wallNow() });
77249
77471
  this.scheduler = createCronScheduler({
77250
77472
  clocks: this.clocks,
77251
77473
  source: () => this.store.list(),
@@ -77297,7 +77519,10 @@ var init_manager$3 = __esmMin((() => {
77297
77519
  */
77298
77520
  removeTasks(ids) {
77299
77521
  const removed = this.store.remove(ids);
77300
- for (const id of removed) this.persistEnqueue(id, () => this.persistStore.remove(id));
77522
+ for (const id of removed) {
77523
+ this.persistEnqueue(id, () => this.persistStore.remove(id));
77524
+ this.runStore.markJobDeletedById(id);
77525
+ }
77301
77526
  return removed;
77302
77527
  }
77303
77528
  updateTask(id, patch) {
@@ -77337,6 +77562,11 @@ var init_manager$3 = __esmMin((() => {
77337
77562
  * input, so a regenerated value would corrupt both.
77338
77563
  */
77339
77564
  async loadFromDisk() {
77565
+ const loadedRuns = this.runStore.load();
77566
+ for (const runId of loadedRuns.lostRunIds ?? []) {
77567
+ const receipt = this.runStore.get(runId);
77568
+ if (receipt !== void 0) this.emitRunTerminal(receipt);
77569
+ }
77340
77570
  if (this.persistStore === void 0) return;
77341
77571
  const tasks = await this.persistStore.list();
77342
77572
  this.store.clear();
@@ -77404,6 +77634,8 @@ var init_manager$3 = __esmMin((() => {
77404
77634
  * would be missing from the resume's `loadFromDisk()`.
77405
77635
  */
77406
77636
  async stop() {
77637
+ if (this.drainTimer !== null) clearTimeout(this.drainTimer);
77638
+ this.drainTimer = null;
77407
77639
  this.unbindSigusr1();
77408
77640
  await this.scheduler.stop();
77409
77641
  await this.flushPersist();
@@ -77469,24 +77701,49 @@ var init_manager$3 = __esmMin((() => {
77469
77701
  */
77470
77702
  handleFire(task, ctx) {
77471
77703
  const stale = this.isStale(task);
77704
+ const toolScope = cronToolScopeForTask(task);
77705
+ const runId = randomBytes(8).toString("hex");
77472
77706
  const origin = {
77473
77707
  kind: "cron_job",
77474
77708
  jobId: task.id,
77709
+ runId,
77475
77710
  cron: task.cron,
77476
77711
  recurring: task.recurring !== false,
77477
77712
  coalescedCount: ctx.coalescedCount,
77478
- stale
77713
+ stale,
77714
+ ...(toolScope.mode === "scoped" ? { toolScope } : {})
77479
77715
  };
77480
77716
  const content = [{
77481
77717
  type: "text",
77482
77718
  text: task.owner === "session-loop" ? renderSessionLoopWakeupXml(origin, task.prompt, task.loopInterval ?? "auto") : renderCronFireXml(origin, task.prompt)
77483
77719
  }];
77720
+ const receipt = createCronRunReceipt({
77721
+ runId,
77722
+ jobId: task.id,
77723
+ cron: task.cron,
77724
+ recurring: task.recurring !== false,
77725
+ stale,
77726
+ coalescedCount: ctx.coalescedCount,
77727
+ toolScopeDigest: toolScope.digest,
77728
+ firedAt: new Date(this.clocks.wallNow()).toISOString()
77729
+ });
77730
+ this.runStore.create(receipt);
77731
+ this.bufferedRuns.push({ runId, content, origin });
77732
+ this.runAccumulators.set(runId, {
77733
+ toolCalls: /* @__PURE__ */ new Map(),
77734
+ fileCandidates: /* @__PURE__ */ new Map(),
77735
+ outputs: [],
77736
+ finalStepId: null
77737
+ });
77738
+ this.agent.emitEvent({ type: "cron.fired", origin });
77484
77739
  this.agent.emitEvent({
77485
- type: "cron.fired",
77486
- origin,
77487
- prompt: task.prompt
77740
+ type: "cron.run.created",
77741
+ runId,
77742
+ jobId: task.id,
77743
+ coalescedCount: ctx.coalescedCount,
77744
+ toolScopeDigest: toolScope.digest
77488
77745
  });
77489
- const turnId = this.agent.turn.steer(content, origin);
77746
+ const turnId = this.launchBufferedRuns();
77490
77747
  this.agent.telemetry.track(CRON_FIRED, {
77491
77748
  recurring: task.recurring !== false,
77492
77749
  coalesced_count: ctx.coalescedCount,
@@ -77498,6 +77755,137 @@ var init_manager$3 = __esmMin((() => {
77498
77755
  this.emitDeleted(task.id);
77499
77756
  }
77500
77757
  }
77758
+ launchBufferedRuns() {
77759
+ if (this.bufferedRuns.length === 0) return null;
77760
+ if (this.agent.turn.hasActiveTurn || this.agent.fullCompaction.isCompacting) {
77761
+ this.scheduleBufferedRunDrain();
77762
+ return null;
77763
+ }
77764
+ const next = this.bufferedRuns.shift();
77765
+ const acceptance = this.agent.turn.promptWithAcceptance(next.content, next.origin);
77766
+ if (acceptance.accepted !== true || acceptance.turnId === null) {
77767
+ this.bufferedRuns.unshift(next);
77768
+ this.scheduleBufferedRunDrain();
77769
+ return null;
77770
+ }
77771
+ return acceptance.turnId;
77772
+ }
77773
+ scheduleBufferedRunDrain() {
77774
+ if (this.drainTimer !== null || this.bufferedRuns.length === 0) return;
77775
+ this.drainTimer = setTimeout(() => {
77776
+ this.drainTimer = null;
77777
+ this.launchBufferedRuns();
77778
+ }, 250);
77779
+ this.drainTimer.unref?.();
77780
+ }
77781
+ observeLoopEvent(turnId, event) {
77782
+ const runId = this.runByTurnId.get(turnId);
77783
+ if (runId === void 0) return;
77784
+ const accumulator = this.runAccumulators.get(runId);
77785
+ if (accumulator === void 0) return;
77786
+ if (event.type === "step.begin" && typeof event.uuid === "string") accumulator.finalStepId = event.uuid;
77787
+ if (event.type === "tool.call") {
77788
+ accumulator.toolCalls.set(event.toolCallId, { name: event.name, isError: false });
77789
+ const candidate = buildCronFileCandidate({
77790
+ toolName: event.name,
77791
+ toolCallId: event.toolCallId,
77792
+ display: event.display,
77793
+ workspaceRoot: this.agent.config.cwd,
77794
+ additionalRoots: this.agent.getAdditionalDirs(),
77795
+ pathExists: typeof event.display?.path === "string" && existsSync(event.display.path)
77796
+ });
77797
+ if (candidate !== null) accumulator.fileCandidates.set(event.toolCallId, candidate);
77798
+ }
77799
+ if (event.type === "tool.result") {
77800
+ const call = accumulator.toolCalls.get(event.toolCallId);
77801
+ if (call !== void 0) call.isError = event.result.isError === true;
77802
+ const candidate = accumulator.fileCandidates.get(event.toolCallId);
77803
+ if (candidate !== void 0 && event.result.isError !== true) accumulator.outputs.push(candidate);
77804
+ accumulator.fileCandidates.delete(event.toolCallId);
77805
+ }
77806
+ }
77807
+ observeAgentEvent(event) {
77808
+ if (event.type === "turn.started") {
77809
+ 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;
77810
+ if (runId === void 0) return;
77811
+ const receipt = this.runStore.get(runId);
77812
+ if (receipt?.status !== "buffered" && receipt?.status !== "running") return;
77813
+ this.runByTurnId.set(event.turnId, runId);
77814
+ if (receipt.status === "buffered") {
77815
+ const running = this.runStore.transition(runId, "running", {
77816
+ turnId: event.turnId,
77817
+ startedAt: new Date(this.clocks.wallNow()).toISOString()
77818
+ });
77819
+ this.agent.emitEvent({
77820
+ type: "cron.run.started",
77821
+ runId: running.runId,
77822
+ jobId: running.jobId,
77823
+ turnId: event.turnId
77824
+ });
77825
+ }
77826
+ return;
77827
+ }
77828
+ if (event.type !== "turn.ended") return;
77829
+ const runId = this.runByTurnId.get(event.turnId);
77830
+ if (runId === void 0) return;
77831
+ const accumulator = this.runAccumulators.get(runId);
77832
+ if (accumulator !== void 0) accumulator.lastTurnEnd = event;
77833
+ this.runByTurnId.delete(event.turnId);
77834
+ }
77835
+ observeRunWorkerEnded(runId, event) {
77836
+ const current = this.runStore.get(runId);
77837
+ if (current?.status !== "running" && current?.status !== "buffered") return;
77838
+ const accumulator = this.runAccumulators.get(runId) ?? {
77839
+ toolCalls: /* @__PURE__ */ new Map(),
77840
+ outputs: [],
77841
+ finalStepId: null
77842
+ };
77843
+ const status = event.reason === "cancelled" ? "cancelled" : event.reason === "failed" || event.reason === "filtered" ? "failed" : "completed";
77844
+ const terminal = this.runStore.transition(runId, status, {
77845
+ endedAt: new Date(this.clocks.wallNow()).toISOString(),
77846
+ toolCalls: [...accumulator.toolCalls.values()],
77847
+ outputs: accumulator.outputs,
77848
+ finalStepId: accumulator.finalStepId,
77849
+ error: status === "failed" ? {
77850
+ category: event.reason === "filtered" ? "policy" : "executor",
77851
+ code: event.error?.code ?? (event.reason === "filtered" ? "PROVIDER_FILTERED" : "TURN_FAILED")
77852
+ } : void 0
77853
+ });
77854
+ this.emitRunTerminal(terminal);
77855
+ this.runAccumulators.delete(runId);
77856
+ this.scheduleBufferedRunDrain();
77857
+ }
77858
+ observeRunWorkerFailed(runId) {
77859
+ this.observeRunWorkerEnded(runId, {
77860
+ reason: "failed",
77861
+ error: { code: "TURN_WORKER_FAILED" }
77862
+ });
77863
+ }
77864
+ emitRunTerminal(receipt) {
77865
+ const durationMs = receipt.startedAt === null || receipt.endedAt === null ? void 0 : Math.max(0, Date.parse(receipt.endedAt) - Date.parse(receipt.startedAt));
77866
+ this.agent.emitEvent({
77867
+ type: `cron.run.${receipt.status}`,
77868
+ runId: receipt.runId,
77869
+ jobId: receipt.jobId,
77870
+ durationMs,
77871
+ toolCalls: receipt.toolSummary.calls,
77872
+ toolErrors: receipt.toolSummary.errors,
77873
+ outputCount: receipt.outputs.length,
77874
+ errorCategory: receipt.error?.category
77875
+ });
77876
+ }
77877
+ listRuns(filters) {
77878
+ return publicCronRunList(this.runStore.list(), filters);
77879
+ }
77880
+ readRunOutput(runId) {
77881
+ const receipt = this.runStore.get(runId);
77882
+ if (receipt === void 0) return null;
77883
+ let finalMessage = null;
77884
+ if (receipt.finalMessageRef !== null && this.agent.homedir !== void 0) try {
77885
+ finalMessage = readCronFinalMessage(join$4(this.agent.homedir, "wire.jsonl"), receipt.finalMessageRef.stepId);
77886
+ } catch {}
77887
+ return { receipt, finalMessage };
77888
+ }
77501
77889
  /**
77502
77890
  * Reserved hook for an explicit "you missed N fires while offline"
77503
77891
  * banner. Today the scheduler's `coalescedCount` semantics already
@@ -77962,7 +78350,8 @@ var init_cron_create = __esmMin((() => {
77962
78350
  CronCreateInputSchema = object({
77963
78351
  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)."),
77964
78352
  prompt: string().min(1).max(MAX_PROMPT_BYTES).describe("The prompt to enqueue at each fire time. Limited to 8 KiB (UTF-8)."),
77965
- 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.")
78353
+ 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."),
78354
+ 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.")
77966
78355
  });
77967
78356
  CronCreateTool = class {
77968
78357
  manager;
@@ -78002,6 +78391,15 @@ var init_cron_create = __esmMin((() => {
78002
78391
  output: `Prompt exceeds ${String(MAX_PROMPT_BYTES)} bytes (got ${String(byteLen)}).`
78003
78392
  };
78004
78393
  const recurring = args.recurring !== false;
78394
+ let toolScope;
78395
+ try {
78396
+ toolScope = normalizeCronAllowedTools(args.allowed_tools, this.manager.agent.tools.loopTools);
78397
+ } catch (error) {
78398
+ return {
78399
+ isError: true,
78400
+ output: error instanceof Error ? error.message : String(error)
78401
+ };
78402
+ }
78005
78403
  if (!recurring) {
78006
78404
  const firstFire = computeNextCronRun(parsed, nowAtPrepare);
78007
78405
  if (firstFire !== null && firstFire - nowAtPrepare > ONE_SHOT_MAX_FUTURE_MS) return {
@@ -78014,7 +78412,8 @@ var init_cron_create = __esmMin((() => {
78014
78412
  approvalRule: literalRulePattern(this.name, JSON.stringify({
78015
78413
  cron: normalizedCron,
78016
78414
  prompt: args.prompt,
78017
- recurring
78415
+ recurring,
78416
+ ...(args.allowed_tools === void 0 ? {} : { allowed_tools: toolScope.names })
78018
78417
  })),
78019
78418
  execute: async () => {
78020
78419
  const nowMs = this.manager.clocks.wallNow();
@@ -78025,7 +78424,11 @@ var init_cron_create = __esmMin((() => {
78025
78424
  const task = this.manager.addTask({
78026
78425
  cron: normalizedCron,
78027
78426
  prompt: args.prompt,
78028
- recurring
78427
+ recurring,
78428
+ ...(toolScope.mode === "scoped" ? {
78429
+ allowedTools: toolScope.names,
78430
+ toolScopeDigest: toolScope.digest
78431
+ } : {})
78029
78432
  });
78030
78433
  const ideal = computeNextCronRun(parsed, nowMs);
78031
78434
  const nextFireAt = ideal === null ? null : recurring ? jitteredNextCronRunMs(task, parsed, ideal) : oneShotJitteredNextCronRunMs(task, ideal);
@@ -78992,6 +79395,14 @@ var init_context$2 = __esmMin((() => {
78992
79395
  keptHeadUserMessageCount,
78993
79396
  droppedCount: input.droppedCount
78994
79397
  };
79398
+ this.agent.records.logRecord({
79399
+ type: "policy.intervention",
79400
+ policy: "full_context_compaction",
79401
+ location: "AgentContext.applyCompaction",
79402
+ size_before: result.tokensBefore,
79403
+ size_after: result.tokensAfter,
79404
+ unit: "tokens"
79405
+ });
78995
79406
  this.agent.records.logRecord({
78996
79407
  type: "context.apply_compaction",
78997
79408
  ...result
@@ -79052,6 +79463,7 @@ var init_context$2 = __esmMin((() => {
79052
79463
  }
79053
79464
  project(messages, options) {
79054
79465
  const anomalies = [];
79466
+ const underPressure = toolResultOffloadPressureForAgent(this.agent);
79055
79467
  const userOffloaded = this.agent.userMessageOffload.compact(messages);
79056
79468
  const historicalMediaProjected = projectHistoricalMediaParts(userOffloaded);
79057
79469
  const historicalUserReferencesProjected = compactHistoricalPersistedUserMessageReferences(historicalMediaProjected);
@@ -79059,7 +79471,9 @@ var init_context$2 = __esmMin((() => {
79059
79471
  const historicalTelegramProjected = projectHistoricalUnaddressedTelegramMessages(duplicateUserMessagesProjected);
79060
79472
  const assistantOffloaded = this.agent.assistantMessageOffload.compact(historicalTelegramProjected);
79061
79473
  const repeatedAssistantProjected = projectRepeatedAssistantResponses(assistantOffloaded);
79062
- const result = project(this.agent.microCompaction.compact(compactHistoricalSuccessfulToolResults(dedupeRepeatedSuccessfulToolResults(repeatedAssistantProjected, this.agent.toolResultBatchOffload.compact(dedupeRecurringCronWakeups(dedupeRepeatedInjections(compactHistoricalSkillActivations(compactBaselineSkillInjections(repeatedAssistantProjected)))))))), {
79474
+ const batchProjected = this.agent.toolResultBatchOffload.compact(dedupeRecurringCronWakeups(dedupeRepeatedInjections(compactHistoricalSkillActivations(compactBaselineSkillInjections(repeatedAssistantProjected)))));
79475
+ const toolResultsProjected = compactHistoricalSuccessfulToolResults(dedupeRepeatedSuccessfulToolResults(repeatedAssistantProjected, batchProjected), { underPressure });
79476
+ const result = project(this.agent.microCompaction.compact(toolResultsProjected), {
79063
79477
  ...options,
79064
79478
  onAnomaly: (anomaly) => {
79065
79479
  anomalies.push(anomaly);
@@ -79191,6 +79605,7 @@ var init_context$2 = __esmMin((() => {
79191
79605
  type: "context.append_loop_event",
79192
79606
  event: projectLoopEventForRecord(event)
79193
79607
  });
79608
+ if (isWireOnlyProgrammaticEvent(event)) return;
79194
79609
  switch (event.type) {
79195
79610
  case "step.begin": {
79196
79611
  const closed = this.closePendingToolResults();
@@ -233363,6 +233778,7 @@ var init_default_tool_approve = __esmMin((() => {
233363
233778
  "Agent",
233364
233779
  "AskUserQuestion",
233365
233780
  "Skill",
233781
+ "ProgrammaticTool",
233366
233782
  "GetGoal",
233367
233783
  "SetGoalBudget",
233368
233784
  "UpdateGoal"
@@ -233752,9 +234168,9 @@ var init_plan_mode_guard_deny = __esmMin((() => {
233752
234168
  message: planModeWriteDeniedMessage(planFilePath)
233753
234169
  };
233754
234170
  }
233755
- if (toolName === "TaskStop") return {
234171
+ if (toolName === "TaskStop" || toolName === "TaskResume") return {
233756
234172
  kind: "deny",
233757
- message: "TaskStop is not available in plan mode. Call ExitPlanMode to exit plan mode before stopping a background task."
234173
+ message: `${toolName} is not available in plan mode. Call ExitPlanMode before changing background task execution.`
233758
234174
  };
233759
234175
  if (toolName === "CronCreate" || toolName === "CronDelete") return {
233760
234176
  kind: "deny",
@@ -234120,6 +234536,16 @@ var init_permission = __esmMin((() => {
234120
234536
  if (pattern === void 0) return;
234121
234537
  this.localSessionApprovalRulePatterns.add(pattern);
234122
234538
  }
234539
+ recordApprovalEdited(context, editedArgs) {
234540
+ const event = buildApprovalEditedEvent({
234541
+ turnId: Number(context.turnId),
234542
+ toolCallId: context.toolCall.id,
234543
+ toolName: context.toolCall.name,
234544
+ originalArgs: context.args,
234545
+ editedArgs
234546
+ });
234547
+ this.agent.records.logRecord(event);
234548
+ }
234123
234549
  get sessionApprovalRulePatterns() {
234124
234550
  return [...this.localSessionApprovalRulePatterns, ...this.parent?.sessionApprovalRulePatterns ?? []];
234125
234551
  }
@@ -234139,6 +234565,8 @@ var init_permission = __esmMin((() => {
234139
234565
  const { signal } = context;
234140
234566
  const id = context.toolCall.id;
234141
234567
  const name = context.toolCall.name;
234568
+ const approvalEditCount = Number.isSafeInteger(context.approvalEditCount) ? context.approvalEditCount : 0;
234569
+ const allowEdit = approvalEditCount === 0 && isEditableToolApprovalEligible(name);
234142
234570
  const display = context.execution.display ?? {
234143
234571
  kind: "generic",
234144
234572
  summary: context.execution.description ?? `Approve ${name}`,
@@ -234176,7 +234604,10 @@ var init_permission = __esmMin((() => {
234176
234604
  toolCallId: id,
234177
234605
  toolName: name,
234178
234606
  action,
234179
- display
234607
+ display,
234608
+ allowEdit,
234609
+ approvalEditCount,
234610
+ editableToolInput: allowEdit ? context.args : void 0
234180
234611
  }, { signal });
234181
234612
  } catch (error) {
234182
234613
  this.agent.telemetry.track("permission_approval_result", {
@@ -234204,6 +234635,19 @@ var init_permission = __esmMin((() => {
234204
234635
  return resolved === void 0 ? Promise.reject(error) : this.permissionPolicyResolutionToPrepare(resolved, context, policyName);
234205
234636
  }
234206
234637
  } else response = { decision: "approved" };
234638
+ let editedDecision;
234639
+ if (response.decision === "edited") try {
234640
+ editedDecision = validateEditedApprovalDecision({
234641
+ response,
234642
+ toolName: name,
234643
+ editCount: approvalEditCount
234644
+ });
234645
+ } catch (error) {
234646
+ response = {
234647
+ decision: "rejected",
234648
+ feedback: `Edited approval was rejected before tool preparation: ${error instanceof Error ? error.message : String(error)}`
234649
+ };
234650
+ }
234207
234651
  const sessionApprovalRule = response.decision === "approved" && response.scope === "session" ? context.execution.approvalRule : void 0;
234208
234652
  if (requestedApproval) this.agent.hooks?.fireAndForgetTrigger?.("PermissionResult", {
234209
234653
  matcherValue: name,
@@ -234218,13 +234662,14 @@ var init_permission = __esmMin((() => {
234218
234662
  selectedLabel: response.selectedLabel
234219
234663
  }
234220
234664
  });
234665
+ const approvalRecordResponse = response.decision === "edited" ? { decision: "edited" } : response;
234221
234666
  this.recordApprovalResult({
234222
234667
  turnId: Number(context.turnId),
234223
234668
  toolCallId: id,
234224
234669
  toolName: name,
234225
234670
  action,
234226
234671
  sessionApprovalRule,
234227
- result: response
234672
+ result: approvalRecordResponse
234228
234673
  });
234229
234674
  this.agent.telemetry.track("permission_approval_result", {
234230
234675
  policy_name: policyName ?? null,
@@ -234236,6 +234681,17 @@ var init_permission = __esmMin((() => {
234236
234681
  session_cache_written: sessionApprovalRule !== void 0,
234237
234682
  has_feedback: response.feedback !== void 0 && response.feedback.length > 0
234238
234683
  });
234684
+ if (response.decision === "edited" && editedDecision !== void 0) {
234685
+ let recorded = false;
234686
+ return { approvalEdit: {
234687
+ args: editedDecision.editedToolInput,
234688
+ record: (validatedArgs) => {
234689
+ if (recorded) throw new Error("Edited approval Wire event was already recorded");
234690
+ recorded = true;
234691
+ this.recordApprovalEdited(context, validatedArgs);
234692
+ }
234693
+ } };
234694
+ }
234239
234695
  const resolved = result.resolveApproval?.(response);
234240
234696
  if (resolved !== void 0) return this.permissionPolicyResolutionToPrepare(resolved, context, policyName);
234241
234697
  if (response.decision === "approved") return;
@@ -244071,6 +244527,49 @@ async function runToolCallBatch(step, response) {
244071
244527
  }
244072
244528
  return { stopTurn };
244073
244529
  }
244530
+ function createNestedToolInvoker(step, parentToolCall) {
244531
+ let nestedSequence = 0;
244532
+ const invoke = async ({ name, args, callId, signal }) => {
244533
+ if (invoke.stopTurn === true) throw new Error("No nested tool calls are allowed after a turn-stop result.");
244534
+ if (name === PROGRAMMATIC_TOOL_NAME) throw new Error("Nested ProgrammaticTool calls are not allowed.");
244535
+ const nestedSignal = signal ?? step.signal;
244536
+ nestedSignal.throwIfAborted();
244537
+ nestedSequence += 1;
244538
+ const safeCallId = typeof callId === "string" && callId.length > 0 ? callId : `call_${nestedSequence}`;
244539
+ const nestedToolCall = {
244540
+ id: `${parentToolCall.id}:ptc:${safeCallId}`,
244541
+ name,
244542
+ arguments: JSON.stringify(args ?? {})
244543
+ };
244544
+ const nestedStep = {
244545
+ ...step,
244546
+ signal: nestedSignal,
244547
+ toolCalls: [nestedToolCall],
244548
+ dispatchEvent: (event) => step.dispatchEvent(markProgrammaticNestedEvent(event))
244549
+ };
244550
+ const preflight = preflightToolCall(nestedStep, nestedToolCall);
244551
+ const prepared = await prepareToolCall(nestedStep, preflight);
244552
+ const started = await prepared.task.start();
244553
+ const pendingResult = await started.result;
244554
+ const finalized = await finalizePendingToolResult(nestedStep, pendingResult);
244555
+ if (finalized.stopTurn === true) invoke.stopTurn = true;
244556
+ await nestedStep.dispatchEvent({
244557
+ type: "tool.result",
244558
+ parentUuid: nestedToolCall.id,
244559
+ toolCallId: nestedToolCall.id,
244560
+ result: finalized.result
244561
+ });
244562
+ if (finalized.result.isError === true) throw new Error(nestedToolResultText(finalized.result));
244563
+ return finalized.result;
244564
+ };
244565
+ invoke.stopTurn = false;
244566
+ return invoke;
244567
+ }
244568
+ function nestedToolResultText(result) {
244569
+ if (typeof result.output === "string") return result.output;
244570
+ const text = result.output.filter((part) => part.type === "text").map((part) => part.text).join("");
244571
+ return text.length > 0 ? text : "Nested tool call failed.";
244572
+ }
244074
244573
  /**
244075
244574
  * Provider-order validation pass. It does not run hooks, spawn tools, or write
244076
244575
  * events. Validator compilation may populate the local cache.
@@ -244118,7 +244617,7 @@ function validateExecutableToolArgs(tool, args) {
244118
244617
  }
244119
244618
  return validateToolArgs(validator, args);
244120
244619
  }
244121
- async function prepareToolCall(step, call) {
244620
+ async function prepareToolCall(step, call, approvalEditCount = 0) {
244122
244621
  const settleError = async (args, output, displayFields) => {
244123
244622
  await dispatchToolCall(step, call, args, displayFields);
244124
244623
  return { task: makeResolvedToolCallTask(makeErrorToolResult(call, args, output)) };
@@ -244153,10 +244652,31 @@ async function prepareToolCall(step, call) {
244153
244652
  const settleAborted = () => settleError(effectiveArgs, abortedToolOutput(call.toolName, step.signal), displayFields);
244154
244653
  if (step.signal.aborted) return settleAborted();
244155
244654
  if (execution.isError === true) return settleSynthetic(effectiveArgs, execution, displayFields);
244156
- const authorization = await runAuthorizeToolExecutionHook(step, call, effectiveArgs, execution);
244655
+ const authorization = await runAuthorizeToolExecutionHook(step, call, effectiveArgs, execution, approvalEditCount);
244157
244656
  if (step.signal.aborted) return settleAborted();
244158
244657
  if (authorization?.block === true) return settleError(effectiveArgs, authorization.reason ?? `Tool call "${call.toolName}" was blocked`, displayFields);
244159
244658
  if (authorization?.syntheticResult !== void 0) return settleSynthetic(effectiveArgs, authorization.syntheticResult, displayFields);
244659
+ if (authorization?.approvalEdit !== void 0) {
244660
+ let plan;
244661
+ try {
244662
+ plan = buildEditedToolCallPlan({
244663
+ step,
244664
+ call,
244665
+ editedArgs: authorization.approvalEdit.args,
244666
+ editCount: approvalEditCount,
244667
+ preflightToolCall
244668
+ });
244669
+ } catch (error) {
244670
+ return settleError(authorization.approvalEdit.args, `Edited approval could not be re-prepared: ${errorMessage$12(error)}`, displayFields);
244671
+ }
244672
+ if (plan.kind === "rejected") return settleError(plan.call.args, plan.output ?? `Edited args for tool "${call.toolName}" were rejected`, displayFields);
244673
+ try {
244674
+ authorization.approvalEdit.record(plan.call.args);
244675
+ } catch (error) {
244676
+ return settleError(plan.call.args, `Edited approval evidence could not be recorded: ${errorMessage$12(error)}`, displayFields);
244677
+ }
244678
+ return prepareToolCall(plan.step, plan.call, plan.editCount);
244679
+ }
244160
244680
  const executionMetadata = authorization?.executionMetadata ?? decision.metadata;
244161
244681
  await dispatchToolCall(step, call, effectiveArgs, displayFields);
244162
244682
  return {
@@ -244230,7 +244750,7 @@ async function runPrepareToolExecutionHook(step, call) {
244230
244750
  metadata: hookResult?.executionMetadata
244231
244751
  };
244232
244752
  }
244233
- async function runAuthorizeToolExecutionHook(step, call, args, execution) {
244753
+ async function runAuthorizeToolExecutionHook(step, call, args, execution, approvalEditCount = 0) {
244234
244754
  const { hooks, signal, turnId, currentStep, llm } = step;
244235
244755
  if (hooks?.authorizeToolExecution === void 0) return void 0;
244236
244756
  try {
@@ -244240,6 +244760,7 @@ async function runAuthorizeToolExecutionHook(step, call, args, execution) {
244240
244760
  tool: call.tool,
244241
244761
  args,
244242
244762
  execution,
244763
+ approvalEditCount,
244243
244764
  turnId,
244244
244765
  stepNumber: currentStep,
244245
244766
  signal,
@@ -244326,11 +244847,13 @@ async function finalizePendingToolResult(step, pendingResult) {
244326
244847
  async function executeTool(step, execution, toolCall, toolName, metadata) {
244327
244848
  const { dispatchEvent, signal, turnId } = step;
244328
244849
  signal.throwIfAborted();
244850
+ const invokeTool = toolName === PROGRAMMATIC_TOOL_NAME ? createNestedToolInvoker(step, toolCall) : void 0;
244329
244851
  return raceExecuteWithGraceTimeout(execution.execute({
244330
244852
  turnId,
244331
244853
  toolCallId: toolCall.id,
244332
244854
  metadata,
244333
244855
  signal,
244856
+ invokeTool,
244334
244857
  onUpdate: (update) => {
244335
244858
  if (signal.aborted) return;
244336
244859
  dispatchEvent({
@@ -244462,8 +244985,9 @@ async function dispatchToolCall(step, call, args, displayFields) {
244462
244985
  display: displayFields?.display
244463
244986
  });
244464
244987
  }
244465
- var GRACE_TIMEOUT_MS, TOOL_OUTPUT_EMPTY, TOOL_OUTPUT_NON_TEXT, validators;
244988
+ var markProgrammaticNestedEvent, GRACE_TIMEOUT_MS, TOOL_OUTPUT_EMPTY, TOOL_OUTPUT_NON_TEXT, validators;
244466
244989
  var init_tool_call = __esmMin((() => {
244990
+ ({ markProgrammaticNestedEvent } = createRequire(import.meta.url)("./bin/programmatic-context-isolation.cjs"));
244467
244991
  init_args_validator();
244468
244992
  init_path_access();
244469
244993
  init_abort();
@@ -245764,7 +246288,7 @@ var init_modelCatalog$2 = __esmMin((() => {
245764
246288
  function isVolatileEventType(type) {
245765
246289
  return volatileEventTypeSet.has(type);
245766
246290
  }
245767
- 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;
246291
+ 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;
245768
246292
  var init_events$1 = __esmMin((() => {
245769
246293
  init_zod$1();
245770
246294
  init_display();
@@ -245838,9 +246362,16 @@ var init_events$1 = __esmMin((() => {
245838
246362
  isError: boolean$1().optional()
245839
246363
  });
245840
246364
  compactionSummaryOriginSchema = object({ kind: literal("compaction_summary") });
246365
+ cronToolScopeSchema = object({
246366
+ mode: literal("scoped"),
246367
+ names: array(string()).max(64),
246368
+ digest: string()
246369
+ });
245841
246370
  systemTriggerOriginSchema = object({
245842
246371
  kind: literal("system_trigger"),
245843
- name: string()
246372
+ name: string(),
246373
+ cronRunId: string().optional(),
246374
+ toolScope: cronToolScopeSchema.optional()
245844
246375
  });
245845
246376
  agentCoreBackgroundTaskStatusSchema = _enum([
245846
246377
  "running",
@@ -245859,10 +246390,12 @@ var init_events$1 = __esmMin((() => {
245859
246390
  cronJobOriginSchema = object({
245860
246391
  kind: literal("cron_job"),
245861
246392
  jobId: string(),
246393
+ runId: string().optional(),
245862
246394
  cron: string(),
245863
246395
  recurring: boolean$1(),
245864
246396
  coalescedCount: number$1(),
245865
- stale: boolean$1()
246397
+ stale: boolean$1(),
246398
+ toolScope: cronToolScopeSchema.optional()
245866
246399
  });
245867
246400
  cronMissedOriginSchema = object({
245868
246401
  kind: literal("cron_missed"),
@@ -245875,7 +246408,8 @@ var init_events$1 = __esmMin((() => {
245875
246408
  });
245876
246409
  retryOriginSchema = object({
245877
246410
  kind: literal("retry"),
245878
- trigger: string().optional()
246411
+ trigger: string().optional(),
246412
+ toolScope: cronToolScopeSchema.optional()
245879
246413
  });
245880
246414
  promptOriginSchema = discriminatedUnion("kind", [
245881
246415
  userPromptOriginSchema,
@@ -246395,8 +246929,30 @@ var init_events$1 = __esmMin((() => {
246395
246929
  });
246396
246930
  cronFiredEventSchema = object({
246397
246931
  type: literal("cron.fired"),
246398
- origin: cronJobOriginSchema,
246399
- prompt: string()
246932
+ origin: cronJobOriginSchema
246933
+ });
246934
+ cronRunCreatedEventSchema = object({
246935
+ type: literal("cron.run.created"),
246936
+ runId: string(),
246937
+ jobId: string(),
246938
+ coalescedCount: number$1(),
246939
+ toolScopeDigest: string().nullable()
246940
+ });
246941
+ cronRunStartedEventSchema = object({
246942
+ type: literal("cron.run.started"),
246943
+ runId: string(),
246944
+ jobId: string(),
246945
+ turnId: number$1()
246946
+ });
246947
+ cronRunTerminalEventSchema = object({
246948
+ type: _enum(["cron.run.completed", "cron.run.failed", "cron.run.cancelled", "cron.run.lost"]),
246949
+ runId: string(),
246950
+ jobId: string(),
246951
+ durationMs: number$1().optional(),
246952
+ toolCalls: number$1(),
246953
+ toolErrors: number$1(),
246954
+ outputCount: number$1(),
246955
+ errorCategory: string().optional()
246400
246956
  });
246401
246957
  attentionIntentSchema = object({
246402
246958
  accepted: literal(true),
@@ -246510,6 +247066,9 @@ var init_events$1 = __esmMin((() => {
246510
247066
  backgroundTaskStartedEventSchema,
246511
247067
  backgroundTaskTerminatedEventSchema,
246512
247068
  cronFiredEventSchema,
247069
+ cronRunCreatedEventSchema,
247070
+ cronRunStartedEventSchema,
247071
+ cronRunTerminalEventSchema,
246513
247072
  attentionAuthorizedEventSchema,
246514
247073
  promptSubmittedEventSchema
246515
247074
  ]);
@@ -247055,7 +247614,8 @@ var init_approval$2 = __esmMin((() => {
247055
247614
  approvalDecisionSchema = _enum([
247056
247615
  "approved",
247057
247616
  "rejected",
247058
- "cancelled"
247617
+ "cancelled",
247618
+ "edited"
247059
247619
  ]);
247060
247620
  approvalScopeSchema = _enum(["session"]);
247061
247621
  approvalRequestSchema = object({
@@ -247066,6 +247626,7 @@ var init_approval$2 = __esmMin((() => {
247066
247626
  tool_name: string().min(1),
247067
247627
  action: string(),
247068
247628
  tool_input_display: unknown(),
247629
+ allow_edit: boolean$1().optional(),
247069
247630
  created_at: isoDateTimeSchema,
247070
247631
  expires_at: isoDateTimeSchema
247071
247632
  });
@@ -247073,7 +247634,8 @@ var init_approval$2 = __esmMin((() => {
247073
247634
  decision: approvalDecisionSchema,
247074
247635
  scope: approvalScopeSchema.optional(),
247075
247636
  feedback: string().optional(),
247076
- selected_label: string().optional()
247637
+ selected_label: string().optional(),
247638
+ edited_tool_input: unknown().optional()
247077
247639
  });
247078
247640
  }));
247079
247641
  //#endregion
@@ -251417,6 +251979,7 @@ var init_task_output = __esmMin((() => {
251417
251979
  init_zod$1();
251418
251980
  init_background();
251419
251981
  init_input_schema();
251982
+ init_args_validator();
251420
251983
  init_rule_match();
251421
251984
  init_format();
251422
251985
  init_task_output$1();
@@ -251528,6 +252091,89 @@ var init_task_update = __esmMin((() => {
251528
252091
  };
251529
252092
  }));
251530
252093
  //#endregion
252094
+ //#region ../../packages/agent-core/src/tools/background/task-resume.ts
252095
+ var DurableTaskResumeRuntime$1, TaskResumeInputSchema, TaskResumeTool;
252096
+ var init_task_resume = __esmMin((() => {
252097
+ init_zod$1();
252098
+ init_input_schema();
252099
+ init_rule_match();
252100
+ init_agent_task();
252101
+ ({ DurableTaskResumeRuntime: DurableTaskResumeRuntime$1 } = createRequire(import.meta.url)("./bin/durable-task-resume-runtime.cjs"));
252102
+ TaskResumeInputSchema = object({
252103
+ task_id: string().trim().min(1).describe("The lost agent task ID, or completed TaskResume successor, to continue."),
252104
+ prompt: string().trim().min(1).max(32768).describe("New instructions for the preserved agent context."),
252105
+ description: string().trim().min(1).max(1024).describe("Short description for the replacement background task."),
252106
+ 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.")
252107
+ });
252108
+ TaskResumeTool = class {
252109
+ manager;
252110
+ subagentHost;
252111
+ runtime;
252112
+ name = "TaskResume";
252113
+ 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.";
252114
+ parameters = toInputJsonSchema(TaskResumeInputSchema);
252115
+ constructor(manager, subagentHost) {
252116
+ this.manager = manager;
252117
+ this.subagentHost = subagentHost;
252118
+ this.runtime = new DurableTaskResumeRuntime$1({
252119
+ getTask: (taskId) => manager.getTask(taskId),
252120
+ getIntent: (taskId) => manager.resumeStore?.getBySourceTaskId(taskId),
252121
+ writeIntent: (intent) => manager.resumeStore.write(intent),
252122
+ markIntentStarted: (taskId, startedAt) => manager.resumeStore.markStarted(taskId, startedAt),
252123
+ reserveTaskId: (prefix) => manager.reserveTaskId(prefix),
252124
+ resumeAgent: (agentId, options) => subagentHost.resume(agentId, options),
252125
+ createTask: (handle, description, metadata) => new AgentBackgroundTask(handle, description, subagentHost, metadata.controller ?? new AbortController(), {
252126
+ timeoutMs: resolveSubagentTimeoutMs({ perRunMinutes: metadata.timeoutMinutes }),
252127
+ runInBackground: true,
252128
+ parentToolCallId: metadata.parentToolCallId,
252129
+ responseFormat: void 0,
252130
+ resumed: true,
252131
+ replacesTaskId: metadata.replacesTaskId,
252132
+ resumeRootTaskId: metadata.resumeRootTaskId
252133
+ }),
252134
+ registerTask: (task, options) => manager.registerTask(task, options),
252135
+ awaitTaskPersisted: (taskId) => manager.awaitTaskPersisted(taskId),
252136
+ emitEvent: (event) => manager.agent.emitEvent(event),
252137
+ now: () => Date.now()
252138
+ });
252139
+ }
252140
+ resolveExecution(args) {
252141
+ return {
252142
+ description: `Resuming agent task ${args.task_id}`,
252143
+ approvalRule: this.name,
252144
+ matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.task_id),
252145
+ execute: (ctx) => this.execute(args, ctx)
252146
+ };
252147
+ }
252148
+ async execute(args, { toolCallId, signal, turnId }) {
252149
+ const controller = new AbortController();
252150
+ try {
252151
+ signal.throwIfAborted();
252152
+ const result = await this.runtime.resume({
252153
+ taskId: args.task_id,
252154
+ prompt: args.prompt,
252155
+ description: args.description,
252156
+ timeoutMinutes: args.timeout_minutes,
252157
+ parentToolCallId: toolCallId,
252158
+ toolScope: this.subagentHost.toolScopeForTurn(Number(turnId)),
252159
+ controller,
252160
+ signal
252161
+ });
252162
+ return {
252163
+ 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`,
252164
+ isError: false
252165
+ };
252166
+ } catch (error) {
252167
+ controller.abort();
252168
+ return {
252169
+ output: error instanceof Error ? error.message : String(error),
252170
+ isError: true
252171
+ };
252172
+ }
252173
+ }
252174
+ };
252175
+ }));
252176
+ //#endregion
251531
252177
  //#region ../../packages/agent-core/src/tools/background/task-stop.md?raw
251532
252178
  var task_stop_default;
251533
252179
  var init_task_stop$1 = __esmMin((() => {
@@ -251715,6 +252361,67 @@ var init_cron_list = __esmMin((() => {
251715
252361
  };
251716
252362
  }));
251717
252363
  //#endregion
252364
+ //#region ../../packages/agent-core/src/tools/cron/cron-runs.ts
252365
+ var CronRunListInputSchema, CronRunOutputInputSchema, CronRunListTool, CronRunOutputTool;
252366
+ var init_cron_runs = __esmMin((() => {
252367
+ init_zod$1();
252368
+ init_input_schema();
252369
+ CronRunListInputSchema = object({
252370
+ job_id: string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u).optional().describe("Optional cron job id filter."),
252371
+ status: string().regex(/^(buffered|running|completed|failed|cancelled|lost)$/u).optional().describe("Optional run status filter."),
252372
+ limit: number$1().int().min(1).max(100).optional().default(20).describe("Maximum number of newest run receipts.")
252373
+ }).strict();
252374
+ CronRunOutputInputSchema = object({
252375
+ run_id: string().regex(/^[0-9a-f]{16}$/u).describe("The 16-hex run id returned by CronRunList.")
252376
+ }).strict();
252377
+ CronRunListTool = class {
252378
+ manager;
252379
+ name = "CronRunList";
252380
+ 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.";
252381
+ parameters = toInputJsonSchema(CronRunListInputSchema);
252382
+ constructor(manager) {
252383
+ this.manager = manager;
252384
+ }
252385
+ resolveExecution(args) {
252386
+ return {
252387
+ description: "Listing private cron run receipts",
252388
+ approvalRule: this.name,
252389
+ execute: async () => {
252390
+ const runs = this.manager.listRuns({
252391
+ jobId: args.job_id,
252392
+ status: args.status,
252393
+ limit: args.limit
252394
+ });
252395
+ return { output: JSON.stringify({ runs }, null, 2), isError: false };
252396
+ }
252397
+ };
252398
+ }
252399
+ };
252400
+ CronRunOutputTool = class {
252401
+ manager;
252402
+ name = "CronRunOutput";
252403
+ 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.";
252404
+ parameters = toInputJsonSchema(CronRunOutputInputSchema);
252405
+ constructor(manager) {
252406
+ this.manager = manager;
252407
+ }
252408
+ resolveExecution(args) {
252409
+ return {
252410
+ description: `Reading private cron run ${args.run_id}`,
252411
+ approvalRule: this.name,
252412
+ execute: async () => {
252413
+ const run = this.manager.readRunOutput(args.run_id);
252414
+ if (run === null) return {
252415
+ output: `No cron run with id ${args.run_id} exists in this session.`,
252416
+ isError: true
252417
+ };
252418
+ return { output: JSON.stringify(run, null, 2), isError: false };
252419
+ }
252420
+ };
252421
+ }
252422
+ };
252423
+ }));
252424
+ //#endregion
251718
252425
  //#region ../../packages/agent-core/src/agent/permission/policies/deny-all.ts
251719
252426
  var DenyAllPermissionPolicy;
251720
252427
  var init_deny_all = __esmMin((() => {
@@ -252126,6 +252833,7 @@ var init_subagent_batch = __esmMin((() => {
252126
252833
  description: task.description,
252127
252834
  swarmIndex: task.swarmIndex,
252128
252835
  runInBackground: task.runInBackground,
252836
+ responseFormat: task.responseFormat,
252129
252837
  compactBeforeRetry: attempt.state.retryCount > 0,
252130
252838
  signal: attempt.controller.signal,
252131
252839
  onReady: () => {
@@ -252150,11 +252858,13 @@ var init_subagent_batch = __esmMin((() => {
252150
252858
  return this.failedAttemptOutcome(attempt, error);
252151
252859
  }
252152
252860
  attempt.state.agentId = handle.agentId;
252861
+ attempt.state.profileName = handle.profileName;
252153
252862
  try {
252154
252863
  const completion = await handle.completion;
252155
252864
  return {
252156
252865
  task,
252157
252866
  agentId: handle.agentId,
252867
+ profileName: handle.profileName,
252158
252868
  status: "completed",
252159
252869
  result: completion.result,
252160
252870
  usage: completion.usage
@@ -252178,6 +252888,7 @@ var init_subagent_batch = __esmMin((() => {
252178
252888
  return {
252179
252889
  task: attempt.state.task,
252180
252890
  agentId: attempt.state.agentId,
252891
+ profileName: attempt.state.profileName,
252181
252892
  status,
252182
252893
  state: attempt.state.agentId === void 0 ? "not_started" : "started",
252183
252894
  error: this.attemptErrorMessage(attempt, error, status)
@@ -252441,7 +253152,7 @@ async function runChildTurnToCompletion(child, signal) {
252441
253152
  }
252442
253153
  return completion.stopReason;
252443
253154
  }
252444
- async function completeChildTurnWithMaxTokensHandoff(child, signal) {
253155
+ async function completeChildTurnWithMaxTokensHandoff(child, signal, promptOrigin = SUBAGENT_PROMPT_ORIGIN) {
252445
253156
  let stopReason = await runChildTurnToCompletion(child, signal);
252446
253157
  let handoffAttempts = 0;
252447
253158
  while (shouldRequestSubagentHandoff(stopReason, handoffAttempts)) {
@@ -252450,7 +253161,7 @@ async function completeChildTurnWithMaxTokensHandoff(child, signal) {
252450
253161
  if (child.turn.prompt([{
252451
253162
  type: "text",
252452
253163
  text: SUBAGENT_MAX_TOKENS_HANDOFF_PROMPT
252453
- }], SUBAGENT_PROMPT_ORIGIN) === null) throw new Error("Subagent could not start its max_tokens recovery handoff.");
253164
+ }], promptOrigin) === null) throw new Error("Subagent could not start its max_tokens recovery handoff.");
252454
253165
  stopReason = await runChildTurnToCompletion(child, signal);
252455
253166
  }
252456
253167
  if (stopReason === "max_tokens") throw new Error(buildSubagentMaxTokensFailure(lastAssistantText(child)));
@@ -252467,12 +253178,29 @@ function lastAssistantText(agent) {
252467
253178
  }
252468
253179
  return "";
252469
253180
  }
253181
+ async function completeStructuredSubagentResult(child, childId, profileName, responseFormat, signal, promptOrigin = SUBAGENT_PROMPT_ORIGIN) {
253182
+ let validation = validateStructuredSubagentOutput(lastAssistantText(child), responseFormat);
253183
+ if (validation.validatorException === true) throw new Error(validation.error);
253184
+ if (!validation.ok) {
253185
+ signal.throwIfAborted();
253186
+ if (child.turn.prompt([{
253187
+ type: "text",
253188
+ text: buildStructuredResponseRepairPrompt(responseFormat, validation.error)
253189
+ }], promptOrigin) === null) throw new Error("Subagent could not start its structured-output repair turn.");
253190
+ await completeChildTurnWithMaxTokensHandoff(child, signal, promptOrigin);
253191
+ signal.throwIfAborted();
253192
+ validation = validateStructuredSubagentOutput(lastAssistantText(child), responseFormat);
253193
+ if (validation.validatorException === true) throw new Error(validation.error);
253194
+ if (!validation.ok) throw new Error(`${STRUCTURED_SUBAGENT_OUTPUT_ERROR}: ${validation.error}. Resume with Agent(resume="${childId}", prompt="return the corrected JSON object", response_format=...) using the same response format.`);
253195
+ }
253196
+ return validation.value;
253197
+ }
252470
253198
  function shouldSuppressQueuedAttemptFailureEvent(options, error) {
252471
253199
  if (options.suppressRateLimitFailureEvent !== true) return false;
252472
253200
  if (isProviderRateLimitError(error)) return true;
252473
253201
  return isAbortError$4(error) || options.signal.aborted;
252474
253202
  }
252475
- var DEFAULT_SUBAGENT_TIMEOUT_MS, resolveSubagentTimeoutMs, runAgentWithTimeoutContinuation, buildSubagentUsageDelta, inheritSubagentAllowedTools, inheritSubagentLifecycleTools, 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;
253203
+ 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;
252476
253204
  var init_subagent_host = __esmMin((() => {
252477
253205
  init_src$4();
252478
253206
  init_errors$8();
@@ -252487,6 +253215,16 @@ var init_subagent_host = __esmMin((() => {
252487
253215
  ({ DEFAULT_SUBAGENT_TIMEOUT_MS, resolveSubagentTimeoutMs, runAgentWithTimeoutContinuation } = createRequire(import.meta.url)("./bin/subagent-timeout-policy.cjs"));
252488
253216
  ({ buildSubagentUsageDelta } = createRequire(import.meta.url)("./bin/subagent-usage-rollup-policy.cjs"));
252489
253217
  ({ inheritSubagentAllowedTools, inheritSubagentLifecycleTools } = createRequire(import.meta.url)("./bin/subagent-tool-policy.cjs"));
253218
+ ({ prepareSubagentSkillPolicy, profileWithSubagentSkillTools, restoreSubagentSkillPolicy } = createRequire(import.meta.url)("./bin/subagent-skill-policy.cjs"));
253219
+ ({ SUBAGENT_FORK_REMINDER, projectSubagentForkContext, resolveSubagentContextMode } = createRequire(import.meta.url)("./bin/subagent-context-fork-policy.cjs"));
253220
+ ({
253221
+ STRUCTURED_SUBAGENT_OUTPUT_ERROR,
253222
+ prepareStructuredResponseFormat,
253223
+ validateStructuredSubagentOutput,
253224
+ buildStructuredResponseFormatReminder,
253225
+ buildStructuredResponseRepairPrompt,
253226
+ buildStructuredSubagentEnvelope
253227
+ } = createRequire(import.meta.url)("./bin/structured-subagent-output.cjs"));
252490
253228
  ({
252491
253229
  SUBAGENT_MAX_TOKENS_ERROR,
252492
253230
  SUBAGENT_MAX_TOKENS_HANDOFF_PROMPT,
@@ -252502,6 +253240,12 @@ var init_subagent_host = __esmMin((() => {
252502
253240
  kind: "system_trigger",
252503
253241
  name: "subagent"
252504
253242
  };
253243
+ function subagentPromptOrigin(toolScope) {
253244
+ return toolScope === void 0 ? SUBAGENT_PROMPT_ORIGIN : {
253245
+ ...SUBAGENT_PROMPT_ORIGIN,
253246
+ toolScope
253247
+ };
253248
+ }
252505
253249
  SIDE_QUESTION_SYSTEM_REMINDER = `
252506
253250
  This is a side-channel conversation with the user. You should answer user questions directly based on what you already know.
252507
253251
 
@@ -252540,21 +253284,37 @@ IMPORTANT:
252540
253284
  }
252541
253285
  return this.session.getReadyAgent(currentId);
252542
253286
  }
253287
+ toolScopeForTurn(turnId) {
253288
+ return inheritedCronToolScope(this.session.getReadyAgent(this.ownerAgentId)?.turn.toolScopeForTurn(turnId));
253289
+ }
253290
+ isRootAgent() {
253291
+ return this.session.metadata.agents[this.ownerAgentId]?.parentAgentId == null;
253292
+ }
252543
253293
  async spawn(options) {
252544
253294
  options.signal.throwIfAborted();
252545
253295
  const parent = await this.session.ensureAgentResumed(this.ownerAgentId);
253296
+ const contextMode = resolveSubagentContextMode({
253297
+ requested: options.contextMode,
253298
+ isRoot: this.isRootAgent()
253299
+ });
252546
253300
  const profile = this.resolveProfile(parent, options.profileName);
253301
+ const skillPolicy = prepareSubagentSkillPolicy(profile.subagentSkills, this.session.skills);
253302
+ const effectiveProfile = profileWithSubagentSkillTools(profile, skillPolicy);
252547
253303
  const { id, agent } = await this.session.createAgent({
252548
253304
  type: "sub",
252549
- generate: parent.rawGenerate
253305
+ generate: parent.rawGenerate,
253306
+ skillRegistry: skillPolicy.registry
252550
253307
  }, {
252551
253308
  parentAgentId: this.ownerAgentId,
252552
- swarmItem: options.swarmItem
253309
+ swarmItem: options.swarmItem,
253310
+ profileName: profile.name,
253311
+ skillPolicy: skillPolicy.metadata
252553
253312
  });
252554
253313
  const completion = this.runWithTrackedChildUsage(parent, agent, id, options, async (runOptions) => {
252555
253314
  this.emitSubagentSpawned(parent, id, profile.name, runOptions);
252556
253315
  try {
252557
- await this.configureChild(parent, agent, profile);
253316
+ await this.configureChild(parent, agent, effectiveProfile);
253317
+ if (contextMode === "fork") this.seedForkedContext(parent, agent);
252558
253318
  return await this.runPromptTurn(parent, id, agent, profile.name, runOptions);
252559
253319
  } catch (error) {
252560
253320
  this.emitSubagentFailed(parent, id, runOptions, error);
@@ -252628,7 +253388,7 @@ IMPORTANT:
252628
253388
  await child.fullCompaction.block(runOptions.signal);
252629
253389
  }
252630
253390
  this.emitSubagentStarted(parent, agentId);
252631
- if (child.turn.retry("agent-host") === null) throw new Error(`Agent instance "${agentId}" could not start a retry turn`);
253391
+ if (child.turn.retry("agent-host", runOptions.toolScope) === null) throw new Error(`Agent instance "${agentId}" could not start a retry turn`);
252632
253392
  this.observeFirstRequest(child, runOptions);
252633
253393
  return await this.waitForChildCompletion(parent, agentId, child, profileName, runOptions);
252634
253394
  } catch (error) {
@@ -252751,27 +253511,49 @@ IMPORTANT:
252751
253511
  const gitContext = await collectGitContext(child.kaos, child.config.cwd);
252752
253512
  if (gitContext) childPrompt = `${gitContext}\n\n${childPrompt}`;
252753
253513
  }
253514
+ if (options.systemReminder !== void 0) child.context.appendSystemReminder(options.systemReminder, {
253515
+ kind: "system_trigger",
253516
+ name: "durable_task_resume"
253517
+ });
253518
+ if (options.responseFormat !== void 0) child.context.appendSystemReminder(buildStructuredResponseFormatReminder(options.responseFormat), {
253519
+ kind: "system_trigger",
253520
+ name: "subagent_response_format"
253521
+ });
252754
253522
  this.emitSubagentStarted(parent, childId);
253523
+ const childOrigin = subagentPromptOrigin(options.toolScope);
252755
253524
  if (child.turn.prompt([{
252756
253525
  type: "text",
252757
253526
  text: childPrompt
252758
- }], SUBAGENT_PROMPT_ORIGIN) === null) throw new Error(`Agent instance "${childId}" could not start a turn`);
253527
+ }], childOrigin) === null) throw new Error(`Agent instance "${childId}" could not start a turn`);
252759
253528
  this.observeFirstRequest(child, options);
252760
253529
  return this.waitForChildCompletion(parent, childId, child, profileName, options);
252761
253530
  }
252762
253531
  async waitForChildCompletion(parent, childId, child, profileName, options) {
252763
- await completeChildTurnWithMaxTokensHandoff(child, options.signal);
252764
- let result = lastAssistantText(child);
252765
- let remainingContinuations = SUMMARY_CONTINUATION_ATTEMPTS;
252766
- while (remainingContinuations > 0 && result.length < SUMMARY_MIN_LENGTH) {
252767
- remainingContinuations -= 1;
252768
- options.signal.throwIfAborted();
252769
- child.turn.prompt([{
252770
- type: "text",
252771
- text: summary_continuation_default
252772
- }], SUBAGENT_PROMPT_ORIGIN);
252773
- await completeChildTurnWithMaxTokensHandoff(child, options.signal);
253532
+ const childOrigin = subagentPromptOrigin(options.toolScope);
253533
+ await completeChildTurnWithMaxTokensHandoff(child, options.signal, childOrigin);
253534
+ let result;
253535
+ if (options.responseFormat !== void 0) {
253536
+ const structuredResult = await completeStructuredSubagentResult(child, childId, profileName, options.responseFormat, options.signal, childOrigin);
253537
+ result = buildStructuredSubagentEnvelope({
253538
+ agentId: childId,
253539
+ profileName,
253540
+ responseFormat: options.responseFormat,
253541
+ result: structuredResult,
253542
+ usage: child.usage.data().total
253543
+ });
253544
+ } else {
252774
253545
  result = lastAssistantText(child);
253546
+ let remainingContinuations = SUMMARY_CONTINUATION_ATTEMPTS;
253547
+ while (remainingContinuations > 0 && result.length < SUMMARY_MIN_LENGTH) {
253548
+ remainingContinuations -= 1;
253549
+ options.signal.throwIfAborted();
253550
+ child.turn.prompt([{
253551
+ type: "text",
253552
+ text: summary_continuation_default
253553
+ }], childOrigin);
253554
+ await completeChildTurnWithMaxTokensHandoff(child, options.signal, childOrigin);
253555
+ result = lastAssistantText(child);
253556
+ }
252775
253557
  }
252776
253558
  const usage = child.usage.data().total;
252777
253559
  parent.emitEvent({
@@ -252796,10 +253578,22 @@ IMPORTANT:
252796
253578
  });
252797
253579
  const context = await prepareSystemPromptContext(this.session.systemContextKaos(child.kaos.getcwd()), this.session.options.blunHomeDir, { additionalDirs: child.getAdditionalDirs() });
252798
253580
  child.useProfile(profile, context, this.session.options.blunHomeDir);
252799
- child.tools.inheritUserTools(parent.tools);
253581
+ child.tools.inheritUserTools(parent.tools, /* @__PURE__ */ new Set(["Skill"]));
252800
253582
  inheritSubagentLifecycleTools(parent.tools, child.tools);
252801
253583
  inheritSubagentAllowedTools(parent.tools, child.tools);
252802
253584
  }
253585
+ seedForkedContext(parent, child) {
253586
+ const projection = projectSubagentForkContext(parent.context.history);
253587
+ child.context.useProjectedHistoryFrom({
253588
+ history: projection.messages,
253589
+ project: (history) => history
253590
+ });
253591
+ child.context.appendSystemReminder(SUBAGENT_FORK_REMINDER, {
253592
+ kind: "system_trigger",
253593
+ name: "subagent_context_fork"
253594
+ });
253595
+ return projection;
253596
+ }
252803
253597
  async triggerSubagentStart(parent, profileName, prompt, signal) {
252804
253598
  await parent.hooks?.trigger("SubagentStart", {
252805
253599
  matcherValue: profileName,
@@ -252831,10 +253625,11 @@ IMPORTANT:
252831
253625
  subagentId: childId,
252832
253626
  subagentName: profileName,
252833
253627
  parentToolCallId: options.parentToolCallId,
252834
- parentToolCallUuid: options.parentToolCallUuid,
252835
- parentAgentId: this.ownerAgentId,
252836
- description: options.description,
252837
- swarmIndex: options.swarmIndex,
253628
+ parentToolCallUuid: options.parentToolCallUuid,
253629
+ parentAgentId: this.ownerAgentId,
253630
+ description: options.description,
253631
+ contextMode: options.contextMode === "fork" ? "fork" : "isolated",
253632
+ swarmIndex: options.swarmIndex,
252838
253633
  runInBackground: options.runInBackground
252839
253634
  });
252840
253635
  parent.telemetry.track("subagent_created", {
@@ -252868,7 +253663,7 @@ var init_agent_background_disabled = __esmMin((() => {
252868
253663
  //#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-background-enabled.md?raw
252869
253664
  var agent_background_enabled_default;
252870
253665
  var init_agent_background_enabled = __esmMin((() => {
252871
- agent_background_enabled_default = "Subagents run detached whenever task management is available, so the parent remains responsive while delegated work continues. Completion arrives automatically in a later turn. Do not poll, sleep, or block on TaskOutput. Continue with other work or respond to the user. Use TaskUpdate to steer the running subagent and TaskStop only when it must be cancelled. Never fabricate or predict its result.";
253666
+ agent_background_enabled_default = "Subagents run detached whenever task management is available, so the parent remains responsive while delegated work continues. A call with `response_format` is the deliberate exception: it runs in the foreground so BLUN can validate and, at most once, repair the final JSON before returning it. Detached completion arrives automatically in a later turn. Do not poll, sleep, or block on TaskOutput. Continue with other work or respond to the user. Use TaskUpdate to steer a running detached subagent and TaskStop only when it must be cancelled. Never fabricate or predict its result.";
252872
253667
  }));
252873
253668
  //#endregion
252874
253669
  //#region ../../packages/agent-core/src/tools/builtin/collaboration/agent.md?raw
@@ -252910,7 +253705,7 @@ function formatForegroundAgentFailure(handle, message, timedOut) {
252910
253705
  "",
252911
253706
  `subagent error: ${message}`
252912
253707
  ];
252913
- if (timedOut || message.includes(SUBAGENT_MAX_TOKENS_ERROR)) lines.push(`resume_hint: Continue with Agent(resume="${handle.agentId}", prompt="continue"). Use agent_id only; do not set subagent_type. The subagent retains its prior context; redo any unfinished tool call if its result was lost.`);
253708
+ if (timedOut || message.includes(SUBAGENT_MAX_TOKENS_ERROR) || message.includes(STRUCTURED_SUBAGENT_OUTPUT_ERROR)) lines.push(`resume_hint: Continue with Agent(resume="${handle.agentId}", prompt="continue"). Use agent_id only; do not set subagent_type. The subagent retains its prior context; redo any unfinished tool call if its result was lost.`);
252914
253709
  return lines.join("\n");
252915
253710
  }
252916
253711
  function launchErrorMessage(error, signal) {
@@ -252927,7 +253722,7 @@ function buildSubagentDescriptions(subagents) {
252927
253722
  return `${header}\n Tools: ${subagent.tools.join(", ")}`;
252928
253723
  }).join("\n");
252929
253724
  }
252930
- var AgentToolInputSchema, BACKGROUND_AGENT_UNAVAILABLE, AgentTool, USER_INTERRUPTED_SUBAGENT_MESSAGE, resolveSubagentRunMode;
253725
+ var AgentToolInputSchema, BACKGROUND_AGENT_UNAVAILABLE, SUBAGENT_CONTEXT_FORK_TOOL_DESCRIPTION, AgentTool, USER_INTERRUPTED_SUBAGENT_MESSAGE, resolveSubagentRunMode;
252931
253726
  var init_agent$1 = __esmMin((() => {
252932
253727
  init_zod$1();
252933
253728
  init_tool_access();
@@ -252941,6 +253736,7 @@ var init_agent$1 = __esmMin((() => {
252941
253736
  init_agent_background_enabled();
252942
253737
  init_agent$2();
252943
253738
  ({ resolveSubagentRunMode } = createRequire(import.meta.url)("./bin/subagent-parent-responsiveness.cjs"));
253739
+ 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.";
252944
253740
  AgentToolInputSchema = preprocess((input) => {
252945
253741
  if (typeof input !== "object" || input === null || Array.isArray(input)) return input;
252946
253742
  const normalized = { ...input };
@@ -252953,9 +253749,14 @@ var init_agent$1 = __esmMin((() => {
252953
253749
  prompt: string().describe("Full task prompt for the subagent"),
252954
253750
  description: string().describe("Short task description (3-5 words) for UI display"),
252955
253751
  subagent_type: string().optional().describe("One of the available agent types (see \"Available agent types\" in this tool description). Defaults to \"coder\" when omitted."),
253752
+ 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."),
252956
253753
  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."),
252957
- run_in_background: boolean$1().optional().describe("Compatibility option. When task management is available, subagents always run detached so the parent remains responsive."),
252958
- 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.")
253754
+ 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."),
253755
+ 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."),
253756
+ response_format: object({
253757
+ name: string().min(1).max(64).describe("Stable name for the structured result"),
253758
+ schema: record(string(), unknown()).describe("Restricted JSON Schema for one object result")
253759
+ }).optional().describe("Require a validated JSON object from a foreground subagent. Structured background agents are not supported yet.")
252959
253760
  }));
252960
253761
  object({
252961
253762
  result: string().describe("Aggregated text output from the subagent"),
@@ -252967,7 +253768,7 @@ var init_agent$1 = __esmMin((() => {
252967
253768
  }).describe("Cumulative token usage")
252968
253769
  });
252969
253770
  BACKGROUND_AGENT_UNAVAILABLE = "Background agent execution is not available for this agent because TaskList, TaskOutput, and TaskStop are not enabled.";
252970
- agent_default = "Launch a subagent for substantial, multi-step work in its own context and wire file. It returns a final report while keeping intermediate file contents out of your context.\n\nThe subagent starts with zero conversation context. Give it a self-contained prompt with the goal, known facts, constraints, and required result. For a direct lookup, include the exact path or command. For an investigation, state the question and evidence needed instead of prescribing rigid steps.\n\nWhen continuing earlier work, resume the existing agent ID instead of spawning a new agent; its context remains available. A subagent report is only visible to you, so relay the relevant conclusions to the user. `timeout_minutes` sets the wall-clock interval before the same agent continues automatically with preserved context; `timeout_minutes=0` disables that interval.\n\nUse Agent for complex, context-heavy work, not a trivial one- or two-step task. Launch independent agents in parallel in one response when useful. After assigning a scope, do not duplicate its searches or reads and do not abandon it to redo the same work manually; both erase the intended context savings.";
253771
+ agent_default = "Launch a subagent for substantial, multi-step work in its own context and wire file. It returns a final report while keeping intermediate file contents out of your context.\n\nThe subagent starts with zero conversation context. Give it a self-contained prompt with the goal, known facts, constraints, and required result. For a direct lookup, include the exact path or command. For an investigation, state the question and evidence needed instead of prescribing rigid steps.\n\nWhen continuing earlier work, resume the existing agent ID instead of spawning a new agent; its context remains available. A subagent report is only visible to you, so relay the relevant conclusions to the user. `timeout_minutes` sets the wall-clock interval before the same agent continues automatically with preserved context; `timeout_minutes=0` disables that interval.\n\nUse Agent for complex, context-heavy work, not a trivial one- or two-step task. Launch independent agents in parallel in one response when useful. After assigning a scope, do not duplicate its searches or reads and do not abandon it to redo the same work manually; both erase the intended context savings.\n\nFor a machine-readable foreground result, pass `response_format` with a stable name and restricted object JSON Schema. The child gets no additional tools or permissions. It must return exactly one matching JSON object; BLUN validates it and allows at most one bounded repair turn. Do not combine `response_format` with `run_in_background=true`.";
252971
253772
  AgentTool = class {
252972
253773
  subagentHost;
252973
253774
  backgroundManager;
@@ -252980,7 +253781,7 @@ var init_agent$1 = __esmMin((() => {
252980
253781
  const log = options?.log;
252981
253782
  this.allowBackground = options?.allowBackground ?? true;
252982
253783
  const typeLines = buildSubagentDescriptions(subagents);
252983
- const baseDescription = `${agent_default}\n\n${this.allowBackground ? agent_background_enabled_default : agent_background_disabled_default}`;
253784
+ const baseDescription = `${agent_default}\n\n${SUBAGENT_CONTEXT_FORK_TOOL_DESCRIPTION}\n\n${this.allowBackground ? agent_background_enabled_default : agent_background_disabled_default}`;
252984
253785
  this.description = typeLines ? `${baseDescription}\n\nAvailable agent types (pass via subagent_type):\n${typeLines}` : baseDescription;
252985
253786
  this.log = log;
252986
253787
  }
@@ -252990,10 +253791,11 @@ var init_agent$1 = __esmMin((() => {
252990
253791
  let profileName = args.subagent_type?.length ? args.subagent_type : "coder";
252991
253792
  const resumeAgentId = args.resume?.trim();
252992
253793
  if (resumeAgentId !== void 0 && resumeAgentId.length > 0) profileName = await this.subagentHost.getProfileName?.(resumeAgentId) ?? "subagent";
252993
- const { runInBackground } = resolveSubagentRunMode({
253794
+ const resolvedRunMode = resolveSubagentRunMode({
252994
253795
  allowBackground: this.allowBackground,
252995
253796
  requested: args.run_in_background
252996
253797
  });
253798
+ const runInBackground = args.response_format === void 0 ? resolvedRunMode.runInBackground : false;
252997
253799
  return {
252998
253800
  description: `${runInBackground ? "Launching background" : "Launching"} ${profileName} agent: ${args.description}`,
252999
253801
  accesses: ToolAccesses.none(),
@@ -253008,15 +253810,42 @@ var init_agent$1 = __esmMin((() => {
253008
253810
  execute: (ctx) => this.execution(args, ctx)
253009
253811
  };
253010
253812
  }
253011
- async execution(args, { toolCallId, signal }) {
253813
+ async execution(args, { toolCallId, signal, turnId }) {
253012
253814
  try {
253013
253815
  signal.throwIfAborted();
253014
- const { runInBackground } = resolveSubagentRunMode({
253816
+ if (args.response_format !== void 0 && args.run_in_background === true) return {
253817
+ output: "response_format is supported for foreground Agent runs only; remove run_in_background=true.",
253818
+ isError: true
253819
+ };
253820
+ let responseFormat;
253821
+ try {
253822
+ responseFormat = prepareStructuredResponseFormat(args.response_format, compileToolArgsValidator);
253823
+ } catch (error) {
253824
+ return {
253825
+ output: `Invalid response_format: ${error instanceof Error ? error.message : String(error)}`,
253826
+ isError: true
253827
+ };
253828
+ }
253829
+ const resolvedRunMode = resolveSubagentRunMode({
253015
253830
  allowBackground: this.allowBackground,
253016
253831
  requested: args.run_in_background
253017
253832
  });
253833
+ const runInBackground = responseFormat === void 0 ? resolvedRunMode.runInBackground : false;
253018
253834
  const requestedProfileName = args.subagent_type?.length ? args.subagent_type : void 0;
253019
253835
  const resumeAgentId = args.resume?.trim();
253836
+ let contextMode;
253837
+ try {
253838
+ contextMode = resolveSubagentContextMode({
253839
+ requested: args.context_mode,
253840
+ resume: resumeAgentId !== void 0 && resumeAgentId.length > 0,
253841
+ isRoot: this.subagentHost.isRootAgent()
253842
+ });
253843
+ } catch (error) {
253844
+ return {
253845
+ output: error instanceof Error ? error.message : String(error),
253846
+ isError: true
253847
+ };
253848
+ }
253020
253849
  if (resumeAgentId !== void 0 && resumeAgentId.length > 0 && requestedProfileName !== void 0) return {
253021
253850
  output: "Cannot set subagent_type when resuming an existing agent. Resume by agent id only.",
253022
253851
  isError: true
@@ -253036,6 +253865,9 @@ var init_agent$1 = __esmMin((() => {
253036
253865
  prompt: args.prompt,
253037
253866
  description: args.description,
253038
253867
  runInBackground,
253868
+ responseFormat,
253869
+ contextMode,
253870
+ toolScope: this.subagentHost.toolScopeForTurn(Number(turnId)),
253039
253871
  signal: controller.signal
253040
253872
  };
253041
253873
  let handle;
@@ -253061,7 +253893,8 @@ var init_agent$1 = __esmMin((() => {
253061
253893
  taskId = this.backgroundManager.registerTask(new AgentBackgroundTask(handle, args.description, this.subagentHost, controller, {
253062
253894
  timeoutMs: resolveSubagentTimeoutMs({ perRunMinutes: args.timeout_minutes }),
253063
253895
  runInBackground,
253064
- parentToolCallId: toolCallId
253896
+ parentToolCallId: toolCallId,
253897
+ responseFormat
253065
253898
  }), {
253066
253899
  detached: runInBackground,
253067
253900
  signal: runInBackground ? void 0 : signal
@@ -253084,7 +253917,7 @@ var init_agent$1 = __esmMin((() => {
253084
253917
  }
253085
253918
  if (runInBackground) return { output: formatBackgroundAgentResult(taskId, handle, args.description, this.allowBackground) };
253086
253919
  if (await this.backgroundManager.waitForForegroundRelease(taskId) === "detached") return { output: formatBackgroundAgentResult(taskId, handle, args.description, this.allowBackground) };
253087
- return await this.formatForegroundResult(taskId, handle);
253920
+ return await this.formatForegroundResult(taskId, handle, responseFormat);
253088
253921
  } catch (error) {
253089
253922
  return {
253090
253923
  output: `subagent error: ${launchErrorMessage(error, signal)}`,
@@ -253092,9 +253925,12 @@ var init_agent$1 = __esmMin((() => {
253092
253925
  };
253093
253926
  }
253094
253927
  }
253095
- async formatForegroundResult(taskId, handle) {
253928
+ async formatForegroundResult(taskId, handle, responseFormat) {
253096
253929
  const info = this.backgroundManager.getTask(taskId);
253097
- if (info?.status === "completed") return { output: formatForegroundAgentSuccess(handle, await this.backgroundManager.readOutput(taskId)) };
253930
+ if (info?.status === "completed") {
253931
+ const output = await this.backgroundManager.readOutput(taskId);
253932
+ return { output: responseFormat === void 0 ? formatForegroundAgentSuccess(handle, output) : output };
253933
+ }
253098
253934
  const timedOut = info?.status === "timed_out";
253099
253935
  return {
253100
253936
  output: formatForegroundAgentFailure(handle, timedOut ? "Agent timed out before automatic continuation could start." : info?.stopReason === "Interrupted by user" ? USER_INTERRUPTED_SUBAGENT_MESSAGE : info?.stopReason !== void 0 ? info.stopReason : "The subagent was stopped before it finished.", timedOut),
@@ -253108,7 +253944,7 @@ var init_agent$1 = __esmMin((() => {
253108
253944
  //#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-swarm.md?raw
253109
253945
  var agent_swarm_default;
253110
253946
  var init_agent_swarm$1 = __esmMin((() => {
253111
- 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";
253947
+ 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";
253112
253948
  }));
253113
253949
  //#endregion
253114
253950
  //#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-swarm.ts
@@ -253191,13 +254027,14 @@ function renderSwarmSummary(completed, failed, aborted = 0) {
253191
254027
  function escapeXmlAttribute(value) {
253192
254028
  return value.replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
253193
254029
  }
253194
- var DEFAULT_SUBAGENT_TYPE, PROMPT_TEMPLATE_PLACEHOLDER, MAX_AGENT_SWARM_SUBAGENTS, AgentSwarmToolInputSchema, AgentSwarmTool;
254030
+ var DEFAULT_SUBAGENT_TYPE, PROMPT_TEMPLATE_PLACEHOLDER, MAX_AGENT_SWARM_SUBAGENTS, renderStructuredSwarmResults, parseStructuredSwarmDisplay, structuredSwarmToolResult, AgentSwarmToolInputSchema, AgentSwarmTool;
253195
254031
  var init_agent_swarm = __esmMin((() => {
253196
254032
  init_zod$1();
253197
254033
  init_subagent_host();
253198
254034
  init_tool_access();
253199
254035
  init_input_schema();
253200
254036
  init_agent_swarm$1();
254037
+ ({ renderStructuredSwarmResults, parseStructuredSwarmDisplay, structuredSwarmToolResult } = createRequire(import.meta.url)("./bin/structured-agent-swarm-output.cjs"));
253201
254038
  DEFAULT_SUBAGENT_TYPE = "coder";
253202
254039
  PROMPT_TEMPLATE_PLACEHOLDER = "{{item}}";
253203
254040
  MAX_AGENT_SWARM_SUBAGENTS = 128;
@@ -253207,7 +254044,11 @@ var init_agent_swarm = __esmMin((() => {
253207
254044
  prompt_template: string().trim().min(1).optional().describe(`Prompt template for each subagent. The ${PROMPT_TEMPLATE_PLACEHOLDER} placeholder is replaced with each item value.`),
253208
254045
  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.`),
253209
254046
  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."),
253210
- 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.")
254047
+ 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."),
254048
+ response_format: object({
254049
+ name: string().min(1).max(64).describe("Stable name for the shared structured result"),
254050
+ schema: record(string(), unknown()).describe("Restricted JSON Schema applied to every child result")
254051
+ }).optional().describe("Require one shared validated JSON object shape from every spawned or resumed swarm child.")
253211
254052
  }).strict();
253212
254053
  AgentSwarmTool = class {
253213
254054
  subagentHost;
@@ -253235,8 +254076,17 @@ var init_agent_swarm = __esmMin((() => {
253235
254076
  }
253236
254077
  async execution(args, context) {
253237
254078
  try {
254079
+ let responseFormat;
254080
+ if (args.response_format !== void 0) try {
254081
+ responseFormat = prepareStructuredResponseFormat(args.response_format, compileToolArgsValidator);
254082
+ } catch (error) {
254083
+ return {
254084
+ output: `Invalid response_format: ${error instanceof Error ? error.message : String(error)}`,
254085
+ isError: true
254086
+ };
254087
+ }
253238
254088
  this.swarmMode.enter("tool");
253239
- return { output: await this.runSwarm(args, context.signal, context.toolCallId) };
254089
+ return structuredSwarmToolResult(await this.runSwarm(args, context.signal, context.toolCallId, responseFormat, context.turnId));
253240
254090
  } catch (error) {
253241
254091
  return {
253242
254092
  output: error instanceof Error ? error.message : String(error),
@@ -253244,7 +254094,7 @@ var init_agent_swarm = __esmMin((() => {
253244
254094
  };
253245
254095
  }
253246
254096
  }
253247
- async runSwarm(args, signal, toolCallId) {
254097
+ async runSwarm(args, signal, toolCallId, responseFormat, turnId) {
253248
254098
  const profileName = normalizeOptionalString$2(args.subagent_type) ?? DEFAULT_SUBAGENT_TYPE;
253249
254099
  const tasks = createAgentSwarmSpecs(args, (agentId) => this.subagentHost.getSwarmItem(agentId)).map((spec) => {
253250
254100
  const descriptionName = spec.kind === "resume" ? "resume" : profileName;
@@ -253256,6 +254106,8 @@ var init_agent_swarm = __esmMin((() => {
253256
254106
  description: childDescription(args.description, spec.index, descriptionName),
253257
254107
  swarmIndex: spec.index,
253258
254108
  runInBackground: false,
254109
+ responseFormat,
254110
+ toolScope: this.subagentHost.toolScopeForTurn(Number(turnId)),
253259
254111
  swarmItem: spec.item,
253260
254112
  signal,
253261
254113
  timeout: resolveSubagentTimeoutMs({ perRunMinutes: args.timeout_minutes })
@@ -253270,10 +254122,11 @@ var init_agent_swarm = __esmMin((() => {
253270
254122
  kind: "spawn"
253271
254123
  };
253272
254124
  });
253273
- return renderSwarmResults((await this.subagentHost.runQueued(tasks)).map(({ task, ...result }) => ({
254125
+ const results = (await this.subagentHost.runQueued(tasks)).map(({ task, ...result }) => ({
253274
254126
  spec: task.data,
253275
254127
  ...result
253276
- })));
254128
+ }));
254129
+ return responseFormat === void 0 ? renderSwarmResults(results) : renderStructuredSwarmResults(results, responseFormat);
253277
254130
  }
253278
254131
  };
253279
254132
  }));
@@ -259389,7 +260242,7 @@ function renderLine(entry, lineEndingStyle) {
259389
260242
  function renderedLineBytes(renderedLine, isFirst) {
259390
260243
  return (isFirst ? 0 : 1) + Buffer.byteLength(renderedLine, "utf8");
259391
260244
  }
259392
- function renderEntries(entries, lineEndingStyle) {
260245
+ function renderEntries(entries, lineEndingStyle, maxBytes) {
259393
260246
  const renderedLines = [];
259394
260247
  const truncatedLineNumbers = [];
259395
260248
  let bytes = 0;
@@ -259397,14 +260250,14 @@ function renderEntries(entries, lineEndingStyle) {
259397
260250
  for (const entry of entries) {
259398
260251
  const rendered = renderLine(entry, lineEndingStyle);
259399
260252
  const lineBytes = renderedLineBytes(rendered.line, renderedLines.length === 0);
259400
- if (renderedLines.length > 0 && bytes + lineBytes > MAX_BYTES) {
260253
+ if (renderedLines.length > 0 && bytes + lineBytes > maxBytes) {
259401
260254
  maxBytesReached = true;
259402
260255
  break;
259403
260256
  }
259404
260257
  if (rendered.wasTruncated) truncatedLineNumbers.push(entry.lineNo);
259405
260258
  renderedLines.push(rendered.line);
259406
260259
  bytes += lineBytes;
259407
- if (bytes >= MAX_BYTES) {
260260
+ if (bytes >= maxBytes) {
259408
260261
  maxBytesReached = true;
259409
260262
  break;
259410
260263
  }
@@ -259435,7 +260288,7 @@ function containsNulByte(text) {
259435
260288
  function notReadableFileOutput(path) {
259436
260289
  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.`;
259437
260290
  }
259438
- 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;
260291
+ 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;
259439
260292
  var init_read = __esmMin((() => {
259440
260293
  init_zod$1();
259441
260294
  init_tool_access();
@@ -259446,46 +260299,47 @@ var init_read = __esmMin((() => {
259446
260299
  init_rule_match();
259447
260300
  init_line_endings();
259448
260301
  init_read$1();
259449
- ({ readContinuationNotice, READ_MODEL_VISIBLE_BYTES } = createRequire(import.meta.url)("./bin/read-continuation-policy.cjs"));
260302
+ ({ readContinuationNotice, readModelVisibleBytes, readModelVisibleLines } = createRequire(import.meta.url)("./bin/read-continuation-policy.cjs"));
259450
260303
  ({ MAX_READ_BATCH_REQUESTS, readBatchAllFailed, renderReadBatchOutput } = createRequire(import.meta.url)("./bin/read-batch-policy.cjs"));
259451
260304
  MAX_LINES$1 = 1e3;
259452
260305
  MAX_LINE_LENGTH = 2e3;
259453
- MAX_BYTES = READ_MODEL_VISIBLE_BYTES;
259454
260306
  S_IFMT$1 = 61440;
259455
260307
  S_IFREG = 32768;
259456
260308
  PositiveLineOffsetSchema = number$1().int().min(1);
259457
- TailLineOffsetSchema = number$1().int().min(-MAX_LINES$1).max(-1);
260309
+ TailLineOffsetSchema = number$1().int().max(-1);
259458
260310
  ReadInputSchema = object({
259459
260311
  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."),
259460
- 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)}.`),
259461
- 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.`)
260312
+ 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."),
260313
+ 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.")
259462
260314
  });
259463
260315
  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.`) });
259464
260316
  object({
259465
260317
  content: string(),
259466
260318
  lineCount: number$1().int().nonnegative()
259467
260319
  });
260320
+ 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.";
259468
260321
  READ_DESCRIPTION = renderPrompt(read_default, {
259469
260322
  MAX_LINES: MAX_LINES$1,
259470
- MAX_BYTES_KB: MAX_BYTES / 1024,
259471
- MAX_LINE_LENGTH
259472
- });
259473
- 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.";
259474
- READ_DESCRIPTION = renderPrompt(read_default, {
259475
- MAX_LINES: MAX_LINES$1,
259476
- MAX_BYTES_KB: MAX_BYTES / 1024,
259477
260323
  MAX_LINE_LENGTH
259478
260324
  });
259479
260325
  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.`;
259480
260326
  ReadTool = class {
259481
260327
  kaos;
259482
260328
  workspace;
260329
+ contextWindowState;
259483
260330
  name = "Read";
259484
260331
  description = READ_DESCRIPTION;
259485
260332
  parameters = toInputJsonSchema(ReadInputSchema);
259486
- constructor(kaos, workspace) {
260333
+ constructor(kaos, workspace, contextWindowState = () => ({})) {
259487
260334
  this.kaos = kaos;
259488
260335
  this.workspace = workspace;
260336
+ this.contextWindowState = contextWindowState;
260337
+ }
260338
+ modelVisibleBytes() {
260339
+ return readModelVisibleBytes(this.contextWindowState());
260340
+ }
260341
+ modelVisibleLines() {
260342
+ return readModelVisibleLines(this.contextWindowState());
259489
260343
  }
259490
260344
  resolveExecution(args) {
259491
260345
  const path = resolvePathAccessPath(args.path, {
@@ -259536,10 +260390,12 @@ var init_read = __esmMin((() => {
259536
260390
  output: notReadableFileOutput(args.path)
259537
260391
  };
259538
260392
  const lineOffset = args.line_offset ?? 1;
259539
- const requestedLines = args.n_lines ?? 1e3;
259540
- const effectiveLimit = Math.min(requestedLines, MAX_LINES$1);
259541
- if (lineOffset < 0) return await this.readTail(safePath, args.path, lineOffset, effectiveLimit, requestedLines);
259542
- return await this.readForward(safePath, args.path, lineOffset, effectiveLimit, requestedLines);
260393
+ const maxLines = this.modelVisibleLines();
260394
+ const requestedLines = args.n_lines ?? maxLines;
260395
+ const effectiveLimit = Math.min(requestedLines, maxLines);
260396
+ const maxBytes = this.modelVisibleBytes();
260397
+ if (lineOffset < 0) return await this.readTail(safePath, args.path, lineOffset, effectiveLimit, requestedLines, maxBytes, maxLines);
260398
+ return await this.readForward(safePath, args.path, lineOffset, effectiveLimit, requestedLines, maxBytes, maxLines);
259543
260399
  } catch (error) {
259544
260400
  if (isTextDecodeError(error)) return {
259545
260401
  isError: true,
@@ -259551,7 +260407,7 @@ var init_read = __esmMin((() => {
259551
260407
  };
259552
260408
  }
259553
260409
  }
259554
- async readForward(safePath, displayPath, lineOffset, effectiveLimit, requestedLines) {
260410
+ async readForward(safePath, displayPath, lineOffset, effectiveLimit, requestedLines, maxBytes, maxLines) {
259555
260411
  const rangeKaos = this.kaos;
259556
260412
  if (rangeKaos.scanTextFile !== void 0 && rangeKaos.readLineRange !== void 0) {
259557
260413
  const scan = await rangeKaos.scanTextFile(safePath);
@@ -259560,31 +260416,47 @@ var init_read = __esmMin((() => {
259560
260416
  output: notReadableFileOutput(displayPath)
259561
260417
  };
259562
260418
  const selectedEntries = [];
260419
+ const lineEndingStyle = lineEndingStyleFromFlags(scan.lineEndingFlags);
260420
+ let selectedBytes = 0;
260421
+ let maxBytesReached = false;
259563
260422
  let lineNo = lineOffset;
259564
260423
  for await (const rawLine of rangeKaos.readLineRange(safePath, {
259565
260424
  startLine: lineOffset,
259566
260425
  maxLines: effectiveLimit,
259567
260426
  errors: "strict"
259568
260427
  })) {
259569
- selectedEntries.push({
260428
+ const entry = {
259570
260429
  lineNo,
259571
260430
  rawContent: stripTrailingLf(rawLine)
259572
- });
260431
+ };
260432
+ const rendered = renderLine(entry, lineEndingStyle);
260433
+ const lineBytes = renderedLineBytes(rendered.line, selectedEntries.length === 0);
260434
+ if (selectedEntries.length > 0 && selectedBytes + lineBytes > maxBytes) {
260435
+ maxBytesReached = true;
260436
+ break;
260437
+ }
260438
+ selectedEntries.push(entry);
260439
+ selectedBytes += lineBytes;
259573
260440
  lineNo += 1;
260441
+ if (selectedBytes >= maxBytes) {
260442
+ maxBytesReached = true;
260443
+ break;
260444
+ }
259574
260445
  }
259575
- const lineEndingStyle = lineEndingStyleFromFlags(scan.lineEndingFlags);
259576
- const rendered = renderEntries(selectedEntries, lineEndingStyle);
260446
+ const rendered = renderEntries(selectedEntries, lineEndingStyle, maxBytes);
259577
260447
  return this.finishReadResult({
259578
260448
  renderedLines: rendered.renderedLines,
259579
260449
  truncatedLineNumbers: rendered.truncatedLineNumbers,
259580
- maxLinesReached: effectiveLimit >= 1e3 && lineOffset + 1e3 <= scan.totalLines,
259581
- maxBytesReached: rendered.maxBytesReached,
260450
+ maxLinesReached: effectiveLimit >= maxLines && lineOffset + maxLines <= scan.totalLines,
260451
+ maxBytesReached: maxBytesReached || rendered.maxBytesReached,
259582
260452
  lineEndingStyle,
259583
260453
  startLine: selectedEntries.length > 0 ? lineOffset : 0,
259584
260454
  totalLines: scan.totalLines,
259585
260455
  requestedLines,
259586
260456
  lineOffset,
259587
- effectiveLimit
260457
+ effectiveLimit,
260458
+ maxBytes,
260459
+ maxLines
259588
260460
  });
259589
260461
  }
259590
260462
  const selectedEntries = [];
@@ -259595,7 +260467,10 @@ var init_read = __esmMin((() => {
259595
260467
  };
259596
260468
  let currentLineNo = 0;
259597
260469
  let maxLinesReached = false;
260470
+ let maxBytesReached = false;
260471
+ let selectedBytes = 0;
259598
260472
  let collectionClosed = false;
260473
+ let closedByLines = false;
259599
260474
  for await (const rawLine of this.kaos.readLines(safePath, { errors: "strict" })) {
259600
260475
  if (containsNulByte(rawLine)) return {
259601
260476
  isError: true,
@@ -259604,38 +260479,56 @@ var init_read = __esmMin((() => {
259604
260479
  currentLineNo += 1;
259605
260480
  updateLineEndingFlags(flags, rawLine);
259606
260481
  if (collectionClosed) {
259607
- if (effectiveLimit >= 1e3 && currentLineNo >= lineOffset) maxLinesReached = true;
260482
+ if (closedByLines && effectiveLimit >= maxLines && currentLineNo >= lineOffset) maxLinesReached = true;
259608
260483
  continue;
259609
260484
  }
259610
260485
  if (currentLineNo < lineOffset) continue;
259611
260486
  if (selectedEntries.length >= effectiveLimit) {
259612
- if (effectiveLimit >= 1e3) maxLinesReached = true;
260487
+ if (effectiveLimit >= maxLines) maxLinesReached = true;
259613
260488
  collectionClosed = true;
260489
+ closedByLines = true;
259614
260490
  continue;
259615
260491
  }
259616
- selectedEntries.push({
260492
+ const entry = {
259617
260493
  lineNo: currentLineNo,
259618
260494
  rawContent: stripTrailingLf(rawLine)
259619
- });
259620
- if (selectedEntries.length >= effectiveLimit) collectionClosed = true;
260495
+ };
260496
+ const conservative = renderLine(entry, "mixed");
260497
+ const lineBytes = renderedLineBytes(conservative.line, selectedEntries.length === 0);
260498
+ if (selectedEntries.length > 0 && selectedBytes + lineBytes > maxBytes) {
260499
+ maxBytesReached = true;
260500
+ collectionClosed = true;
260501
+ continue;
260502
+ }
260503
+ selectedEntries.push(entry);
260504
+ selectedBytes += lineBytes;
260505
+ if (selectedEntries.length >= effectiveLimit) {
260506
+ collectionClosed = true;
260507
+ closedByLines = true;
260508
+ } else if (selectedBytes >= maxBytes) {
260509
+ maxBytesReached = true;
260510
+ collectionClosed = true;
260511
+ }
259621
260512
  }
259622
260513
  const lineEndingStyle = lineEndingStyleFromFlags(flags);
259623
- const rendered = renderEntries(selectedEntries, lineEndingStyle);
260514
+ const rendered = renderEntries(selectedEntries, lineEndingStyle, maxBytes);
259624
260515
  return this.finishReadResult({
259625
260516
  renderedLines: rendered.renderedLines,
259626
260517
  truncatedLineNumbers: rendered.truncatedLineNumbers,
259627
260518
  maxLinesReached,
259628
- maxBytesReached: rendered.maxBytesReached,
260519
+ maxBytesReached: maxBytesReached || rendered.maxBytesReached,
259629
260520
  lineEndingStyle,
259630
260521
  startLine: selectedEntries.length > 0 ? lineOffset : 0,
259631
260522
  totalLines: currentLineNo,
259632
260523
  requestedLines,
259633
260524
  lineOffset,
259634
- effectiveLimit
260525
+ effectiveLimit,
260526
+ maxBytes,
260527
+ maxLines
259635
260528
  });
259636
260529
  }
259637
- async readTail(safePath, displayPath, lineOffset, effectiveLimit, requestedLines) {
259638
- const tailCount = Math.abs(lineOffset);
260530
+ async readTail(safePath, displayPath, lineOffset, effectiveLimit, requestedLines, maxBytes, maxLines) {
260531
+ const tailCount = Math.min(Math.abs(lineOffset), maxLines);
259639
260532
  const rangeKaos = this.kaos;
259640
260533
  if (rangeKaos.scanTextFile !== void 0 && rangeKaos.readTailLines !== void 0) {
259641
260534
  const scan = await rangeKaos.scanTextFile(safePath);
@@ -259658,7 +260551,9 @@ var init_read = __esmMin((() => {
259658
260551
  lineEndingFlags: scan.lineEndingFlags,
259659
260552
  effectiveLimit,
259660
260553
  totalLines: scan.totalLines,
259661
- requestedLines
260554
+ requestedLines,
260555
+ maxBytes,
260556
+ maxLines
259662
260557
  });
259663
260558
  }
259664
260559
  const entries = [];
@@ -259686,7 +260581,9 @@ var init_read = __esmMin((() => {
259686
260581
  lineEndingFlags: flags,
259687
260582
  effectiveLimit,
259688
260583
  totalLines: currentLineNo,
259689
- requestedLines
260584
+ requestedLines,
260585
+ maxBytes,
260586
+ maxLines
259690
260587
  });
259691
260588
  }
259692
260589
  finishTailEntries(input) {
@@ -259700,7 +260597,7 @@ var init_read = __esmMin((() => {
259700
260597
  let totalBytes = 0;
259701
260598
  for (const [index, candidate] of renderedCandidates.entries()) totalBytes += renderedLineBytes(candidate.rendered.line, index === 0);
259702
260599
  let maxBytesReached = false;
259703
- if (totalBytes > MAX_BYTES) {
260600
+ if (totalBytes > input.maxBytes) {
259704
260601
  maxBytesReached = true;
259705
260602
  const kept = [];
259706
260603
  let bytes = 0;
@@ -259708,7 +260605,7 @@ var init_read = __esmMin((() => {
259708
260605
  const candidate = renderedCandidates[i];
259709
260606
  if (candidate === void 0) continue;
259710
260607
  const lineBytes = renderedLineBytes(candidate.rendered.line, kept.length === 0);
259711
- if (bytes + lineBytes > MAX_BYTES) break;
260608
+ if (bytes + lineBytes > input.maxBytes) break;
259712
260609
  kept.unshift(candidate);
259713
260610
  bytes += lineBytes;
259714
260611
  }
@@ -259728,7 +260625,9 @@ var init_read = __esmMin((() => {
259728
260625
  lineEndingStyle,
259729
260626
  startLine: renderedCandidates[0]?.entry.lineNo ?? 0,
259730
260627
  totalLines: input.totalLines,
259731
- requestedLines: input.requestedLines
260628
+ requestedLines: input.requestedLines,
260629
+ maxBytes: input.maxBytes,
260630
+ maxLines: input.maxLines
259732
260631
  });
259733
260632
  }
259734
260633
  finishReadResult(input) {
@@ -259743,8 +260642,8 @@ var init_read = __esmMin((() => {
259743
260642
  const lineCount = input.renderedLines.length;
259744
260643
  const parts = lineCount > 0 ? [`${String(lineCount)} ${lineCount === 1 ? "line" : "lines"} read from file starting from line ${String(input.startLine)}.`] : ["No lines read from file."];
259745
260644
  parts.push(`Total lines in file: ${String(input.totalLines)}.`);
259746
- if (input.maxLinesReached) parts.push(`Max ${String(MAX_LINES$1)} lines reached.`);
259747
- else if (input.maxBytesReached) parts.push(`Max ${String(MAX_BYTES)} bytes reached.`);
260645
+ if (input.maxLinesReached) parts.push(`Max ${String(input.maxLines)} lines reached.`);
260646
+ else if (input.maxBytesReached) parts.push(`Max ${String(input.maxBytes)} bytes reached.`);
259748
260647
  else if (lineCount < input.requestedLines) parts.push("End of file reached.");
259749
260648
  const continuationNotice = readContinuationNotice({
259750
260649
  ...input,
@@ -259763,10 +260662,10 @@ var init_read = __esmMin((() => {
259763
260662
  name = "ReadBatch";
259764
260663
  description = READ_BATCH_DESCRIPTION;
259765
260664
  parameters = toInputJsonSchema(ReadBatchInputSchema);
259766
- constructor(kaos, workspace) {
260665
+ constructor(kaos, workspace, contextWindowState) {
259767
260666
  this.kaos = kaos;
259768
260667
  this.workspace = workspace;
259769
- this.reader = new ReadTool(kaos, workspace);
260668
+ this.reader = new ReadTool(kaos, workspace, contextWindowState);
259770
260669
  }
259771
260670
  resolveExecution(args) {
259772
260671
  const items = args.requests.map((request) => ({
@@ -261161,7 +262060,7 @@ function renderHistoricalToolResultReference(toolName, toolCallId, text, outputP
261161
262060
  function safeToolResultFileStem(toolName, toolCallId) {
261162
262061
  return `${toolName}-${toolCallId}`.replace(/[^a-zA-Z0-9._-]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 80) || "tool-result";
261163
262062
  }
261164
- 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, dedupeRepeatedSuccessfulToolResults, readContinuationLineOffset, selectToolResultBatchOffloads, selectHistoricalToolResultOffloads, buildToolResultOffloadTelemetry;
262063
+ 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;
261165
262064
  var init_tool_result_budget = __esmMin((() => {
261166
262065
  init_dist$6();
261167
262066
  const toolResultOffloadPolicy = createRequire(import.meta.url)("./bin/tool-result-offload-policy.cjs");
@@ -261177,8 +262076,11 @@ var init_tool_result_budget = __esmMin((() => {
261177
262076
  createToolResultPreview = toolResultOffloadPolicy.createToolResultPreview;
261178
262077
  compactPersistedToolResultReference = toolResultOffloadPolicy.compactPersistedToolResultReference;
261179
262078
  compactHistoricalSuccessfulToolResults = toolResultOffloadPolicy.compactHistoricalSuccessfulToolResults;
262079
+ currentTurnReadToolResultIds = toolResultOffloadPolicy.currentTurnReadToolResultIds;
262080
+ currentUserTurnStartIndex = toolResultOffloadPolicy.currentUserTurnStartIndex;
261180
262081
  dedupeRepeatedSuccessfulToolResults = toolResultOffloadPolicy.dedupeRepeatedSuccessfulToolResults;
261181
262082
  freshToolResultIds = toolResultOffloadPolicy.freshToolResultIds;
262083
+ hasToolResultOffloadPressure = toolResultOffloadPolicy.hasToolResultOffloadPressure;
261182
262084
  readContinuationLineOffset = toolResultOffloadPolicy.readContinuationLineOffset;
261183
262085
  selectToolResultBatchOffloads = toolResultOffloadPolicy.selectToolResultBatchOffloads;
261184
262086
  selectHistoricalToolResultOffloads = toolResultOffloadPolicy.selectHistoricalToolResultOffloads;
@@ -261193,9 +262095,11 @@ var ToolResultBatchOffload = class {
261193
262095
  }
261194
262096
  async detect() {
261195
262097
  const history = this.agent.context.history;
262098
+ if (!toolResultOffloadPressureForAgent(this.agent)) return 0;
261196
262099
  const tailIds = freshToolResultIds(history);
262100
+ const pinnedReadIds = currentTurnReadToolResultIds(history);
261197
262101
  const recentStart = Math.max(0, history.length - TOOL_RESULT_HISTORICAL_KEEP_RECENT_MESSAGES);
261198
- const historical = history.slice(0, recentStart).filter((message) => message?.role === "tool" && !tailIds.has(message.toolCallId));
262102
+ const historical = history.slice(0, recentStart).filter((message) => message?.role === "tool" && !tailIds.has(message.toolCallId) && !pinnedReadIds.has(message.toolCallId));
261199
262103
  const candidateBatches = [{
261200
262104
  messages: historical,
261201
262105
  historical: true,
@@ -261274,6 +262178,7 @@ var ToolResultBatchOffload = class {
261274
262178
  });
261275
262179
  }
261276
262180
  compact(messages) {
262181
+ if (!toolResultOffloadPressureForAgent(this.agent)) return messages;
261277
262182
  const recentStart = Math.max(0, messages.length - TOOL_RESULT_HISTORICAL_KEEP_RECENT_MESSAGES);
261278
262183
  let changed = false;
261279
262184
  const projected = messages.map((message, index) => {
@@ -261324,6 +262229,13 @@ var ToolResultBatchOffload = class {
261324
262229
  }
261325
262230
  }
261326
262231
  };
262232
+ function toolResultOffloadPressureForAgent(agent) {
262233
+ return hasToolResultOffloadPressure({ contextUsageRatio: contextUsageRatioForAgent(agent) });
262234
+ }
262235
+ function contextUsageRatioForAgent(agent) {
262236
+ const maxContextTokens = agent.fullCompaction.getEffectiveMaxContextTokens();
262237
+ return maxContextTokens > 0 ? agent.context.tokenCountWithPending / maxContextTokens : 1;
262238
+ }
261327
262239
  //#endregion
261328
262240
  //#region ../../packages/agent-core/src/agent/turn/user-message-offload.ts
261329
262241
  function persistableUserMessageText(message) {
@@ -261369,7 +262281,7 @@ function renderPersistedUserMessage(text, outputPath) {
261369
262281
  createUserMessagePreview(text)
261370
262282
  ].join("\n");
261371
262283
  }
261372
- var USER_MESSAGE_MAX_CHARS, USER_MESSAGE_OFFLOAD_MARKER, shouldOffloadUserMessage, shouldOffloadHistoricalUserMessage, createUserMessagePreview, compactHistoricalPersistedUserMessageReferences, projectHistoricalMediaParts;
262284
+ var USER_MESSAGE_MAX_CHARS, USER_MESSAGE_OFFLOAD_MARKER, shouldOffloadUserMessage, shouldOffloadHistoricalUserMessage, createUserMessagePreview, compactHistoricalPersistedUserMessageReferences, historyTextChars, projectHistoricalMediaParts;
261373
262285
  var init_user_message_offload = __esmMin((() => {
261374
262286
  const policy = createRequire(import.meta.url)("./bin/user-message-offload-policy.cjs");
261375
262287
  USER_MESSAGE_MAX_CHARS = policy.USER_MESSAGE_MAX_CHARS;
@@ -261377,6 +262289,7 @@ var init_user_message_offload = __esmMin((() => {
261377
262289
  shouldOffloadUserMessage = policy.shouldOffloadUserMessage;
261378
262290
  shouldOffloadHistoricalUserMessage = policy.shouldOffloadHistoricalUserMessage;
261379
262291
  createUserMessagePreview = policy.createUserMessagePreview;
262292
+ historyTextChars = policy.historyTextChars;
261380
262293
  compactHistoricalPersistedUserMessageReferences = policy.compactHistoricalPersistedUserMessageReferences;
261381
262294
  ({ projectHistoricalMediaParts } = createRequire(import.meta.url)("./bin/historical-media-projection-policy.cjs"));
261382
262295
  }));
@@ -261389,8 +262302,12 @@ var UserMessageOffload = class {
261389
262302
  async detect() {
261390
262303
  const history = this.agent.context.history;
261391
262304
  if (this.agent.homedir === void 0) return 0;
262305
+ const currentTurnStart = currentUserTurnStartIndex(history);
262306
+ const totalHistoryChars = historyTextChars(history);
262307
+ const contextUsageRatio = contextUsageRatioForAgent(this.agent);
261392
262308
  let offloaded = 0;
261393
262309
  for (let historyIndex = 0; historyIndex < history.length; historyIndex++) {
262310
+ if (historyIndex === currentTurnStart) continue;
261394
262311
  const message = history[historyIndex];
261395
262312
  const text = persistableUserMessageText(message);
261396
262313
  if (text === void 0) continue;
@@ -261398,7 +262315,9 @@ var UserMessageOffload = class {
261398
262315
  const historicalOversize = shouldOffloadHistoricalUserMessage({
261399
262316
  historyIndex,
261400
262317
  historyLength: history.length,
261401
- textChars: text.length
262318
+ historyChars: totalHistoryChars,
262319
+ textChars: text.length,
262320
+ contextUsageRatio
261402
262321
  });
261403
262322
  if (!immediateOversize && !historicalOversize) continue;
261404
262323
  const messageHash = userMessageOffloadHash(message, text);
@@ -261410,6 +262329,14 @@ var UserMessageOffload = class {
261410
262329
  type: "text",
261411
262330
  text: replacementText
261412
262331
  }, ...message.content.filter((part) => part.type !== "text")];
262332
+ this.agent.records.logRecord({
262333
+ type: "policy.intervention",
262334
+ policy: "user_message_offload",
262335
+ location: "UserMessageOffload.detect",
262336
+ size_before: text.length,
262337
+ size_after: replacementText.length,
262338
+ unit: "chars"
262339
+ });
261413
262340
  this.apply({
261414
262341
  messageHash,
261415
262342
  content,
@@ -261434,7 +262361,7 @@ var UserMessageOffload = class {
261434
262361
  });
261435
262362
  }
261436
262363
  compact(messages) {
261437
- if (this.replacements.size === 0) return messages;
262364
+ if (this.replacements.size === 0 || !toolResultOffloadPressureForAgent(this.agent)) return messages;
261438
262365
  return messages.map((message) => {
261439
262366
  const text = persistableUserMessageText(message);
261440
262367
  if (text === void 0) return message;
@@ -261520,6 +262447,8 @@ var AssistantMessageOffload = class {
261520
262447
  async detect() {
261521
262448
  const history = this.agent.context.history;
261522
262449
  if (this.agent.homedir === void 0) return 0;
262450
+ const totalHistoryChars = historyTextChars(history);
262451
+ const contextUsageRatio = contextUsageRatioForAgent(this.agent);
261523
262452
  let offloaded = 0;
261524
262453
  for (let historyIndex = 0; historyIndex < history.length; historyIndex++) {
261525
262454
  const message = history[historyIndex];
@@ -261527,7 +262456,9 @@ var AssistantMessageOffload = class {
261527
262456
  if (text === void 0 || !shouldOffloadHistoricalAssistantMessage({
261528
262457
  historyIndex,
261529
262458
  historyLength: history.length,
261530
- textChars: text.length
262459
+ historyChars: totalHistoryChars,
262460
+ textChars: text.length,
262461
+ contextUsageRatio
261531
262462
  })) continue;
261532
262463
  const messageHash = assistantMessageOffloadHash(message, text);
261533
262464
  if (this.replacements.has(messageHash)) continue;
@@ -261538,6 +262469,14 @@ var AssistantMessageOffload = class {
261538
262469
  type: "text",
261539
262470
  text: replacementText
261540
262471
  }, ...message.content.filter((part) => part.type !== "text")];
262472
+ this.agent.records.logRecord({
262473
+ type: "policy.intervention",
262474
+ policy: "assistant_message_offload",
262475
+ location: "AssistantMessageOffload.detect",
262476
+ size_before: text.length,
262477
+ size_after: replacementText.length,
262478
+ unit: "chars"
262479
+ });
261541
262480
  this.apply({
261542
262481
  messageHash,
261543
262482
  content,
@@ -261562,7 +262501,9 @@ var AssistantMessageOffload = class {
261562
262501
  });
261563
262502
  }
261564
262503
  compact(messages) {
262504
+ const underPressure = toolResultOffloadPressureForAgent(this.agent);
261565
262505
  const completedToolCallIds = new Set(messages.filter((message) => message?.role === "tool" && message.toolCallId !== void 0).map((message) => message.toolCallId));
262506
+ const totalHistoryChars = historyTextChars(messages);
261566
262507
  let changed = false;
261567
262508
  const projected = messages.map((message, historyIndex) => {
261568
262509
  if (message?.role === "assistant" && message.toolCalls.length > 0) {
@@ -261572,6 +262513,7 @@ var AssistantMessageOffload = class {
261572
262513
  if (shouldCompactHistoricalAssistantToolNarration({
261573
262514
  historyIndex,
261574
262515
  historyLength: messages.length,
262516
+ historyChars: totalHistoryChars,
261575
262517
  textChars,
261576
262518
  toolCallCount: message.toolCalls.length,
261577
262519
  completedToolCallCount
@@ -261589,7 +262531,7 @@ var AssistantMessageOffload = class {
261589
262531
  }
261590
262532
  const text = persistableAssistantMessageText(message);
261591
262533
  if (text === void 0) return message;
261592
- const replacement = this.replacements.get(assistantMessageOffloadHash(message, text));
262534
+ const replacement = underPressure ? this.replacements.get(assistantMessageOffloadHash(message, text)) : void 0;
261593
262535
  if (replacement === void 0) return message;
261594
262536
  changed = true;
261595
262537
  return { ...message, content: replacement.content };
@@ -261616,6 +262558,17 @@ function blunExtractText(content) {
261616
262558
  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(" ");
261617
262559
  return "";
261618
262560
  }
262561
+ function blunRepeatActiveTurnPrompt(history, input, stepNumber) {
262562
+ if (stepNumber <= 1) return history;
262563
+ const prompt = blunExtractText(input);
262564
+ if (prompt.length === 0) return history;
262565
+ return [...history, {
262566
+ role: "user",
262567
+ 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>` }],
262568
+ toolCalls: [],
262569
+ origin: { kind: "injection", variant: "active_turn_prompt" }
262570
+ }];
262571
+ }
261619
262572
  /**
261620
262573
  * BLUN: decide whether a turn should carry the full tool set. Small-context models
261621
262574
  * (e.g. King on an 8k window) lose their identity/language when all tool schemas
@@ -261959,7 +262912,7 @@ function durablePromptOrigin(origin) {
261959
262912
  void externalReportSources;
261960
262913
  return durableOrigin;
261961
262914
  }
261962
- var BLUN_CORE_TOOL_NAMES, BLUN_LEAN_TOOL_NAMES, BLUN_ATTACHMENT_MARKER_RE, BLUN_TELEGRAM_OUTBOUND_TOOL_RE, BLUN_TELEGRAM_CHANNEL_RE, BLUN_TOOL_BUDGET_RATIO, createDeferredToolLoader, mediaToolNamesForTurnText, rankedSupportToolNamesForGoal, rankedToolNamesForTurnText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens, enforceSingleTodoWritePerStep, projectRecurringCronHistory, TelegramDeliveryLedger, createRuntimeCognitiveTurnLifecycle, cognitiveFocusScopesForTurn, buildCognitiveWorkFocus, buildAttentionQueueItem, LLM_NOT_SET_MESSAGE, GOAL_CONTINUATION_ORIGIN, GOAL_COMPLETION_REMINDER_NAME, GOAL_BLOCKED_REMINDER_NAME, GOAL_RATE_LIMIT_PAUSE_REASON, GOAL_PROVIDER_CONNECTION_PAUSE_PREFIX, GOAL_PROVIDER_AUTH_PAUSE_PREFIX, GOAL_PROVIDER_API_PAUSE_PREFIX, GOAL_MODEL_CONFIG_PAUSE_PREFIX, GOAL_RUNTIME_PAUSE_PREFIX, GOAL_PROVIDER_FILTERED_PAUSE_REASON, GOAL_CONTINUATION_PROMPT, TurnFlow;
262915
+ var BLUN_CORE_TOOL_NAMES, BLUN_LEAN_TOOL_NAMES, BLUN_ATTACHMENT_MARKER_RE, BLUN_TELEGRAM_OUTBOUND_TOOL_RE, BLUN_TELEGRAM_CHANNEL_RE, BLUN_TOOL_BUDGET_RATIO, createDeferredToolLoader, mediaToolNamesForTurnText, rankedSupportToolNamesForGoal, rankedToolNamesForTurnText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens, assessTodoListBounds, assessTodoMaintenanceUpdate, enforceSingleTodoWritePerStep, todoRefreshWorkCallLimit, projectRecurringCronHistory, TelegramDeliveryLedger, createRuntimeCognitiveTurnLifecycle, cognitiveFocusScopesForTurn, buildCognitiveWorkFocus, buildAttentionQueueItem, LLM_NOT_SET_MESSAGE, GOAL_CONTINUATION_ORIGIN, GOAL_COMPLETION_REMINDER_NAME, GOAL_BLOCKED_REMINDER_NAME, GOAL_RATE_LIMIT_PAUSE_REASON, GOAL_PROVIDER_CONNECTION_PAUSE_PREFIX, GOAL_PROVIDER_AUTH_PAUSE_PREFIX, GOAL_PROVIDER_API_PAUSE_PREFIX, GOAL_MODEL_CONFIG_PAUSE_PREFIX, GOAL_RUNTIME_PAUSE_PREFIX, GOAL_PROVIDER_FILTERED_PAUSE_REASON, GOAL_CONTINUATION_PROMPT, TurnFlow;
261963
262916
  var init_turn = __esmMin((() => {
261964
262917
  init_dist$4();
261965
262918
  init_src$4();
@@ -261977,7 +262930,7 @@ var init_turn = __esmMin((() => {
261977
262930
  init_user_message_offload();
261978
262931
  init_assistant_message_offload();
261979
262932
  ({ CORE_TOOL_NAMES: BLUN_CORE_TOOL_NAMES, createDeferredToolLoader, mediaToolNamesForTurnText, rankedSupportToolNamesForGoal, rankedToolNamesForTurnText, rememberDeferredToolAfterNotFound, toolSchemaBudgetTokens } = createRequire(import.meta.url)("./bin/turn-tool-performance-policy.cjs"));
261980
- ({ enforceSingleTodoWritePerStep } = createRequire(import.meta.url)("./bin/todo-list-turn-policy.cjs"));
262933
+ ({ assessTodoListBounds, assessTodoMaintenanceUpdate, enforceSingleTodoWritePerStep, todoRefreshWorkCallLimit } = createRequire(import.meta.url)("./bin/todo-list-turn-policy.cjs"));
261981
262934
  ({ projectRecurringCronHistory } = createRequire(import.meta.url)("./bin/recurring-cron-history-policy.cjs"));
261982
262935
  ({ TelegramDeliveryLedger } = createRequire(import.meta.url)("./bin/repeated-user-message-projection.cjs"));
261983
262936
  ({ createRuntimeCognitiveTurnLifecycle } = createRequire(import.meta.url)("./bin/cognitive-turn-lifecycle.cjs"));
@@ -261994,6 +262947,15 @@ var init_turn = __esmMin((() => {
261994
262947
  kind: "system_trigger",
261995
262948
  name: "goal_continuation"
261996
262949
  };
262950
+ function goalContinuationOrigin(origin) {
262951
+ const cronRunId = origin?.kind === "cron_job" ? origin.runId : origin?.cronRunId;
262952
+ if (cronRunId === void 0 && origin?.toolScope === void 0) return GOAL_CONTINUATION_ORIGIN;
262953
+ return {
262954
+ ...GOAL_CONTINUATION_ORIGIN,
262955
+ ...(cronRunId === void 0 ? {} : { cronRunId }),
262956
+ ...(origin?.toolScope === void 0 ? {} : { toolScope: origin.toolScope })
262957
+ };
262958
+ }
261997
262959
  GOAL_COMPLETION_REMINDER_NAME = "goal_completion";
261998
262960
  GOAL_BLOCKED_REMINDER_NAME = "goal_blocked";
261999
262961
  GOAL_RATE_LIMIT_PAUSE_REASON = "Paused after provider rate limit";
@@ -262041,6 +263003,7 @@ var init_turn = __esmMin((() => {
262041
263003
  stepToolCallKeys = /* @__PURE__ */ new Map();
262042
263004
  telemetryModeByTurn = /* @__PURE__ */ new Map();
262043
263005
  currentStepByTurn = /* @__PURE__ */ new Map();
263006
+ toolScopeByTurn = /* @__PURE__ */ new Map();
262044
263007
  interruptedTelemetryTurnIds = /* @__PURE__ */ new Set();
262045
263008
  stepFailureByTurn = /* @__PURE__ */ new Map();
262046
263009
  currentStep = 0;
@@ -262307,10 +263270,11 @@ var init_turn = __esmMin((() => {
262307
263270
  duplicate: false
262308
263271
  };
262309
263272
  }
262310
- retry(trigger) {
263273
+ retry(trigger, toolScope) {
262311
263274
  return this.prompt([], {
262312
263275
  kind: "retry",
262313
- trigger
263276
+ trigger,
263277
+ ...(toolScope === void 0 ? {} : { toolScope })
262314
263278
  });
262315
263279
  }
262316
263280
  launch(input, origin) {
@@ -262388,6 +263352,9 @@ var init_turn = __esmMin((() => {
262388
263352
  get hasActiveTurn() {
262389
263353
  return this.activeTurn !== null && this.activeTurn !== "resuming";
262390
263354
  }
263355
+ toolScopeForTurn(turnId) {
263356
+ return this.toolScopeByTurn.get(turnId);
263357
+ }
262391
263358
  ensureActiveTurn() {
262392
263359
  if (this.activeTurn === null || this.activeTurn === "resuming") throw new Error("No active turn");
262393
263360
  return this.activeTurn;
@@ -262499,15 +263466,23 @@ var init_turn = __esmMin((() => {
262499
263466
  */
262500
263467
  async turnWorker(firstTurnId, input, origin, signal) {
262501
263468
  const ownsActiveTurn = () => this.activeTurn !== null && this.activeTurn !== "resuming" && this.activeTurn.controller.signal === signal;
263469
+ let result;
262502
263470
  try {
262503
- if (this.agent.goal.getGoal().goal?.status === "active") return await this.driveGoal(firstTurnId, input, origin, signal);
262504
- const end = await this.runOneTurn(firstTurnId, input, origin, signal, true);
262505
- 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(), [{
262506
- type: "text",
262507
- text: GOAL_CONTINUATION_PROMPT
262508
- }], GOAL_CONTINUATION_ORIGIN, signal);
262509
- return end;
263471
+ if (this.agent.goal.getGoal().goal?.status === "active") result = await this.driveGoal(firstTurnId, input, origin, signal);
263472
+ else {
263473
+ const end = await this.runOneTurn(firstTurnId, input, origin, signal, true);
263474
+ 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(), [{
263475
+ type: "text",
263476
+ text: GOAL_CONTINUATION_PROMPT
263477
+ }], goalContinuationOrigin(origin), signal);
263478
+ else result = end;
263479
+ }
263480
+ return result;
263481
+ } catch (error) {
263482
+ if (origin.kind === "cron_job" && typeof origin.runId === "string") this.agent.cron?.observeRunWorkerFailed(origin.runId);
263483
+ throw error;
262510
263484
  } finally {
263485
+ if (result !== void 0 && origin.kind === "cron_job" && typeof origin.runId === "string") this.agent.cron?.observeRunWorkerEnded(origin.runId, result.event);
262511
263486
  if (ownsActiveTurn()) this.activeTurn = null;
262512
263487
  }
262513
263488
  }
@@ -262561,7 +263536,7 @@ var init_turn = __esmMin((() => {
262561
263536
  type: "text",
262562
263537
  text: GOAL_CONTINUATION_PROMPT
262563
263538
  }];
262564
- turnOrigin = GOAL_CONTINUATION_ORIGIN;
263539
+ turnOrigin = goalContinuationOrigin(origin);
262565
263540
  }
262566
263541
  }
262567
263542
  async endGoalTurnWithoutModel(turnId, input, origin) {
@@ -262609,6 +263584,7 @@ var init_turn = __esmMin((() => {
262609
263584
  this.currentStepByTurn.set(turnId, 0);
262610
263585
  this.recordExternalReportSources(turnId, origin);
262611
263586
  const persistedOrigin = durablePromptOrigin(origin);
263587
+ if (persistedOrigin.toolScope !== void 0) this.toolScopeByTurn.set(turnId, persistedOrigin.toolScope);
262612
263588
  this.agent.telemetry.track("turn_started", {
262613
263589
  mode: telemetryMode,
262614
263590
  ...this.requestProviderProps()
@@ -262716,6 +263692,7 @@ var init_turn = __esmMin((() => {
262716
263692
  if (ended.reason !== "completed") this.trackTurnInterrupted(turnId, this.currentStepByTurn.get(turnId) ?? this.currentStep);
262717
263693
  this.telemetryModeByTurn.delete(turnId);
262718
263694
  this.currentStepByTurn.delete(turnId);
263695
+ this.toolScopeByTurn.delete(turnId);
262719
263696
  this.interruptedTelemetryTurnIds.delete(turnId);
262720
263697
  this.cognitiveActionEvidenceByTurn.delete(turnId);
262721
263698
  this.cognitiveExternalReportsByTurn.delete(turnId);
@@ -262789,6 +263766,7 @@ var init_turn = __esmMin((() => {
262789
263766
  async runStepLoop(turnId, signal, input, origin) {
262790
263767
  let stopHookContinuationUsed = false;
262791
263768
  let goalOutcomeMessageContinuationUsed = false;
263769
+ let directSteerContinuationPending = false;
262792
263770
  const directReplyTurnStop = createDirectReplyTurnStop(blunExtractText(input));
262793
263771
  const deduper = new ToolCallDeduplicator({ telemetry: this.agent.telemetry });
262794
263772
  if (blunTurnNeedsInitialMcp(input, origin)) await blunWaitForInitialMcpBudget(this.agent.mcp, signal);
@@ -262812,13 +263790,14 @@ var init_turn = __esmMin((() => {
262812
263790
  let previousStepToolOutcome = "initial";
262813
263791
  let currentStepHadTool = false;
262814
263792
  let currentStepHadFailure = false;
263793
+ let currentLoopStep = 0;
262815
263794
  while (true) {
262816
263795
  signal.throwIfAborted();
262817
263796
  const model = this.agent.config.model;
262818
263797
  const loopControl = this.agent.blunConfig?.loopControl;
262819
263798
  let stopForGoalBudget = false;
262820
263799
  try {
262821
- const originTools = blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, this.agent.tools.loopTools), origin);
263800
+ const originTools = filterToolsForCronScope(blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, this.agent.tools.loopTools), origin), origin.toolScope);
262822
263801
  const compactConversationTool = originTools.find((tool) => tool.name === "CompactConversation");
262823
263802
  const eligibleTools = originTools.filter((tool) => tool.name !== "CompactConversation" || this.agent.fullCompaction.isProactiveCompactionEligible());
262824
263803
  const turnRequiredToolNames = new Set(requiredToolNames);
@@ -262844,12 +263823,13 @@ var init_turn = __esmMin((() => {
262844
263823
  eligibleToolSchemaTokens: estimateTokensForTools(eligibleTools),
262845
263824
  selectedToolSchemaTokens: estimateTokensForTools(selectedTools)
262846
263825
  });
263826
+ 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];
262847
263827
  return (await runTurn({
262848
263828
  turnId: String(turnId),
262849
263829
  signal,
262850
263830
  llm: turnLLM,
262851
- 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 }),
262852
- 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], {
263831
+ buildMessages: () => this.agent.context.project(blunRepeatActiveTurnPrompt(turnHistory(), input, currentLoopStep), { dropOrphanResults: true }),
263832
+ buildMessagesStrict: () => this.agent.context.project(blunRepeatActiveTurnPrompt(turnHistory(), input, currentLoopStep), {
262853
263833
  synthesizeMissing: true,
262854
263834
  dropOrphanResults: true,
262855
263835
  dedupeDuplicateToolCalls: true,
@@ -262870,6 +263850,7 @@ var init_turn = __esmMin((() => {
262870
263850
  },
262871
263851
  hooks: {
262872
263852
  beforeStep: async ({ signal: stepSignal, stepNumber }) => {
263853
+ currentLoopStep = stepNumber;
262873
263854
  await this.agent.records.flush();
262874
263855
  await this.agent.toolResultBatchOffload.detect();
262875
263856
  this.agent.microCompaction.detect();
@@ -262913,7 +263894,8 @@ var init_turn = __esmMin((() => {
262913
263894
  });
262914
263895
  return { llm: this.agent.llmForTurn(workStepThinkingEffort), tools: selectedTools };
262915
263896
  }
262916
- const steerEfforts = pendingSteers.map((steer) => blunTurnHasAttachment(steer.input) ? void 0 : selectThinkingEffortForBufferedSteer(blunExtractText(blunThinkingIntentInput(steer.input)), steer.origin.kind));
263897
+ if (pendingSteers.some((steer) => directMessageAllowsWorkContinuation(blunExtractText(steer.input)))) directSteerContinuationPending = true;
263898
+ const steerEfforts = pendingSteers.map((steer) => blunTurnHasAttachment(steer.input) ? void 0 : selectThinkingEffortForBufferedSteer(blunExtractText(blunThinkingIntentInput(steer.input)), steer.origin.kind));
262917
263899
  if (steerEfforts.some((effort) => effort === void 0)) return;
262918
263900
  const steerInput = pendingSteers.flatMap((steer) => [...steer.input]);
262919
263901
  const steerThinkingEffort = "low";
@@ -262959,10 +263941,22 @@ var init_turn = __esmMin((() => {
262959
263941
  deduper.endStep();
262960
263942
  return stopForGoalBudget || directReplyTurnStop.shouldStop() ? { stopTurn: true } : void 0;
262961
263943
  },
262962
- shouldContinueAfterStop: async (ctx) => {
262963
- const { signal } = ctx;
262964
- if (this.matchingSteers().length > 0) return { continue: true };
262965
- signal.throwIfAborted();
263944
+ shouldContinueAfterStop: async (ctx) => {
263945
+ const { signal } = ctx;
263946
+ if (this.matchingSteers().length > 0) return { continue: true };
263947
+ signal.throwIfAborted();
263948
+ if (directSteerContinuationPending) {
263949
+ directSteerContinuationPending = false;
263950
+ this.agent.context.appendUserMessage([{
263951
+ type: "text",
263952
+ text: "The private Telegram DM was handled. Continue the exact work that was active before it arrived. Do not re-read completed evidence; perform the next unfinished action now."
263953
+ }], {
263954
+ kind: "system_trigger",
263955
+ name: "telegram_direct_work_resume"
263956
+ });
263957
+ this.setActiveSteerAcceptance(turnId, true);
263958
+ return { continue: true };
263959
+ }
262966
263960
  if (!goalOutcomeMessageContinuationUsed && isGoalOutcomeReminderOrigin(this.agent.context.history.at(-1)?.origin)) {
262967
263961
  goalOutcomeMessageContinuationUsed = true;
262968
263962
  if (!hasStepBudgetRemaining(loopControl?.maxStepsPerTurn, ctx.stepNumber)) {
@@ -262997,6 +263991,8 @@ var init_turn = __esmMin((() => {
262997
263991
  prepareToolExecution: async (ctx) => {
262998
263992
  const todoTurnPolicy = enforceSingleTodoWritePerStep(ctx);
262999
263993
  if (todoTurnPolicy !== void 0) return todoTurnPolicy;
263994
+ const todoBoundsPolicy = enforceTodoListBounds(this.agent, ctx);
263995
+ if (todoBoundsPolicy !== void 0) return todoBoundsPolicy;
263000
263996
  const goalTodoPolicy = enforceGoalTodoPolicy(this.agent, ctx);
263001
263997
  if (goalTodoPolicy !== void 0) return goalTodoPolicy;
263002
263998
  const ideaPolicy = enforceIdeaToolPolicy(this.agent, ctx);
@@ -263092,6 +264088,7 @@ var init_turn = __esmMin((() => {
263092
264088
  buildDispatchEvent(turnId) {
263093
264089
  return createLoopEventDispatcher({
263094
264090
  appendTranscriptRecord: async (event) => {
264091
+ this.agent.cron?.observeLoopEvent(turnId, event);
263095
264092
  this.agent.context.appendLoopEvent(event);
263096
264093
  },
263097
264094
  emitLiveEvent: (event) => {
@@ -264119,20 +265116,16 @@ var init_codebase_search$1 = __esmMin((() => {
264119
265116
  * `CODEBASE_INDEX_SCRIPT` env override, then to a search from cwd.
264120
265117
  */
264121
265118
  function resolveScriptPath() {
264122
- const envPath = process.env["CODEBASE_INDEX_SCRIPT"];
264123
- if (envPath !== void 0 && envPath.length > 0) return envPath;
264124
- try {
264125
- return fileURLToPath(new URL("../../../../../codebase-index/codebase_index.py", import.meta.url));
264126
- } catch {}
264127
- return "";
265119
+ return resolveCodebaseIndexScript(import.meta.url, process.env["CODEBASE_INDEX_SCRIPT"]);
264128
265120
  }
264129
- var CodebaseSearchInputSchema, SCRIPT_TIMEOUT_MS, CodebaseSearchTool;
265121
+ var resolveCodebaseIndexScript, CodebaseSearchInputSchema, SCRIPT_TIMEOUT_MS, CodebaseSearchTool;
264130
265122
  var init_codebase_search = __esmMin((() => {
264131
265123
  init_zod$1();
264132
265124
  init_rule_match();
264133
265125
  init_input_schema();
264134
265126
  init_result_builder();
264135
265127
  init_codebase_search$1();
265128
+ ({ resolveCodebaseIndexScript } = createRequire(import.meta.url)("./bin/codebase-search-runtime.cjs"));
264136
265129
  CodebaseSearchInputSchema = object({
264137
265130
  query: string().min(1, "Query cannot be empty.").describe("A natural-language question or concept describing what the code does. Examples: \"keyboard event handling\", \"retry with exponential backoff\", \"where chat messages are routed to the model\"."),
264138
265131
  top: number$1().int().positive().default(5).describe("Maximum number of results to return. Defaults to 5.")
@@ -264153,7 +265146,7 @@ var init_codebase_search = __esmMin((() => {
264153
265146
  description: `Semantic search: ${args.query.length > 50 ? `${args.query.slice(0, 50)}…` : args.query}`,
264154
265147
  display: {
264155
265148
  kind: "command",
264156
- command: `python codebase_index.py query . "${args.query}" --top ${String(args.top)}`,
265149
+ command: `python codebase_index.py query . "${args.query}" --top ${String(args.top)} --model auto`,
264157
265150
  cwd: this.cwd,
264158
265151
  description: `Codebase semantic search`,
264159
265152
  language: "bash"
@@ -264173,7 +265166,9 @@ var init_codebase_search = __esmMin((() => {
264173
265166
  this.cwd,
264174
265167
  args.query,
264175
265168
  "--top",
264176
- String(args.top)
265169
+ String(args.top),
265170
+ "--model",
265171
+ "auto"
264177
265172
  ], {
264178
265173
  cwd: this.cwd,
264179
265174
  timeout: SCRIPT_TIMEOUT_MS,
@@ -264806,10 +265801,12 @@ var init_builtin = __esmMin((() => {
264806
265801
  init_task_list();
264807
265802
  init_task_output();
264808
265803
  init_task_update();
265804
+ init_task_resume();
264809
265805
  init_task_stop();
264810
265806
  init_cron_create();
264811
265807
  init_cron_delete();
264812
265808
  init_cron_list();
265809
+ init_cron_runs();
264813
265810
  init_agent$1();
264814
265811
  init_agent_swarm();
264815
265812
  init_ask_user();
@@ -264828,6 +265825,7 @@ var init_builtin = __esmMin((() => {
264828
265825
  init_exit_plan_mode();
264829
265826
  init_bash();
264830
265827
  init_todo_list();
265828
+ init_programmatic_tool();
264831
265829
  init_fetch_url();
264832
265830
  init_web_search();
264833
265831
  init_codebase_search();
@@ -265038,9 +266036,10 @@ var init_tool$1 = __esmMin((() => {
265038
266036
  hasUserTool(name) {
265039
266037
  return this.userTools.has(name);
265040
266038
  }
265041
- inheritUserTools(parent) {
266039
+ inheritUserTools(parent, excludedNames = /* @__PURE__ */ new Set()) {
265042
266040
  for (const tool of parent.userTools.values()) {
265043
266041
  if (!parent.enabledTools.has(tool.name)) continue;
266042
+ if (excludedNames.has(tool.name)) continue;
265044
266043
  this.registerUserTool({
265045
266044
  name: tool.name,
265046
266045
  description: tool.description,
@@ -265255,9 +266254,13 @@ var init_tool$1 = __esmMin((() => {
265255
266254
  }, this.agent.skills?.registry.getSkillRoots() ?? []);
265256
266255
  const allowBackground = this.enabledTools.has("TaskList") && this.enabledTools.has("TaskOutput") && this.enabledTools.has("TaskStop");
265257
266256
  const goalToolsEnabled = this.agent.type === "main";
266257
+ const readBudget = () => ({
266258
+ contextTokens: this.agent.context.tokenCountWithPending,
266259
+ maxContextTokens: this.agent.fullCompaction.getEffectiveMaxContextTokens()
266260
+ });
265258
266261
  this.builtinTools = new Map([
265259
- new ReadTool(kaos, workspace),
265260
- new ReadBatchTool(kaos, workspace),
266262
+ new ReadTool(kaos, workspace, readBudget),
266263
+ new ReadBatchTool(kaos, workspace, readBudget),
265261
266264
  new WriteTool(kaos, workspace, () => this.agent.context.history, toolServices?.lsp),
265262
266265
  new EditTool(kaos, workspace, () => this.agent.context.history, toolServices?.lsp),
265263
266266
  new GrepTool(kaos, workspace, this.agent.telemetry),
@@ -265272,13 +266275,17 @@ var init_tool$1 = __esmMin((() => {
265272
266275
  goalToolsEnabled && new UpdateGoalTool(this.agent),
265273
266276
  this.agent.rpc?.requestQuestion && new AskUserQuestionTool(this.agent),
265274
266277
  new TodoListTool(this.toolStore),
266278
+ new ProgrammaticTool(),
265275
266279
  new CompactConversationTool(this.agent),
265276
266280
  new TaskListTool(background),
265277
266281
  new TaskOutputTool(background),
265278
266282
  new TaskUpdateTool(background),
266283
+ this.agent.subagentHost && allowBackground && background.resumeStore && new TaskResumeTool(background, this.agent.subagentHost),
265279
266284
  new TaskStopTool(background),
265280
266285
  this.agent.cron && new CronCreateTool(this.agent.cron),
265281
266286
  this.agent.cron && new CronListTool(this.agent.cron),
266287
+ this.agent.cron && new CronRunListTool(this.agent.cron),
266288
+ this.agent.cron && new CronRunOutputTool(this.agent.cron),
265282
266289
  this.agent.cron && new CronDeleteTool(this.agent.cron),
265283
266290
  this.agent.skills?.registry.listInvocableSkills().length && new SkillTool(this.agent),
265284
266291
  this.agent.subagentHost && new AgentTool(this.agent.subagentHost, background, DEFAULT_AGENT_PROFILES["agent"]?.subagents, {
@@ -265461,6 +266468,9 @@ var init_fallback_llm = __esmMin((() => {
265461
266468
  get capability() {
265462
266469
  return this.current.llm.capability;
265463
266470
  }
266471
+ get thinkingEffort() {
266472
+ return this.current.llm.thinkingEffort;
266473
+ }
265464
266474
  async prepareRequestBoundary(params, rebuildMessages) {
265465
266475
  params.signal.throwIfAborted();
265466
266476
  this.rebuildBoundaryMessages = rebuildMessages;
@@ -265722,7 +266732,7 @@ var init_agent = __esmMin((() => {
265722
266732
  ({ createEffectiveSystemPromptResolver } = createRequire(import.meta.url)("./bin/effective-system-prompt-cache-policy.cjs"));
265723
266733
  ({ resolveProviderIdleTimeoutMs } = createRequire(import.meta.url)("./bin/provider-idle-timeout-policy.cjs"));
265724
266734
  ({ capCompletionBudgetForAdaptiveEffort, capTurnCompletionTokens, selectThinkingEffortForBufferedSteer, selectThinkingEffortForWorkStep, selectThinkingEffortForTurn } = createRequire(import.meta.url)("./bin/turn-thinking-policy.cjs"));
265725
- PINNED_MODEL_ALIASES = new Set(["king-blun", "pruefstand"]);
266735
+ PINNED_MODEL_ALIASES = new Set(["blun/king"]);
265726
266736
  Agent$1 = class {
265727
266737
  type;
265728
266738
  _kaos;
@@ -266264,6 +267274,7 @@ var init_agent = __esmMin((() => {
266264
267274
  }
266265
267275
  emitEvent(event) {
266266
267276
  if (this.records.restoring) return;
267277
+ this.cron?.observeAgentEvent(event);
266267
267278
  return this.rpc?.emitEvent?.(event);
266268
267279
  }
266269
267280
  emitStatusUpdated() {
@@ -298124,7 +299135,9 @@ var init_session$1 = __esmMin((() => {
298124
299135
  homedir,
298125
299136
  type,
298126
299137
  parentAgentId,
298127
- swarmItem: options.swarmItem
299138
+ swarmItem: options.swarmItem,
299139
+ profileName: options.profileName,
299140
+ skillPolicy: options.skillPolicy
298128
299141
  };
298129
299142
  this.writeMetadata();
298130
299143
  }
@@ -298400,7 +299413,7 @@ var init_session$1 = __esmMin((() => {
298400
299413
  missingCapability: part.missingCapability
298401
299414
  });
298402
299415
  },
298403
- skills: this.skills,
299416
+ skills: config.skillRegistry === void 0 ? this.skills : config.skillRegistry,
298404
299417
  rpc: proxyWithExtraPayload(this.rpc, { agentId: id }),
298405
299418
  modelProvider: this.options.providerManager,
298406
299419
  hookEngine: config.hookEngine ?? this.hookEngine,
@@ -298465,9 +299478,16 @@ var init_session$1 = __esmMin((() => {
298465
299478
  const parentAgentId = meta.parentAgentId ?? null;
298466
299479
  const parent = parentAgentId === null ? void 0 : await this.resumeAgent(parentAgentId, [...stack, id]);
298467
299480
  try {
298468
- const agent = this.instantiateAgent(id, meta.homedir, meta.type, {}, parentAgentId);
299481
+ let restoredSkillPolicy;
299482
+ if (meta.type === "sub" && meta.skillPolicy !== void 0) {
299483
+ if (meta.profileName === void 0) throw new Error("SUBAGENT_SKILL_POLICY_CHANGED: persisted subagent profile is unavailable; spawn a new subagent");
299484
+ const persistedProfile = DEFAULT_AGENT_PROFILES[parent?.agent.config.profileName ?? "agent"]?.subagents?.[meta.profileName] ?? DEFAULT_AGENT_PROFILES["agent"]?.subagents?.[meta.profileName];
299485
+ if (persistedProfile === void 0) throw new Error("SUBAGENT_SKILL_POLICY_CHANGED: persisted subagent profile was not found; spawn a new subagent");
299486
+ restoredSkillPolicy = restoreSubagentSkillPolicy(persistedProfile.subagentSkills, meta.skillPolicy, this.skills);
299487
+ }
299488
+ const agent = this.instantiateAgent(id, meta.homedir, meta.type, restoredSkillPolicy === void 0 ? {} : { skillRegistry: restoredSkillPolicy.registry }, parentAgentId);
298469
299489
  const result = await agent.resume();
298470
- await this.restoreAgentProfileHandle(agent, meta, parent?.agent);
299490
+ await this.restoreAgentProfileHandle(agent, meta, parent?.agent, restoredSkillPolicy);
298471
299491
  this.ensureBaselineSkill(agent);
298472
299492
  agent.setRuntimeSystemPromptAppend(this.accountMemoryContext);
298473
299493
  this.agents.set(id, agent);
@@ -298480,18 +299500,33 @@ var init_session$1 = __esmMin((() => {
298480
299500
  throw error;
298481
299501
  }
298482
299502
  }
298483
- async restoreAgentProfileHandle(agent, meta, parentAgent) {
299503
+ async restoreAgentProfileHandle(agent, meta, parentAgent, restoredSkillPolicy) {
298484
299504
  if (agent.config.systemPrompt === "") return;
298485
- const profile = this.resolvePersistedProfile(agent, meta, parentAgent);
299505
+ let profile = this.resolvePersistedProfile(agent, meta, parentAgent);
298486
299506
  if (profile === void 0) return;
299507
+ if (restoredSkillPolicy !== void 0) profile = profileWithSubagentSkillTools(profile, restoredSkillPolicy);
298487
299508
  agent.setActiveProfile(profile, this.options.blunHomeDir);
298488
299509
  await agent.refreshSystemPrompt();
298489
299510
  }
298490
299511
  ensureBaselineSkill(agent) {
298491
- if (agent.skills?.ensureBaseline(BASELINE_SKILL_NAME) !== true) this.log.warn("baseline skill is unavailable", { skill: BASELINE_SKILL_NAME });
299512
+ const skill = this.skills.getSkill(BASELINE_SKILL_NAME);
299513
+ if (skill === void 0) {
299514
+ this.log.warn("baseline skill is unavailable", { skill: BASELINE_SKILL_NAME });
299515
+ return;
299516
+ }
299517
+ const variant = `${BASELINE_SKILL_ORIGIN_PREFIX}${skill.name}`;
299518
+ if (agent.context.history.some((message) => message.origin?.kind === "injection" && message.origin.variant === variant)) return;
299519
+ agent.context.appendSystemReminder(renderBaselineSkillPrompt({
299520
+ skillName: skill.name,
299521
+ skillSource: skill.source,
299522
+ skillDir: skill.dir
299523
+ }), {
299524
+ kind: "injection",
299525
+ variant
299526
+ });
298492
299527
  }
298493
299528
  resolvePersistedProfile(agent, meta, parentAgent) {
298494
- const profileName = agent.config.profileName;
299529
+ const profileName = meta.profileName ?? agent.config.profileName;
298495
299530
  if (profileName === void 0) return void 0;
298496
299531
  if (meta.type === "sub") return DEFAULT_AGENT_PROFILES[parentAgent?.config.profileName ?? "agent"]?.subagents?.[profileName] ?? DEFAULT_AGENT_PROFILES["agent"]?.subagents?.[profileName];
298497
299532
  return DEFAULT_AGENT_PROFILES[profileName];
@@ -313280,27 +314315,14 @@ var init_local_fetch_url = __esmMin((() => {
313280
314315
  kind: "passthrough"
313281
314316
  };
313282
314317
  return {
313283
- content: this.extractMainContent(body),
314318
+ content: this.extractMainContent(body, url),
313284
314319
  kind: "extracted"
313285
314320
  };
313286
314321
  }
313287
- extractMainContent(html) {
313288
- const primary = parseHTML(html);
313289
- try {
313290
- const article = new import_readability.Readability(primary.document, { charThreshold: 0 }).parse();
313291
- if (article !== null) {
313292
- const text = (article.textContent ?? "").trim();
313293
- if (text.length > 0) {
313294
- const title = (article.title ?? "").trim();
313295
- return title.length > 0 ? `# ${title}\n\n${text}` : text;
313296
- }
313297
- }
313298
- } catch {}
313299
- const { document } = parseHTML(html);
313300
- const titleText = (document.querySelector("title")?.textContent ?? "").trim();
313301
- const fallbackText = ((document.querySelector("article") ?? document.querySelector("main") ?? document.querySelector("body"))?.textContent ?? "").trim();
313302
- if (fallbackText.length === 0) throw new Error("Failed to extract meaningful content from the page. The page may require JavaScript to render.");
313303
- return titleText.length > 0 ? `# ${titleText}\n\n${fallbackText}` : fallbackText;
314322
+ extractMainContent(html, baseUrl) {
314323
+ const content = htmlToResearchMarkdown(html, baseUrl);
314324
+ if (content.length === 0) throw new Error("Failed to extract meaningful content from the page. The page may require JavaScript to render.");
314325
+ return content;
313304
314326
  }
313305
314327
  };
313306
314328
  }));
@@ -314837,7 +315859,7 @@ var init_provider_manager = __esmMin((() => {
314837
315859
  init_config$4();
314838
315860
  init_errors$8();
314839
315861
  MANAGED_PROVIDER_NAME$2 = "managed:blun";
314840
- MANAGED_BLUN_MODEL_ALIASES$1 = new Set(["blun/king", "king-blun"]);
315862
+ MANAGED_BLUN_MODEL_ALIASES$1 = new Set(["blun/king"]);
314841
315863
  ProviderManager = class {
314842
315864
  options;
314843
315865
  runtimeModelContexts = /* @__PURE__ */ new Map();
@@ -314878,7 +315900,7 @@ var init_provider_manager = __esmMin((() => {
314878
315900
  if (!Number.isSafeInteger(input.maxContextTokens) || input.maxContextTokens <= 0) throw new BlunError(ErrorCodes.CONFIG_INVALID, "Runtime model context must be a positive integer.");
314879
315901
  const alias = this.config.models?.[input.modelAlias];
314880
315902
  const providerName = alias?.provider ?? this.config.defaultProvider;
314881
- 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.");
315903
+ 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.");
314882
315904
  const previous = this.runtimeModelContexts.get(input.modelAlias);
314883
315905
  this.runtimeModelContexts.set(input.modelAlias, {
314884
315906
  providerName: input.providerName,
@@ -319113,6 +320135,7 @@ function toBrokerRequest$1(req, params) {
319113
320135
  tool_name: req.toolName,
319114
320136
  action: req.action,
319115
320137
  tool_input_display: req.display,
320138
+ allow_edit: req.allowEdit === true ? true : void 0,
319116
320139
  created_at: params.createdAt,
319117
320140
  expires_at: params.expiresAt
319118
320141
  };
@@ -319127,7 +320150,8 @@ function toAgentCoreResponse$1(resp) {
319127
320150
  decision: resp.decision,
319128
320151
  scope: resp.scope,
319129
320152
  feedback: resp.feedback,
319130
- selectedLabel: resp.selected_label
320153
+ selectedLabel: resp.selected_label,
320154
+ edited_tool_input: resp.edited_tool_input
319131
320155
  };
319132
320156
  }
319133
320157
  var IApprovalService;
@@ -372834,16 +373858,18 @@ var PendingApproval = class {
372834
373858
  createdAt;
372835
373859
  expiresAt;
372836
373860
  protocolRequest;
373861
+ editContext;
372837
373862
  _resolveFn;
372838
373863
  _rejectFn;
372839
373864
  _settled = false;
372840
- constructor(approvalId, sessionId, toolCallId, createdAt, expiresAt, protocolRequest, _resolveFn, _rejectFn) {
373865
+ constructor(approvalId, sessionId, toolCallId, createdAt, expiresAt, protocolRequest, editContext, _resolveFn, _rejectFn) {
372841
373866
  this.approvalId = approvalId;
372842
373867
  this.sessionId = sessionId;
372843
373868
  this.toolCallId = toolCallId;
372844
373869
  this.createdAt = createdAt;
372845
373870
  this.expiresAt = expiresAt;
372846
373871
  this.protocolRequest = protocolRequest;
373872
+ this.editContext = editContext;
372847
373873
  this._resolveFn = _resolveFn;
372848
373874
  this._rejectFn = _rejectFn;
372849
373875
  }
@@ -372917,7 +373943,10 @@ let ApprovalService = class ApprovalService extends Disposable {
372917
373943
  toolCallId: req.toolCallId
372918
373944
  }, "approval requested");
372919
373945
  return new Promise((resolve, reject) => {
372920
- this._pending.set(approvalId, new PendingApproval(approvalId, req.sessionId, req.toolCallId, createdAt, expiresAt, protocolRequest, resolve, reject));
373946
+ this._pending.set(approvalId, new PendingApproval(approvalId, req.sessionId, req.toolCallId, createdAt, expiresAt, protocolRequest, {
373947
+ toolName: req.toolName,
373948
+ editCount: Number.isSafeInteger(req.approvalEditCount) ? req.approvalEditCount : 0
373949
+ }, resolve, reject));
372921
373950
  this._byToolCallId.set(req.toolCallId, approvalId);
372922
373951
  });
372923
373952
  }
@@ -372946,6 +373975,14 @@ let ApprovalService = class ApprovalService extends Disposable {
372946
373975
  isPending(approvalId) {
372947
373976
  return this._pending.has(approvalId);
372948
373977
  }
373978
+ getEditContext(approvalId) {
373979
+ const pending = this._pending.get(approvalId);
373980
+ if (!pending) return void 0;
373981
+ return {
373982
+ toolName: pending.editContext.toolName,
373983
+ editCount: pending.editContext.editCount
373984
+ };
373985
+ }
372949
373986
  listPending(sessionId) {
372950
373987
  return Array.from(this._pending.values()).filter((p) => p.sessionId === sessionId).map((p) => p.protocolRequest);
372951
373988
  }
@@ -372988,6 +374025,24 @@ const approvalParamsSchema = object({
372988
374025
  session_id: string().min(1),
372989
374026
  approval_id: string().min(1)
372990
374027
  });
374028
+ const EDITABLE_APPROVAL_RAW_BODY_LIMIT = 65536;
374029
+ async function captureEditableApprovalRawBody(req, reply, payload) {
374030
+ const chunks = [];
374031
+ let totalBytes = 0;
374032
+ for await (const chunk of payload) {
374033
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
374034
+ totalBytes += bytes.length;
374035
+ if (totalBytes > EDITABLE_APPROVAL_RAW_BODY_LIMIT) {
374036
+ const error = new Error("Approval response body exceeds the editable-input limit");
374037
+ error.statusCode = 413;
374038
+ throw error;
374039
+ }
374040
+ chunks.push(bytes);
374041
+ }
374042
+ const rawBody = Buffer.concat(chunks, totalBytes);
374043
+ req.editableApprovalRawBody = rawBody.toString("utf8");
374044
+ return Readable.from([rawBody]);
374045
+ }
372991
374046
  function registerApprovalsRoutes(app, ix) {
372992
374047
  const listRoute = defineRoute({
372993
374048
  method: "GET",
@@ -373032,7 +374087,27 @@ function registerApprovalsRoutes(app, ix) {
373032
374087
  reply.send(errEnvelope(ErrorCode$1.APPROVAL_NOT_FOUND, `approval ${approval_id} not found`, req.id));
373033
374088
  return;
373034
374089
  }
373035
- const inProc = toAgentCoreResponse$1(body);
374090
+ const editContext = broker.getEditContext(approval_id);
374091
+ if (editContext === void 0 || typeof req.editableApprovalRawBody !== "string") {
374092
+ reply.send(errEnvelope(ErrorCode$1.VALIDATION_FAILED, "approval response could not be validated from its raw JSON body", req.id));
374093
+ return;
374094
+ }
374095
+ let inProc;
374096
+ try {
374097
+ const rawResponse = parseEditedToolInputJson(req.editableApprovalRawBody);
374098
+ const normalized = validateEditedApprovalDecision({
374099
+ response: rawResponse,
374100
+ toolName: editContext.toolName,
374101
+ editCount: editContext.editCount
374102
+ });
374103
+ inProc = normalized.decision === "edited" ? {
374104
+ decision: "edited",
374105
+ edited_tool_input: normalized.editedToolInput
374106
+ } : normalized;
374107
+ } catch (error) {
374108
+ reply.send(errEnvelope(ErrorCode$1.VALIDATION_FAILED, error instanceof Error ? error.message : String(error), req.id));
374109
+ return;
374110
+ }
373036
374111
  broker.resolve(approval_id, inProc);
373037
374112
  broker.markResolved(approval_id);
373038
374113
  const result = {
@@ -373041,6 +374116,7 @@ function registerApprovalsRoutes(app, ix) {
373041
374116
  };
373042
374117
  reply.send(okEnvelope(result, req.id));
373043
374118
  });
374119
+ route.options.preParsing = captureEditableApprovalRawBody;
373044
374120
  app.post(route.path, route.options, route.handler);
373045
374121
  }
373046
374122
  //#endregion
@@ -402988,7 +404064,7 @@ function createProgram(version, onMain, onPluginNodeRunner = () => {}) {
402988
404064
  "high",
402989
404065
  "xhigh",
402990
404066
  "max"
402991
- ])).addOption(new Option("--permission-mode <mode>", "Permission mode for this invocation (auto, manual, yolo).").choices([
404067
+ ])).option("--swarm", "Start in swarm mode.", false).addOption(new Option("--permission-mode <mode>", "Permission mode for this invocation (auto, manual, yolo).").choices([
402992
404068
  "auto",
402993
404069
  "manual",
402994
404070
  "yolo"
@@ -403022,6 +404098,7 @@ function createProgram(version, onMain, onPluginNodeRunner = () => {}) {
403022
404098
  plan: raw["plan"],
403023
404099
  model: raw["model"],
403024
404100
  effort: raw["effort"],
404101
+ swarm: raw["swarm"] === true,
403025
404102
  permissionMode: raw["permissionMode"],
403026
404103
  forkSession: raw["forkSession"],
403027
404104
  outputFormat: raw["outputFormat"],
@@ -416599,7 +417676,7 @@ const EFFORT_STAGE_LABELS = {
416599
417676
  medium: "Deep",
416600
417677
  high: "Forge",
416601
417678
  xhigh: "Apex",
416602
- max: "Swarm"
417679
+ max: "Max"
416603
417680
  };
416604
417681
  const EFFORT_DISPLAY_LABEL_KEYS = {
416605
417682
  off: "effort.value.off",
@@ -416728,15 +417805,13 @@ var EffortSelectorComponent = class extends Container {
416728
417805
  }
416729
417806
  if (matchesKey(data, Key.alt("s")) && this.opts.onSessionOnlySelect !== void 0) {
416730
417807
  const effort = this.selectedEffort;
416731
- if (effort === "max" && this.usesLegacyServerStageScale && this.opts.onBlunSwarmSelect !== void 0) this.opts.onBlunSwarmSelect();
416732
- else if (effort !== void 0) this.opts.onSessionOnlySelect(effort);
417808
+ if (effort !== void 0) this.opts.onSessionOnlySelect(effort);
416733
417809
  return;
416734
417810
  }
416735
417811
  if (matchesKey(data, Key.enter)) if (this.isBlunSwarmSelected) this.opts.onBlunSwarmSelect?.();
416736
417812
  else {
416737
417813
  const effort = this.selectedEffort;
416738
- if (effort === "max" && this.usesLegacyServerStageScale && this.opts.onBlunSwarmSelect !== void 0) this.opts.onBlunSwarmSelect();
416739
- else if (effort !== void 0) this.opts.onSelect(effort);
417814
+ if (effort !== void 0) this.opts.onSelect(effort);
416740
417815
  }
416741
417816
  }
416742
417817
  render(width) {
@@ -416766,9 +417841,6 @@ var EffortSelectorComponent = class extends Container {
416766
417841
  get isBlunSwarmSelected() {
416767
417842
  return this.hasSeparatedBlunSwarm && this.activeIndex === this.efforts.length;
416768
417843
  }
416769
- get usesLegacyServerStageScale() {
416770
- return isServerStageScale(this.efforts);
416771
- }
416772
417844
  get hasSeparatedBlunSwarm() {
416773
417845
  return this.opts.onBlunSwarmSelect !== void 0 && !usesInlineStageScale(this.efforts);
416774
417846
  }
@@ -419762,7 +420834,7 @@ registerUiCatalogFragment({
419762
420834
  */
419763
420835
  var { projectUnaddressedTelegramContext } = createRequire(import.meta.url)("./bin/telegram-context-projection-policy.cjs");
419764
420836
  var { enqueueTelegramUrgent, rewriteTelegramUrgentEnvelope, telegramUrgentMessage } = createRequire(import.meta.url)("./bin/telegram-urgent-policy.cjs");
419765
- var { createDirectFocusController, createDirectReplyTurnStop, enqueueTelegramDirect, readDirectFocusCheckpoint, rewriteTelegramDirectEnvelope, telegramDirectMessage, writeDirectFocusCheckpoint } = createRequire(import.meta.url)("./bin/telegram-direct-focus-policy.cjs");
420837
+ var { createDirectFocusController, createDirectReplyTurnStop, directMessageAllowsWorkContinuation, enqueueTelegramDirect, readDirectFocusCheckpoint, rewriteTelegramDirectEnvelope, telegramDirectMessage, writeDirectFocusCheckpoint } = createRequire(import.meta.url)("./bin/telegram-direct-focus-policy.cjs");
419766
420838
  var { enqueueTelegramAddressed } = createRequire(import.meta.url)("./bin/telegram-addressed-priority.cjs");
419767
420839
  var { enqueueTelegramBotPriority, telegramBotPriorityMessage } = createRequire(import.meta.url)("./bin/telegram-bot-priority.cjs");
419768
420840
  var { createAddressedChannelFocusStore } = createRequire(import.meta.url)("./bin/telegram-addressed-focus.cjs");
@@ -421433,7 +422505,7 @@ async function performEffortSelection(host, alias, effort, persist) {
421433
422505
  host.setAppState({
421434
422506
  thinkingEffort: effort,
421435
422507
  modelFallbackAllowed: false,
421436
- swarmMode: false,
422508
+ swarmMode: input.cliOptions.swarm === true,
421437
422509
  swarmModeEntry: void 0
421438
422510
  });
421439
422511
  renderSwarmModeMarker(host, "inactive");
@@ -423409,7 +424481,6 @@ async function handleGoalCommand(host, args) {
423409
424481
  }
423410
424482
  const IDEA_CONTRACT_MARKER = "Work as a self-directing employee:";
423411
424483
  const IDEA_ALLOWED_CHANNELS = Object.freeze([]);
423412
- const GOAL_TODO_REFRESH_WORK_CALL_LIMIT = 8;
423413
424484
  const GOAL_TODO_EVIDENCE_LIMIT = 8;
423414
424485
  const TODO_MAINTENANCE_RECOVERY_TOOL_NAMES = new Set([
423415
424486
  "TodoList",
@@ -423435,6 +424506,22 @@ function ideaTodos(agent) {
423435
424506
  const value = agent.tools.store?.["todo"];
423436
424507
  return Array.isArray(value) ? value : [];
423437
424508
  }
424509
+ function goalTodoProgressState(agent) {
424510
+ return agent.goalTodoPolicyState ??= {
424511
+ workCallsSinceRefresh: 0,
424512
+ refreshRequired: false,
424513
+ unchangedRefreshStreak: 0,
424514
+ evidenceRevision: 0,
424515
+ lastMaintenanceEvidenceRevision: 0
424516
+ };
424517
+ }
424518
+ function enforceTodoListBounds(agent, context) {
424519
+ if (context.toolCall.name !== "TodoList" || !Array.isArray(context.args?.todos)) return;
424520
+ return assessTodoListBounds({
424521
+ currentTodos: ideaTodos(agent),
424522
+ nextTodos: context.args.todos
424523
+ });
424524
+ }
423438
424525
  function validInitialIdeaPlan(value) {
423439
424526
  if (!Array.isArray(value) || value.length === 0) return false;
423440
424527
  let active = 0;
@@ -423471,28 +424558,21 @@ function goalTodoEvidenceLabel(toolName, args, isError) {
423471
424558
  function recordGoalTodoEvidence(agent, toolName, args, isError) {
423472
424559
  if (isIdeaGoal(agent) || agent.goal.getActiveGoal() === null) return;
423473
424560
  const name = String(toolName ?? "");
423474
- const progress = agent.goalTodoPolicyState ??= {
423475
- workCallsSinceRefresh: 0,
423476
- refreshRequired: false
423477
- };
423478
- if (name === "TodoList") {
423479
- if (isError !== true) progress.recentEvidence = [];
423480
- return;
423481
- }
424561
+ const progress = goalTodoProgressState(agent);
424562
+ if (name === "TodoList") return;
423482
424563
  if (name === "UpdateGoal" || TELEGRAM_DELIVERY_TOOL_RE.test(name)) return;
423483
424564
  const recentEvidence = Array.isArray(progress.recentEvidence) ? progress.recentEvidence : [];
423484
424565
  recentEvidence.push(goalTodoEvidenceLabel(name, args, isError));
423485
424566
  progress.recentEvidence = recentEvidence.slice(-GOAL_TODO_EVIDENCE_LIMIT);
424567
+ progress.evidenceRevision = (Number(progress.evidenceRevision) || 0) + 1;
423486
424568
  }
423487
424569
  function goalTodoMaintenanceMode(agent) {
423488
424570
  if (isIdeaGoal(agent)) return null;
423489
424571
  const todos = ideaTodos(agent);
423490
424572
  if (todos.length === 0) return agent.goal.getActiveGoal() === null ? null : "initial";
423491
- const progress = agent.goalTodoPolicyState ??= {
423492
- workCallsSinceRefresh: 0,
423493
- refreshRequired: false
423494
- };
423495
- if (!progress.refreshRequired && progress.workCallsSinceRefresh < GOAL_TODO_REFRESH_WORK_CALL_LIMIT) return null;
424573
+ const progress = goalTodoProgressState(agent);
424574
+ const refreshWorkCallLimit = todoRefreshWorkCallLimit(progress.unchangedRefreshStreak);
424575
+ if (!progress.refreshRequired && progress.workCallsSinceRefresh < refreshWorkCallLimit) return null;
423496
424576
  progress.refreshRequired = true;
423497
424577
  return "refresh";
423498
424578
  }
@@ -423506,8 +424586,9 @@ function goalTodoMaintenanceTools(eligibleTools, selectedTools) {
423506
424586
  }
423507
424587
  function buildGoalTodoMaintenanceSystemPrompt(agent, mode) {
423508
424588
  const todos = ideaTodos(agent);
424589
+ const requireConcreteProgress = mode === "refresh" && (agent.goalTodoPolicyState?.unchangedRefreshStreak ?? 0) >= 2;
423509
424590
  const visibleTodoList = todos.length === 0 ? "The visible TodoList is empty." : ["Current visible TodoList:", ...todos.map((todo) => `- [${String(todo?.status ?? "pending")}] ${String(todo?.title ?? "").trim()}`)].join("\n");
423510
- const action = mode === "initial" ? "Create the visible task-specific TodoList now. Keep exactly one item in_progress and every later item pending." : "Update the visible TodoList now, before any more task work. Mark only evidenced steps done, keep the actual current step in_progress, and leave later steps pending. If the current title is stale, refine it to the concrete verified substep.";
424591
+ const action = mode === "initial" ? "Create the visible task-specific TodoList now. Keep exactly one item in_progress and every later item pending." : requireConcreteProgress ? "Recent TodoList refreshes stayed semantically unchanged despite new work-tool evidence. Make a truthful concrete transition now: mark evidenced items done, refine the active title to the next verified substep, or record blocked, waiting_approval, or aborted when that is the real state. If the available evidence proves no boundary, preserve the list unchanged; the call remains executable." : "Update the visible TodoList now, before any more task work. Mark only evidenced steps done, keep the actual current step in_progress, and leave later steps pending. If the current title is stale, refine it to the concrete verified substep.";
423511
424592
  return `<todo-maintenance>
423512
424593
  TODO MAINTENANCE IS THE ONLY ACTION FOR THIS STEP.
423513
424594
  ${action}
@@ -423519,11 +424600,12 @@ ${visibleTodoList}
423519
424600
  function buildGoalTodoMaintenanceMessages(agent, mode) {
423520
424601
  const goal = agent.goal.getActiveGoal();
423521
424602
  const todos = ideaTodos(agent);
424603
+ const requireConcreteProgress = mode === "refresh" && (agent.goalTodoPolicyState?.unchangedRefreshStreak ?? 0) >= 2;
423522
424604
  const recentEvidence = Array.isArray(agent.goalTodoPolicyState?.recentEvidence) ? agent.goalTodoPolicyState.recentEvidence.slice(-GOAL_TODO_EVIDENCE_LIMIT) : [];
423523
424605
  const objective = String(goal?.objective ?? "Continue the current multi-step task.").trim();
423524
424606
  const visibleTodoList = todos.length === 0 ? "The visible TodoList is empty." : ["Current visible TodoList:", ...todos.map((todo) => `- [${String(todo?.status ?? "pending")}] ${String(todo?.title ?? "").trim()}`)].join("\n");
423525
424607
  const verifiedEvidence = recentEvidence.length === 0 ? "No new work-tool evidence is available." : ["Recent bounded work-tool evidence since the last accepted TodoList:", ...recentEvidence.map((entry) => `- ${entry}`)].join("\n");
423526
- const action = mode === "initial" ? "Create the task-specific TodoList from the active objective. Keep exactly one item in_progress and every later item pending." : "Refresh the TodoList from the current verified state. Mark finished work done, keep the actual current step in_progress, and leave later work pending. Completed items disappear automatically after this call.";
424608
+ const action = mode === "initial" ? "Create the task-specific TodoList from the active objective. Keep exactly one item in_progress and every later item pending." : requireConcreteProgress ? "The recent refreshes stayed semantically unchanged despite new evidence. Make a truthful concrete transition now: finish evidenced items, refine the active title to the next verified substep, or use blocked, waiting_approval, or aborted when accurate. If no boundary is proven, preserve the list unchanged; never invent progress." : "Refresh the TodoList from the current verified state. Mark finished work done, keep the actual current step in_progress, and leave later work pending. Completed items disappear automatically after this call.";
423527
424609
  const request = [
423528
424610
  "Return exactly one TodoList tool call and no prose.",
423529
424611
  action,
@@ -423542,10 +424624,7 @@ function enforceGoalTodoPolicy(agent, context) {
423542
424624
  if (TELEGRAM_DELIVERY_TOOL_RE.test(String(context.toolCall.name ?? ""))) return;
423543
424625
  const activeGoal = agent.goal.getActiveGoal();
423544
424626
  const todos = ideaTodos(agent);
423545
- const progress = agent.goalTodoPolicyState ??= {
423546
- workCallsSinceRefresh: 0,
423547
- refreshRequired: false
423548
- };
424627
+ const progress = goalTodoProgressState(agent);
423549
424628
  if (todos.length === 0) {
423550
424629
  const startsTrackedList = context.toolCall.name === "TodoList" && Array.isArray(context.args?.todos) && context.args.todos.length > 0;
423551
424630
  if (activeGoal === null && !startsTrackedList) return;
@@ -423561,6 +424640,9 @@ function enforceGoalTodoPolicy(agent, context) {
423561
424640
  };
423562
424641
  progress.workCallsSinceRefresh = 0;
423563
424642
  progress.refreshRequired = false;
424643
+ progress.unchangedRefreshStreak = 0;
424644
+ progress.recentEvidence = [];
424645
+ progress.lastMaintenanceEvidenceRevision = Number(progress.evidenceRevision) || 0;
423564
424646
  progress.allVisibleWorkCompleted = false;
423565
424647
  return;
423566
424648
  }
@@ -423584,9 +424666,26 @@ function enforceGoalTodoPolicy(agent, context) {
423584
424666
  reason: "A maintained TodoList must keep exactly one item in_progress while unfinished work remains."
423585
424667
  };
423586
424668
  }
424669
+ const evidenceRevision = Number(progress.evidenceRevision) || 0;
424670
+ const lastMaintenanceEvidenceRevision = Number(progress.lastMaintenanceEvidenceRevision) || 0;
424671
+ const maintenanceUpdate = assessTodoMaintenanceUpdate({
424672
+ currentTodos: todos,
424673
+ nextTodos,
424674
+ unchangedRefreshStreak: progress.unchangedRefreshStreak,
424675
+ recentEvidenceCount: evidenceRevision > lastMaintenanceEvidenceRevision ? (progress.recentEvidence?.length ?? 0) : 0
424676
+ });
423587
424677
  progress.allVisibleWorkCompleted = nextTodos.length > 0 && nextTodos.every((todo) => todo?.status === "done");
423588
424678
  progress.workCallsSinceRefresh = 0;
423589
424679
  progress.refreshRequired = false;
424680
+ progress.unchangedRefreshStreak = maintenanceUpdate.unchangedRefreshStreak;
424681
+ progress.lastMaintenanceEvidenceRevision = evidenceRevision;
424682
+ if (!maintenanceUpdate.preserveRecentEvidence) progress.recentEvidence = [];
424683
+ if (maintenanceUpdate.emitStalledWarning) agent.emitEvent({
424684
+ type: "warning",
424685
+ code: "todo-maintenance-stalled",
424686
+ message: "TodoList stayed semantically unchanged across three evidence-bearing maintenance cycles. Work tools remain available; the next maintenance check is backed off while the active step is refined.",
424687
+ blocked: false
424688
+ });
423590
424689
  return;
423591
424690
  }
423592
424691
  if (activeGoal !== null && context.toolCall.name === "UpdateGoal" && (context.args?.status === "complete" || context.args?.status === "blocked")) {
@@ -423602,7 +424701,7 @@ function enforceGoalTodoPolicy(agent, context) {
423602
424701
  }
423603
424702
  if (context.toolCall.id === context.toolCalls[0]?.id) {
423604
424703
  progress.workCallsSinceRefresh += 1;
423605
- if (progress.workCallsSinceRefresh > GOAL_TODO_REFRESH_WORK_CALL_LIMIT) progress.refreshRequired = true;
424704
+ if (progress.workCallsSinceRefresh > todoRefreshWorkCallLimit(progress.unchangedRefreshStreak)) progress.refreshRequired = true;
423606
424705
  }
423607
424706
  if (!progress.refreshRequired) return;
423608
424707
  return {
@@ -432019,6 +433118,11 @@ function agentSwarmResultSummaryFromOutput(output) {
432019
433118
  };
432020
433119
  }
432021
433120
  function parseAgentSwarmResultStatuses(output) {
433121
+ const structured = parseStructuredSwarmDisplay(output);
433122
+ if (structured.recognized) return structured.statuses.map((entry) => ({
433123
+ ...entry,
433124
+ status: entry.status === "aborted" ? "cancelled" : entry.status
433125
+ }));
432022
433126
  const xmlStatuses = parseAgentSwarmXmlResultStatuses(output);
432023
433127
  if (xmlStatuses.length > 0) return xmlStatuses;
432024
433128
  return parseAgentSwarmLegacyResultStatuses(output);
@@ -499005,9 +500109,11 @@ registerUiCatalogFragment({
499005
500109
  "approval.search.scope": "scope: {scope}",
499006
500110
  "approval.backgroundTask": "{status} {kind} task {taskId}: {description}",
499007
500111
  "approval.hint.feedback": "Type feedback · ↵ submit.",
500112
+ "approval.hint.editArguments": "Enter the complete replacement JSON object · ↵ submit.",
499008
500113
  "approval.hint.main": "↑/↓ select · {numbers} choose · ↵ confirm{preview}",
499009
500114
  "approval.hint.preview": " · ctrl+e preview",
499010
500115
  "approval.choice.approveOnce": "Approve once",
500116
+ "approval.choice.editArguments": "Edit arguments (JSON)",
499011
500117
  "approval.choice.approveSession": "Approve for this session",
499012
500118
  "approval.choice.reject": "Reject",
499013
500119
  "approval.choice.rejectFeedback": "Reject with feedback",
@@ -499017,6 +500123,7 @@ registerUiCatalogFragment({
499017
500123
  "approval.transcript.approvedSession": "Approved for session",
499018
500124
  "approval.transcript.rejected": "Rejected",
499019
500125
  "approval.transcript.cancelled": "Cancelled",
500126
+ "approval.transcript.edited": "Arguments edited",
499020
500127
  "approval.transcript.action": "{decision}: {action}",
499021
500128
  "approval.transcript.actionWithFeedback": "{decision}: {action} — \"{feedback}\""
499022
500129
  },
@@ -499036,9 +500143,11 @@ registerUiCatalogFragment({
499036
500143
  "approval.search.scope": "Bereich: {scope}",
499037
500144
  "approval.backgroundTask": "Aufgabe {taskId} ({status}, {kind}): {description}",
499038
500145
  "approval.hint.feedback": "Feedback eingeben · ↵ absenden.",
500146
+ "approval.hint.editArguments": "Vollständiges Ersatz-JSON-Objekt eingeben · ↵ absenden.",
499039
500147
  "approval.hint.main": "↑/↓ auswählen · {numbers} wählen · ↵ bestätigen{preview}",
499040
500148
  "approval.hint.preview": " · ctrl+e Vorschau",
499041
500149
  "approval.choice.approveOnce": "Einmal genehmigen",
500150
+ "approval.choice.editArguments": "Argumente bearbeiten (JSON)",
499042
500151
  "approval.choice.approveSession": "Für diese Sitzung genehmigen",
499043
500152
  "approval.choice.reject": "Ablehnen",
499044
500153
  "approval.choice.rejectFeedback": "Ablehnen und Feedback geben",
@@ -499048,6 +500157,7 @@ registerUiCatalogFragment({
499048
500157
  "approval.transcript.approvedSession": "Für diese Sitzung genehmigt",
499049
500158
  "approval.transcript.rejected": "Abgelehnt",
499050
500159
  "approval.transcript.cancelled": "Abgebrochen",
500160
+ "approval.transcript.edited": "Argumente bearbeitet",
499051
500161
  "approval.transcript.action": "{decision}: {action}",
499052
500162
  "approval.transcript.actionWithFeedback": "{decision}: {action} – „{feedback}“"
499053
500163
  },
@@ -499067,9 +500177,11 @@ registerUiCatalogFragment({
499067
500177
  "approval.search.scope": "Ámbito: {scope}",
499068
500178
  "approval.backgroundTask": "Tarea {taskId} ({status}, {kind}): {description}",
499069
500179
  "approval.hint.feedback": "Escribe tus comentarios · ↵ enviar.",
500180
+ "approval.hint.editArguments": "Introduce el objeto JSON completo de sustitución · ↵ enviar.",
499070
500181
  "approval.hint.main": "↑/↓ seleccionar · {numbers} elegir · ↵ confirmar{preview}",
499071
500182
  "approval.hint.preview": " · ctrl+e vista previa",
499072
500183
  "approval.choice.approveOnce": "Aprobar una vez",
500184
+ "approval.choice.editArguments": "Editar argumentos (JSON)",
499073
500185
  "approval.choice.approveSession": "Aprobar durante esta sesión",
499074
500186
  "approval.choice.reject": "Rechazar",
499075
500187
  "approval.choice.rejectFeedback": "Rechazar y enviar comentarios",
@@ -499079,6 +500191,7 @@ registerUiCatalogFragment({
499079
500191
  "approval.transcript.approvedSession": "Aprobado durante esta sesión",
499080
500192
  "approval.transcript.rejected": "Rechazado",
499081
500193
  "approval.transcript.cancelled": "Cancelado",
500194
+ "approval.transcript.edited": "Argumentos modificados",
499082
500195
  "approval.transcript.action": "{decision}: {action}",
499083
500196
  "approval.transcript.actionWithFeedback": "{decision}: {action} — «{feedback}»"
499084
500197
  },
@@ -499098,9 +500211,11 @@ registerUiCatalogFragment({
499098
500211
  "approval.search.scope": "Portée : {scope}",
499099
500212
  "approval.backgroundTask": "Tâche {taskId} ({status}, {kind}) : {description}",
499100
500213
  "approval.hint.feedback": "Saisissez un commentaire · ↵ envoyer.",
500214
+ "approval.hint.editArguments": "Saisissez l’objet JSON de remplacement complet · ↵ envoyer.",
499101
500215
  "approval.hint.main": "↑/↓ sélectionner · {numbers} choisir · ↵ confirmer{preview}",
499102
500216
  "approval.hint.preview": " · ctrl+e aperçu",
499103
500217
  "approval.choice.approveOnce": "Approuver une fois",
500218
+ "approval.choice.editArguments": "Modifier les arguments (JSON)",
499104
500219
  "approval.choice.approveSession": "Approuver pour cette session",
499105
500220
  "approval.choice.reject": "Refuser",
499106
500221
  "approval.choice.rejectFeedback": "Refuser et ajouter un commentaire",
@@ -499110,6 +500225,7 @@ registerUiCatalogFragment({
499110
500225
  "approval.transcript.approvedSession": "Approuvé pour cette session",
499111
500226
  "approval.transcript.rejected": "Refusé",
499112
500227
  "approval.transcript.cancelled": "Annulé",
500228
+ "approval.transcript.edited": "Arguments modifiés",
499113
500229
  "approval.transcript.action": "{decision} : {action}",
499114
500230
  "approval.transcript.actionWithFeedback": "{decision} : {action} — « {feedback} »"
499115
500231
  },
@@ -499129,9 +500245,11 @@ registerUiCatalogFragment({
499129
500245
  "approval.search.scope": "Omfattning: {scope}",
499130
500246
  "approval.backgroundTask": "Uppgift {taskId} ({status}, {kind}): {description}",
499131
500247
  "approval.hint.feedback": "Skriv återkoppling · ↵ skicka.",
500248
+ "approval.hint.editArguments": "Ange hela JSON-objektet som ska ersätta det befintliga · ↵ skicka.",
499132
500249
  "approval.hint.main": "↑/↓ markera · {numbers} välj · ↵ bekräfta{preview}",
499133
500250
  "approval.hint.preview": " · ctrl+e förhandsgranska",
499134
500251
  "approval.choice.approveOnce": "Godkänn en gång",
500252
+ "approval.choice.editArguments": "Redigera argument (JSON)",
499135
500253
  "approval.choice.approveSession": "Godkänn för den här sessionen",
499136
500254
  "approval.choice.reject": "Avvisa",
499137
500255
  "approval.choice.rejectFeedback": "Avvisa och lämna återkoppling",
@@ -499141,6 +500259,7 @@ registerUiCatalogFragment({
499141
500259
  "approval.transcript.approvedSession": "Godkänt för den här sessionen",
499142
500260
  "approval.transcript.rejected": "Avvisat",
499143
500261
  "approval.transcript.cancelled": "Avbrutet",
500262
+ "approval.transcript.edited": "Argument redigerade",
499144
500263
  "approval.transcript.action": "{decision}: {action}",
499145
500264
  "approval.transcript.actionWithFeedback": "{decision}: {action} – ”{feedback}”"
499146
500265
  },
@@ -499324,7 +500443,7 @@ var ApprovalPanelComponent = class extends Container {
499324
500443
  if (!option) return;
499325
500444
  this.onResponse({
499326
500445
  response: option.response,
499327
- feedback: feedback || void 0,
500446
+ ...(option.input_kind === "edited_tool_input_json" ? { edited_tool_input_json: feedback } : { feedback: feedback || void 0 }),
499328
500447
  selected_label: option.selected_label
499329
500448
  });
499330
500449
  }
@@ -499334,6 +500453,7 @@ var ApprovalPanelComponent = class extends Container {
499334
500453
  if (option.requires_feedback === true) {
499335
500454
  this.selectedIndex = index;
499336
500455
  this.feedbackMode = true;
500456
+ if (option.input_kind === "edited_tool_input_json") this.feedbackInput.setValue(this.request.data.editable_tool_input_json ?? "{}");
499337
500457
  } else this.submit(index);
499338
500458
  }
499339
500459
  handleInput(data) {
@@ -499430,7 +500550,7 @@ var ApprovalPanelComponent = class extends Container {
499430
500550
  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)}`));
499431
500551
  }
499432
500552
  lines.push("");
499433
- if (this.feedbackMode) lines.push(indent(dim(uiText("approval.hint.feedback"))));
500553
+ if (this.feedbackMode) lines.push(indent(dim(uiText(this.choiceAt(this.selectedIndex)?.input_kind === "edited_tool_input_json" ? "approval.hint.editArguments" : "approval.hint.feedback"))));
499434
500554
  else {
499435
500555
  const expandHint = hasPreviewable ? uiText("approval.hint.preview") : "";
499436
500556
  lines.push(indent(dim(uiText("approval.hint.main", {
@@ -502687,12 +503807,18 @@ async function refreshAllProviderModels(host, options = {}) {
502687
503807
  }
502688
503808
  //#endregion
502689
503809
  //#region src/tui/reverse-rpc/approval/adapter.ts
502690
- function defaultApprovalChoices() {
503810
+ function defaultApprovalChoices(allowEdit = false) {
502691
503811
  return [
502692
503812
  {
502693
503813
  label: uiText("approval.choice.approveOnce"),
502694
503814
  response: "approved"
502695
503815
  },
503816
+ ...allowEdit ? [{
503817
+ label: uiText("approval.choice.editArguments"),
503818
+ response: "edited",
503819
+ requires_feedback: true,
503820
+ input_kind: "edited_tool_input_json"
503821
+ }] : [],
502696
503822
  {
502697
503823
  label: uiText("approval.choice.approveSession"),
502698
503824
  response: "approved_for_session"
@@ -502729,7 +503855,8 @@ function adaptApprovalRequest(event) {
502729
503855
  action: resolved.action ?? event.action,
502730
503856
  description: resolved.description,
502731
503857
  display: resolved.blocks,
502732
- choices: adaptChoices(event.toolName, event.display)
503858
+ choices: adaptChoices(event.toolName, event.display, event.allowEdit === true),
503859
+ editable_tool_input_json: event.allowEdit === true ? canonicalEditedToolInputJson(event.editableToolInput) : void 0
502733
503860
  };
502734
503861
  }
502735
503862
  function resolveDisplay(toolName, display, action) {
@@ -502833,6 +503960,10 @@ function inferFileOp(toolName) {
502833
503960
  return "read";
502834
503961
  }
502835
503962
  function adaptPanelResponse(response) {
503963
+ if (response.response === "edited") return {
503964
+ decision: "edited",
503965
+ edited_tool_input_json: response.edited_tool_input_json
503966
+ };
502836
503967
  if (response.response === "approved_for_session") return {
502837
503968
  decision: "approved",
502838
503969
  scope: "session",
@@ -502996,10 +504127,10 @@ function adaptDisplay(display) {
502996
504127
  default: return [];
502997
504128
  }
502998
504129
  }
502999
- function adaptChoices(toolName, display) {
504130
+ function adaptChoices(toolName, display, allowEdit = false) {
503000
504131
  if (toolName === "ExitPlanMode" || display.kind === "plan_review") return adaptPlanReviewChoices(display);
503001
504132
  if (display.kind === "goal_start") return adaptGoalStartChoices(display);
503002
- return defaultApprovalChoices();
504133
+ return defaultApprovalChoices(allowEdit);
503003
504134
  }
503004
504135
  function adaptGoalStartChoices(display) {
503005
504136
  return goalStartOptions(display.mode).map((option) => option.value === "cancel" ? {
@@ -503095,7 +504226,7 @@ function createApprovalRequestHandler(controller, onResponse, options = {}) {
503095
504226
  }).catch(() => {});
503096
504227
  }
503097
504228
  const response = await pending;
503098
- relay?.complete(response);
504229
+ relay?.complete(response.decision === "edited" ? { decision: "edited" } : response);
503099
504230
  onResponse?.(event, response);
503100
504231
  return response;
503101
504232
  } catch {
@@ -517611,6 +518742,8 @@ var BlunTUI = class {
517611
518742
  yolo: startupInput.cliOptions.yolo,
517612
518743
  auto: startupInput.cliOptions.auto,
517613
518744
  plan: startupInput.cliOptions.plan,
518745
+ effort: startupInput.cliOptions.effort,
518746
+ swarm: startupInput.cliOptions.swarm,
517614
518747
  model: startupInput.cliOptions.model,
517615
518748
  startupNotice: startupInput.startupNotice
517616
518749
  }
@@ -518027,6 +519160,7 @@ var BlunTUI = class {
518027
519160
  const createSessionOptions = {
518028
519161
  workDir,
518029
519162
  model: BLUN_KING_MODEL_ALIAS,
519163
+ thinking: startup.effort,
518030
519164
  permission: startup.auto ? "auto" : startup.yolo ? "yolo" : void 0,
518031
519165
  planMode: startup.plan ? true : void 0
518032
519166
  };
@@ -518073,7 +519207,7 @@ var BlunTUI = class {
518073
519207
  }
518074
519208
  }
518075
519209
  } else session = await this.harness.createSession(createSessionOptions);
518076
- if (session !== void 0 && shouldReplayHistory) await this.applyStartupModesToResumedSession(session);
519210
+ if (session !== void 0 && (shouldReplayHistory || startup.effort !== void 0 || startup.swarm)) await this.applyStartupModesToResumedSession(session);
518077
519211
  } catch (error) {
518078
519212
  if (!isOAuthLoginRequiredError(error)) throw error;
518079
519213
  this.authFlow.enterLoginRequiredStartupState();
@@ -519225,16 +520359,16 @@ var BlunTUI = class {
519225
520359
  };
519226
520360
  if (installedGuard !== void 0) this.pendingChannelReplyGuard = installedGuard;
519227
520361
  const imagePart = channelImagePath !== void 0 ? buildChannelImagePart(channelImagePath) : void 0;
519228
- this.setAppState({
519229
- model: BLUN_KING_MODEL_ALIAS,
519230
- modelFallbackAllowed: false
519231
- });
519232
520362
  const directNotice = channelDirect === true ? ["A private Telegram DM has priority over background, group, and loop work.", channelDirectResume === true ? "The user explicitly resumed work. Answer any remaining direct content, then continue the exact saved work checkpoint." : "The runtime saved the active work checkpoint. Answer the private conversation naturally, without exposing internal task, cron, checkpoint, queue, or lane narration. Unless the user explicitly asks to pause, stop, or wait, continue the exact saved work checkpoint automatically after the direct conversation."].join("\n") : void 0;
519233
520363
  const focusedModelInput = directNotice === void 0 ? modelInput : `${directNotice}\n\n${modelInput}`;
519234
520364
  const promptInput = imagePart !== void 0 && this.canReadImages() ? [{
519235
520365
  type: "text",
519236
520366
  text: focusedModelInput
519237
520367
  }, imagePart] : focusedModelInput;
520368
+ this.setAppState({
520369
+ model: BLUN_KING_MODEL_ALIAS,
520370
+ modelFallbackAllowed: false
520371
+ });
519238
520372
  session.promptAccepted(promptInput, channelPromptOrigin(channelReportSources)).then((result) => {
519239
520373
  if (result.duplicate === true) {
519240
520374
  this.traceTelegramDelivery?.({ stage: "committed", ...channelDeliveryTrace, route: "prompt", reason: "duplicate" });
@@ -519966,6 +521100,8 @@ var BlunTUI = class {
519966
521100
  const { startup } = this.options;
519967
521101
  if (startup.auto) await session.setPermission("auto");
519968
521102
  else if (startup.yolo) await session.setPermission("yolo");
521103
+ if (startup.effort !== void 0) await session.setThinking(startup.effort);
521104
+ if (startup.swarm && !(await session.getStatus()).swarmMode) await session.setSwarmMode(true, "effort");
519969
521105
  if (startup.plan) {
519970
521106
  if (!(await session.getStatus()).planMode) await session.setPlanMode(true);
519971
521107
  }
@@ -519974,6 +521110,8 @@ var BlunTUI = class {
519974
521110
  const { startup } = this.options;
519975
521111
  if (startup.auto) this.setAppState({ permissionMode: "auto" });
519976
521112
  else if (startup.yolo) this.setAppState({ permissionMode: "yolo" });
521113
+ if (startup.effort !== void 0) this.setAppState({ thinkingEffort: startup.effort });
521114
+ if (startup.swarm) this.setAppState({ swarmMode: true, swarmModeEntry: "effort" });
519977
521115
  if (startup.plan) this.setAppState({ planMode: true });
519978
521116
  }
519979
521117
  async activateRuntime() {
@@ -520286,6 +521424,9 @@ var BlunTUI = class {
520286
521424
  case "cancelled":
520287
521425
  decision = uiText("approval.transcript.cancelled");
520288
521426
  break;
521427
+ case "edited":
521428
+ decision = uiText("approval.transcript.edited");
521429
+ break;
520289
521430
  }
520290
521431
  const content = response.feedback !== void 0 && response.feedback.length > 0 ? uiText("approval.transcript.actionWithFeedback", {
520291
521432
  decision,