bare-agent 0.19.0 → 0.21.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.
@@ -0,0 +1,376 @@
1
+ /**
2
+ * The per-run runtime blob — the wiring, threaded down the whole recursion tree (and forwarded to the worker
3
+ * Loop's `policy`/governance via `options.ctx`). Distinct from `opts` (the policy knobs).
4
+ */
5
+ export type RecurseCtx = {
6
+ /**
7
+ * - The model the workers call. Required (here or on `opts.provider`).
8
+ */
9
+ provider?: import("../types").Provider | undefined;
10
+ /**
11
+ * - bareguard `policy(tool, args, ctx)` — the gate. Sees `ctx.depth` so it can
12
+ * enforce `limits.maxDepth`/budget/calls. recurse adds NO second guard layer (§6).
13
+ */
14
+ policy?: Function | undefined;
15
+ /**
16
+ * - Budget hook forwarded to every worker Loop AND the verifier — judge
17
+ * and worker tokens are all real spend (BA1: never invisible).
18
+ */
19
+ onLlmResult?: Function | undefined;
20
+ /**
21
+ * - The current recursion depth (0 at the top). Incremented on each self-call;
22
+ * threaded into `policy`. Callers normally omit it (defaults to 0).
23
+ */
24
+ depth?: number | undefined;
25
+ /**
26
+ * - Optional event stream forwarded to each worker Loop (receipts substrate).
27
+ */
28
+ stream?: object;
29
+ /**
30
+ * - Optional litectx handle (RC-5, §10 step 7). Backs the `search`
31
+ * retrieval mode (`recall`). NOT used by `scan` — litectx has no exhaustive enumerate verb today; scan reads
32
+ * the generic array slice-source `opts.corpus` instead (the litectx-resident scan case waits on the litectx
33
+ * `enumerate` verb and drops in behind the same socket).
34
+ */
35
+ litectx?: {
36
+ recall: Function;
37
+ } | undefined;
38
+ };
39
+ export type RecurseOptions = {
40
+ /**
41
+ * - Fallback provider if `ctx.provider` is absent.
42
+ */
43
+ provider?: import("../types").Provider | undefined;
44
+ /**
45
+ * - Open topology ceiling (§1): the depth past which the `spawn_child` tool is
46
+ * no longer offered (`maxDepth=1` ⇒ flat fan-out, no nesting). NOT the safety halt — that is bareguard's,
47
+ * and actual depth is always ≤ `limits.maxDepth`.
48
+ */
49
+ maxDepth?: number | undefined;
50
+ /**
51
+ * - (Gap 3 / 0.21.0) An optional caller stance PREPENDED to every Family-A worker's
52
+ * system prompt (e.g. "You are a senior security engineer; …"). It AUGMENTS the built-in decomposition policy +
53
+ * depth-scrub, never replaces them (that text drives the spawn mechanics), and CARRIES DOWN the whole tree
54
+ * (preserved by `forChild` — a durable worker stance, unlike the top-only `contract`/`evaluate`). Deliberately
55
+ * NOT applied to the isolated verifier (would defeat the anti-sycophancy isolation, A1) nor the deterministic
56
+ * scan judge. Absent/blank ⇒ the worker prompt is byte-identical to pre-0.21 (backward-compatible).
57
+ */
58
+ persona?: string | undefined;
59
+ /**
60
+ * - Handle tools offered to EVERY worker (RC-5 pull-default: litectx
61
+ * `recall`/`get`, wired at build step 7). Workers query on demand; never the whole corpus.
62
+ */
63
+ tools?: import("../types").ToolDef[] | undefined;
64
+ /**
65
+ * - Definition of done (A3). When present, the verifier grades against THIS,
66
+ * not the loose task, and verification always runs.
67
+ */
68
+ contract?: string | undefined;
69
+ /**
70
+ * Override the verifier (fills `recurse()`'s verify slot, §7.1). Default = an `Evaluator` rubric pass.
71
+ */
72
+ evaluate?: ((result: any, ctx: {
73
+ contract: string | null;
74
+ task: string;
75
+ }) => (Verdict | Promise<Verdict>)) | undefined;
76
+ /**
77
+ * Override synthesis/reduce (NB-3). A FUNCTION is a deterministic code-reduce over the child `results` — the
78
+ * §9.1 aggregation path (LLM arithmetic over partials carried ~10–15% error). A STRATEGY string runs the
79
+ * built-in reducer: `'concat'` (lossless no-LLM join) or `'merge'` (an isolated Loop-driven subjective
80
+ * merge); a string is ignored when no child ran. Default (unset) = the worker's own final text (Family A:
81
+ * the parent model already combined the children's results in its closing turn).
82
+ */
83
+ synthesize?: "concat" | "merge" | ((args: {
84
+ task: string;
85
+ text: string | null;
86
+ results: any[];
87
+ children: object[];
88
+ ctx: RecurseCtx;
89
+ }) => any) | undefined;
90
+ /**
91
+ * - (Opt-in, NB-2 / Family B) FORCED fan-out: decompose into exactly this many
92
+ * independent parallel workers via `Planner`→`runPlan`, then reduce. A positive integer here is the count;
93
+ * it OVERRIDES the tier→count map. Setting it (or `mode:'fanout'`) takes the deterministic-parallelism path
94
+ * instead of the model-driven Family-A default. For known-parallel tasks where the caller wants guaranteed
95
+ * fan-out, not the model's adaptive choice.
96
+ */
97
+ count?: number | undefined;
98
+ /**
99
+ * - (Opt-in, NB-2 / Family B) `'fanout'` = forced semantic fan-out
100
+ * WITHOUT a fixed count — derived from `assessComplexity`'s tier via the calibrated map (medium/complex/
101
+ * critical → 2/4/6; simple → 1); `opts.count` takes precedence. `'partition'` = the DATA-DRIVEN WIDTH path
102
+ * (§11): measure `opts.corpus` and partition it into `max(opts.count floor, ⌈size/workerBudget⌉)` parallel
103
+ * scan-workers (capped by the guards), CODE-reducing the per-chunk counts. Distinct from `'fanout'`: a data
104
+ * partition, not a `Planner` semantic split.
105
+ */
106
+ mode?: "fanout" | "partition" | undefined;
107
+ /**
108
+ * - (`mode:'partition'`) items per worker; width = `⌈corpus.length /
109
+ * workerBudget⌉` (default 100). A calibratable knob (the §9.1 algorithm), not a discovered constant.
110
+ */
111
+ workerBudget?: number | undefined;
112
+ /**
113
+ * - (Family B) max workers run at once per wave (default 4). The wave
114
+ * structure is `runPlan`'s; bareguard still bounds the family rate independently.
115
+ */
116
+ concurrency?: number | undefined;
117
+ /**
118
+ * - (§10 step 7) the retrieval shape for a task OVER A
119
+ * CORPUS, routed by question shape (§9.2.1). `'scan'` (the default WHEN `opts.corpus` is present) = process
120
+ * every slice + LLM-judge + CODE-count — the only COMPLETE path (for "how many / all"). `'search'` = litectx
121
+ * `recall` handle tool offered to the worker (needle; CANNOT count; requires `ctx.litectx`). `'exact'` = a
122
+ * deterministic code-side AND-term filter tool over `opts.corpus`. `'tools'` = the PER-QUERY Family-A face:
123
+ * offer the worker `scan_count` (over `opts.corpus`) + `search_memory` (when `ctx.litectx`) + `exact_match`
124
+ * (array corpus) ALL AT ONCE, and let it pick the shape PER SUB-QUERY — the routing lives in the tool
125
+ * descriptions (scan says "use for how many / all / count"; search says "never count"), so a mixed task gets
126
+ * needle-search AND complete-count without per-sub-query adopter declaration. The completeness guard upgrades a
127
+ * `'search'` on a "how many / all" ask to `'scan'` (UPGRADE-only, never a silent downgrade); it does NOT fire
128
+ * for `'tools'` (the complete `scan_count` is always offered there, so a mixed task keeps its search tool).
129
+ * Absent `corpus` AND `retrieval`, behaviour is unchanged (Family A / single-shot) — fully backward-compatible.
130
+ */
131
+ retrieval?: "tools" | "search" | "scan" | "exact" | undefined;
132
+ /**
133
+ * - (§10 step 7) the generic slice-source scan/partition
134
+ * reads: an in-hand `{id, text}[]` array, OR an async `() => Promise<Slice[]>` (e.g. `litectxCorpus(litectx,
135
+ * {kind})` materializing a litectx-resident corpus via `enumerate`). recurse depends on this SHAPE, never on
136
+ * litectx. Malformed entries are dropped, never miscounted.
137
+ */
138
+ corpus?: Slice[] | (() => Promise<Slice[]>) | undefined;
139
+ /**
140
+ * - (scan) items per judge window. Default 8 (§9.2.1 recall knee — the one
141
+ * calibrated number; per-model).
142
+ */
143
+ window?: number | undefined;
144
+ /**
145
+ * - (scan) shuffled-boundary passes unioned for recall. Default 2 (~0.91 recall).
146
+ */
147
+ passes?: number | undefined;
148
+ };
149
+ /**
150
+ * One audit/receipts node (RC-10) — the recursion tree reconstructs from these alone: parent→child lineage
151
+ * (`spawned`), each subgoal (`task`), each gap report (`verdict`), cost per node (`tokens`).
152
+ */
153
+ export type RecurseNode = {
154
+ task: string;
155
+ depth: number;
156
+ complexity: {
157
+ level: string;
158
+ score: number;
159
+ };
160
+ critical: boolean;
161
+ /**
162
+ * - Child nodes (lineage).
163
+ */
164
+ spawned: RecurseNode[];
165
+ verdict: Verdict | null;
166
+ incomplete: boolean;
167
+ halted: boolean;
168
+ /**
169
+ * - The worker Loop's `metrics.tokens`.
170
+ */
171
+ tokens: object | null;
172
+ model: string | null;
173
+ /**
174
+ * - (§10 step 7) the retrieval mode this node ran (`scan`/`search`/`exact`),
175
+ * or null/absent for a plain reasoning node.
176
+ */
177
+ retrieval?: string | null | undefined;
178
+ /**
179
+ * - set when the completeness guard upgraded the mode (e.g.
180
+ * `'search→scan (completeness)'`) — the audit trail for RC-9-applied-to-retrieval.
181
+ */
182
+ retrievalUpgraded?: string | undefined;
183
+ /**
184
+ * - (scan) the scan
185
+ * shape: window/passes used, slices scanned, ids matched (CODE-counted).
186
+ */
187
+ scan?: {
188
+ window: number;
189
+ passes: number;
190
+ scanned: number;
191
+ matched: number;
192
+ } | undefined;
193
+ /**
194
+ * - (`mode:'partition'`) the data-driven width audit: corpus size, the budget knob, the count floor, the
195
+ * data-derived width `⌈size/budget⌉`, the chosen `width = max(floor, dataWidth)`, and matched count.
196
+ */
197
+ partition?: {
198
+ size: number;
199
+ workerBudget: number;
200
+ floor: number;
201
+ dataWidth: number;
202
+ width: number;
203
+ matched?: number;
204
+ } | undefined;
205
+ };
206
+ export type RecurseResult = {
207
+ /**
208
+ * - The synthesized answer (on convergence).
209
+ */
210
+ result?: any;
211
+ /**
212
+ * - The verifier's gap report (null when verification did not run).
213
+ */
214
+ verdict?: import("./evaluator").Verdict | null | undefined;
215
+ /**
216
+ * - true on guard exhaustion / a dead worker / an incomplete child (RC-9) —
217
+ * never a faked pass.
218
+ */
219
+ incomplete?: boolean | undefined;
220
+ /**
221
+ * - The best partial answer when `incomplete` (RC-9).
222
+ */
223
+ best?: any;
224
+ /**
225
+ * - When `incomplete` because a child failed: the sub-task(s) that came
226
+ * back incomplete (§9 scenario 1) — the anti-survivor-sum signal, not a quiet undercount.
227
+ */
228
+ missingSlices?: string[] | undefined;
229
+ /**
230
+ * - The audit node for this call (RC-10).
231
+ */
232
+ receipts: RecurseNode;
233
+ };
234
+ export type Provider = import("../types").Provider;
235
+ export type ToolDef = import("../types").ToolDef;
236
+ export type Verdict = import("./evaluator").Verdict;
237
+ export type Slice = {
238
+ id: string;
239
+ text: string;
240
+ };
241
+ /**
242
+ * @typedef {object} RecurseCtx
243
+ * The per-run runtime blob — the wiring, threaded down the whole recursion tree (and forwarded to the worker
244
+ * Loop's `policy`/governance via `options.ctx`). Distinct from `opts` (the policy knobs).
245
+ * @property {Provider} [provider] - The model the workers call. Required (here or on `opts.provider`).
246
+ * @property {Function} [policy] - bareguard `policy(tool, args, ctx)` — the gate. Sees `ctx.depth` so it can
247
+ * enforce `limits.maxDepth`/budget/calls. recurse adds NO second guard layer (§6).
248
+ * @property {Function} [onLlmResult] - Budget hook forwarded to every worker Loop AND the verifier — judge
249
+ * and worker tokens are all real spend (BA1: never invisible).
250
+ * @property {number} [depth] - The current recursion depth (0 at the top). Incremented on each self-call;
251
+ * threaded into `policy`. Callers normally omit it (defaults to 0).
252
+ * @property {object} [stream] - Optional event stream forwarded to each worker Loop (receipts substrate).
253
+ * @property {{recall: Function}} [litectx] - Optional litectx handle (RC-5, §10 step 7). Backs the `search`
254
+ * retrieval mode (`recall`). NOT used by `scan` — litectx has no exhaustive enumerate verb today; scan reads
255
+ * the generic array slice-source `opts.corpus` instead (the litectx-resident scan case waits on the litectx
256
+ * `enumerate` verb and drops in behind the same socket).
257
+ */
258
+ /**
259
+ * @typedef {object} RecurseOptions
260
+ * @property {Provider} [provider] - Fallback provider if `ctx.provider` is absent.
261
+ * @property {number} [maxDepth=3] - Open topology ceiling (§1): the depth past which the `spawn_child` tool is
262
+ * no longer offered (`maxDepth=1` ⇒ flat fan-out, no nesting). NOT the safety halt — that is bareguard's,
263
+ * and actual depth is always ≤ `limits.maxDepth`.
264
+ * @property {string} [persona] - (Gap 3 / 0.21.0) An optional caller stance PREPENDED to every Family-A worker's
265
+ * system prompt (e.g. "You are a senior security engineer; …"). It AUGMENTS the built-in decomposition policy +
266
+ * depth-scrub, never replaces them (that text drives the spawn mechanics), and CARRIES DOWN the whole tree
267
+ * (preserved by `forChild` — a durable worker stance, unlike the top-only `contract`/`evaluate`). Deliberately
268
+ * NOT applied to the isolated verifier (would defeat the anti-sycophancy isolation, A1) nor the deterministic
269
+ * scan judge. Absent/blank ⇒ the worker prompt is byte-identical to pre-0.21 (backward-compatible).
270
+ * @property {ToolDef[]} [tools] - Handle tools offered to EVERY worker (RC-5 pull-default: litectx
271
+ * `recall`/`get`, wired at build step 7). Workers query on demand; never the whole corpus.
272
+ * @property {string} [contract] - Definition of done (A3). When present, the verifier grades against THIS,
273
+ * not the loose task, and verification always runs.
274
+ * @property {(result: any, ctx: {contract: string|null, task: string}) => (Verdict|Promise<Verdict>)} [evaluate]
275
+ * Override the verifier (fills `recurse()`'s verify slot, §7.1). Default = an `Evaluator` rubric pass.
276
+ * @property {((args: {task: string, text: string|null, results: any[], children: object[], ctx: RecurseCtx}) => any) | 'concat' | 'merge'} [synthesize]
277
+ * Override synthesis/reduce (NB-3). A FUNCTION is a deterministic code-reduce over the child `results` — the
278
+ * §9.1 aggregation path (LLM arithmetic over partials carried ~10–15% error). A STRATEGY string runs the
279
+ * built-in reducer: `'concat'` (lossless no-LLM join) or `'merge'` (an isolated Loop-driven subjective
280
+ * merge); a string is ignored when no child ran. Default (unset) = the worker's own final text (Family A:
281
+ * the parent model already combined the children's results in its closing turn).
282
+ * @property {number} [count] - (Opt-in, NB-2 / Family B) FORCED fan-out: decompose into exactly this many
283
+ * independent parallel workers via `Planner`→`runPlan`, then reduce. A positive integer here is the count;
284
+ * it OVERRIDES the tier→count map. Setting it (or `mode:'fanout'`) takes the deterministic-parallelism path
285
+ * instead of the model-driven Family-A default. For known-parallel tasks where the caller wants guaranteed
286
+ * fan-out, not the model's adaptive choice.
287
+ * @property {'fanout'|'partition'} [mode] - (Opt-in, NB-2 / Family B) `'fanout'` = forced semantic fan-out
288
+ * WITHOUT a fixed count — derived from `assessComplexity`'s tier via the calibrated map (medium/complex/
289
+ * critical → 2/4/6; simple → 1); `opts.count` takes precedence. `'partition'` = the DATA-DRIVEN WIDTH path
290
+ * (§11): measure `opts.corpus` and partition it into `max(opts.count floor, ⌈size/workerBudget⌉)` parallel
291
+ * scan-workers (capped by the guards), CODE-reducing the per-chunk counts. Distinct from `'fanout'`: a data
292
+ * partition, not a `Planner` semantic split.
293
+ * @property {number} [workerBudget] - (`mode:'partition'`) items per worker; width = `⌈corpus.length /
294
+ * workerBudget⌉` (default 100). A calibratable knob (the §9.1 algorithm), not a discovered constant.
295
+ * @property {number} [concurrency] - (Family B) max workers run at once per wave (default 4). The wave
296
+ * structure is `runPlan`'s; bareguard still bounds the family rate independently.
297
+ * @property {'scan'|'search'|'exact'|'tools'} [retrieval] - (§10 step 7) the retrieval shape for a task OVER A
298
+ * CORPUS, routed by question shape (§9.2.1). `'scan'` (the default WHEN `opts.corpus` is present) = process
299
+ * every slice + LLM-judge + CODE-count — the only COMPLETE path (for "how many / all"). `'search'` = litectx
300
+ * `recall` handle tool offered to the worker (needle; CANNOT count; requires `ctx.litectx`). `'exact'` = a
301
+ * deterministic code-side AND-term filter tool over `opts.corpus`. `'tools'` = the PER-QUERY Family-A face:
302
+ * offer the worker `scan_count` (over `opts.corpus`) + `search_memory` (when `ctx.litectx`) + `exact_match`
303
+ * (array corpus) ALL AT ONCE, and let it pick the shape PER SUB-QUERY — the routing lives in the tool
304
+ * descriptions (scan says "use for how many / all / count"; search says "never count"), so a mixed task gets
305
+ * needle-search AND complete-count without per-sub-query adopter declaration. The completeness guard upgrades a
306
+ * `'search'` on a "how many / all" ask to `'scan'` (UPGRADE-only, never a silent downgrade); it does NOT fire
307
+ * for `'tools'` (the complete `scan_count` is always offered there, so a mixed task keeps its search tool).
308
+ * Absent `corpus` AND `retrieval`, behaviour is unchanged (Family A / single-shot) — fully backward-compatible.
309
+ * @property {Slice[] | (() => Promise<Slice[]>)} [corpus] - (§10 step 7) the generic slice-source scan/partition
310
+ * reads: an in-hand `{id, text}[]` array, OR an async `() => Promise<Slice[]>` (e.g. `litectxCorpus(litectx,
311
+ * {kind})` materializing a litectx-resident corpus via `enumerate`). recurse depends on this SHAPE, never on
312
+ * litectx. Malformed entries are dropped, never miscounted.
313
+ * @property {number} [window] - (scan) items per judge window. Default 8 (§9.2.1 recall knee — the one
314
+ * calibrated number; per-model).
315
+ * @property {number} [passes] - (scan) shuffled-boundary passes unioned for recall. Default 2 (~0.91 recall).
316
+ */
317
+ /**
318
+ * @typedef {object} RecurseNode
319
+ * One audit/receipts node (RC-10) — the recursion tree reconstructs from these alone: parent→child lineage
320
+ * (`spawned`), each subgoal (`task`), each gap report (`verdict`), cost per node (`tokens`).
321
+ * @property {string} task
322
+ * @property {number} depth
323
+ * @property {{level: string, score: number}} complexity
324
+ * @property {boolean} critical
325
+ * @property {RecurseNode[]} spawned - Child nodes (lineage).
326
+ * @property {Verdict|null} verdict
327
+ * @property {boolean} incomplete
328
+ * @property {boolean} halted
329
+ * @property {object|null} tokens - The worker Loop's `metrics.tokens`.
330
+ * @property {string|null} model
331
+ * @property {string|null} [retrieval] - (§10 step 7) the retrieval mode this node ran (`scan`/`search`/`exact`),
332
+ * or null/absent for a plain reasoning node.
333
+ * @property {string} [retrievalUpgraded] - set when the completeness guard upgraded the mode (e.g.
334
+ * `'search→scan (completeness)'`) — the audit trail for RC-9-applied-to-retrieval.
335
+ * @property {{window: number, passes: number, scanned: number, matched: number}} [scan] - (scan) the scan
336
+ * shape: window/passes used, slices scanned, ids matched (CODE-counted).
337
+ * @property {{size: number, workerBudget: number, floor: number, dataWidth: number, width: number, matched?: number}} [partition]
338
+ * - (`mode:'partition'`) the data-driven width audit: corpus size, the budget knob, the count floor, the
339
+ * data-derived width `⌈size/budget⌉`, the chosen `width = max(floor, dataWidth)`, and matched count.
340
+ */
341
+ /**
342
+ * @typedef {object} RecurseResult
343
+ * @property {any} [result] - The synthesized answer (on convergence).
344
+ * @property {Verdict|null} [verdict] - The verifier's gap report (null when verification did not run).
345
+ * @property {boolean} [incomplete] - true on guard exhaustion / a dead worker / an incomplete child (RC-9) —
346
+ * never a faked pass.
347
+ * @property {any} [best] - The best partial answer when `incomplete` (RC-9).
348
+ * @property {string[]} [missingSlices] - When `incomplete` because a child failed: the sub-task(s) that came
349
+ * back incomplete (§9 scenario 1) — the anti-survivor-sum signal, not a quiet undercount.
350
+ * @property {RecurseNode} receipts - The audit node for this call (RC-10).
351
+ */
352
+ /**
353
+ * Decompose a task into fresh-context workers, verify against a setpoint, and synthesize one result —
354
+ * assembled from existing primitives, not reimplemented (G1/G6).
355
+ *
356
+ * ⚠️ RESOURCE BOUNDS ARE bareguard's, not recurse()'s — OPEN BY DESIGN (§6, "no second guard layer"), and the
357
+ * one thing to know before running it. `recurse()` adds NO intrinsic total-work cap. The **Family-A default**
358
+ * (model-driven `spawn_child`) lets a node spawn UP TO each Loop's `HARD_ROUND_LIMIT` (100) children PER LEVEL,
359
+ * each recursing to `opts.maxDepth` (default 3) — so node count, and therefore TOKEN + $ SPEND, compounds
360
+ * multiplicatively and is **not capped by recurse itself**. (The forced paths — `mode:'fanout'`/`'partition'` —
361
+ * ARE bounded: a deterministic `count` + a `concurrency` cap. The uncapped path is the model-driven default.)
362
+ * This is real, not theoretical: a live POC (`poc/rlm-defer2-history-overflow.mjs`) showed a weak model
363
+ * over-decomposing into 40–117 calls on a single run. **So: running WITHOUT bareguard — or without ANY
364
+ * token/cost cap — CAN BURN TOKENS / $ unboundedly (up to ~100×depth nodes).** **WIRE bareguard**
365
+ * (`ctx.policy` via `wireGate`) for any non-trivial or untrusted run — it enforces depth/budget/call caps and
366
+ * the pre-wave fan-out checkpoint, turning a runaway into a clean `{incomplete}`. With no gate available, the
367
+ * only local brakes are `opts.maxDepth: 1` (flat — no nesting) and the provider/key's own usage limits.
368
+ *
369
+ * @param {string} task - The goal.
370
+ * @param {RecurseCtx} [ctx] - The runtime wiring (provider, policy, depth, …). Threaded down the tree.
371
+ * @param {RecurseOptions} [opts] - The policy knobs.
372
+ * @returns {Promise<RecurseResult>} `{ result, verdict, receipts }` on convergence; `{ incomplete, best,
373
+ * receipts }` on guard exhaustion. NEVER a fabricated success (RC-9).
374
+ * @throws {Error} no provider supplied (on neither `ctx.provider` nor `opts.provider`).
375
+ */
376
+ export function recurse(task: string, ctx?: RecurseCtx, opts?: RecurseOptions): Promise<RecurseResult>;