@namzu/sdk 62.6.0 → 62.7.0

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 (295) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/agents/QueryAgent.d.ts.map +1 -1
  3. package/dist/agents/QueryAgent.js +5 -0
  4. package/dist/agents/QueryAgent.js.map +1 -1
  5. package/dist/agents/examples/SupervisorAgent.d.ts.map +1 -1
  6. package/dist/agents/examples/SupervisorAgent.js +1 -0
  7. package/dist/agents/examples/SupervisorAgent.js.map +1 -1
  8. package/dist/agents/explore.d.ts.map +1 -1
  9. package/dist/agents/explore.js +2 -1
  10. package/dist/agents/explore.js.map +1 -1
  11. package/dist/compaction/index.d.ts +1 -1
  12. package/dist/compaction/index.d.ts.map +1 -1
  13. package/dist/compaction/index.js +1 -1
  14. package/dist/compaction/index.js.map +1 -1
  15. package/dist/compaction/model-summary.js +2 -2
  16. package/dist/compaction/model-summary.js.map +1 -1
  17. package/dist/compaction/summary.d.ts +16 -1
  18. package/dist/compaction/summary.d.ts.map +1 -1
  19. package/dist/compaction/summary.js +25 -2
  20. package/dist/compaction/summary.js.map +1 -1
  21. package/dist/config/runtime.d.ts +8 -0
  22. package/dist/config/runtime.d.ts.map +1 -1
  23. package/dist/config/runtime.js +15 -0
  24. package/dist/config/runtime.js.map +1 -1
  25. package/dist/execution/workflow/runtime.d.ts.map +1 -1
  26. package/dist/execution/workflow/runtime.js +3 -0
  27. package/dist/execution/workflow/runtime.js.map +1 -1
  28. package/dist/execution/workflow/types.d.ts +8 -0
  29. package/dist/execution/workflow/types.d.ts.map +1 -1
  30. package/dist/manager/agent/child-session.d.ts +12 -0
  31. package/dist/manager/agent/child-session.d.ts.map +1 -1
  32. package/dist/manager/agent/child-session.js +29 -0
  33. package/dist/manager/agent/child-session.js.map +1 -1
  34. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  35. package/dist/manager/agent/lifecycle.js +8 -0
  36. package/dist/manager/agent/lifecycle.js.map +1 -1
  37. package/dist/manager/session/turn-recorder.d.ts +13 -2
  38. package/dist/manager/session/turn-recorder.d.ts.map +1 -1
  39. package/dist/manager/session/turn-recorder.js +57 -3
  40. package/dist/manager/session/turn-recorder.js.map +1 -1
  41. package/dist/prompt/coding-agent-doctrine.d.ts +3 -3
  42. package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
  43. package/dist/prompt/coding-agent-doctrine.js +5 -3
  44. package/dist/prompt/coding-agent-doctrine.js.map +1 -1
  45. package/dist/provider/fallback.d.ts.map +1 -1
  46. package/dist/provider/fallback.js +5 -1
  47. package/dist/provider/fallback.js.map +1 -1
  48. package/dist/provider/retry.d.ts +25 -0
  49. package/dist/provider/retry.d.ts.map +1 -1
  50. package/dist/provider/retry.js +28 -0
  51. package/dist/provider/retry.js.map +1 -1
  52. package/dist/public-runtime.d.ts +3 -3
  53. package/dist/public-runtime.d.ts.map +1 -1
  54. package/dist/public-runtime.js +3 -3
  55. package/dist/public-runtime.js.map +1 -1
  56. package/dist/public-tools.d.ts +4 -2
  57. package/dist/public-tools.d.ts.map +1 -1
  58. package/dist/public-tools.js +5 -2
  59. package/dist/public-tools.js.map +1 -1
  60. package/dist/runtime/query/auto-review/classifier.d.ts +7 -1
  61. package/dist/runtime/query/auto-review/classifier.d.ts.map +1 -1
  62. package/dist/runtime/query/auto-review/classifier.js +8 -4
  63. package/dist/runtime/query/auto-review/classifier.js.map +1 -1
  64. package/dist/runtime/query/auto-review/prompt.d.ts.map +1 -1
  65. package/dist/runtime/query/auto-review/prompt.js +2 -0
  66. package/dist/runtime/query/auto-review/prompt.js.map +1 -1
  67. package/dist/runtime/query/auto-review/script-evidence.d.ts +93 -0
  68. package/dist/runtime/query/auto-review/script-evidence.d.ts.map +1 -0
  69. package/dist/runtime/query/auto-review/script-evidence.js +566 -0
  70. package/dist/runtime/query/auto-review/script-evidence.js.map +1 -0
  71. package/dist/runtime/query/checkpoint.d.ts +13 -0
  72. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  73. package/dist/runtime/query/checkpoint.js +37 -0
  74. package/dist/runtime/query/checkpoint.js.map +1 -1
  75. package/dist/runtime/query/executor.d.ts +38 -1
  76. package/dist/runtime/query/executor.d.ts.map +1 -1
  77. package/dist/runtime/query/executor.js +130 -11
  78. package/dist/runtime/query/executor.js.map +1 -1
  79. package/dist/runtime/query/finalize-turn.d.ts +7 -1
  80. package/dist/runtime/query/finalize-turn.d.ts.map +1 -1
  81. package/dist/runtime/query/finalize-turn.js +2 -0
  82. package/dist/runtime/query/finalize-turn.js.map +1 -1
  83. package/dist/runtime/query/index.d.ts +8 -0
  84. package/dist/runtime/query/index.d.ts.map +1 -1
  85. package/dist/runtime/query/index.js +7 -0
  86. package/dist/runtime/query/index.js.map +1 -1
  87. package/dist/runtime/query/iteration/index.d.ts +32 -1
  88. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  89. package/dist/runtime/query/iteration/index.js +158 -10
  90. package/dist/runtime/query/iteration/index.js.map +1 -1
  91. package/dist/runtime/query/iteration/phases/compaction.d.ts +12 -0
  92. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  93. package/dist/runtime/query/iteration/phases/compaction.js +48 -1
  94. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  95. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  96. package/dist/runtime/query/iteration/phases/context.js +5 -0
  97. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  98. package/dist/runtime/query/iteration/stream-turn.js +3 -3
  99. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  100. package/dist/runtime/query/prelude-lease.d.ts.map +1 -1
  101. package/dist/runtime/query/prelude-lease.js +22 -0
  102. package/dist/runtime/query/prelude-lease.js.map +1 -1
  103. package/dist/runtime/query/prepare-turn.d.ts.map +1 -1
  104. package/dist/runtime/query/prepare-turn.js +13 -4
  105. package/dist/runtime/query/prepare-turn.js.map +1 -1
  106. package/dist/runtime/query/review-policy.d.ts.map +1 -1
  107. package/dist/runtime/query/review-policy.js +29 -0
  108. package/dist/runtime/query/review-policy.js.map +1 -1
  109. package/dist/runtime/query/tooling.d.ts +2 -0
  110. package/dist/runtime/query/tooling.d.ts.map +1 -1
  111. package/dist/runtime/query/tooling.js +1 -0
  112. package/dist/runtime/query/tooling.js.map +1 -1
  113. package/dist/runtime/query/turn/completion-audit.d.ts +27 -1
  114. package/dist/runtime/query/turn/completion-audit.d.ts.map +1 -1
  115. package/dist/runtime/query/turn/completion-audit.js +71 -6
  116. package/dist/runtime/query/turn/completion-audit.js.map +1 -1
  117. package/dist/runtime/query/turn/outcome-ledger.d.ts +113 -0
  118. package/dist/runtime/query/turn/outcome-ledger.d.ts.map +1 -0
  119. package/dist/runtime/query/turn/outcome-ledger.js +578 -0
  120. package/dist/runtime/query/turn/outcome-ledger.js.map +1 -0
  121. package/dist/sandbox/file-walk.d.ts.map +1 -1
  122. package/dist/sandbox/file-walk.js +34 -17
  123. package/dist/sandbox/file-walk.js.map +1 -1
  124. package/dist/sandbox/glob-segment.d.ts +35 -0
  125. package/dist/sandbox/glob-segment.d.ts.map +1 -0
  126. package/dist/sandbox/glob-segment.js +300 -0
  127. package/dist/sandbox/glob-segment.js.map +1 -0
  128. package/dist/store/session-log/index.d.ts +1 -0
  129. package/dist/store/session-log/index.d.ts.map +1 -1
  130. package/dist/store/session-log/index.js +1 -0
  131. package/dist/store/session-log/index.js.map +1 -1
  132. package/dist/store/session-log/turn-outcome.d.ts +37 -0
  133. package/dist/store/session-log/turn-outcome.d.ts.map +1 -0
  134. package/dist/store/session-log/turn-outcome.js +77 -0
  135. package/dist/store/session-log/turn-outcome.js.map +1 -0
  136. package/dist/tools/builtins/bash.js +1 -1
  137. package/dist/tools/builtins/bash.js.map +1 -1
  138. package/dist/tools/builtins/edit-apply.d.ts.map +1 -1
  139. package/dist/tools/builtins/edit-apply.js +24 -3
  140. package/dist/tools/builtins/edit-apply.js.map +1 -1
  141. package/dist/tools/builtins/edit.d.ts +31 -17
  142. package/dist/tools/builtins/edit.d.ts.map +1 -1
  143. package/dist/tools/builtins/edit.js +92 -27
  144. package/dist/tools/builtins/edit.js.map +1 -1
  145. package/dist/tools/builtins/glob.js +1 -1
  146. package/dist/tools/builtins/glob.js.map +1 -1
  147. package/dist/tools/builtins/grep.js +1 -1
  148. package/dist/tools/builtins/grep.js.map +1 -1
  149. package/dist/tools/builtins/notebook-guard.d.ts +19 -0
  150. package/dist/tools/builtins/notebook-guard.d.ts.map +1 -0
  151. package/dist/tools/builtins/notebook-guard.js +75 -0
  152. package/dist/tools/builtins/notebook-guard.js.map +1 -0
  153. package/dist/tools/builtins/read-render.d.ts.map +1 -1
  154. package/dist/tools/builtins/read-render.js +8 -2
  155. package/dist/tools/builtins/read-render.js.map +1 -1
  156. package/dist/tools/builtins/write-file.d.ts.map +1 -1
  157. package/dist/tools/builtins/write-file.js +14 -1
  158. package/dist/tools/builtins/write-file.js.map +1 -1
  159. package/dist/tools/coordinator/agent.d.ts.map +1 -1
  160. package/dist/tools/coordinator/agent.js +25 -6
  161. package/dist/tools/coordinator/agent.js.map +1 -1
  162. package/dist/tools/coordinator/index.d.ts.map +1 -1
  163. package/dist/tools/coordinator/index.js +6 -1
  164. package/dist/tools/coordinator/index.js.map +1 -1
  165. package/dist/tools/coordinator/outcome-record.d.ts +22 -0
  166. package/dist/tools/coordinator/outcome-record.d.ts.map +1 -0
  167. package/dist/tools/coordinator/outcome-record.js +91 -0
  168. package/dist/tools/coordinator/outcome-record.js.map +1 -0
  169. package/dist/tools/defineTool.d.ts +2 -0
  170. package/dist/tools/defineTool.d.ts.map +1 -1
  171. package/dist/tools/defineTool.js +1 -0
  172. package/dist/tools/defineTool.js.map +1 -1
  173. package/dist/tools/file-read-tracker.d.ts +23 -2
  174. package/dist/tools/file-read-tracker.d.ts.map +1 -1
  175. package/dist/tools/file-read-tracker.js +37 -2
  176. package/dist/tools/file-read-tracker.js.map +1 -1
  177. package/dist/tools/untrusted-envelope.d.ts +6 -0
  178. package/dist/tools/untrusted-envelope.d.ts.map +1 -1
  179. package/dist/tools/untrusted-envelope.js +22 -1
  180. package/dist/tools/untrusted-envelope.js.map +1 -1
  181. package/dist/toolsets/manager.d.ts.map +1 -1
  182. package/dist/toolsets/manager.js +3 -4
  183. package/dist/toolsets/manager.js.map +1 -1
  184. package/dist/toolsets/validation-issues.d.ts +27 -0
  185. package/dist/toolsets/validation-issues.d.ts.map +1 -0
  186. package/dist/toolsets/validation-issues.js +83 -0
  187. package/dist/toolsets/validation-issues.js.map +1 -0
  188. package/dist/turn/memory-recall.d.ts +13 -0
  189. package/dist/turn/memory-recall.d.ts.map +1 -1
  190. package/dist/turn/memory-recall.js +18 -0
  191. package/dist/turn/memory-recall.js.map +1 -1
  192. package/dist/types/agent/base.d.ts +19 -0
  193. package/dist/types/agent/base.d.ts.map +1 -1
  194. package/dist/types/agent/query.d.ts +2 -0
  195. package/dist/types/agent/query.d.ts.map +1 -1
  196. package/dist/types/common/index.d.ts +17 -0
  197. package/dist/types/common/index.d.ts.map +1 -1
  198. package/dist/types/common/index.js +8 -1
  199. package/dist/types/common/index.js.map +1 -1
  200. package/dist/types/hitl/index.d.ts +22 -0
  201. package/dist/types/hitl/index.d.ts.map +1 -1
  202. package/dist/types/hitl/index.js.map +1 -1
  203. package/dist/types/session/config.d.ts +20 -0
  204. package/dist/types/session/config.d.ts.map +1 -1
  205. package/dist/types/session/events.d.ts +3 -3
  206. package/dist/types/session/events.d.ts.map +1 -1
  207. package/dist/types/session/index.d.ts +1 -0
  208. package/dist/types/session/index.d.ts.map +1 -1
  209. package/dist/types/session/index.js +1 -0
  210. package/dist/types/session/index.js.map +1 -1
  211. package/dist/types/session/outcome.d.ts +95 -0
  212. package/dist/types/session/outcome.d.ts.map +1 -0
  213. package/dist/types/session/outcome.js +45 -0
  214. package/dist/types/session/outcome.js.map +1 -0
  215. package/dist/types/session/prepare-step.d.ts +2 -0
  216. package/dist/types/session/prepare-step.d.ts.map +1 -1
  217. package/dist/types/session/records.d.ts +167 -2
  218. package/dist/types/session/records.d.ts.map +1 -1
  219. package/dist/types/session/records.js +42 -0
  220. package/dist/types/session/records.js.map +1 -1
  221. package/dist/types/session/turn.d.ts +18 -0
  222. package/dist/types/session/turn.d.ts.map +1 -1
  223. package/dist/types/session/turn.js.map +1 -1
  224. package/dist/types/tool/index.d.ts +30 -0
  225. package/dist/types/tool/index.d.ts.map +1 -1
  226. package/dist/types/tool/index.js.map +1 -1
  227. package/package.json +2 -2
  228. package/src/agents/QueryAgent.ts +5 -0
  229. package/src/agents/examples/SupervisorAgent.ts +1 -0
  230. package/src/agents/explore.ts +2 -1
  231. package/src/compaction/index.ts +1 -0
  232. package/src/compaction/model-summary.ts +2 -2
  233. package/src/compaction/summary.ts +30 -2
  234. package/src/config/runtime.ts +15 -0
  235. package/src/execution/workflow/runtime.ts +4 -0
  236. package/src/execution/workflow/types.ts +9 -0
  237. package/src/manager/agent/child-session.ts +36 -0
  238. package/src/manager/agent/lifecycle.ts +9 -0
  239. package/src/manager/session/turn-recorder.ts +62 -3
  240. package/src/pricing/rates.source.json +1 -1
  241. package/src/prompt/coding-agent-doctrine.ts +5 -3
  242. package/src/provider/fallback.ts +6 -1
  243. package/src/provider/retry.ts +51 -0
  244. package/src/public-runtime.ts +10 -1
  245. package/src/public-tools.ts +6 -1
  246. package/src/runtime/query/auto-review/classifier.ts +21 -5
  247. package/src/runtime/query/auto-review/prompt.ts +2 -0
  248. package/src/runtime/query/auto-review/script-evidence.ts +618 -0
  249. package/src/runtime/query/checkpoint.ts +53 -1
  250. package/src/runtime/query/executor.ts +159 -19
  251. package/src/runtime/query/finalize-turn.ts +8 -1
  252. package/src/runtime/query/index.ts +19 -0
  253. package/src/runtime/query/iteration/index.ts +167 -14
  254. package/src/runtime/query/iteration/phases/compaction.ts +53 -3
  255. package/src/runtime/query/iteration/phases/context.ts +6 -0
  256. package/src/runtime/query/iteration/stream-turn.ts +3 -3
  257. package/src/runtime/query/prelude-lease.ts +19 -0
  258. package/src/runtime/query/prepare-turn.ts +13 -4
  259. package/src/runtime/query/review-policy.ts +33 -0
  260. package/src/runtime/query/tooling.ts +3 -0
  261. package/src/runtime/query/turn/completion-audit.ts +76 -5
  262. package/src/runtime/query/turn/outcome-ledger.ts +633 -0
  263. package/src/sandbox/file-walk.ts +38 -17
  264. package/src/sandbox/glob-segment.ts +309 -0
  265. package/src/store/session-log/index.ts +7 -0
  266. package/src/store/session-log/turn-outcome.ts +84 -0
  267. package/src/tools/builtins/bash.ts +1 -1
  268. package/src/tools/builtins/edit-apply.ts +26 -4
  269. package/src/tools/builtins/edit.ts +106 -41
  270. package/src/tools/builtins/glob.ts +1 -1
  271. package/src/tools/builtins/grep.ts +1 -1
  272. package/src/tools/builtins/notebook-guard.ts +76 -0
  273. package/src/tools/builtins/read-render.ts +12 -2
  274. package/src/tools/builtins/write-file.ts +12 -1
  275. package/src/tools/coordinator/agent.ts +31 -7
  276. package/src/tools/coordinator/index.ts +6 -1
  277. package/src/tools/coordinator/outcome-record.ts +93 -0
  278. package/src/tools/defineTool.ts +3 -0
  279. package/src/tools/file-read-tracker.ts +51 -2
  280. package/src/tools/untrusted-envelope.ts +23 -1
  281. package/src/toolsets/manager.ts +6 -10
  282. package/src/toolsets/validation-issues.ts +97 -0
  283. package/src/turn/memory-recall.ts +28 -0
  284. package/src/types/agent/base.ts +20 -0
  285. package/src/types/agent/query.ts +2 -0
  286. package/src/types/common/index.ts +25 -1
  287. package/src/types/hitl/index.ts +27 -0
  288. package/src/types/session/config.ts +20 -0
  289. package/src/types/session/events.ts +3 -3
  290. package/src/types/session/index.ts +1 -0
  291. package/src/types/session/outcome.ts +139 -0
  292. package/src/types/session/prepare-step.ts +2 -0
  293. package/src/types/session/records.ts +67 -1
  294. package/src/types/session/turn.ts +19 -0
  295. package/src/types/tool/index.ts +30 -0
@@ -27,6 +27,7 @@ import { compressShellOutput } from '../../utils/shell-compress.js';
27
27
  import { parseStructuredResultJson } from '../../utils/structured-result-json.js';
28
28
  import { ensureScratchpadDirectory } from '../../utils/temp.js';
29
29
  import { bindOwner } from '../jobs/registry.js';
30
+ import { analyzeLaunches, changedSinceRead, readLaunchedScripts, } from './auto-review/script-evidence.js';
30
31
  import { stillRunningResult } from './detached-calls.js';
31
32
  import { formatFailedToolOutput, hookNote, isUnregistered, prepareDirectCall, runPreToolHook, unknownToolMessage, } from './executor/tool-call-admission.js';
32
33
  import { describeVisibleFileEvidence, visibleFileEvidence, } from './file-evidence-context.js';
@@ -252,6 +253,9 @@ export class ToolExecutor {
252
253
  toolCallBudget;
253
254
  preparedBatches = new WeakSet();
254
255
  preparedBashDirectories = new WeakMap();
256
+ /** Script files a classifier read for a call, by call id, to be checked again when it runs. */
257
+ reviewedScripts = new Map();
258
+ startedAt = Date.now();
255
259
  /** Ephemeral proof of actual execution; restored messages do not acquire it. */
256
260
  recordedObservations = new Map();
257
261
  /** Set per turn by the orchestrator; see {@link setStepAllowedTools}. */
@@ -463,6 +467,44 @@ export class ToolExecutor {
463
467
  fileEvidenceEntries(messages) {
464
468
  return visibleFileEvidence(messages, this.fileReadTracker, this.config.workingDirectory, this.sandboxed);
465
469
  }
470
+ /**
471
+ * The script files a shell line launches that the agent wrote or that
472
+ * appeared during the session, read now for the auto-mode classifier.
473
+ * Remembers what was read for `callId`, so the file can be checked again
474
+ * just before the call runs.
475
+ */
476
+ async launchedScripts(callId, line, dialect) {
477
+ if (this.sandboxed) {
478
+ // A sandbox's files are not on this host's disk. Say so rather than
479
+ // letting a launch inside one look like a launch of nothing.
480
+ const analysis = analyzeLaunches(line, dialect);
481
+ const named = analysis.launches.map((l) => l.path);
482
+ return named.length === 0 && analysis.unresolved.length === 0
483
+ ? []
484
+ : [
485
+ {
486
+ path: named[0] ?? '(launch form not resolved)',
487
+ origin: 'unknown',
488
+ state: 'unreadable',
489
+ note: 'the command runs in a sandbox whose files are not read for this review, so what the script does is not known',
490
+ },
491
+ ];
492
+ }
493
+ const evidence = await readLaunchedScripts(line, dialect, {
494
+ cwd: effectiveBashWorkingDirectory(this.config.sessionId, this.config.workingDirectory, {
495
+ sandboxed: false,
496
+ }),
497
+ startedAt: this.fileReadTracker.startedAt ?? this.startedAt,
498
+ ...(this.fileReadTracker.authoredFingerprint
499
+ ? { authoredFingerprint: (key) => this.fileReadTracker.authoredFingerprint?.(key) }
500
+ : {}),
501
+ });
502
+ if (evidence.watch.length > 0)
503
+ this.reviewedScripts.set(callId, evidence.watch);
504
+ else
505
+ this.reviewedScripts.delete(callId);
506
+ return evidence.scripts;
507
+ }
466
508
  /** The whole of the evidence as one text, from the same ledger. No filesystem I/O. */
467
509
  describeFileEvidence(messages) {
468
510
  return describeVisibleFileEvidence(messages, this.fileReadTracker, this.config.workingDirectory, this.sandboxed);
@@ -655,12 +697,13 @@ export class ToolExecutor {
655
697
  const earlierPaths = [];
656
698
  for (const toolCall of response.message.toolCalls ?? []) {
657
699
  const prepared = await prepareDirectCall(this.admissionHost(), toolCall, !hostModifiedCallIds?.has(toolCall.id));
658
- const call = await this.refusedBeforeReview(prepared, earlierPaths);
700
+ const beforeReview = await this.refusedBeforeReview(prepared, earlierPaths);
659
701
  const path = inputPathOf(prepared);
660
702
  if (path !== undefined)
661
703
  earlierPaths.push(path);
704
+ this.admitScratchpad(beforeReview);
705
+ const call = await this.refusedOutsideRoot(beforeReview);
662
706
  calls.set(toolCall.id, call);
663
- this.admitScratchpad(call);
664
707
  const escalation = await this.escalationOrUnfinished(call);
665
708
  if (escalation)
666
709
  escalations.set(toolCall.id, escalation);
@@ -670,6 +713,52 @@ export class ToolExecutor {
670
713
  this.config.abortSignal.throwIfAborted();
671
714
  return this.publishPreparedBatch(calls, escalations, scratchpadWrites);
672
715
  }
716
+ /**
717
+ * A file tool's path outside the roots, refused with the host's own words
718
+ * (`QueryParams.outsideRootRefusal`) instead of the tool's generic one.
719
+ *
720
+ * It takes the place of the call like any refusal found while preparing it,
721
+ * so it holds in every permission mode and reaches no reviewer. Only a turn
722
+ * that refuses (`outsideRootAccess: 'refuse'`) and has no sandbox is looked
723
+ * at, and only a tool that declares `pathArgument`. The exemptions are the
724
+ * review's: the scratch folder is a root, and so is this session's retained
725
+ * output for `read`.
726
+ */
727
+ async refusedOutsideRoot(call) {
728
+ const note = this.config.outsideRootRefusal;
729
+ if (call.kind !== 'ready' || note === undefined)
730
+ return call;
731
+ if (this.config.outsideRootAccess !== 'refuse' || this.sandboxed)
732
+ return call;
733
+ const tool = this.config.tools.get(call.toolName);
734
+ if (tool?.pathArgument === undefined)
735
+ return call;
736
+ if (call.input === null || typeof call.input !== 'object')
737
+ return call;
738
+ const value = call.input[tool.pathArgument];
739
+ if (typeof value !== 'string')
740
+ return call;
741
+ try {
742
+ const retained = tool.name === 'read' && (await resolveRetainedOutput(this.outputDirectory(), value));
743
+ if (retained)
744
+ return call;
745
+ const outside = await pathOutsideRoots(this.rootsNow(), value);
746
+ if (outside === undefined)
747
+ return call;
748
+ return {
749
+ kind: 'synthetic',
750
+ toolCall: call.toolCall,
751
+ toolName: call.toolName,
752
+ input: call.input,
753
+ message: formatFailedToolOutput(undefined, `${outside} is outside the working directory. ${note}`),
754
+ isError: true,
755
+ };
756
+ }
757
+ catch {
758
+ this.config.abortSignal.throwIfAborted();
759
+ return call;
760
+ }
761
+ }
673
762
  /**
674
763
  * A ready call the tool already knows cannot run, answered now instead of
675
764
  * after a reviewer has been asked about it (`ToolDefinition.refuseBeforeReview`).
@@ -879,9 +968,10 @@ export class ToolExecutor {
879
968
  const earlierPaths = [];
880
969
  for (const toolCall of response.message.toolCalls ?? []) {
881
970
  if (changedCallIds.has(toolCall.id)) {
882
- const call = await this.refusedBeforeReview(await prepareDirectCall(this.admissionHost(), toolCall, false), earlierPaths);
971
+ const beforeReview = await this.refusedBeforeReview(await prepareDirectCall(this.admissionHost(), toolCall, false), earlierPaths);
972
+ this.admitScratchpad(beforeReview);
973
+ const call = await this.refusedOutsideRoot(beforeReview);
883
974
  calls.set(toolCall.id, call);
884
- this.admitScratchpad(call);
885
975
  const escalation = await this.escalationOrUnfinished(call);
886
976
  if (escalation)
887
977
  escalations.set(toolCall.id, escalation);
@@ -1123,7 +1213,18 @@ export class ToolExecutor {
1123
1213
  let outcome;
1124
1214
  started.add(toolCall.id);
1125
1215
  try {
1126
- outcome = await this.executeSingle(toolCall, ctx, recordObservation, () => progress.close(), preparedCall);
1216
+ const reviewedScripts = this.reviewedScripts.get(toolCall.id);
1217
+ this.reviewedScripts.delete(toolCall.id);
1218
+ const moved = reviewedScripts === undefined ? undefined : await changedSinceRead(reviewedScripts);
1219
+ outcome =
1220
+ moved !== undefined
1221
+ ? {
1222
+ toolCallId: toolCall.id,
1223
+ toolName: toolCall.function.name,
1224
+ output: `Error: ${moved} changed after the safety check read it, so the command was not run. Run it again and it will be checked against the new text.`,
1225
+ isError: true,
1226
+ }
1227
+ : await this.executeSingle(toolCall, ctx, recordObservation, () => progress.close(), preparedCall);
1127
1228
  }
1128
1229
  catch (error) {
1129
1230
  // A call already answered with the placeholder has no batch
@@ -1312,6 +1413,7 @@ export class ToolExecutor {
1312
1413
  failure ??= { error };
1313
1414
  }
1314
1415
  finally {
1416
+ this.reviewedScripts.delete(unit.toolCall.id);
1315
1417
  settledUnit();
1316
1418
  inFlight.delete(unit);
1317
1419
  pump();
@@ -1611,7 +1713,7 @@ export class ToolExecutor {
1611
1713
  toolName: name,
1612
1714
  toolUseId: nestedId,
1613
1715
  output: rawOutput,
1614
- maxChars: this.config.maxToolOutputChars ?? DEFAULT_MAX_TOOL_OUTPUT_CHARS,
1716
+ maxChars: this.toolOutputCap(this.config.tools.get(name), false),
1615
1717
  retainedPreviewChars: this.config.retainedToolPreviewChars,
1616
1718
  spillDir: this.outputDirectory(),
1617
1719
  recoveryRoutes: this.recoveryRoutes(),
@@ -2040,10 +2142,7 @@ export class ToolExecutor {
2040
2142
  ];
2041
2143
  }
2042
2144
  }
2043
- // A tool that bounds its own output is exempt from the DEFAULT per-result
2044
- // cap only; a host that set the cap explicitly still gets it.
2045
- const maxToolOutputChars = this.config.maxToolOutputChars ??
2046
- (executedDefinition?.selfLimitingOutput === true ? 0 : DEFAULT_MAX_TOOL_OUTPUT_CHARS);
2145
+ const maxToolOutputChars = this.toolOutputCap(executedDefinition, true);
2047
2146
  const sourceOutput = output;
2048
2147
  // This owner-bound channel follows the selected receipt after both result
2049
2148
  // screening and post-tool replacement. ToolResult.data and raw input can
@@ -2246,6 +2345,7 @@ export class ToolExecutor {
2246
2345
  ? { handoff: result.handoff }
2247
2346
  : {}),
2248
2347
  ...(revealedTools !== undefined ? { revealedTools } : {}),
2348
+ ...(result.facts !== undefined && !postOverride ? { facts: result.facts } : {}),
2249
2349
  };
2250
2350
  }
2251
2351
  /**
@@ -2683,6 +2783,8 @@ export class ToolExecutor {
2683
2783
  * `executing`, and records a failed activity for the trace.
2684
2784
  */
2685
2785
  async recordDenial(toolCall, reason, preparedCall, declined) {
2786
+ // A call that does not run has no use for what a review read of its scripts.
2787
+ this.reviewedScripts.delete(toolCall.id);
2686
2788
  const toolName = preparedCall?.toolName ?? toolCall.function.name;
2687
2789
  let input = preparedCall?.input ?? {};
2688
2790
  if (!preparedCall) {
@@ -2816,6 +2918,7 @@ export class ToolExecutor {
2816
2918
  toolName,
2817
2919
  output: outcome.output,
2818
2920
  isError: outcome.kind === 'error',
2921
+ ...(outcome.facts ? { facts: outcome.facts } : {}),
2819
2922
  ...(outcome.inputFailure ? { inputFailure: outcome.inputFailure } : {}),
2820
2923
  ...(outcome.skipped ? { skipped: true } : {}),
2821
2924
  };
@@ -2829,6 +2932,22 @@ export class ToolExecutor {
2829
2932
  ...(call.skipped ? { skipped: true } : {}),
2830
2933
  });
2831
2934
  }
2935
+ /**
2936
+ * The per-result character cap for one tool: the turn's cap, tightened by
2937
+ * the tool's own `maxOutputChars`. A tool that bounds its own output is
2938
+ * exempt from the DEFAULT cap only (`exemptSelfLimiting`); a host that set
2939
+ * the cap explicitly still gets it. 0 means no cap.
2940
+ */
2941
+ toolOutputCap(definition, exemptSelfLimiting) {
2942
+ const turn = this.config.maxToolOutputChars ??
2943
+ (exemptSelfLimiting && definition?.selfLimitingOutput === true
2944
+ ? 0
2945
+ : DEFAULT_MAX_TOOL_OUTPUT_CHARS);
2946
+ const own = definition?.maxOutputChars;
2947
+ if (own === undefined || !Number.isFinite(own) || own <= 0)
2948
+ return turn;
2949
+ return turn > 0 ? Math.min(turn, Math.floor(own)) : Math.floor(own);
2950
+ }
2832
2951
  /**
2833
2952
  * The host preview and model text may differ; each gets its own text
2834
2953
  * budget. Rich bytes are measured separately and withheld whole when
@@ -2858,7 +2977,7 @@ export class ToolExecutor {
2858
2977
  toolName,
2859
2978
  toolUseId,
2860
2979
  output: text,
2861
- maxChars: this.config.maxToolOutputChars ?? DEFAULT_MAX_TOOL_OUTPUT_CHARS,
2980
+ maxChars: this.toolOutputCap(this.config.tools.get(toolName), false),
2862
2981
  ...(notice ? { notice } : {}),
2863
2982
  // A tool may return different host and model text. They must
2864
2983
  // never compete for the same exclusive spill filename.