@sema-agent/core 7.5.0 → 7.5.1

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 (62) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/core/auto-mode.d.ts +9 -0
  3. package/dist/core/auto-mode.js +11 -0
  4. package/dist/core/checkpoint-store.js +5 -1
  5. package/dist/core/runner/checkpoint-scope.d.ts +32 -0
  6. package/dist/core/runner/checkpoint-scope.js +4 -0
  7. package/dist/core/runner/contracts.d.ts +1878 -0
  8. package/dist/core/runner/contracts.js +1 -0
  9. package/dist/core/runner/denial-limit-arms.d.ts +1 -1
  10. package/dist/core/runner/derived-route-fallback.d.ts +34 -0
  11. package/dist/core/runner/derived-route-fallback.js +16 -0
  12. package/dist/core/runner/prepare-acquire-reconcile.d.ts +1 -1
  13. package/dist/core/runner/prepare-caps-and-workflow.d.ts +170 -0
  14. package/dist/core/runner/prepare-caps-and-workflow.js +255 -0
  15. package/dist/core/runner/prepare-config-doors.d.ts +2 -10
  16. package/dist/core/runner/prepare-defer-classify.d.ts +86 -0
  17. package/dist/core/runner/prepare-defer-classify.js +107 -0
  18. package/dist/core/runner/prepare-delegation-surface.d.ts +104 -0
  19. package/dist/core/runner/prepare-delegation-surface.js +144 -0
  20. package/dist/core/runner/prepare-execution-env.d.ts +54 -0
  21. package/dist/core/runner/prepare-execution-env.js +86 -0
  22. package/dist/core/runner/prepare-file-history.d.ts +95 -0
  23. package/dist/core/runner/prepare-file-history.js +383 -0
  24. package/dist/core/runner/prepare-hands-readface.d.ts +5 -7
  25. package/dist/core/runner/prepare-hands-readface.js +1 -1
  26. package/dist/core/runner/prepare-inherited-gate.d.ts +268 -0
  27. package/dist/core/runner/prepare-inherited-gate.js +266 -0
  28. package/dist/core/runner/prepare-listings.d.ts +77 -0
  29. package/dist/core/runner/prepare-listings.js +76 -0
  30. package/dist/core/runner/prepare-lsp.d.ts +55 -0
  31. package/dist/core/runner/prepare-lsp.js +27 -0
  32. package/dist/core/runner/prepare-memory.d.ts +1 -1
  33. package/dist/core/runner/prepare-offload-wrappers.d.ts +62 -0
  34. package/dist/core/runner/prepare-offload-wrappers.js +45 -0
  35. package/dist/core/runner/prepare-project-context.d.ts +131 -0
  36. package/dist/core/runner/prepare-project-context.js +150 -0
  37. package/dist/core/runner/prepare-prompt-inputs.d.ts +138 -0
  38. package/dist/core/runner/prepare-prompt-inputs.js +141 -0
  39. package/dist/core/runner/prepare-protocol-tools.d.ts +91 -0
  40. package/dist/core/runner/prepare-protocol-tools.js +182 -0
  41. package/dist/core/runner/prepare-question-face.d.ts +119 -0
  42. package/dist/core/runner/prepare-question-face.js +83 -0
  43. package/dist/core/runner/prepare-run-refs.d.ts +89 -0
  44. package/dist/core/runner/prepare-run-refs.js +39 -0
  45. package/dist/core/runner/prepare-safety-scan.d.ts +3 -2
  46. package/dist/core/runner/prepare-task.d.ts +11 -1846
  47. package/dist/core/runner/prepare-task.js +83 -2366
  48. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +111 -0
  49. package/dist/core/runner/prepare-tool-disclosure-mount.js +219 -0
  50. package/dist/core/runner/prepare-wiring-manifest.d.ts +184 -0
  51. package/dist/core/runner/prepare-wiring-manifest.js +240 -0
  52. package/dist/core/runner/prepare-workspace-restore.d.ts +1 -27
  53. package/dist/core/runner/prepare-workspace-restore.js +1 -22
  54. package/dist/core/runner/rollback-stack.d.ts +32 -0
  55. package/dist/core/runner/rollback-stack.js +30 -0
  56. package/dist/core/runner/workspace-path.d.ts +33 -0
  57. package/dist/core/runner/workspace-path.js +22 -0
  58. package/dist/core/tool-policy.d.ts +16 -0
  59. package/dist/core/tool-policy.js +3 -0
  60. package/dist/core/types.d.ts +2 -2
  61. package/dist/core/write-protect.js +3 -2
  62. package/package.json +6 -2
@@ -0,0 +1 @@
1
+ export {};
@@ -3,7 +3,7 @@ import { type AutoModeArmingRecipe } from "../auto-mode-arming.js";
3
3
  import type { PermissionResult, ResolvedAsk, ToolCallRequest } from "../tool-policy.js";
4
4
  import { type EngineNotice } from "../types.js";
5
5
  import { type AskOrigin } from "../ask-origin.js";
6
- import type { Prepared } from "./prepare-task.js";
6
+ import type { Prepared } from "./contracts.js";
7
7
  /**
8
8
  * #548 — the classifier DENIAL-LIMIT arms of the tool gate's inherited (delegation) lane, extracted
9
9
  * from `prepareTask` as a phase module (design/238 D-7: extract, don't accrete). The gate's OWN
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The derived-leg route pre-flight shared by prepareTask's two derived seats: the compaction-summary model (the
3
+ * driver's own seat, resolved before the offload prelude) and the auto-mode classifier model (the caps-and-workflow
4
+ * phase's arming). Moved whole out of the orchestrator so the phase reaches DOWN for it instead of the two callers
5
+ * spelling it twice. The judgment law itself lives in the brain's route adjudicator; this is the one guarded seat
6
+ * around it.
7
+ */
8
+ import type { Model } from "../../internal/llm.js";
9
+ import type { RunnerDeps, TaskSpec } from "../types.js";
10
+ /**
11
+ * The derived-leg pairing pre-flight as ONE guarded seat: judge the derived model where its route
12
+ * differs from the primary's, announce the fallback on a broken pairing, and ABSTAIN (keep the
13
+ * derived model) on ANY throw. The pre-flight is advisory — the brain's request gate re-runs the
14
+ * same law — so neither a throwing judge face nor a garbage catalog value (the route-identity
15
+ * normalization throws a TypeError on a non-string baseUrl) may widen into "task preparation
16
+ * failed": at the compaction seat the session is already acquired and the throw-cleanup contract
17
+ * is not yet armed, so a throw here would leak the acquired session view, and the garbage value
18
+ * still earns its loud refusal at the request gate the moment the derived leg is actually used.
19
+ * Returns whether the seat should fall back to the primary model.
20
+ */
21
+ export declare function derivedRouteFallsBack(args: {
22
+ seat: string;
23
+ derived: Model;
24
+ primary: Model;
25
+ brain: RunnerDeps["brain"];
26
+ getApiKeyAndHeaders: TaskSpec["getApiKeyAndHeaders"];
27
+ onNotice: RunnerDeps["onNotice"];
28
+ /** #433 — the run this seat resolution belongs to; carried onto the notice as its routing key
29
+ * (the audience stays operator: correlation, not entitlement). Absent ⇒ nothing is fabricated. */
30
+ sessionId?: string;
31
+ /** #499 — the INVOCATION this seat resolution belongs to. The session cannot stand in for it: two
32
+ * runs of one session that both fall back on the same seat mint otherwise byte-identical lines. */
33
+ runId?: string;
34
+ }): Promise<boolean>;
@@ -0,0 +1,16 @@
1
+ import { adjudicateDerivedRoute, fallbackToPrimaryNotice, sameRouteIdentity } from "../../brain/route-adjudicator.js";
2
+ import { deliverEngineNotice } from "../types.js";
3
+ export async function derivedRouteFallsBack(args) {
4
+ try {
5
+ if (sameRouteIdentity(args.derived, args.primary))
6
+ return false;
7
+ const verdict = await adjudicateDerivedRoute({ brain: args.brain, model: args.derived, getApiKeyAndHeaders: args.getApiKeyAndHeaders });
8
+ if (verdict === undefined || verdict.ok)
9
+ return false;
10
+ deliverEngineNotice(args.onNotice, fallbackToPrimaryNotice({ seat: args.seat, from: args.derived.id, to: args.primary.id, verdict, ...(args.sessionId !== undefined ? { sessionId: args.sessionId } : {}), ...(args.runId !== undefined ? { runId: args.runId } : {}) }));
11
+ return true;
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
@@ -22,7 +22,7 @@ import { StoredSession } from "../session.js";
22
22
  import type { AcquiredSession, SessionStore } from "../session.js";
23
23
  import { type RecoveredOrphan } from "../session-reconcile.js";
24
24
  import type { TaskSpec, ToolEffect } from "../types.js";
25
- import type { PrepareResume } from "./prepare-task.js";
25
+ import type { PrepareResume } from "./contracts.js";
26
26
  export interface PrepareAcquireReconcileInput {
27
27
  /** borrowed-mutable (service port) — the deployment's session store. This phase's verbs on it are
28
28
  * the acquire/forget half of the session resource protocol: `acquire` per attempt, `forget` to
@@ -0,0 +1,170 @@
1
+ /**
2
+ * design/390 §1.2 M4 — prepareTask's CAPS-AND-WORKFLOW phase, verbatim from the driver: the caller-tool roster
3
+ * map (the defineTool-product branch and the rich-ctx wrap through the large-result wrapper), the ReportBlocked /
4
+ * ReportFindings / plan-pair mounts, the per-principal runtime caps resolve with its fail-closed degrade and value
5
+ * screen, the compliance posture veto with its two refusal codes, the fork verdict and the observers grant, the
6
+ * auto-mode arming (classifier model, lane rule, decider + denial tracker + persisted recipe) with its manifest
7
+ * reason, the self-orchestration gate with its governance note, and the Workflow mount with its size-guideline
8
+ * seat. The three arming helpers and the parent-capture-state join moved with the segment (only this phase calls
9
+ * them). The interface is the dependency list the segment had implicitly (design/238 R-1).
10
+ *
11
+ * ASYNC PHASE: the segment awaits the two resolvers, the classifier route pre-flight and the Workflow factory,
12
+ * exactly where the driver awaited them; the roster map and the synthetic mounts before the first of those awaits
13
+ * run synchronously as they did. Read-stability of the host handles for the call: {@link RunInternals}
14
+ * (`@contract prepare.deps-read-stable`).
15
+ *
16
+ * THE ROSTER IS MINTED HERE (`tools`): every later phase that mounts pushes into this same array — the writer table
17
+ * lives on {@link Prepared.tools} (design/238 R-3). LATE-BOUND SEATS: the Workflow mount's call-time getters read
18
+ * three facts later stations resolve (the memory session, the center adoption, the hands mount's deny additions);
19
+ * each enters as a getter on the Input and is read exactly where the driver's getter read the variable.
20
+ */
21
+ import type { AgentHarness, AgentTool, ThinkingLevel } from "../../internal/harness.js";
22
+ import type { Model } from "../../internal/llm.js";
23
+ import { forkGovernanceDenial } from "../../agents/subagent.js";
24
+ import type { PromptEpochArtifact } from "../../prompt-assembly/artifact.js";
25
+ import { createRunWorkflowTool } from "../../orchestration/run-workflow-tool.js";
26
+ import { type WorkflowSizeGuideline } from "../../orchestration/workflow-size-guideline.js";
27
+ import { type AutoModeArmingRecipe } from "../auto-mode-arming.js";
28
+ import { type AutoModeDecider, type AutoModeDenialTracker } from "../auto-mode.js";
29
+ import { type ComplianceCapability } from "../compliance.js";
30
+ import type { LockedPreflight } from "../locked-config.js";
31
+ import type { StoredSession } from "../session.js";
32
+ import type { OnAsk } from "../tool-policy.js";
33
+ import type { RunnerDeps, RuntimeCaps, TaskEvent, TaskSpec, ToolExecuteContext } from "../types.js";
34
+ import type { AutoModeArmReason } from "../wiring-manifest.js";
35
+ import type { ReadFace } from "../../tools/fs/index.js";
36
+ import type { InheritedGate, Prepared, RunInternals, ToolFaceSnapshot } from "./contracts.js";
37
+ import { type BlockedRef } from "./synthetic-tools.js";
38
+ /** The runner the Workflow mount accepts — spelled as the factory's own option type so this phase names no runner
39
+ * module of its own (the narrow `RunnerSelfSeat` contract is a design decision still open; see the layering registry). */
40
+ type WorkflowMountRunner = Parameters<typeof createRunWorkflowTool>[0]["runner"];
41
+ export interface PrepareCapsAndWorkflowInput {
42
+ /** borrowed-readonly — the REBOUND spec, whole: the roster map reads `tools`; the mounts read `enableBlockedReport`,
43
+ * `enablePlanMode`, `interactiveTools`, `checkpointStore`; the caps/compliance stations read `principal`, `selfOrchestration`,
44
+ * `enableFork`, `getApiKeyAndHeaders`; the Workflow mount forwards `oneShot`, `handsReadOnly`, `interactiveTools`. The
45
+ * self-orchestration predicate takes the whole spec. Never mutated. */
46
+ spec: TaskSpec;
47
+ /** borrowed-readonly — the deployment seats, whole: `runtimeCapsResolver`, `compliancePostureResolver`, `onError`, `onNotice`,
48
+ * `autoMode`, `brain`, `models`, `checkpointStore` (the plan-pair face), and the Workflow mount's dozen deps (`workflowScriptRunner`,
49
+ * `workflowGovernanceBaseline`, `workflowRunStore`, `workflowJournalStore`, `workflowScriptStore`, `builtinWorkflows`,
50
+ * `onWorkflowAgentSpawn`, `workflowCompletionNotifier`, `workflowLimits`, `agents`, `builtinAgents`, `onBackgroundChildEvent`).
51
+ * The self-orchestration predicate takes the whole record. */
52
+ deps: RunnerDeps;
53
+ /** borrowed-readonly — the trusted spawn-side channel; the Workflow mount forwards `rootSessionId`, `placementRoot`,
54
+ * `onTaskNotification`, `workflowDepth`, and the capture-floor getter reads `memoryCaptureAncestors`. */
55
+ internals: Pick<RunInternals, "rootSessionId" | "placementRoot" | "onTaskNotification" | "workflowDepth" | "memoryCaptureAncestors"> | undefined;
56
+ /** borrowed-readonly — the acquired session; the classifier leg rebuilds its transcript window from `buildContext`. */
57
+ session: Pick<StoredSession, "buildContext">;
58
+ /** borrowed-readonly — the acquired session id (operator-line context, the refusal codes' phase record). */
59
+ sessionId: string;
60
+ /** borrowed-readonly — the run's invocation id (the classifier route pre-flight's notice names it). */
61
+ runId: string;
62
+ /** borrowed-readonly — the per-task identity the Workflow mount registers its children under. */
63
+ hostTaskId: string;
64
+ /** borrowed-readonly — the registry scope the Workflow mount registers in. */
65
+ taskScope: string;
66
+ /** borrowed-readonly — the SETTLED task root the Workflow mount hands its children as `parentCwd`. */
67
+ taskRootFinal: string;
68
+ /** borrowed-readonly — the run's resolved model: the classifier leg's fallback and the route pre-flight's primary. */
69
+ model: Model;
70
+ /** borrowed-readonly — the run's resolved thinking level, when one is (the Workflow mount's parentThinking fallback). */
71
+ thinking: ThinkingLevel | undefined;
72
+ /** borrowed-readonly — the frozen preflight; only `mcp` (the compliance veto's mcp_servers conflict check). */
73
+ lockedPreflight: Pick<LockedPreflight, "mcp">;
74
+ /** borrowed-mutable — the effect collection (`Prepared.toolEffects`). Writer here: ONE set, `Workflow → write`, at its mount.
75
+ * Every other writer is the safety scan (the seed) and the later mounts (see the roster table on `Prepared.tools`). */
76
+ toolEffects: Prepared["toolEffects"];
77
+ /** borrowed-readonly — the frozen tool-face snapshot the Workflow mount forwards (exclude / defer / alwaysLoad / restoreGated). */
78
+ toolFaceSnapshot: ToolFaceSnapshot;
79
+ /** borrowed-readonly — the resolved prompt profile (the Workflow mount's parentPromptProfile). */
80
+ promptProfile: ToolExecuteContext["promptProfile"];
81
+ /** borrowed-readonly — the resolved interaction posture (the Workflow mount's parentInteractionPosture; absent ⇒ no key). */
82
+ resolvedInteractionPosture: ToolExecuteContext["interactionPosture"];
83
+ /** borrowed-readonly — the harness seat; the Workflow mount's parentModel / parentThinking getters read it call-time. */
84
+ harnessRef: {
85
+ current?: AgentHarness;
86
+ };
87
+ /** borrowed-readonly — the FROZEN approver seat (the Workflow mount's parentOnAsk). */
88
+ frozenOnAsk: OnAsk | undefined;
89
+ /** borrowed-readonly — the ONE read-face carrier expression (the Workflow mount's parentReadFace getter calls it). */
90
+ carrierReadFace: () => ReadFace | undefined;
91
+ /** borrowed-readonly — the filtered display-forwarding wrapper (the Workflow mount's forwardEvent; absent ⇒ no key). */
92
+ forwardEvent: ((e: TaskEvent) => void) | undefined;
93
+ /** borrowed-readonly — the child-chain assembly (the Workflow mount's inheritedGateForChildren). */
94
+ inheritedGateForChildren: () => InheritedGate;
95
+ /** borrowed-readonly — the caller-tool ctx enrichment the roster map wraps every raw ToolSpec with. */
96
+ enrichSpecToolCtx: (ctx: ToolExecuteContext) => ToolExecuteContext;
97
+ /** borrowed-readonly — the large-result wrapper every roster entry passes through (per-tool policy honored inside). */
98
+ maybeOffload: (tool: AgentTool, perTool?: {
99
+ offload?: boolean;
100
+ offloadThresholdChars?: number;
101
+ }) => AgentTool;
102
+ /** borrowed-readonly — the plan-review primitive the ExitPlanMode tool calls. */
103
+ requestReview: (opts?: {
104
+ reason?: string;
105
+ }) => void;
106
+ /** borrowed-readonly — the plan-mode primitive the EnterPlanMode tool calls. */
107
+ enterPlanMode: () => void;
108
+ /** borrowed-readonly — the auto-mode INTENT (own seat ∨ chain ∨ checkpoint), the arming's first arm. */
109
+ autoModeIntent: boolean;
110
+ /** borrowed-readonly — the peer lane's mount verdict (the classifier's cross-session rule fills only while mounted). */
111
+ peerLaneActive: boolean;
112
+ /** borrowed-readonly — whether the BUILT-IN SendMessage is on this face (the lane rule's second term). */
113
+ peerSendMessageBuiltIn: boolean;
114
+ /** borrowed-readonly — the trusted Runner self-reference the Workflow mount executes children through; undefined when
115
+ * prepareTask runs standalone (then Workflow is simply not mounted). */
116
+ runnerSelf: WorkflowMountRunner | undefined;
117
+ /** borrowed-readonly — LATE-BOUND: the memory-engine session; the Workflow mount's capture-floor getter reads it at ITS call time. */
118
+ memoryEngineSession: () => Prepared["memoryEngineSession"];
119
+ /** borrowed-readonly — LATE-BOUND: the adopted center artifact; the Workflow mount's two center getters read it at THEIR call time. */
120
+ centerAdoption: () => {
121
+ artifact: PromptEpochArtifact;
122
+ sourceRevision?: string;
123
+ } | undefined;
124
+ /** borrowed-readonly — LATE-BOUND: the normalized deny additions; the Workflow mount's parentReadDenyPatterns getter reads it at call time. */
125
+ readDenyAdditionsNormalized: () => ReadonlyArray<{
126
+ pattern: string;
127
+ caseSensitive: boolean;
128
+ }>;
129
+ }
130
+ export interface PrepareCapsAndWorkflowResult {
131
+ /** owned — THE run's roster, minted here from the caller's tools; every later mount pushes into this same array
132
+ * (`Prepared.tools`, whose JSDoc carries the writer table). Writers here: the map that mints it, then the ReportBlocked,
133
+ * ReportFindings, ExitPlanMode, EnterPlanMode and Workflow pushes. */
134
+ tools: AgentTool[];
135
+ /** borrowed-mutable — the ReportBlocked tool's write seat (`Prepared.blockedRef`). Writer: the tool at run time; read at
136
+ * result assembly. */
137
+ blockedRef: BlockedRef;
138
+ /** owned — the per-principal entitlements as resolved (or the fail-closed degrade), undefined = no restriction. */
139
+ runtimeCaps: RuntimeCaps | undefined;
140
+ /** owned — whether the caps resolve FAULTED (throw or value screen) — never read off a coined explicit value. */
141
+ runtimeCapsFaulted: boolean;
142
+ /** owned — the compliance deny set (every capability under a resolver fault). */
143
+ complianceDenies: ReadonlySet<ComplianceCapability>;
144
+ /** owned — whether the compliance resolve faulted (the refusal code distinguishes it). */
145
+ complianceDegraded: boolean;
146
+ /** owned — the fork-governance verdict (present only when denied; the ctx reads it call-time). */
147
+ agentForkDenial: ReturnType<typeof forkGovernanceDenial>;
148
+ /** owned — the observers grant (`allowObservers === true`, explicit opt-in). */
149
+ observersActive: boolean;
150
+ /** owned — the arming outcome as a closed reason (the manifest's auto-mode face). */
151
+ autoModeArmReason: AutoModeArmReason;
152
+ /** owned — the armed classifier, or undefined when any arming arm failed. */
153
+ autoModeDecider: AutoModeDecider | undefined;
154
+ /** owned — the denial tracker built beside the decider (same face, same arming). */
155
+ autoModeDenialTracking: AutoModeDenialTracker | undefined;
156
+ /** owned — the serializable arming recipe (persistArming opt-in only). */
157
+ autoModeArming: AutoModeArmingRecipe | undefined;
158
+ /** owned — self-orchestration is ACTIVE for this leg (deployment ready ∧ not entitlement-denied); drives the prompt injection. */
159
+ selfOrchestrationActive: boolean;
160
+ /** owned — the Workflow tool is on the roster (the delegation surface's second door). */
161
+ workflowToolsActive: boolean;
162
+ /** owned — the mid-session size-guideline seat, armed with the Workflow mount (`Prepared.workflowSizeGuideline`). */
163
+ workflowSizeGuideline: {
164
+ legGuideline: WorkflowSizeGuideline;
165
+ current: () => WorkflowSizeGuideline;
166
+ } | undefined;
167
+ }
168
+ /** The M4 phase body — prepareTask's caps-and-workflow stretch, verbatim (see the module header). */
169
+ export declare function prepareCapsAndWorkflow(input: PrepareCapsAndWorkflowInput): Promise<PrepareCapsAndWorkflowResult>;
170
+ export {};
@@ -0,0 +1,255 @@
1
+ import { isSyntheticApiErrorMessage } from "../../internal/harness.js";
2
+ import { createHash } from "node:crypto";
3
+ import { forkGovernanceDenial } from "../../agents/subagent.js";
4
+ import { CROSS_SESSION_CLASSIFIER_RULE } from "../../agents/cross-session-envelope.js";
5
+ import { createRunWorkflowTool, RUN_WORKFLOW_TOOL_NAME } from "../../orchestration/run-workflow-tool.js";
6
+ import { isSelfOrchestrationActive } from "../../orchestration/workflow-script-runner.js";
7
+ import { resolveWorkflowSizeGuideline } from "../../orchestration/workflow-size-guideline.js";
8
+ import { autoModeArmingRecipeOf } from "../auto-mode-arming.js";
9
+ import { buildAutoModePrompt, renderAutoModeAction, renderAutoModeWindow } from "../auto-mode-prompt.js";
10
+ import { createAutoModeDecider, createAutoModeDenialTracker } from "../auto-mode.js";
11
+ import { resolveCheckpointStore } from "../checkpoint-store.js";
12
+ import { COMPLIANCE_CAPABILITIES, WEB_FETCH_TOOL_NAME, resolveComplianceDenies } from "../compliance.js";
13
+ import { createPresentPlanTool, createEnterPlanModeTool } from "../present-plan-tool.js";
14
+ import { resolveTaskModel } from "../roles.js";
15
+ import { brainToRuntime } from "../runtime.js";
16
+ import { defaultTaskRegistry } from "../task-registry.js";
17
+ import { defineTool, isDefineToolProduct } from "../tools.js";
18
+ import { derivedRouteFallsBack } from "./derived-route-fallback.js";
19
+ import { REPORT_FINDINGS_TOOL_NAME, createReportBlockedTool, createReportFindingsTool } from "./synthetic-tools.js";
20
+ function assembleParentCaptureState(o, i, ctl, ancestors) {
21
+ const build = (optedOut, indeterminate) => ({
22
+ optedOut: optedOut === true,
23
+ indeterminate: indeterminate === true,
24
+ ...(ctl !== undefined ? { controlDir: ctl } : {}),
25
+ ancestors,
26
+ });
27
+ return o instanceof Promise || i instanceof Promise ? Promise.all([o, i]).then(([ov, iv]) => build(ov, iv)) : build(o, i);
28
+ }
29
+ function screenAutoModeCap(caps, onError, sessionId) {
30
+ if (caps === undefined)
31
+ return { caps, faulted: false };
32
+ if (typeof caps !== "object" || caps === null || Array.isArray(caps)) {
33
+ onError?.(new Error(`runtimeCapsResolver returned a non-record value (${JSON.stringify(caps)}) — read as a resolver fault: every per-principal capability is DENIED for this run (auto mode is not armed; asks flow the original chain). Return a RuntimeCaps object or undefined.`), { phase: "config", sessionId });
34
+ return { caps: { allowWorkflows: false, allowFork: false, autoMode: false }, faulted: true };
35
+ }
36
+ const record = caps;
37
+ if (record.autoMode === undefined || typeof record.autoMode === "boolean")
38
+ return { caps: record, faulted: false };
39
+ onError?.(new Error(`runtimeCapsResolver returned a non-boolean autoMode (${JSON.stringify(record.autoMode)}) — read as a resolver fault: auto mode is DENIED for this run (the classifier is not armed; asks flow the original chain). Return true, false, or omit the key.`), { phase: "config", sessionId });
40
+ return { caps: { ...record, autoMode: false }, faulted: true };
41
+ }
42
+ function mintPersistedArming(am, laneRule, classifierSystemPrompt, onError, sessionId) {
43
+ const arming = autoModeArmingRecipeOf(laneRule ? { ...am, crossSessionMessagesRule: true } : am, {
44
+ promptDigest: `apv1:${createHash("sha256").update(classifierSystemPrompt).digest("hex")}`,
45
+ });
46
+ if (arming === undefined) {
47
+ onError?.(new Error("RunnerDeps.autoMode.persistArming is set but the auto-mode face did not canonicalize into an arming recipe " +
48
+ "(a rule list carrying a non-string, or a non-finite/out-of-range timeoutMs / failureThreshold / window bound) — " +
49
+ "NO arming recipe is recorded on this run's parked constraint chain, and a cross-process redemption keeps the " +
50
+ "conservative behavior (the ancestor classifier answers unavailable and the inherited ask flows to a human)"), { phase: "config", sessionId });
51
+ }
52
+ return arming;
53
+ }
54
+ function autoModeArmReasonOf(intent, facePresent, capsAutoMode, capsFaulted) {
55
+ if (!intent)
56
+ return "no_intent";
57
+ if (!facePresent)
58
+ return "no_face";
59
+ if (capsAutoMode === false)
60
+ return capsFaulted ? "resolver_fault" : "denied";
61
+ return "armed";
62
+ }
63
+ export async function prepareCapsAndWorkflow(input) {
64
+ const { spec, deps, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, carrierReadFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf } = input;
65
+ const tools = (spec.tools ?? []).map((t) => {
66
+ if (isDefineToolProduct(t)) {
67
+ return maybeOffload(t, t);
68
+ }
69
+ return maybeOffload(defineTool({
70
+ ...t,
71
+ execute: (args, ctx) => t.execute(args, enrichSpecToolCtx(ctx)),
72
+ }), t);
73
+ });
74
+ const blockedRef = {};
75
+ if (spec.enableBlockedReport !== false) {
76
+ tools.push(createReportBlockedTool(blockedRef));
77
+ }
78
+ if (!(spec.tools ?? []).some((t) => t.name === REPORT_FINDINGS_TOOL_NAME || t.aliases?.includes(REPORT_FINDINGS_TOOL_NAME))) {
79
+ tools.push(createReportFindingsTool());
80
+ }
81
+ if (spec.enablePlanMode === true && spec.interactiveTools !== false) {
82
+ const planReviewFace = resolveCheckpointStore(spec, deps) !== undefined;
83
+ if (spec.interactiveTools === true || planReviewFace) {
84
+ tools.push(defineTool(createPresentPlanTool(requestReview)));
85
+ if (planReviewFace) {
86
+ tools.push(defineTool(createEnterPlanModeTool(enterPlanMode)));
87
+ }
88
+ }
89
+ }
90
+ let runtimeCaps;
91
+ let runtimeCapsFaulted = false;
92
+ if (deps.runtimeCapsResolver) {
93
+ try {
94
+ runtimeCaps = (await deps.runtimeCapsResolver(spec.principal)) ?? undefined;
95
+ }
96
+ catch (err) {
97
+ deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
98
+ runtimeCaps = { allowWorkflows: false, allowFork: false, autoMode: false };
99
+ runtimeCapsFaulted = true;
100
+ }
101
+ const screened = screenAutoModeCap(runtimeCaps, deps.onError, sessionId);
102
+ runtimeCaps = screened.caps;
103
+ runtimeCapsFaulted ||= screened.faulted;
104
+ }
105
+ let complianceDenies = new Set();
106
+ let complianceDegraded = false;
107
+ if (deps.compliancePostureResolver) {
108
+ try {
109
+ const posture = (await deps.compliancePostureResolver(spec.principal)) ?? undefined;
110
+ if (posture !== undefined)
111
+ complianceDenies = resolveComplianceDenies(posture);
112
+ }
113
+ catch (err) {
114
+ deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
115
+ complianceDenies = new Set(COMPLIANCE_CAPABILITIES);
116
+ complianceDegraded = true;
117
+ }
118
+ const complianceRefuse = (capability, requested) => {
119
+ const e = new Error(`${requested} is denied for this principal by the compliance posture (capability "${capability}"` +
120
+ `${complianceDegraded ? "; the posture resolver is currently failing, so every managed capability is denied fail-closed" : ""}) — ` +
121
+ `the task is refused rather than silently narrowed.`);
122
+ e.code = complianceDegraded ? "config.compliance_required" : "config.compliance_denied";
123
+ throw e;
124
+ };
125
+ if (complianceDenies.has("mcp_servers") && lockedPreflight.mcp?.length) {
126
+ complianceRefuse("mcp_servers", "TaskSpec.mcp (MCP server materialization)");
127
+ }
128
+ if (complianceDenies.has("workflows") && spec.selfOrchestration === true) {
129
+ complianceRefuse("workflows", "TaskSpec.selfOrchestration (workflow self-orchestration)");
130
+ }
131
+ if (complianceDenies.has("web_fetch")) {
132
+ const webTool = (spec.tools ?? []).find((t) => t.name === WEB_FETCH_TOOL_NAME || (t.aliases ?? []).includes(WEB_FETCH_TOOL_NAME));
133
+ if (webTool !== undefined) {
134
+ complianceRefuse("web_fetch", `TaskSpec.tools["${webTool.name}"] (the WebFetch tool face)`);
135
+ }
136
+ }
137
+ }
138
+ const agentForkDenial = forkGovernanceDenial(spec.enableFork, runtimeCaps?.allowFork);
139
+ const observersActive = runtimeCaps?.allowObservers === true;
140
+ let autoModeDecider;
141
+ let autoModeDenialTracking;
142
+ let autoModeArming;
143
+ const autoModeArmReason = autoModeArmReasonOf(autoModeIntent, deps.autoMode !== undefined, runtimeCaps?.autoMode, runtimeCapsFaulted);
144
+ if (autoModeIntent && deps.autoMode !== undefined && runtimeCaps?.autoMode !== false) {
145
+ const am = deps.autoMode;
146
+ let classifierModel;
147
+ try {
148
+ classifierModel = resolveTaskModel({ modelRole: "classifier" }, deps).model;
149
+ }
150
+ catch {
151
+ classifierModel = model;
152
+ }
153
+ if (await derivedRouteFallsBack({ seat: "auto-mode-classifier", derived: classifierModel, primary: model, brain: deps.brain, getApiKeyAndHeaders: spec.getApiKeyAndHeaders, onNotice: deps.onNotice, sessionId, runId })) {
154
+ classifierModel = model;
155
+ }
156
+ const classifierLaneRule = peerLaneActive && peerSendMessageBuiltIn;
157
+ const classifierSystemPrompt = buildAutoModePrompt(classifierLaneRule ? { ...am, crossSessionMessagesRule: CROSS_SESSION_CLASSIFIER_RULE } : am);
158
+ const classifierRuntime = brainToRuntime(deps.brain);
159
+ autoModeDenialTracking = createAutoModeDenialTracker(am.denialLimit);
160
+ autoModeDecider = createAutoModeDecider({
161
+ ...(am.timeoutMs !== undefined ? { timeoutMs: am.timeoutMs } : {}),
162
+ ...(am.failureThreshold !== undefined ? { failureThreshold: am.failureThreshold } : {}),
163
+ ...(am.onBreakerOpen !== undefined ? { onBreakerOpen: am.onBreakerOpen } : {}),
164
+ classify: async (input, signal) => {
165
+ const ctx = await session.buildContext();
166
+ const known = ctx.messages.filter((m) => !isSyntheticApiErrorMessage(m) &&
167
+ (m.role === "user" || m.role === "assistant" || m.role === "toolResult"));
168
+ const userPrompt = renderAutoModeWindow(known, am.window) + renderAutoModeAction(input);
169
+ const classifierAuth = await spec.getApiKeyAndHeaders?.(classifierModel);
170
+ const response = await classifierRuntime.completeSimple(classifierModel, { systemPrompt: classifierSystemPrompt, messages: [{ role: "user", content: userPrompt, timestamp: Date.now() }] }, {
171
+ signal,
172
+ ...(classifierAuth?.apiKey !== undefined ? { apiKey: classifierAuth.apiKey } : {}),
173
+ ...(classifierAuth?.headers !== undefined ? { headers: classifierAuth.headers } : {}),
174
+ });
175
+ return response.content
176
+ .filter((c) => c.type === "text")
177
+ .map((c) => c.text)
178
+ .join("");
179
+ },
180
+ });
181
+ if (am.persistArming === true)
182
+ autoModeArming = mintPersistedArming(am, classifierLaneRule, classifierSystemPrompt, deps.onError, sessionId);
183
+ }
184
+ const deploymentWorkflowReady = runnerSelf !== undefined && isSelfOrchestrationActive(spec, deps);
185
+ const selfOrchestrationActive = deploymentWorkflowReady && runtimeCaps?.allowWorkflows !== false;
186
+ if (deploymentWorkflowReady && runtimeCaps?.allowWorkflows === false) {
187
+ deps.onError?.(new Error(`self-orchestration DENIED for principal "${spec.principal ?? ""}" by runtimeCaps.allowWorkflows=false ` +
188
+ `(per-principal entitlement governance, not a misconfiguration — the run_workflow tool is not mounted)`), { phase: "config", sessionId });
189
+ }
190
+ let workflowToolsActive = false;
191
+ let workflowSizeGuideline;
192
+ if (selfOrchestrationActive && runnerSelf && deps.workflowScriptRunner && deps.workflowGovernanceBaseline) {
193
+ workflowToolsActive = true;
194
+ const currentSizeGuideline = () => resolveWorkflowSizeGuideline(deps.workflowLimits?.sizeGuideline).size;
195
+ workflowSizeGuideline = { legGuideline: currentSizeGuideline(), current: currentSizeGuideline };
196
+ toolEffects.set(RUN_WORKFLOW_TOOL_NAME, "write");
197
+ tools.push(await createRunWorkflowTool({
198
+ runner: runnerSelf,
199
+ scriptRunner: deps.workflowScriptRunner,
200
+ governanceBaseline: deps.workflowGovernanceBaseline,
201
+ parentExcludeTools: toolFaceSnapshot.exclude,
202
+ parentDeferTools: toolFaceSnapshot.defer,
203
+ parentAlwaysLoadTools: toolFaceSnapshot.alwaysLoad,
204
+ ...(toolFaceSnapshot.restoreGated !== undefined ? { parentRestoreGatedTools: toolFaceSnapshot.restoreGated } : {}),
205
+ parentPromptProfile: promptProfile,
206
+ models: deps.models,
207
+ agents: deps.agents,
208
+ builtinAgents: deps.builtinAgents,
209
+ store: deps.workflowRunStore,
210
+ journalStore: deps.workflowJournalStore,
211
+ ...(deps.onBackgroundChildEvent ? { onBackgroundChildEvent: deps.onBackgroundChildEvent } : {}),
212
+ scriptStore: deps.workflowScriptStore,
213
+ builtinWorkflows: deps.builtinWorkflows,
214
+ onAgentSpawn: deps.onWorkflowAgentSpawn,
215
+ scope: taskScope,
216
+ notifier: deps.workflowCompletionNotifier,
217
+ originatingSessionId: sessionId,
218
+ rootSessionId: internals?.rootSessionId ?? sessionId, ...(internals?.placementRoot !== undefined ? { placementRoot: internals.placementRoot } : {}),
219
+ taskRegistry: defaultTaskRegistry,
220
+ taskNotification: internals?.onTaskNotification,
221
+ taskOwner: hostTaskId,
222
+ limits: deps.workflowLimits,
223
+ sourceTaskId: hostTaskId,
224
+ parentModel: () => harnessRef.current?.getModel(),
225
+ ...(spec.getApiKeyAndHeaders !== undefined ? { parentGetApiKeyAndHeaders: spec.getApiKeyAndHeaders } : {}),
226
+ ...(frozenOnAsk !== undefined ? { parentOnAsk: frozenOnAsk } : {}),
227
+ principal: spec.principal,
228
+ oneShot: spec.oneShot,
229
+ ...(resolvedInteractionPosture !== undefined ? { parentInteractionPosture: resolvedInteractionPosture } : {}),
230
+ parentMemoryCaptureState: () => {
231
+ const memoryEngineSession = input.memoryEngineSession();
232
+ const ctl = memoryEngineSession?.engine.controlPlaneDir;
233
+ const co = memoryEngineSession?.captureOptOut;
234
+ return assembleParentCaptureState(co?.optedOut() ?? false, co?.indeterminate() ?? false, ctl, [...(internals?.memoryCaptureAncestors ?? []), { sessionId, ...(ctl !== undefined ? { controlDir: ctl } : {}) }]);
235
+ },
236
+ autoModeReview: () => (autoModeDecider !== undefined ? { decider: autoModeDecider } : undefined),
237
+ workflowDepth: internals?.workflowDepth,
238
+ parentCwd: taskRootFinal,
239
+ parentThinking: () => harnessRef.current?.getThinkingLevel() ?? thinking,
240
+ parentReadFace: () => carrierReadFace(),
241
+ parentReadDenyPatterns: () => {
242
+ const readDenyAdditionsNormalized = input.readDenyAdditionsNormalized();
243
+ return readDenyAdditionsNormalized.length > 0 ? readDenyAdditionsNormalized : undefined;
244
+ },
245
+ ...(spec.handsReadOnly === true ? { parentHandsReadOnly: true } : {}), ...(spec.interactiveTools === false ? { parentInteractiveTools: false } : {}),
246
+ onNotice: deps.onNotice,
247
+ parentCheckpointStoreDisabled: spec.checkpointStore === null,
248
+ parentCenterArtifactDigest: () => input.centerAdoption()?.artifact.artifactDigest,
249
+ parentCenterSourceRevision: () => input.centerAdoption()?.sourceRevision,
250
+ ...(forwardEvent ? { forwardEvent } : {}),
251
+ inheritedGateForChildren,
252
+ }));
253
+ }
254
+ return { tools, blockedRef, runtimeCaps, runtimeCapsFaulted, complianceDenies, complianceDegraded, agentForkDenial, observersActive, autoModeArmReason, autoModeDecider, autoModeDenialTracking, autoModeArming, selfOrchestrationActive, workflowToolsActive, workflowSizeGuideline };
255
+ }
@@ -28,7 +28,7 @@ import { type ResolvedRole } from "../roles.js";
28
28
  import type { SessionStore } from "../session.js";
29
29
  import type { RunnerDeps, TaskLimits, TaskSpec } from "../types.js";
30
30
  import { type UsageWindow } from "../usage-window-store.js";
31
- import type { PrepareResume, RunInternals } from "./prepare-task.js";
31
+ import type { PrepareResume, RunInternals, ToolFaceSnapshot } from "./contracts.js";
32
32
  export declare function limitConfigError(code: string, message: string): Error & {
33
33
  code?: string;
34
34
  };
@@ -138,15 +138,7 @@ export interface PrepareConfigDoorsResult {
138
138
  /** owned — the frozen task-start snapshot of the caller's tool-face control arrays; the ONLY thing
139
139
  * later face reads consult (own-task filter, defer classify, delegation ctx). Frozen-immutable ⇒
140
140
  * shared by reference into tool execution ctxs. */
141
- toolFaceSnapshot: {
142
- exclude: readonly string[] | undefined;
143
- defer: readonly string[] | undefined;
144
- alwaysLoad: readonly string[] | undefined;
145
- /** design/277 — the model-gate restore selector ({@link TaskSpec.restoreGatedTools}), fourth
146
- * seat of the same frozen task-start snapshot: the gate decision and the delegation carrier
147
- * read THIS, never the live spec. */
148
- restoreGated: readonly string[] | true | undefined;
149
- };
141
+ toolFaceSnapshot: ToolFaceSnapshot;
150
142
  /** owned — the profile half of the RB-50 single decision point (model-independent by contract). */
151
143
  promptProfile: "simple" | "classic";
152
144
  /** owned — the administrator lock snapshot; the rest of prepare reads guarded slots through it. */
@@ -0,0 +1,86 @@
1
+ /**
2
+ * design/390 M11 — prepareTask's TOOL-FACE FOLD + DEFERRED CLASSIFICATION phase: the exclusion valve's
3
+ * true unmount (in place, on the shared mount array), the full-shell anti-drift invariant, the classic-
4
+ * profile description swap, `classifyDeferredOverFace` (the one classifier both counterfactual passes
5
+ * run), the built-in memory pairs' support-name pre-check (sole-cause counterfactual, whole-group
6
+ * retraction, the engine pair's recall paragraph stripped back out of the memory block) and the final
7
+ * `deferred` set. The body is the driver's stretch moved verbatim (one exception, named below); the
8
+ * interface is the dependency list it had implicitly (design/238 R-1).
9
+ *
10
+ * SYNCHRONOUS FUNCTION, SYNCHRONOUS CALL: the stretch has no await, so the phase adds no yield between
11
+ * the git-status probe before it and the content-origin wrap after it (design/390 §1.5 S1: a stretch
12
+ * with no await is extracted as a sync function — an `async` wrapper would open a microtask window).
13
+ *
14
+ * The one non-move: the stretch used to write `sharedMemoryPairMounted = false` /
15
+ * `memoryEnginePairMounted = false` on the retraction arm. Nothing reads either flag after this stretch
16
+ * (the driver's next reader was this stretch's own pair derivation, which runs first), so the two dead
17
+ * writes are not carried into the Result — the flags arrive as borrowed-readonly inputs.
18
+ *
19
+ * Throws pass through unchanged: `internal.full_shell_reachable_mismatch` (an engine invariant, never a
20
+ * configuration error). The reserved-name refusal for a standing ToolSearch collision is NOT here — it
21
+ * belongs to the disclosure mount downstream, which reads the `deferred` set this phase returns.
22
+ */
23
+ import type { AgentTool } from "../../internal/harness.js";
24
+ import type { Model } from "../../internal/llm.js";
25
+ import type { MaterializedA2a } from "../a2a.js";
26
+ import type { MaterializedMcp } from "../mcp.js";
27
+ import type { RunnerDeps, TaskSpec } from "../types.js";
28
+ import type { AnnounceOnceSink, ToolFaceSnapshot } from "./contracts.js";
29
+ export interface PrepareDeferClassifyInput {
30
+ /** borrowed-readonly — the REBOUND spec (`spec′`); only `tools` is read (the caller roster the
31
+ * classifier judges: names for the full-schema filter, specs for the `defer` declarations). */
32
+ spec: Pick<TaskSpec, "tools">;
33
+ /** borrowed-readonly — deployment deps; only `deferMode` is read (the classifier's mode knob). */
34
+ deps: Pick<RunnerDeps, "deferMode">;
35
+ /** borrowed-mutable — the shared mount array (later refs alias it; in-place contract, never
36
+ * re-created). Mutated here, in order: `splice` of every excluded name; element REPLACEMENT with a
37
+ * shallow copy for the classic-profile description swap (the caller's ToolSpec object is never
38
+ * mutated); `splice` of a retracted memory group. After this phase: the content-origin wrap
39
+ * (element replacement with the wrapped object), the disclosure mount, the MCP refresh re-splice. */
40
+ tools: AgentTool[];
41
+ /** borrowed-readonly — the frozen task-start tool face: `exclude` (the valve), `defer` (operator
42
+ * defers, exact wire names), `alwaysLoad` (the inline pins). */
43
+ toolFaceSnapshot: Pick<ToolFaceSnapshot, "exclude" | "defer" | "alwaysLoad">;
44
+ /** borrowed-readonly — whether a real execution env is mounted (the full-shell invariant runs only
45
+ * where a shell could be on the roster). */
46
+ handsEnabled: boolean;
47
+ /** borrowed-readonly — the spec-time precomputation the invariant checks the post-exclusion roster
48
+ * against (design/199 D-6): a mismatch is an engine bug, thrown. */
49
+ fullShellReachable: boolean;
50
+ /** borrowed-readonly — the resolved prompt profile (`classic` swaps in `descriptionClassic`). */
51
+ promptProfile: "simple" | "classic";
52
+ /** borrowed-readonly — the resolved model (the classifier's constant-defer arm reads its shape). */
53
+ model: Model;
54
+ /** borrowed-readonly — the materialized MCP roster; only `tools` is read (protocol names for the
55
+ * remote-roster arm; `mcpAlwaysLoad` self-declarations, losing to an explicit operator defer). */
56
+ mcp: Pick<MaterializedMcp, "tools">;
57
+ /** borrowed-readonly — the materialized A2A roster; only `tools` is read (protocol names). */
58
+ a2a: Pick<MaterializedA2a, "tools">;
59
+ /** borrowed-readonly — whether the shared-memory pair mounted (project-context phase). */
60
+ sharedMemoryPairMounted: boolean;
61
+ /** borrowed-readonly — whether the engine-memory pair mounted (project-context phase). */
62
+ memoryEnginePairMounted: boolean;
63
+ /** borrowed-readonly — the memory block as the project-context phase left it. The engine pair's
64
+ * retraction strips the recall paragraph from it and the stripped value returns as
65
+ * {@link PrepareDeferClassifyResult.memoryBlock}; the input value itself is never mutated. */
66
+ memoryBlock: string | undefined;
67
+ /** borrowed-readonly — the exact recall-discipline segment the memory phase composed (the strip
68
+ * removes THIS string, never a re-composition). */
69
+ memoryRecallSegment: string | undefined;
70
+ /** borrowed-readonly — the once-per-session ledger's deduplicated operator sink (a retraction is a
71
+ * session-level fact, announced once). */
72
+ onceLedger: AnnounceOnceSink;
73
+ /** borrowed-readonly — the acquired session's id (operator-line context). */
74
+ sessionId: string;
75
+ }
76
+ export interface PrepareDeferClassifyResult {
77
+ /** owned — the FINAL deferred set over the post-exclusion, post-retraction roster: the disclosure
78
+ * mount, the deferred registry and `Prepared.deferredToolNames` all read this one set (there is
79
+ * deliberately no second classification). Empty ⇒ nothing is deferred. */
80
+ deferred: Set<string>;
81
+ /** owned — the memory block after the engine pair's retraction strip (unchanged when no retraction
82
+ * ran). The driver binds it under the name the prompt assembly reads. */
83
+ memoryBlock: string | undefined;
84
+ }
85
+ /** The M11 phase body — prepareTask's tool-face fold + deferred classification, verbatim (module header). */
86
+ export declare function prepareDeferClassify(input: PrepareDeferClassifyInput): PrepareDeferClassifyResult;