@sema-agent/core 2.13.0 → 4.0.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 (184) hide show
  1. package/CHANGELOG.md +2345 -0
  2. package/dist/agents/cascade.d.ts +6 -1
  3. package/dist/agents/cascade.js +76 -32
  4. package/dist/agents/cumulative-stats.d.ts +29 -0
  5. package/dist/agents/cumulative-stats.js +29 -0
  6. package/dist/agents/observer.d.ts +4 -0
  7. package/dist/agents/observer.js +11 -10
  8. package/dist/agents/repair-loop.d.ts +2 -0
  9. package/dist/agents/repair-loop.js +110 -3
  10. package/dist/agents/retain-ledger.d.ts +20 -2
  11. package/dist/agents/retain-ledger.js +38 -8
  12. package/dist/agents/roster-store.d.ts +4 -0
  13. package/dist/agents/roster-store.js +20 -1
  14. package/dist/agents/subagent.js +66 -64
  15. package/dist/agents/teacher.d.ts +1 -9
  16. package/dist/agents/teacher.js +23 -24
  17. package/dist/agents/team.js +7 -4
  18. package/dist/agents/verify.d.ts +15 -2
  19. package/dist/agents/verify.js +39 -3
  20. package/dist/bin/sema-tb.js +2 -2
  21. package/dist/brain/anthropic.js +24 -21
  22. package/dist/brain/circuit-breaker.d.ts +1 -0
  23. package/dist/brain/circuit-breaker.js +26 -9
  24. package/dist/brain/degrading.js +13 -1
  25. package/dist/brain/failover.js +2 -0
  26. package/dist/brain/openai.js +24 -21
  27. package/dist/brain/repetition.js +10 -1
  28. package/dist/brain/routing.js +5 -1
  29. package/dist/brain/status-sink.js +5 -1
  30. package/dist/brain/stream-engine.js +5 -2
  31. package/dist/brain/stream-shared.d.ts +1 -0
  32. package/dist/brain/stream-shared.js +14 -0
  33. package/dist/brain/terminal-cause.d.ts +4 -0
  34. package/dist/brain/terminal-cause.js +12 -0
  35. package/dist/brain/tool-call-id.d.ts +1 -0
  36. package/dist/brain/tool-call-id.js +3 -0
  37. package/dist/brain/tool-call-repair.js +34 -15
  38. package/dist/core/auto-compaction.js +33 -32
  39. package/dist/core/background-agent-store.d.ts +22 -22
  40. package/dist/core/background-agent-store.js +19 -23
  41. package/dist/core/checkpoint-store.d.ts +7 -13
  42. package/dist/core/checkpoint-store.js +39 -15
  43. package/dist/core/consolidate-scope.js +4 -3
  44. package/dist/core/context-edit.js +3 -0
  45. package/dist/core/context-guard.js +3 -0
  46. package/dist/core/file-snapshot-store.d.ts +8 -0
  47. package/dist/core/file-snapshot-store.js +4 -3
  48. package/dist/core/git-worktree-env.d.ts +6 -1
  49. package/dist/core/git-worktree-env.js +12 -1
  50. package/dist/core/hooks.d.ts +4 -1
  51. package/dist/core/hooks.js +35 -7
  52. package/dist/core/lsp-diagnostics.js +13 -7
  53. package/dist/core/lsp-protocol.d.ts +1 -1
  54. package/dist/core/lsp-protocol.js +20 -8
  55. package/dist/core/lsp-session.d.ts +12 -2
  56. package/dist/core/lsp-session.js +114 -49
  57. package/dist/core/lsp.d.ts +13 -1
  58. package/dist/core/lsp.js +65 -9
  59. package/dist/core/mailbox-store.d.ts +7 -10
  60. package/dist/core/mcp.d.ts +7 -10
  61. package/dist/core/mcp.js +7 -3
  62. package/dist/core/memory-engine/data-plane.js +4 -0
  63. package/dist/core/memory-engine/engine.d.ts +2 -2
  64. package/dist/core/memory-engine/engine.js +96 -31
  65. package/dist/core/memory-engine/file-backend.d.ts +2 -2
  66. package/dist/core/memory-engine/file-backend.js +38 -39
  67. package/dist/core/memory-engine/layout.d.ts +8 -0
  68. package/dist/core/memory-engine/layout.js +71 -4
  69. package/dist/core/memory-engine/scope-contract.js +9 -3
  70. package/dist/core/memory-engine/types.d.ts +1 -1
  71. package/dist/core/memory.js +3 -0
  72. package/dist/core/permission-rules.d.ts +2 -1
  73. package/dist/core/permission-rules.js +24 -3
  74. package/dist/core/runner/active-skill-scope.d.ts +0 -1
  75. package/dist/core/runner/active-skill-scope.js +1 -15
  76. package/dist/core/runner/assemble-result.d.ts +3 -8
  77. package/dist/core/runner/assemble-result.js +3 -5
  78. package/dist/core/runner/compaction-call-options.d.ts +7 -0
  79. package/dist/core/runner/compaction-call-options.js +30 -0
  80. package/dist/core/runner/prepare-task.d.ts +6 -23
  81. package/dist/core/runner/prepare-task.js +31 -53
  82. package/dist/core/runner/runtask.d.ts +1 -0
  83. package/dist/core/runner/runtask.js +86 -178
  84. package/dist/core/runner/session-rule-policy.js +4 -1
  85. package/dist/core/runner/teardown-bounded.d.ts +7 -0
  86. package/dist/core/runner/teardown-bounded.js +36 -0
  87. package/dist/core/runner/tool-disclosure.d.ts +2 -5
  88. package/dist/core/runner/turn-attachments.d.ts +5 -15
  89. package/dist/core/runner/turn-attachments.js +1 -1
  90. package/dist/core/runner/usage-accounting.d.ts +6 -0
  91. package/dist/core/runner/usage-accounting.js +9 -8
  92. package/dist/core/safe-notify.d.ts +17 -0
  93. package/dist/core/safe-notify.js +59 -0
  94. package/dist/core/secret-env.js +5 -1
  95. package/dist/core/sensitive-path-policy.js +11 -4
  96. package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
  97. package/dist/core/store-contracts/session-repo-contract.js +40 -0
  98. package/dist/core/stub-env.d.ts +2 -6
  99. package/dist/core/surrogate-safe-slice.d.ts +4 -0
  100. package/dist/core/surrogate-safe-slice.js +18 -0
  101. package/dist/core/task-registry-monitor.js +15 -14
  102. package/dist/core/task-registry-shared.d.ts +22 -0
  103. package/dist/core/task-registry-shared.js +16 -0
  104. package/dist/core/task-registry.d.ts +1 -0
  105. package/dist/core/task-registry.js +40 -57
  106. package/dist/core/tool-errors.js +5 -4
  107. package/dist/core/tool-name-aliases.js +2 -1
  108. package/dist/core/tool-policy.js +72 -19
  109. package/dist/core/tool-result-store.d.ts +1 -0
  110. package/dist/core/tool-result-store.js +17 -1
  111. package/dist/core/trace.d.ts +3 -9
  112. package/dist/core/types.d.ts +16 -12
  113. package/dist/core/untrusted-egress.js +7 -5
  114. package/dist/core/workflow-journal-store.d.ts +9 -20
  115. package/dist/core/workflow-run-store.d.ts +11 -10
  116. package/dist/core/workflow-run-store.js +22 -16
  117. package/dist/engine/compaction/compaction.d.ts +1 -0
  118. package/dist/engine/compaction/compaction.js +14 -5
  119. package/dist/engine/compaction/utils.js +4 -2
  120. package/dist/engine/execution-env/node-execution-env.d.ts +2 -24
  121. package/dist/engine/harness/agent-harness.d.ts +1 -0
  122. package/dist/engine/harness/agent-harness.js +13 -33
  123. package/dist/engine/harness/types.d.ts +29 -67
  124. package/dist/engine/llm/types.d.ts +1 -1
  125. package/dist/engine/loop/agent-loop.js +11 -4
  126. package/dist/engine/loop/types.d.ts +11 -9
  127. package/dist/engine/lsp/frame-decoder.js +6 -3
  128. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -0
  129. package/dist/engine/lsp/node-lsp-manager.js +103 -26
  130. package/dist/engine/lsp/stdio-lsp-transport.js +16 -7
  131. package/dist/engine/session/memory-repo.d.ts +2 -6
  132. package/dist/engine/session/session.d.ts +5 -30
  133. package/dist/index.d.ts +3 -1
  134. package/dist/index.js +2 -1
  135. package/dist/internal/harness-types.d.ts +3 -1
  136. package/dist/internal/harness.d.ts +1 -1
  137. package/dist/internal/harness.js +1 -1
  138. package/dist/orchestration/run-spec.js +7 -4
  139. package/dist/orchestration/run-workflow-tool.js +3 -35
  140. package/dist/orchestration/workflow-governance.js +43 -9
  141. package/dist/orchestration/workflow-sandbox-conformance.js +85 -51
  142. package/dist/orchestration/workflow-script-store.js +34 -4
  143. package/dist/orchestration/workflow.d.ts +3 -11
  144. package/dist/orchestration/workflow.js +164 -204
  145. package/dist/prompt-assembly/artifact-store.d.ts +2 -0
  146. package/dist/prompt-assembly/artifact-store.js +39 -24
  147. package/dist/prompt-assembly/assemble.js +38 -7
  148. package/dist/prompt-assembly/epoch.js +19 -2
  149. package/dist/prompt-assembly/event-registry.js +3 -3
  150. package/dist/prompt-assembly/explain.js +1 -1
  151. package/dist/prompt-assembly/tool-catalog.d.ts +10 -9
  152. package/dist/prompt-assembly/tool-catalog.js +16 -1
  153. package/dist/prompt-assembly/turn-snapshot.d.ts +2 -5
  154. package/dist/prompt-assembly/turn-snapshot.js +4 -1
  155. package/dist/stores/file/background-agent-store.d.ts +3 -12
  156. package/dist/stores/file/background-agent-store.js +3 -41
  157. package/dist/stores/file/checkpoint-store.js +6 -6
  158. package/dist/stores/file/fs-atomic.d.ts +3 -0
  159. package/dist/stores/file/fs-atomic.js +53 -8
  160. package/dist/stores/file/index.d.ts +1 -0
  161. package/dist/stores/file/index.js +7 -0
  162. package/dist/stores/file/mailbox-store.d.ts +2 -6
  163. package/dist/stores/file/session-policy-store.js +15 -1
  164. package/dist/stores/file/session-store.d.ts +4 -6
  165. package/dist/stores/file/session-store.js +28 -1
  166. package/dist/stores/file/workflow-journal-store.d.ts +3 -11
  167. package/dist/stores/file/workflow-run-store.d.ts +3 -7
  168. package/dist/stores/file/workflow-run-store.js +4 -17
  169. package/dist/tools/fs/bash-readonly-classifier.d.ts +2 -0
  170. package/dist/tools/fs/bash-readonly-classifier.js +73 -21
  171. package/dist/tools/fs/fs-bash.d.ts +1 -1
  172. package/dist/tools/fs/fs-bash.js +407 -91
  173. package/dist/tools/fs/fs-pdf.d.ts +2 -12
  174. package/dist/tools/fs/fs-shared.js +2 -2
  175. package/dist/tools/fs/notebook.d.ts +2 -5
  176. package/dist/tools/fs/safety.d.ts +3 -0
  177. package/dist/tools/fs/safety.js +43 -14
  178. package/dist/tools/fs/search.js +5 -5
  179. package/dist/tools/loop-tick.js +1 -1
  180. package/dist/tools/monitor.d.ts +1 -0
  181. package/dist/tools/monitor.js +57 -9
  182. package/dist/tools/worktree.d.ts +4 -7
  183. package/dist/tools/worktree.js +235 -143
  184. package/package.json +9 -2
@@ -1,5 +1,11 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { dirname, join, resolve } from "node:path";
3
+ import { canonicalize } from "./layout.js";
4
+ function pathSegmentsDualFamily(p) {
5
+ return p.split(/[\\/]/).filter(Boolean);
6
+ }
7
+ const CASE_INSENSITIVE_FS = process.platform === "darwin" || process.platform === "win32";
8
+ const foldPathCase = (s) => (CASE_INSENSITIVE_FS ? s.toLowerCase() : s);
3
9
  export const SCOPE_SEGMENT_MAX_ENCODED = 64;
4
10
  const SEGMENT_SAFE = /^[A-Za-z0-9._-]$/;
5
11
  export function encodeScopeSegment(raw) {
@@ -117,9 +123,9 @@ export function assertScopeContractPlacement(args) {
117
123
  const personal = args.parsedScopes.filter(isCentralAuthorityScope);
118
124
  if (personal.length === 0)
119
125
  return;
120
- const root = resolve(args.repoRoot);
121
- const dir = resolve(args.memoryDir);
122
- if (dir === root || dir.startsWith(root + "/")) {
126
+ const rootSegs = pathSegmentsDualFamily(canonicalize(resolve(args.repoRoot))).map(foldPathCase);
127
+ const dirSegs = pathSegmentsDualFamily(canonicalize(resolve(args.memoryDir))).map(foldPathCase);
128
+ if (rootSegs.length <= dirSegs.length && rootSegs.every((s, i) => s === dirSegs[i])) {
123
129
  const e = new Error(`memory scope contract v2: central-authority scope(s) ${personal
124
130
  .map((p) => `"${p.kind}"`)
125
131
  .join(", ")} cannot materialize into an IN-REPO memory dir (${args.memoryDir}) — ` +
@@ -88,7 +88,7 @@ export interface MemorySessionHandle {
88
88
  indexBaselineLines: number;
89
89
  indexText: string;
90
90
  }
91
- export type HarvestRejectionCode = "outside_root" | "symlink" | "secret" | "injection" | "filename" | "too_large" | "file_cap" | "readonly_layer" | "stub_modified" | "nested_too_deep" | "quarantine_failed" | "invalid";
91
+ export type HarvestRejectionCode = "outside_root" | "symlink" | "secret" | "injection" | "filename" | "too_large" | "file_cap" | "readonly_layer" | "stub_modified" | "nested_too_deep" | "quarantine_failed" | "unreadable" | "invalid";
92
92
  export interface HarvestRejection {
93
93
  path: string;
94
94
  code: HarvestRejectionCode;
@@ -32,6 +32,9 @@ const SECRET_PATTERNS = [
32
32
  { label: "slack_token", re: /\bxox[baprs]-(?:[A-Za-z0-9]+-){1,3}[A-Za-z0-9]{16,}\b/ },
33
33
  { label: "google_api_key", re: /\bAIza[0-9A-Za-z_-]{35}\b/ },
34
34
  { label: "private_key", re: /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?-----/ },
35
+ { label: "jwt", re: /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]{16,}\b/ },
36
+ { label: "azure_storage_account_key", re: /AccountKey=[A-Za-z0-9+/]{40,}={0,2}/ },
37
+ { label: "bearer_token", re: /\bAuthorization:\s*Bearer\s+(?=[A-Za-z0-9._~+/-]*[0-9])[A-Za-z0-9._~+/-]{20,}=*/ },
35
38
  ];
36
39
  export function detectSecret(text) {
37
40
  if (!text)
@@ -11,7 +11,7 @@ export interface ParsedPermissionRule {
11
11
  }
12
12
  export interface PermissionRuleIssue {
13
13
  rule: string;
14
- code: "invalid.empty_tool" | "invalid.paren" | "invalid.param_split" | "invalid.allow_param_rule" | "invalid.primary_field" | "invalid.cap_exceeded" | "unsupported.bash_prefix" | "unsupported.file_glob" | "unsupported.mcp_paren";
14
+ code: "invalid.empty_tool" | "invalid.paren" | "invalid.param_split" | "invalid.allow_param_rule" | "invalid.primary_field" | "invalid.cap_exceeded" | "unsupported.bash_prefix" | "unsupported.file_glob" | "unsupported.mcp_paren" | "unsupported.unknown_param";
15
15
  message: string;
16
16
  }
17
17
  export interface PermissionRuleCaps {
@@ -30,5 +30,6 @@ export interface PermissionRulePolicyOptions {
30
30
  }
31
31
  export declare function parsePermissionRule(rule: string): ParsedPermissionRule;
32
32
  export declare function wildcardMatch(pattern: string, value: string): boolean;
33
+ export declare const fileToolParamVocabulary: (canonicalTool: string) => ReadonlySet<string> | undefined;
33
34
  export declare function validatePermissionRules(rules: PermissionRule[], opts?: Pick<PermissionRulePolicyOptions, "primaryFieldGeneric" | "caps">): PermissionRuleIssue[];
34
35
  export declare function createPermissionRulePolicy(rules: PermissionRule[], opts?: PermissionRulePolicyOptions): ToolPolicy;
@@ -90,6 +90,18 @@ const PRIMARY_FIELDS = {
90
90
  WebSearch: new Set(["query"]),
91
91
  };
92
92
  const FILE_TOOLS = new Set(["Read", "Edit", "Write", "MultiEdit", "NotebookEdit", "Grep", "Glob"]);
93
+ const FILE_TOOL_PARAMS = {
94
+ Read: new Set(["file_path", "path", "offset", "limit", "pages"]),
95
+ Edit: new Set(["file_path", "path", "old_string", "new_string", "replace_all"]),
96
+ Write: new Set(["file_path", "path", "content"]),
97
+ NotebookEdit: new Set(["notebook_path", "path", "cell_id", "cell_type", "edit_mode", "new_source"]),
98
+ Grep: new Set([
99
+ "pattern", "path", "glob", "type", "output_mode", "head_limit", "max_results", "offset",
100
+ "multiline", "context", "ignore_case", "-i", "-n", "-o", "-A", "-B", "-C",
101
+ ]),
102
+ Glob: new Set(["pattern", "path", "max_results"]),
103
+ };
104
+ export const fileToolParamVocabulary = (canonicalTool) => FILE_TOOL_PARAMS[canonicalTool];
93
105
  function countStars(s) {
94
106
  let n = 0;
95
107
  for (const c of s)
@@ -151,9 +163,18 @@ function compile(rules, caps, primaryFieldGeneric) {
151
163
  continue;
152
164
  }
153
165
  }
154
- else if (FILE_TOOLS.has(toolName) && colon <= 0) {
155
- bad(text, "unsupported.file_glob", "file-tool glob rules (`Edit(src/**)`) are the tool-specific lane — not supported by the generic param DSL");
156
- continue;
166
+ else if (FILE_TOOLS.has(toolName)) {
167
+ if (colon <= 0) {
168
+ bad(text, "unsupported.file_glob", "file-tool glob rules (`Edit(src/**)`) are the tool-specific lane — not supported by the generic param DSL");
169
+ continue;
170
+ }
171
+ const paramPart = content.slice(0, colon).trim();
172
+ const vocabulary = FILE_TOOL_PARAMS[toolName];
173
+ if (vocabulary !== undefined && !vocabulary.has(paramPart)) {
174
+ bad(text, "unsupported.unknown_param", `"${paramPart}" is not a parameter of ${toolName} (it carries ${[...vocabulary].sort().join(", ")}) — the rule would compile and never match. ` +
175
+ `For a path glob use the tool-specific lane (\`${toolName}(src/**)\` is not the generic param DSL); a Windows path such as \`${toolName}(C:/foo)\` parses as the param "C".`);
176
+ continue;
177
+ }
157
178
  }
158
179
  if (colon <= 0) {
159
180
  bad(text, "invalid.param_split", "param-level ruleContent must be `param:pattern`");
@@ -16,7 +16,6 @@ export declare class ActiveSkillScope {
16
16
  active(): readonly ActiveSkillFrame[];
17
17
  get size(): number;
18
18
  }
19
- export declare function isWithin(root: string, p: string): boolean;
20
19
  export declare function createActiveSkillScopePolicy(opts: {
21
20
  scope: ActiveSkillScope;
22
21
  env: ExecutionEnv;
@@ -1,4 +1,5 @@
1
1
  import { canonicalizeTarget, fileArgPath } from "../../tools/fs/safety.js";
2
+ import { PATH_WRITE_TOOLS, isWithin } from "./session-rule-policy.js";
2
3
  import { canonicalToolName } from "../tool-name-aliases.js";
3
4
  import { parseSkillToolEntry, skillSpecifierRejection } from "../skill-tool-specifier.js";
4
5
  export class ActiveSkillScope {
@@ -16,21 +17,6 @@ export class ActiveSkillScope {
16
17
  return this.frames.length;
17
18
  }
18
19
  }
19
- const PATH_WRITE_TOOLS = new Set(["Write", "Edit", "MultiEdit"]);
20
- export function isWithin(root, p) {
21
- const norm = (x) => {
22
- let n = x.replace(/\\/g, "/");
23
- if (/^[A-Za-z]:(\/|$)/.test(n))
24
- n = n[0].toLowerCase() + n.slice(1);
25
- return n;
26
- };
27
- const r = norm(root);
28
- const c = norm(p);
29
- if (c === r)
30
- return true;
31
- const base = r.endsWith("/") ? r : r + "/";
32
- return c.startsWith(base);
33
- }
34
20
  export function createActiveSkillScopePolicy(opts) {
35
21
  const { scope, env, rootPath, toolEffects } = opts;
36
22
  return {
@@ -1,5 +1,5 @@
1
1
  import type { AssistantMessage } from "../../internal/llm.js";
2
- import type { TaskResult, TaskSpec } from "../types.js";
2
+ import type { NestedUsage, TaskResult, TaskSpec } from "../types.js";
3
3
  export interface Stats {
4
4
  turns: number;
5
5
  tokens: number;
@@ -10,14 +10,9 @@ export interface Stats {
10
10
  cacheWriteTokensLong: number;
11
11
  outputTokens: number;
12
12
  cacheHitRate?: number;
13
- totalInputTokens?: number;
13
+ totalInputTokens: number;
14
14
  costMicroUsd: number;
15
- nested?: {
16
- tokens: number;
17
- turns: number;
18
- tasks: number;
19
- costMicroUsd?: number;
20
- };
15
+ nested?: NestedUsage;
21
16
  memory?: {
22
17
  tokens: number;
23
18
  costMicroUsd: number;
@@ -1,5 +1,4 @@
1
- import { DEGENERATE_MESSAGE } from "../../brain/repetition.js";
2
- import { WALLTIME_CUTOFF_MESSAGE } from "../../brain/walltime.js";
1
+ import { isDegenerateCutMessage, isWalltimeCutMessage } from "../../brain/terminal-cause.js";
3
2
  import { extractErrorCode, stripErrorCodePrefix } from "../../brain/errors.js";
4
3
  export function errorCodeOf(err) {
5
4
  let cur = err;
@@ -35,7 +34,6 @@ function assistantText(msg) {
35
34
  export function assembleResult(spec, sessionId, final, stats, flags) {
36
35
  const taskId = spec.taskId ?? sessionId;
37
36
  const text = final ? assistantText(final) : "";
38
- stats.totalInputTokens = stats.promptTokens;
39
37
  if (!flags.unpricedSpend) {
40
38
  const compactionMicroUsd = stats.compactionMicroUsd ?? 0;
41
39
  const nestedSubagentMicroUsd = stats.nested?.costMicroUsd ?? 0;
@@ -55,8 +53,8 @@ export function assembleResult(spec, sessionId, final, stats, flags) {
55
53
  let checkpointToken;
56
54
  let checkpointGate;
57
55
  let workspaceRestoreMode;
58
- const isDegenerate = final?.stopReason === "error" && final.errorMessage === DEGENERATE_MESSAGE;
59
- const isWalltimeCutoff = final?.stopReason === "error" && final.errorMessage === WALLTIME_CUTOFF_MESSAGE;
56
+ const isDegenerate = final?.stopReason === "error" && isDegenerateCutMessage(final);
57
+ const isWalltimeCutoff = final?.stopReason === "error" && isWalltimeCutMessage(final);
60
58
  if (flags.outputInvalid) {
61
59
  status = "failed";
62
60
  errorCode = "output.invalid";
@@ -0,0 +1,7 @@
1
+ import { type TracerHook } from "../trace.js";
2
+ import type { MaybeCompactOptions } from "../auto-compaction.js";
3
+ import type { TaskSpec } from "../types.js";
4
+ import type { Prepared } from "./prepare-task.js";
5
+ export declare function buildWorkingFileAttachments(spec: TaskSpec, prepared: Prepared): MaybeCompactOptions["workingFileAttachments"];
6
+ export declare function centerAdoptionOption(prepared: Prepared): Partial<Pick<MaybeCompactOptions, "centerAdoption">>;
7
+ export declare function emitInputTruncated(tracer: TracerHook | undefined, taskId: string): NonNullable<MaybeCompactOptions["onInputTruncated"]>;
@@ -0,0 +1,30 @@
1
+ import { emitTrace } from "../trace.js";
2
+ export function buildWorkingFileAttachments(spec, prepared) {
3
+ if (spec.compaction?.attachWorkingFiles === false || !prepared.readTaskFile)
4
+ return undefined;
5
+ return {
6
+ readFile: prepared.readTaskFile,
7
+ ...(prepared.recentlyReadFiles ? { recentlyReadFiles: prepared.recentlyReadFiles } : {}),
8
+ ...(prepared.normalizeAttachmentPath ? { normalizePath: prepared.normalizeAttachmentPath } : {}),
9
+ ...(prepared.isDedupStubResult ? { isDedupStubResult: prepared.isDedupStubResult } : {}),
10
+ ...(prepared.instructionSources
11
+ ? { instructionSourcePaths: prepared.instructionSources.filter((s) => s.contentHash !== null).map((s) => s.path) }
12
+ : {}),
13
+ ...(typeof spec.compaction?.attachWorkingFiles === "object" ? spec.compaction.attachWorkingFiles : undefined),
14
+ };
15
+ }
16
+ export function centerAdoptionOption(prepared) {
17
+ const ca = prepared.centerCompactionCandidate?.();
18
+ return ca !== undefined ? { centerAdoption: ca } : {};
19
+ }
20
+ export function emitInputTruncated(tracer, taskId) {
21
+ return (info) => emitTrace(tracer, () => ({
22
+ kind: "compaction.input_truncated",
23
+ version: 1,
24
+ taskId,
25
+ label: info.label,
26
+ droppedChars: info.droppedChars,
27
+ keptChars: info.keptChars,
28
+ ts: Date.now(),
29
+ }));
30
+ }
@@ -12,12 +12,13 @@ import type { SessionPermissionRules } from "../session-policy-store.js";
12
12
  import { CacheBreakDetector, type ToolFingerprintInput } from "../cache-break-detector.js";
13
13
  import { type OutputRef, type BlockedRef, type SkillListingEntry } from "./synthetic-tools.js";
14
14
  import type { MemoryEngine } from "../memory-engine/engine.js";
15
+ import { type ToolManifestRow } from "../../prompt-assembly/tool-catalog.js";
15
16
  import type { TaskNotificationPayload } from "../task-notification.js";
16
17
  import { type CwdRef } from "../../tools/fs/index.js";
17
18
  import type { Runner } from "./runtask.js";
18
19
  import { type CheckpointGate, type CheckpointState, type CheckpointToken, type ResourceLedger, type ResourceLimitReason } from "../checkpoint-store.js";
19
- import type { AgentMessage, AgentTool, ExecutionEnv } from "../../internal/harness.js";
20
- import type { RunnerDeps, TaskEvent, TaskResult, TaskSpec, ToolActivity, ToolEffect } from "../types.js";
20
+ import type { ActiveWorktreeSession, AgentMessage, AgentTool, ExecutionEnv } from "../../internal/harness.js";
21
+ import type { NestedUsageAccum, RunnerDeps, TaskEvent, TaskResult, TaskSpec, ToolActivity, ToolEffect } from "../types.js";
21
22
  import type { RepairBundle } from "../../agents/repair-loop.js";
22
23
  export declare const DEFAULT_IRREVERSIBLE_SCOPE = "irreversible";
23
24
  export declare function checkpointScopeOf(spec: {
@@ -42,21 +43,11 @@ export interface Prepared {
42
43
  hit: boolean;
43
44
  };
44
45
  blockedToolCalls: Set<string>;
45
- nestedStats: {
46
- tokens: number;
47
- turns: number;
48
- tasks: number;
49
- costMicroUsd: number;
50
- };
46
+ nestedStats: NestedUsageAccum;
51
47
  rewindNotes?: NonNullable<TaskResult["rewindNotes"]>;
52
48
  cwdRef?: CwdRef;
53
49
  worktreeSessionRef?: {
54
- current?: {
55
- worktreeDir: string;
56
- originalCwd: string;
57
- baseSha: string;
58
- entered?: boolean;
59
- };
50
+ current?: ActiveWorktreeSession;
60
51
  };
61
52
  workspaceStateSettle?: {
62
53
  rootCanonical: string;
@@ -89,15 +80,7 @@ export interface Prepared {
89
80
  hash: string;
90
81
  contentHash?: string;
91
82
  }>;
92
- tools?: Array<{
93
- wireName: string;
94
- aliases: string[];
95
- contractId: string;
96
- implementationRevision: string;
97
- cardId: string;
98
- shapeDigest: string;
99
- wireSchemaDigest: string;
100
- }>;
83
+ tools?: ToolManifestRow[];
101
84
  snapshot?: {
102
85
  cacheIdentity: string;
103
86
  elements: import("../../prompt-assembly/turn-snapshot.js").CacheIdentityElements;
@@ -31,7 +31,7 @@ import { reservedCollisions, reservedFor } from "../../brain/request-params.js";
31
31
  import { defineTool, isDefineToolProduct } from "../tools.js";
32
32
  import { canonicalToolName } from "../tool-name-aliases.js";
33
33
  import { pathToUri } from "../lsp-protocol.js";
34
- import { DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, buildToolResultRef, firstPartyOffloadPolicy, InMemoryToolResultStore, RunnerSharedToolResultStore, ScopedToolResultStore, isVolatileOffloadStore, OFFLOAD_TOOL_NAME, createReadToolResultTool, withToolResultOffload, } from "../tool-result-store.js";
34
+ import { DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, createOffloadPersist, firstPartyOffloadPolicy, InMemoryToolResultStore, RunnerSharedToolResultStore, ScopedToolResultStore, isVolatileOffloadStore, OFFLOAD_TOOL_NAME, createReadToolResultTool, withToolResultOffload, } from "../tool-result-store.js";
35
35
  import { OUTPUT_TOOL_NAME, REPORT_FINDINGS_TOOL_NAME, SKILL_CONTENT_MAX_CHARS, SKILL_TOOL_NAME, createOutputTool, createReportBlockedTool, createReportFindingsTool, createSkillTool, normalizeSkills } from "./synthetic-tools.js";
36
36
  import { compileOutputSchema } from "./strict-output-schema.js";
37
37
  import { TOOL_SEARCH_NAME, buildDeferredRegistry, classifyDeferred, extractDiscoveredToolNames, createPlaceholderTool, createToolSearchTool, } from "./tool-disclosure.js";
@@ -51,6 +51,7 @@ import { dropOrphanToolResults, guardBudget, insertTrimNotice, trimToBudget } fr
51
51
  import { StubExecutionEnv } from "../stub-env.js";
52
52
  import { hasDestroy, isIsolated, isRemoteExecutionEnv, isRetryableRemoteErrorCode, isSuspendable, missingRestoreSurface, RETRYABLE_REMOTE_ERROR_CODES } from "../remote-env.js";
53
53
  import { withRetry } from "../with-retry.js";
54
+ import { settleTeardownLeg } from "./teardown-bounded.js";
54
55
  import { hasBackgroundShell, sweepBackgroundShells } from "../background-shell.js";
55
56
  import { createTaskOutputTool, createTaskStopTool, defaultTaskRegistry } from "../task-registry.js";
56
57
  import { createMonitorTool } from "../../tools/monitor.js";
@@ -62,7 +63,7 @@ import { createSchedulerTools } from "../../tools/scheduler-tools.js";
62
63
  import { createPresentPlanTool, createEnterPlanModeTool, PRESENT_PLAN_TOOL_NAME, ENTER_PLAN_MODE_TOOL_NAME } from "../present-plan-tool.js";
63
64
  import { isSelfOrchestrationActive, selfOrchestrationFailClosedReason } from "../../orchestration/workflow-script-runner.js";
64
65
  import { createRunWorkflowTool, RUN_WORKFLOW_TOOL_NAME } from "../../orchestration/run-workflow-tool.js";
65
- import { createLspTool, gitCheckIgnoreFilter } from "../lsp.js";
66
+ import { createLspTool, gitCheckIgnoreFilter, resolveLspPath } from "../lsp.js";
66
67
  import { resolveKey } from "../../tools/fs/safety.js";
67
68
  import { BINDING_CHECKPOINT_VERSION, mintCheckpointToken, RESOURCE_CHECKPOINT_VERSION, WALLTIME_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, remainingBudgetMicroUsd, } from "../checkpoint-store.js";
68
69
  import { boundInputHashOf } from "../canonical-json.js";
@@ -433,24 +434,30 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
433
434
  }
434
435
  const taskScope = internals?.registryScope ?? spec.principal ?? "default";
435
436
  const offloadScope = spec.principal ?? "default";
437
+ if (internals?.registryScope !== undefined && internals.registryScope !== offloadScope) {
438
+ deps.onError?.(new Error(`offload/tool-result namespace note: this run mounts in registry domain "${internals.registryScope}" but its offloaded tool results live under the TRUST identity "${offloadScope}" (principal${spec.principal === undefined ? " absent → default" : ""}). Before 2.13.0 the registry domain named this namespace too; if a deployment used registryScope as its ref-tenancy boundary, that boundary is now the principal — pass one, or read refs under "${offloadScope}".`), { phase: "config", sessionId });
439
+ }
436
440
  defaultTaskRegistry.maybeGc();
437
441
  const forgetOnThrow = () => forgetQuietly(sessions, sessionId);
438
442
  const extraBodyCollisions = reservedCollisions(model.extraBody, reservedFor(model.api));
439
443
  if (extraBodyCollisions.length > 0) {
440
444
  deps.onError?.(new Error(`model.extraBody contains reserved key(s) [${extraBodyCollisions.join(", ")}] that core owns and sets itself — they are ignored. Remove them from extraBody.`), { phase: "config", sessionId });
441
445
  }
442
- const nestedStats = { tokens: 0, turns: 0, tasks: 0, costMicroUsd: 0 };
446
+ const nestedStats = { tokens: 0, turns: 0, tasks: 0, costMicroUsd: 0, anyUnpriced: false };
443
447
  if (resume) {
444
448
  nestedStats.tokens = resume.seed.nestedStats.tokens;
445
449
  nestedStats.turns = resume.seed.nestedStats.turns;
446
450
  nestedStats.tasks = resume.seed.nestedStats.tasks;
447
451
  nestedStats.costMicroUsd = resume.seed.nestedStats.costMicroUsd;
452
+ nestedStats.anyUnpriced = resume.seed.nestedStats.anyUnpriced ?? true;
448
453
  }
449
454
  const reportUsage = (u) => {
450
455
  nestedStats.tokens += u.tokens;
451
456
  nestedStats.turns += u.turns;
452
457
  nestedStats.tasks += u.tasks;
453
458
  nestedStats.costMicroUsd += u.costMicroUsd ?? 0;
459
+ if (u.costMicroUsd === undefined)
460
+ nestedStats.anyUnpriced = true;
454
461
  };
455
462
  const explicitGlobalThreshold = spec.toolResultThresholdChars ?? deps.toolResultThresholdChars;
456
463
  const offloadThreshold = explicitGlobalThreshold ?? DEFAULT_TOOL_RESULT_THRESHOLD_CHARS;
@@ -479,13 +486,13 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
479
486
  if (offloadStore && (spec.tools ?? []).some((t) => t.name === OFFLOAD_TOOL_NAME)) {
480
487
  const e = new Error(`Tool name "${OFFLOAD_TOOL_NAME}" is reserved when large-result offload is enabled.`);
481
488
  e.code = "config.reserved_tool_name";
482
- await forgetOnThrow();
489
+ await settleTeardownLeg(() => forgetOnThrow(), "forgetOnThrow (reserved-name leg)", (err) => deps.onError?.(err, { phase: "config", sessionId }));
483
490
  throw e;
484
491
  }
485
492
  let ownedEnv;
486
493
  let mcp;
487
494
  if (internals?.requestedCwd !== undefined && deps.executionEnvFactory === undefined) {
488
- await forgetOnThrow();
495
+ await settleTeardownLeg(() => forgetOnThrow(), "forgetOnThrow (cwd-unsupported leg)", (err) => deps.onError?.(err, { phase: "config", sessionId }));
489
496
  const e = new Error(`Agent cwd "${internals.requestedCwd}" cannot take effect: this deployment has no executionEnvFactory (a static execution environment cannot be re-rooted per agent). Drop the cwd parameter or deploy a factory.`);
490
497
  e.code = "config.cwd_unsupported";
491
498
  throw e;
@@ -501,7 +508,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
501
508
  : undefined;
502
509
  }
503
510
  catch (factoryErr) {
504
- await forgetOnThrow();
511
+ await settleTeardownLeg(() => forgetOnThrow(), "forgetOnThrow (env-factory-throw leg)", (err) => deps.onError?.(err, { phase: "config", sessionId }));
505
512
  throw factoryErr;
506
513
  }
507
514
  const executionEnv = ownedEnv ?? deps.executionEnv ?? new StubExecutionEnv();
@@ -512,13 +519,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
512
519
  };
513
520
  const want = await canon(internals.requestedCwd);
514
521
  const rejectCwd = async (message, code) => {
515
- await forgetOnThrow();
516
- try {
517
- if (ownedEnv && hasDestroy(ownedEnv))
518
- await ownedEnv.destroy();
519
- }
520
- catch {
521
- }
522
+ await settleTeardownLeg(() => forgetOnThrow(), "forgetOnThrow (cwd-reject leg)", (err) => deps.onError?.(err, { phase: "config", sessionId }));
523
+ await settleTeardownLeg(() => (ownedEnv && hasDestroy(ownedEnv) ? ownedEnv.destroy() : undefined), "ownedEnv.destroy (cwd-reject leg)", (err) => deps.onError?.(err, { phase: "config", sessionId }));
522
524
  const e = new Error(message);
523
525
  e.code = code;
524
526
  throw e;
@@ -1400,6 +1402,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1400
1402
  ...(internals?.onTaskNotification !== undefined ? { onTaskNotification: internals.onTaskNotification } : {}),
1401
1403
  ...(handsCwdRef !== undefined ? { cwdRef: handsCwdRef } : {}),
1402
1404
  ...(offloadStore !== undefined ? { toolResultStore: offloadStore } : {}),
1405
+ ...(spec.retainBackgroundProcesses === true ? { retainBackgroundProcesses: true } : {}),
1403
1406
  })));
1404
1407
  }
1405
1408
  if (handsCwdRef !== undefined) {
@@ -1463,30 +1466,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1463
1466
  const nudgeLspOnEdit = lspDiagnostics
1464
1467
  ? (rawPath) => {
1465
1468
  const baseDir = handsCwdRef?.current ?? taskRootPath;
1466
- const isAbsForm = rawPath.startsWith("/") || /^[A-Za-z]:[\\/]/.test(rawPath);
1467
- const joinSep = baseDir.includes("\\") ? "\\" : "/";
1468
- const normalizeSegments = (pth) => {
1469
- const isUnc = pth.startsWith("\\\\");
1470
- const drive = /^[A-Za-z]:/.exec(pth)?.[0] ?? "";
1471
- const rest = pth.slice(drive.length + (isUnc ? 2 : 0));
1472
- const sep = pth.includes("\\") ? "\\" : "/";
1473
- const abs = rest.startsWith("/") || rest.startsWith("\\");
1474
- const outSegs = [];
1475
- for (const seg of rest.split(/[\\/]+/)) {
1476
- if (!seg || seg === ".")
1477
- continue;
1478
- if (seg === "..") {
1479
- if (outSegs.length > 0 && outSegs[outSegs.length - 1] !== "..")
1480
- outSegs.pop();
1481
- else if (!abs)
1482
- outSegs.push("..");
1483
- continue;
1484
- }
1485
- outSegs.push(seg);
1486
- }
1487
- return (isUnc ? sep + sep : "") + drive + (abs ? sep : "") + outSegs.join(sep);
1488
- };
1489
- const filePath = normalizeSegments(isAbsForm ? rawPath : baseDir.replace(/[\\/]+$/, "") + joinSep + rawPath);
1469
+ const filePath = resolveLspPath(rawPath, baseDir);
1490
1470
  lspDiagnostics.fileEdited(pathToUri(filePath));
1491
1471
  void lspManager
1492
1472
  .sessionFor(filePath, undefined, executionEnv)
@@ -2743,6 +2723,13 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
2743
2723
  }
2744
2724
  }
2745
2725
  : undefined;
2726
+ const notifyHookError = (err) => {
2727
+ try {
2728
+ deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "hook", sessionId });
2729
+ }
2730
+ catch {
2731
+ }
2732
+ };
2746
2733
  const checkpointStore = spec.checkpointStore ?? deps.checkpointStore;
2747
2734
  const durableApproval = spec.durableApproval ??
2748
2735
  (runtimeCaps?.forceDurableGate ? { scope: spec.principal || DEFAULT_IRREVERSIBLE_SCOPE } : undefined);
@@ -3183,6 +3170,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3183
3170
  reversibilityProbe: reversibilityProbes.get(e.toolName),
3184
3171
  abortSignal: abortController.signal,
3185
3172
  ...(notifyPermissionDenied ? { permissionDenied: notifyPermissionDenied } : {}),
3173
+ onHookError: notifyHookError,
3186
3174
  shellGated: (e.toolName === "Bash" && shellGatedBash) || (e.toolName === "Monitor" && shellGatedMonitor),
3187
3175
  ...(autoModeDecider ? { autoMode: { decider: autoModeDecider } } : {}),
3188
3176
  isMarkedUnresolvable: (toolCallId) => inheritedUnavailableAsks.has(toolCallId),
@@ -3285,11 +3273,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3285
3273
  ...(offloadStore
3286
3274
  ? {
3287
3275
  offload: {
3288
- persist: (toolCallId, fullText) => {
3289
- const ref = buildToolResultRef(sessionId, toolCallId);
3290
- void offloadStore.put(ref, fullText);
3291
- return ref;
3292
- },
3276
+ persist: createOffloadPersist(offloadStore, sessionId),
3293
3277
  },
3294
3278
  }
3295
3279
  : {}),
@@ -3490,20 +3474,14 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3490
3474
  }
3491
3475
  catch (prepareErr) {
3492
3476
  if (mcp) {
3493
- try {
3494
- await mcp.dispose();
3495
- }
3496
- catch {
3497
- }
3477
+ const mcpHandle = mcp;
3478
+ await settleTeardownLeg(() => mcpHandle.dispose(), "mcp.dispose (prepare-throw leg)", (e) => deps.onError?.(e, { phase: "config", sessionId }));
3498
3479
  }
3499
3480
  if (ownedEnv && hasDestroy(ownedEnv)) {
3500
- try {
3501
- await ownedEnv.destroy();
3502
- }
3503
- catch {
3504
- }
3481
+ const env = ownedEnv;
3482
+ await settleTeardownLeg(() => env.destroy(), "ownedEnv.destroy (prepare-throw leg)", (e) => deps.onError?.(e, { phase: "config", sessionId }));
3505
3483
  }
3506
- await forgetOnThrow();
3484
+ await settleTeardownLeg(() => forgetOnThrow(), "forgetOnThrow (prepare-throw leg)", (e) => deps.onError?.(e, { phase: "config", sessionId }));
3507
3485
  throw prepareErr;
3508
3486
  }
3509
3487
  }
@@ -19,6 +19,7 @@ interface ResumeRun {
19
19
  trusted: boolean;
20
20
  };
21
21
  onEnvRestoreFailed?: (reason: ReopenReason) => Promise<void>;
22
+ decisionDelivered?: boolean;
22
23
  }
23
24
  export declare class Runner {
24
25
  private deps;