@sema-agent/core 5.13.0 → 5.15.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 (108) hide show
  1. package/CHANGELOG.md +418 -0
  2. package/dist/agents/send-message-tool.js +1 -0
  3. package/dist/agents/subagent.d.ts +4 -0
  4. package/dist/agents/subagent.js +133 -41
  5. package/dist/brain/anthropic.js +33 -10
  6. package/dist/brain/context-overflow.d.ts +20 -0
  7. package/dist/brain/context-overflow.js +58 -0
  8. package/dist/brain/errors.js +21 -1
  9. package/dist/brain/open-responses.js +24 -10
  10. package/dist/brain/openai.js +29 -11
  11. package/dist/brain/request-params.d.ts +2 -0
  12. package/dist/brain/request-params.js +16 -0
  13. package/dist/brain/retry.d.ts +5 -0
  14. package/dist/brain/retry.js +16 -4
  15. package/dist/brain/stream-engine.d.ts +9 -1
  16. package/dist/brain/stream-engine.js +261 -28
  17. package/dist/brain/timeout.d.ts +1 -0
  18. package/dist/brain/timeout.js +1 -0
  19. package/dist/core/a2a.d.ts +2 -2
  20. package/dist/core/a2a.js +3 -3
  21. package/dist/core/ask-question.d.ts +47 -2
  22. package/dist/core/ask-question.js +209 -28
  23. package/dist/core/background-agent-store.d.ts +2 -0
  24. package/dist/core/checkpoint-store.d.ts +41 -17
  25. package/dist/core/checkpoint-store.js +137 -6
  26. package/dist/core/hooks.d.ts +24 -2
  27. package/dist/core/hooks.js +97 -10
  28. package/dist/core/human-input-projection.d.ts +12 -0
  29. package/dist/core/human-input-projection.js +27 -0
  30. package/dist/core/mcp.d.ts +7 -2
  31. package/dist/core/mcp.js +7 -7
  32. package/dist/core/memory-admission.d.ts +4 -0
  33. package/dist/core/memory-admission.js +3 -0
  34. package/dist/core/memory-engine/engine.d.ts +3 -1
  35. package/dist/core/memory-engine/engine.js +4 -3
  36. package/dist/core/memory-recall.d.ts +1 -1
  37. package/dist/core/memory-recall.js +3 -2
  38. package/dist/core/runner/assemble-result.d.ts +1 -0
  39. package/dist/core/runner/assemble-result.js +1 -1
  40. package/dist/core/runner/prepare-memory.d.ts +1 -0
  41. package/dist/core/runner/prepare-memory.js +3 -3
  42. package/dist/core/runner/prepare-task.d.ts +19 -6
  43. package/dist/core/runner/prepare-task.js +343 -35
  44. package/dist/core/runner/runtask.d.ts +3 -6
  45. package/dist/core/runner/runtask.js +290 -64
  46. package/dist/core/runner/tool-disclosure.d.ts +5 -0
  47. package/dist/core/runner/tool-disclosure.js +65 -16
  48. package/dist/core/runner/tool-output-projection.js +1 -0
  49. package/dist/core/runner/turn-attachments.d.ts +4 -0
  50. package/dist/core/runner/turn-attachments.js +15 -2
  51. package/dist/core/session-store.d.ts +3 -0
  52. package/dist/core/session-store.js +4 -0
  53. package/dist/core/session.d.ts +1 -0
  54. package/dist/core/store-contracts/background-agent-store-contract.js +19 -0
  55. package/dist/core/store-contracts/checkpoint-store-contract.js +62 -3
  56. package/dist/core/task-notification.d.ts +2 -0
  57. package/dist/core/task-notification.js +5 -3
  58. package/dist/core/task-registry-agent.d.ts +1 -0
  59. package/dist/core/task-registry-agent.js +6 -0
  60. package/dist/core/task-registry.d.ts +1 -0
  61. package/dist/core/task-registry.js +4 -1
  62. package/dist/core/task-tool-shape.js +4 -3
  63. package/dist/core/tool-policy.d.ts +5 -0
  64. package/dist/core/tool-policy.js +2 -1
  65. package/dist/core/trace.d.ts +6 -0
  66. package/dist/core/types.d.ts +32 -1
  67. package/dist/core/wiring-manifest.d.ts +97 -0
  68. package/dist/core/wiring-manifest.js +186 -0
  69. package/dist/engine/compaction/compaction.js +2 -2
  70. package/dist/engine/harness/agent-harness.d.ts +2 -1
  71. package/dist/engine/harness/agent-harness.js +8 -1
  72. package/dist/engine/harness/types.d.ts +3 -1
  73. package/dist/engine/llm/types.d.ts +7 -0
  74. package/dist/engine/llm/types.js +8 -1
  75. package/dist/engine/session/import-validate.d.ts +6 -1
  76. package/dist/engine/session/import-validate.js +29 -6
  77. package/dist/engine/session/memory-repo.d.ts +3 -1
  78. package/dist/engine/session/memory-repo.js +2 -2
  79. package/dist/index.d.ts +10 -7
  80. package/dist/index.js +8 -5
  81. package/dist/internal/harness-types.d.ts +1 -1
  82. package/dist/internal/llm.d.ts +2 -2
  83. package/dist/internal/llm.js +1 -1
  84. package/dist/orchestration/run-workflow-tool.d.ts +4 -0
  85. package/dist/orchestration/run-workflow-tool.js +3 -0
  86. package/dist/orchestration/workflow-types.d.ts +8 -0
  87. package/dist/orchestration/workflow-types.js +14 -0
  88. package/dist/orchestration/workflow.d.ts +4 -0
  89. package/dist/orchestration/workflow.js +134 -5
  90. package/dist/prompts/default.js +1 -1
  91. package/dist/prompts/supervisor.d.ts +2 -2
  92. package/dist/prompts/supervisor.js +5 -4
  93. package/dist/stores/file/checkpoint-store.d.ts +3 -5
  94. package/dist/stores/file/checkpoint-store.js +31 -2
  95. package/dist/stores/file/index.js +1 -1
  96. package/dist/stores/file/session-store.d.ts +3 -1
  97. package/dist/stores/file/session-store.js +2 -2
  98. package/dist/stores/file/shared-ledger.js +8 -1
  99. package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -0
  100. package/dist/tools/fs/bash-readonly-classifier.js +94 -0
  101. package/dist/tools/fs/fs-bash.d.ts +1 -0
  102. package/dist/tools/fs/fs-bash.js +32 -13
  103. package/dist/tools/fs/gh-rate-limit.d.ts +1 -1
  104. package/dist/tools/fs/gh-rate-limit.js +4 -3
  105. package/dist/tools/fs/index.d.ts +1 -0
  106. package/dist/tools/fs/index.js +1 -0
  107. package/dist/tools/fs/safety.js +34 -10
  108. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import type { DocumentContent, ImageContent, TextContent } from "../internal/llm.js";
2
- import type { SessionTreeEntry } from "../internal/harness-types.js";
2
+ import type { ExecutionEnv, FileError, Result, SessionTreeEntry } from "../internal/harness-types.js";
3
3
  import type { PermissionResult, ResolvedAsk, ToolCallRequest } from "./tool-policy.js";
4
4
  export interface Hooks {
5
5
  preToolUse?(toolName: string, input: unknown, ctx: HookToolContext): PreToolUseResult | undefined | Promise<PreToolUseResult | undefined>;
@@ -72,9 +72,17 @@ export interface StopHookResult {
72
72
  block?: string;
73
73
  additionalContext?: string;
74
74
  }
75
+ export interface HookEnvCapabilities {
76
+ canonicalPath?(path: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
77
+ exists?(path: string, abortSignal?: AbortSignal): Promise<Result<boolean, FileError>>;
78
+ readLink?(path: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
79
+ cwd?(): string;
80
+ }
81
+ export declare function createHookEnvCapabilities(env: ExecutionEnv): HookEnvCapabilities;
75
82
  export interface HookToolContext {
76
83
  toolCallId: string;
77
84
  toolName: string;
85
+ env?: HookEnvCapabilities;
78
86
  }
79
87
  export interface HookToolOutput {
80
88
  content: Array<TextContent | ImageContent | DocumentContent>;
@@ -103,6 +111,18 @@ export interface ToolGateResult {
103
111
  };
104
112
  preToolContext: string[];
105
113
  }
114
+ export type ContentAskOutcome = {
115
+ kind: "answered";
116
+ presentedInput: unknown;
117
+ } | {
118
+ kind: "unavailable";
119
+ presentedInput?: unknown;
120
+ parkDeclined: boolean;
121
+ } | {
122
+ kind: "delivery_failure";
123
+ code: string;
124
+ presentedInput?: unknown;
125
+ };
106
126
  export interface ToolGateInput {
107
127
  onNotifyError?: (failure: import("./safe-notify.js").SafeNotifyFailure) => void;
108
128
  event: {
@@ -111,9 +131,11 @@ export interface ToolGateInput {
111
131
  input: Record<string, unknown>;
112
132
  };
113
133
  preToolUse?: Hooks["preToolUse"];
134
+ hookEnv?: HookEnvCapabilities;
114
135
  adjudicate?: (req: ToolCallRequest) => Promise<PermissionResult>;
115
136
  resolveAsk: (decision: PermissionResult, req: ToolCallRequest) => Promise<ResolvedAsk>;
116
- suspendAsk?: (req: ToolCallRequest, postHookArgs: unknown, safety?: import("./checkpoint-store.js").SafetyAxis, approverUnavailable?: boolean) => Promise<ToolGateResult["suspend"] | undefined>;
137
+ suspendAsk?: (req: ToolCallRequest, postHookArgs: unknown, safety?: import("./checkpoint-store.js").SafetyAxis, liveFaceUnavailable?: boolean) => Promise<ToolGateResult["suspend"] | undefined>;
138
+ resolveContentAsk?: (req: ToolCallRequest) => Promise<ContentAskOutcome>;
117
139
  egress?: boolean;
118
140
  irreversibility?: "never" | "maybe" | "always";
119
141
  reversibilityProbe?: (args: unknown) => {
@@ -14,6 +14,67 @@ export function cloneObserverInput(input) {
14
14
  return input;
15
15
  }
16
16
  }
17
+ const reflectApply = Reflect.apply;
18
+ const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
19
+ const getPrototypeOf = Object.getPrototypeOf;
20
+ const objectPrototype = Object.prototype;
21
+ function findEnvSlot(env, key) {
22
+ for (let o = env; o !== null && o !== objectPrototype; o = getPrototypeOf(o)) {
23
+ const desc = getOwnPropertyDescriptor(o, key);
24
+ if (desc !== undefined)
25
+ return { holder: o, desc };
26
+ }
27
+ return undefined;
28
+ }
29
+ function readEnvPrimitive(env, key) {
30
+ const slot = findEnvSlot(env, key);
31
+ if (slot === undefined)
32
+ return undefined;
33
+ return slot.desc.get !== undefined ? reflectApply(slot.desc.get, env, []) : slot.desc.value;
34
+ }
35
+ function createCwdReader(env) {
36
+ const slot = findEnvSlot(env, "cwd");
37
+ if (slot === undefined)
38
+ return undefined;
39
+ const getter = slot.desc.get;
40
+ const initial = getter !== undefined ? reflectApply(getter, env, []) : slot.desc.value;
41
+ if (typeof initial !== "string")
42
+ return undefined;
43
+ let last = initial;
44
+ return () => {
45
+ const desc = getOwnPropertyDescriptor(slot.holder, "cwd");
46
+ const value = desc === undefined
47
+ ? undefined
48
+ : desc.get !== undefined
49
+ ? desc.get === getter
50
+ ? reflectApply(desc.get, env, [])
51
+ : undefined
52
+ : desc.value;
53
+ if (typeof value === "string")
54
+ last = value;
55
+ return last;
56
+ };
57
+ }
58
+ export function createHookEnvCapabilities(env) {
59
+ const face = Object.create(null);
60
+ const canonicalPath = readEnvPrimitive(env, "canonicalPath");
61
+ const exists = readEnvPrimitive(env, "exists");
62
+ const readLink = readEnvPrimitive(env, "readLink");
63
+ const cwd = createCwdReader(env);
64
+ if (typeof canonicalPath === "function") {
65
+ face.canonicalPath = (path, abortSignal) => reflectApply(canonicalPath, env, [path, abortSignal]);
66
+ }
67
+ if (typeof exists === "function") {
68
+ face.exists = (path, abortSignal) => reflectApply(exists, env, [path, abortSignal]);
69
+ }
70
+ if (typeof readLink === "function") {
71
+ face.readLink = (path, abortSignal) => reflectApply(readLink, env, [path, abortSignal]);
72
+ }
73
+ if (cwd !== undefined) {
74
+ face.cwd = cwd;
75
+ }
76
+ return Object.freeze(face);
77
+ }
17
78
  export function formatHookFeedback(text) {
18
79
  return `<system-reminder>\n${text}\n</system-reminder>`;
19
80
  }
@@ -61,6 +122,7 @@ function withProbeTimeout(p, ms, signal) {
61
122
  export async function runToolGate(input) {
62
123
  const { event, preToolUse, adjudicate, resolveAsk, suspendAsk } = input;
63
124
  const { toolCallId, toolName } = event;
125
+ const hookCtx = () => ({ toolCallId, toolName, ...(input.hookEnv !== undefined ? { env: input.hookEnv } : {}) });
64
126
  let currentInput = event.input;
65
127
  const preToolContext = [];
66
128
  let hookAsk;
@@ -68,7 +130,7 @@ export async function runToolGate(input) {
68
130
  if (preToolUse) {
69
131
  let r;
70
132
  try {
71
- r = screenPreToolUseResult(await preToolUse(toolName, currentInput, { toolCallId, toolName }));
133
+ r = screenPreToolUseResult(await preToolUse(toolName, currentInput, hookCtx()));
72
134
  }
73
135
  catch (err) {
74
136
  const reason = preToolUseCrashReason(`this call to "${toolName}"`, err);
@@ -147,7 +209,10 @@ export async function runToolGate(input) {
147
209
  currentInput = policyRewrite;
148
210
  req.args = policyRewrite;
149
211
  }
150
- if (input.autoMode && decision.action === "ask" && input.isMarkedUnresolvable?.(input.event.toolCallId) !== true) {
212
+ if (input.autoMode &&
213
+ decision.action === "ask" &&
214
+ req.toolName !== ASK_USER_QUESTION_TOOL_NAME &&
215
+ input.isMarkedUnresolvable?.(input.event.toolCallId) !== true) {
151
216
  const verdict = await input.autoMode.decider
152
217
  .decide({ req, askMessage: decisionText(decision) }, input.abortSignal)
153
218
  .catch(() => ({ kind: "unavailable", cause: "error" }));
@@ -180,13 +245,35 @@ export async function runToolGate(input) {
180
245
  }
181
246
  }
182
247
  if (decision.action === "ask" && req.toolName === ASK_USER_QUESTION_TOOL_NAME) {
183
- decision = {
184
- action: "deny",
185
- message: "AskUserQuestion could not be parked for a durable human answer on this path (no checkpoint " +
186
- "facility, or the suspend failed) and a synchronous permission approver cannot carry an answer — " +
187
- "the question was NOT shown to anyone. Proceed with your best judgment and state the assumption " +
188
- "you made.",
189
- };
248
+ const outcome = input.resolveContentAsk !== undefined ? await input.resolveContentAsk(req) : { kind: "unavailable", parkDeclined: false };
249
+ if (outcome.kind === "answered") {
250
+ decision = { action: "allow", updatedInput: outcome.presentedInput };
251
+ }
252
+ else if (outcome.kind === "unavailable") {
253
+ if (outcome.presentedInput !== undefined) {
254
+ currentInput = outcome.presentedInput;
255
+ req.args = outcome.presentedInput;
256
+ }
257
+ if (suspendAsk && outcome.parkDeclined) {
258
+ const suspended = await suspendAsk(req, currentInput, safety, true);
259
+ if (suspended) {
260
+ return { suspend: suspended, preToolContext };
261
+ }
262
+ }
263
+ decision = {
264
+ action: "deny",
265
+ message: "AskUserQuestion could not be parked for a durable human answer on this path (no checkpoint " +
266
+ "facility, or the suspend failed) and a synchronous permission approver cannot carry an answer — " +
267
+ "the question was NOT shown to anyone. Proceed with your best judgment and state the assumption " +
268
+ "you made.",
269
+ };
270
+ }
271
+ else {
272
+ if (outcome.presentedInput !== undefined)
273
+ decision = { action: "allow", updatedInput: outcome.presentedInput };
274
+ else
275
+ decision = { action: "allow" };
276
+ }
190
277
  }
191
278
  if (decision.action === "ask") {
192
279
  const resolved = await resolveAsk(decision, req);
@@ -212,7 +299,7 @@ export async function runToolGate(input) {
212
299
  if (preToolUse) {
213
300
  let hr;
214
301
  try {
215
- hr = screenPreToolUseResult(await preToolUse(toolName, editArgs, { toolCallId, toolName }));
302
+ hr = screenPreToolUseResult(await preToolUse(toolName, editArgs, hookCtx()));
216
303
  }
217
304
  catch (err) {
218
305
  traceHookCrash(input, err, notifier);
@@ -0,0 +1,12 @@
1
+ import { type ActorAssertion } from "../internal/llm.js";
2
+ import type { HumanInputEvent, HumanInputSource, TaskEventIdentity } from "./types.js";
3
+ export type { HumanInputSource, HumanInputDelivery, HumanInputEvent } from "./types.js";
4
+ export interface HumanInputFrame {
5
+ text: string;
6
+ actor?: ActorAssertion;
7
+ source: HumanInputSource;
8
+ }
9
+ export declare function projectHumanInput(frame: HumanInputFrame): string;
10
+ export declare function buildHumanInputEvent(input: Omit<HumanInputEvent, "type" | "inputId" | keyof TaskEventIdentity> & {
11
+ inputId?: string;
12
+ }): HumanInputEvent;
@@ -0,0 +1,27 @@
1
+ import { snapshotActorAssertion } from "../internal/llm.js";
2
+ import { uuidv7 } from "../internal/harness.js";
3
+ import { inlineUntrusted } from "./untrusted-text.js";
4
+ import { attrEscape, EXTERNAL_SOURCE_MAX } from "./task-notification.js";
5
+ export function projectHumanInput(frame) {
6
+ if (frame.actor === undefined || frame.source === "system")
7
+ return frame.text;
8
+ if (frame.text.trim().length === 0)
9
+ return frame.text;
10
+ const label = attrEscape(inlineUntrusted(frame.actor.id, EXTERNAL_SOURCE_MAX));
11
+ const mark = frame.actor.hostAsserted ? "" : " (unverified)";
12
+ return `[from "${label}"${mark}]\n${frame.text}`;
13
+ }
14
+ export function buildHumanInputEvent(input) {
15
+ return {
16
+ type: "human_input",
17
+ inputId: input.inputId ?? uuidv7(),
18
+ sessionSeq: input.sessionSeq,
19
+ carrier: input.carrier,
20
+ source: input.source,
21
+ delivery: input.delivery,
22
+ ...(input.issuer !== undefined ? { issuer: input.issuer } : {}),
23
+ ...(input.actor !== undefined ? { actor: snapshotActorAssertion(input.actor) } : {}),
24
+ ...(input.principal !== undefined ? { principal: input.principal } : {}),
25
+ ...(input.entryId !== undefined ? { entryId: input.entryId } : {}),
26
+ };
27
+ }
@@ -5,8 +5,8 @@ import { type McpImageResizer } from "./image-downsample.js";
5
5
  import type { McpServerSpec, OnElicit, ToolEffect } from "./types.js";
6
6
  export interface McpToolAxis {
7
7
  name: string;
8
- irreversibility?: "always";
9
- egress?: true;
8
+ irreversibility?: "always" | "never";
9
+ egress?: boolean;
10
10
  effect?: ToolEffect;
11
11
  }
12
12
  export interface McpDroppedTool {
@@ -114,6 +114,11 @@ export type McpSchemaNormalizeResult = {
114
114
  export declare function normalizeMcpToolSchema(schema: unknown): McpSchemaNormalizeResult;
115
115
  export declare function mcpToolSchemaProblem(schema: unknown): string | undefined;
116
116
  export declare function materializeMcpTools(specs: McpServerSpec[], principal?: string, onElicit?: OnElicit, imageResizer?: McpImageResizer): Promise<MaterializedMcp>;
117
+ export declare function applyCallerAxisOverride(name: string, hint: McpToolAxis | undefined, override: {
118
+ effect?: ToolEffect;
119
+ egress?: boolean;
120
+ irreversibility?: "always" | "never";
121
+ } | undefined): McpToolAxis | undefined;
117
122
  export declare function classifyDirReadInvalidParams(message: string): "not_found" | "not_directory";
118
123
  export declare function parseCallToolResultLenient(data: unknown): {
119
124
  success: true;
package/dist/core/mcp.js CHANGED
@@ -720,7 +720,7 @@ function mcpAxisFor(namespacedName, annotations) {
720
720
  }
721
721
  return any ? axis : undefined;
722
722
  }
723
- function applyCallerAxisOverride(name, hint, override) {
723
+ export function applyCallerAxisOverride(name, hint, override) {
724
724
  if (!override)
725
725
  return hint;
726
726
  let effect = hint?.effect;
@@ -729,16 +729,16 @@ function applyCallerAxisOverride(name, hint, override) {
729
729
  if (override.effect !== undefined)
730
730
  effect = override.effect;
731
731
  if (override.egress !== undefined)
732
- egress = override.egress ? true : undefined;
732
+ egress = override.egress;
733
733
  if (override.irreversibility !== undefined)
734
- irrev = override.irreversibility === "always" ? "always" : undefined;
734
+ irrev = override.irreversibility;
735
735
  const axis = { name };
736
736
  if (effect !== undefined)
737
737
  axis.effect = effect;
738
- if (egress)
739
- axis.egress = true;
740
- if (irrev)
741
- axis.irreversibility = "always";
738
+ if (egress !== undefined)
739
+ axis.egress = egress;
740
+ if (irrev !== undefined)
741
+ axis.irreversibility = irrev;
742
742
  return axis.effect !== undefined || axis.egress !== undefined || axis.irreversibility !== undefined ? axis : undefined;
743
743
  }
744
744
  const LIST_MCP_RESOURCES = "ListMcpResourcesTool";
@@ -44,4 +44,8 @@ export interface OwnOrgAdmissionVerdict {
44
44
  scopes: readonly string[];
45
45
  writeScope: string | null;
46
46
  }
47
+ export declare function readDurableOrgAdmission(row: {
48
+ admittedOrgScopes?: readonly string[];
49
+ admittedOrgWriteScope?: string | null;
50
+ }): OwnOrgAdmissionVerdict;
47
51
  export declare function admitMemoryScopes(input: MemoryAdmissionInput): Promise<MemoryAdmissionOutcome>;
@@ -7,6 +7,9 @@ function codedError(code, message) {
7
7
  export function foldAdmissionFreeze(input) {
8
8
  return input.delegated ? (input.inherited ?? []) : input.inherited;
9
9
  }
10
+ export function readDurableOrgAdmission(row) {
11
+ return { scopes: row.admittedOrgScopes ?? [], writeScope: row.admittedOrgWriteScope ?? null };
12
+ }
10
13
  const ORG_SHAPE = /^org:/;
11
14
  function orgScopesOf(spec) {
12
15
  if (spec.scopeContract !== "v2")
@@ -49,7 +49,9 @@ export declare class MemoryEngine {
49
49
  constructor(opts: MemoryEngineOptions);
50
50
  private discloseAnnounceFailure;
51
51
  materialize(scopes: readonly string[], writeScope: string | null): Promise<MemorySessionHandle>;
52
- inject(handle: MemorySessionHandle): MemoryInjection;
52
+ inject(handle: MemorySessionHandle, opts?: {
53
+ writeToolMounted?: boolean;
54
+ }): MemoryInjection;
53
55
  gateWrite(handle: MemorySessionHandle, canonicalPath: string, content: string): {
54
56
  ok: true;
55
57
  } | {
@@ -188,14 +188,15 @@ export class MemoryEngine {
188
188
  }
189
189
  return handle;
190
190
  }
191
- inject(handle) {
192
- const instruction = handle.writeScope !== null ? buildMemoryInstruction(handle.writableRoot) : "";
191
+ inject(handle, opts) {
192
+ const writeChannel = handle.writeScope !== null && opts?.writeToolMounted !== false;
193
+ const instruction = writeChannel ? buildMemoryInstruction(handle.writableRoot) : "";
193
194
  const indexPath = join(handle.writableRoot, MEMORY_INDEX_FILENAME);
194
195
  const onDisk = readSafe(indexPath);
195
196
  const indexText = onDisk !== undefined && onDisk.trim() !== "" ? onDisk : handle.indexText;
196
197
  const truncated = truncateIndex(indexText);
197
198
  const index = composeMemoryBlock(truncated, handle.writeScope ?? handle.scopes[0] ?? "memory");
198
- const indexSeed = handle.writeScope !== null && onDisk !== undefined && (onDisk.trim() === "" || truncated === onDisk)
199
+ const indexSeed = writeChannel && onDisk !== undefined && (onDisk.trim() === "" || truncated === onDisk)
199
200
  ? { path: indexPath, content: onDisk }
200
201
  : undefined;
201
202
  let announcements;
@@ -36,7 +36,7 @@ export type SelectiveRecallResult = {
36
36
  export declare function resolveLinkedIds(headers: MemoryNoteHeader[], selected: MemoryNoteRecord[], max: number): string[];
37
37
  export declare function buildManifestText(headers: MemoryNoteHeader[]): string;
38
38
  export declare function validateSelectedIds(headers: MemoryNoteHeader[], ids: string[], max: number): string[];
39
- export declare function composeSelectiveBody(manifestText: string, selected: MemoryNoteRecord[], nowMs: number, linked?: MemoryNoteRecord[], recallable?: boolean): string;
39
+ export declare function composeSelectiveBody(manifestText: string, selected: MemoryNoteRecord[], nowMs: number, linked?: MemoryNoteRecord[], recallable?: boolean, recallToolName?: string): string;
40
40
  export declare function encodeSurfacedKey(scope: string, id: string): string;
41
41
  export interface ScopedNoteHeader extends MemoryNoteHeader {
42
42
  scope: string;
@@ -102,7 +102,7 @@ export function validateSelectedIds(headers, ids, max) {
102
102
  }
103
103
  return out;
104
104
  }
105
- export function composeSelectiveBody(manifestText, selected, nowMs, linked = [], recallable = true) {
105
+ export function composeSelectiveBody(manifestText, selected, nowMs, linked = [], recallable = true, recallToolName) {
106
106
  const renderNote = (r, label) => {
107
107
  const ageMs = nowMs - r.mtimeMs;
108
108
  const verify = r.timestampMissing || ageMs > ONE_DAY_MS ? " — verify it's still current" : "";
@@ -124,8 +124,9 @@ export function composeSelectiveBody(manifestText, selected, nowMs, linked = [],
124
124
  body = `${buf.subarray(0, cut).toString("utf8")}\n<selected notes truncated to ${SELECTED_BODY_MAX_BYTES} bytes>`;
125
125
  }
126
126
  const selectedSection = selected.length > 0 ? `\n\nRelevant notes:\n${body}` : "\n\n(no notes selected as relevant to this task)";
127
+ const recallCall = recallToolName !== undefined ? `call ${recallToolName}` : `search the memory-recall tool bound to this scope`;
127
128
  const manifestSection = recallable
128
- ? `Memory index — to load a note in full, call Recall with keywords from its description:\n${sanitizeUntrustedText(manifestText, ["user_memory"])}`
129
+ ? `Memory index — to load a note in full, ${recallCall} with keywords from its description:\n${sanitizeUntrustedText(manifestText, ["user_memory"])}`
129
130
  : "";
130
131
  return `${manifestSection}${selectedSection}`;
131
132
  }
@@ -58,6 +58,7 @@ export interface ResultFlags {
58
58
  model?: string;
59
59
  unpricedSpend?: boolean;
60
60
  rewindNotes?: TaskResult["rewindNotes"];
61
+ strandedHumanAnswers?: TaskResult["strandedHumanAnswers"];
61
62
  remoteEnvFailures?: TaskResult["remoteEnvFailures"];
62
63
  retryAfterMs?: number;
63
64
  abortedForTimeout: boolean;
@@ -159,5 +159,5 @@ export function assembleResult(spec, sessionId, final, stats, flags) {
159
159
  void _internalCompaction;
160
160
  if (flags.unpricedSpend)
161
161
  delete publicStats.costMicroUsd;
162
- return { taskId, sessionId, status, ...(flags.model !== undefined ? { model: flags.model } : {}), result: result.trim(), salvagedOutput, blockedReason, errorMessage, errorCode, ...(retryAfterMs !== undefined ? { retryAfterMs } : {}), checkpointToken, checkpointGate, ...(workspaceRestoreMode !== undefined ? { workspaceRestoreMode } : {}), ...(flags.rewindNotes !== undefined && flags.rewindNotes.length > 0 ? { rewindNotes: flags.rewindNotes } : {}), ...(flags.remoteEnvFailures !== undefined && flags.remoteEnvFailures.length > 0 ? { remoteEnvFailures: flags.remoteEnvFailures } : {}), stats: publicStats };
162
+ return { taskId, sessionId, status, ...(flags.model !== undefined ? { model: flags.model } : {}), result: result.trim(), salvagedOutput, blockedReason, errorMessage, errorCode, ...(retryAfterMs !== undefined ? { retryAfterMs } : {}), checkpointToken, checkpointGate, ...(workspaceRestoreMode !== undefined ? { workspaceRestoreMode } : {}), ...(flags.rewindNotes !== undefined && flags.rewindNotes.length > 0 ? { rewindNotes: flags.rewindNotes } : {}), ...(flags.remoteEnvFailures !== undefined && flags.remoteEnvFailures.length > 0 ? { remoteEnvFailures: flags.remoteEnvFailures } : {}), ...(flags.strandedHumanAnswers !== undefined && flags.strandedHumanAnswers.length > 0 ? { strandedHumanAnswers: flags.strandedHumanAnswers } : {}), stats: publicStats };
163
163
  }
@@ -8,6 +8,7 @@ export interface PrepareMemoryInput {
8
8
  memoryWriteGateRef: {
9
9
  current?: BeforeWriteHook;
10
10
  };
11
+ writeToolsMounted: boolean;
11
12
  admissionCtx: {
12
13
  orgMemoryDenied: boolean;
13
14
  complianceDegraded: boolean;
@@ -135,7 +135,7 @@ export async function prepareMemory(input) {
135
135
  const writeIsPersonal = p.writePlane === "personal";
136
136
  writeEngine = writeIsPersonal ? personalEngine : projectEngine;
137
137
  writeHandle = writeIsPersonal ? personalHandle : projectHandle;
138
- injectFn = () => mergeInjections(projectEngine.inject(projectHandle), personalEngine.inject(personalHandle));
138
+ injectFn = () => mergeInjections(projectEngine.inject(projectHandle, { writeToolMounted: input.writeToolsMounted }), personalEngine.inject(personalHandle, { writeToolMounted: input.writeToolsMounted }));
139
139
  harvestBoth = async () => {
140
140
  const writeFirst = writeIsPersonal ? [personalEngine, personalHandle] : [projectEngine, projectHandle];
141
141
  const readOther = writeIsPersonal ? [projectEngine, projectHandle] : [personalEngine, personalHandle];
@@ -159,7 +159,7 @@ export async function prepareMemory(input) {
159
159
  const handle = await personalEngine.materialize(memorySpec.scopes, memorySpec.writeScope);
160
160
  writeEngine = personalEngine;
161
161
  writeHandle = handle;
162
- injectFn = () => personalEngine.inject(handle);
162
+ injectFn = () => personalEngine.inject(handle, { writeToolMounted: input.writeToolsMounted });
163
163
  harvestBoth = () => personalEngine.harvest(handle);
164
164
  }
165
165
  else {
@@ -171,7 +171,7 @@ export async function prepareMemory(input) {
171
171
  const handle = await engine.materialize(memorySpec.scopes, memorySpec.writeScope);
172
172
  writeEngine = engine;
173
173
  writeHandle = handle;
174
- injectFn = () => engine.inject(handle);
174
+ injectFn = () => engine.inject(handle, { writeToolMounted: input.writeToolsMounted });
175
175
  harvestBoth = () => engine.harvest(handle);
176
176
  }
177
177
  memoryWriteGateRef.current = (w) => writeEngine.gateWrite(writeHandle, w.key, w.content);
@@ -16,11 +16,13 @@ import { type BrainCallGuardrailRef } from "../../brain/timeout.js";
16
16
  import { type OutputRef, type BlockedRef, type SkillListingEntry } from "./synthetic-tools.js";
17
17
  import type { MemoryEngine } from "../memory-engine/engine.js";
18
18
  import { type ToolManifestRow } from "../../prompt-assembly/tool-catalog.js";
19
+ import type { ToolDisclosureManifest } from "../trace.js";
19
20
  import type { TaskNotificationPayload } from "../task-notification.js";
20
21
  import { type CwdRef } from "../../tools/fs/index.js";
21
22
  import { type WorkflowSizeGuideline } from "../../orchestration/workflow-size-guideline.js";
22
23
  import type { Runner } from "./runtask.js";
23
- import { type CheckpointGate, type CheckpointState, type CheckpointStore, type CheckpointToken, type ResourceLedger, type PlatformLimitReason, type ResourceLimitReason } from "../checkpoint-store.js";
24
+ import { type CheckpointGate, type CheckpointState, type CheckpointToken, type ResourceLedger, type PlatformLimitReason, type ResourceLimitReason } from "../checkpoint-store.js";
25
+ import { type WiringManifest } from "../wiring-manifest.js";
24
26
  import type { ActiveWorktreeSession, AgentMessage, AgentTool, ExecutionEnv } from "../../internal/harness.js";
25
27
  import type { NestedUsageAccum, RunnerDeps, TaskEvent, TaskLimits, TaskResult, TaskSpec, ToolActivity, ToolEffect } from "../types.js";
26
28
  import type { RepairBundle } from "../../agents/repair-loop.js";
@@ -44,11 +46,7 @@ export declare function checkpointScopeOf(spec: {
44
46
  };
45
47
  principal?: string;
46
48
  }): string;
47
- export declare function resolveCheckpointStore(spec: {
48
- checkpointStore?: CheckpointStore | null;
49
- }, deps: {
50
- checkpointStore?: CheckpointStore;
51
- }): CheckpointStore | undefined;
49
+ export { resolveCheckpointStore } from "../checkpoint-store.js";
52
50
  export interface Prepared {
53
51
  harness: AgentHarness;
54
52
  session: StoredSession;
@@ -81,11 +79,16 @@ export interface Prepared {
81
79
  denyNarrowingPolicy?: ToolPolicy;
82
80
  basePolicyForResumeEdit?: ToolPolicy;
83
81
  releaseSignal: () => void;
82
+ settleContentAskBindings: () => ReadonlyArray<{
83
+ deliveryId: string;
84
+ toolCallId: string;
85
+ }>;
84
86
  cacheBreakDetector?: CacheBreakDetector;
85
87
  cacheFingerprint?: {
86
88
  systemPrompt: string;
87
89
  tools: ToolFingerprintInput[];
88
90
  };
91
+ wiringManifest: WiringManifest;
89
92
  promptManifest: {
90
93
  constitution: "core" | "replaced" | "provider-assembled";
91
94
  blocks: Array<{
@@ -109,6 +112,7 @@ export interface Prepared {
109
112
  elements: import("../../prompt-assembly/turn-snapshot.js").CacheIdentityElements;
110
113
  };
111
114
  lowering?: import("../../prompt-assembly/turn-snapshot.js").LoweringRecord;
115
+ toolDisclosure?: ToolDisclosureManifest;
112
116
  };
113
117
  epochDeclaredSections: import("../../prompt-assembly/epoch.js").EpochDeclaredSections;
114
118
  turnSnapshot?: import("../../prompt-assembly/turn-snapshot.js").TurnPromptSnapshot;
@@ -123,6 +127,7 @@ export interface Prepared {
123
127
  activeTools: Set<string>;
124
128
  deferredToolNames?: ReadonlySet<string>;
125
129
  toolMaterializeStatic: boolean;
130
+ staticFaceFor?: (name: string) => boolean;
126
131
  memoryEngineSession?: {
127
132
  engine: MemoryEngine;
128
133
  handle: MemorySessionHandle;
@@ -294,6 +299,8 @@ export interface PrepareResume {
294
299
  }>;
295
300
  };
296
301
  workspaceHandle?: import("../remote-env.js").WorkspaceHandle;
302
+ redeemedContentAskCallId?: string;
303
+ redeemedContentAskQuestionsHash?: string;
297
304
  executesApprovedAction?: boolean;
298
305
  }
299
306
  export interface InheritedGate {
@@ -325,8 +332,13 @@ export declare function resolveModelPromptTraits(model: {
325
332
  };
326
333
  export interface RunInternals {
327
334
  repairBundle?: RepairBundle;
335
+ questionFaceStripped?: true;
336
+ parentInteractionPosture?: "interactive" | "headless";
328
337
  afterCheckpointResolve?: () => Promise<void>;
329
338
  inheritedGate?: InheritedGate;
339
+ ownOrgAdmissionRef?: {
340
+ current: import("../memory-admission.js").OwnOrgAdmissionVerdict | undefined;
341
+ };
330
342
  workflowDepth?: number;
331
343
  insideFork?: boolean;
332
344
  isDelegatedChild?: boolean;
@@ -338,6 +350,7 @@ export interface RunInternals {
338
350
  explicitAgentName?: string;
339
351
  parentTaskId?: string;
340
352
  parentSessionId?: string;
353
+ delegationTaskType?: import("../types.js").DelegationTaskType;
341
354
  rootSessionId?: string;
342
355
  registryScope?: string;
343
356
  parentCenterArtifactDigest?: string;