@yycholla/pi-dynamic-workflows 3.3.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 (179) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +325 -0
  3. package/assets/readme/hero.png +0 -0
  4. package/assets/readme/hero.svg +70 -0
  5. package/assets/readme/package-cover.png +0 -0
  6. package/assets/readme/package-cover.svg +66 -0
  7. package/assets/readme/workflow.png +0 -0
  8. package/assets/readme/workflow.svg +77 -0
  9. package/dist/accept-workflow-guidance.d.ts +14 -0
  10. package/dist/accept-workflow-guidance.js +53 -0
  11. package/dist/adversarial-review.d.ts +30 -0
  12. package/dist/adversarial-review.js +107 -0
  13. package/dist/agent-history.d.ts +20 -0
  14. package/dist/agent-history.js +122 -0
  15. package/dist/agent-registry.d.ts +83 -0
  16. package/dist/agent-registry.js +190 -0
  17. package/dist/agent.d.ts +364 -0
  18. package/dist/agent.js +714 -0
  19. package/dist/builtin-commands.d.ts +19 -0
  20. package/dist/builtin-commands.js +251 -0
  21. package/dist/builtin-workflows.d.ts +45 -0
  22. package/dist/builtin-workflows.js +121 -0
  23. package/dist/code-review.d.ts +26 -0
  24. package/dist/code-review.js +181 -0
  25. package/dist/config.d.ts +37 -0
  26. package/dist/config.js +44 -0
  27. package/dist/deep-research.d.ts +30 -0
  28. package/dist/deep-research.js +124 -0
  29. package/dist/display.d.ts +134 -0
  30. package/dist/display.js +248 -0
  31. package/dist/effort-command.d.ts +28 -0
  32. package/dist/effort-command.js +68 -0
  33. package/dist/enums.d.ts +69 -0
  34. package/dist/enums.js +78 -0
  35. package/dist/errors.d.ts +113 -0
  36. package/dist/errors.js +140 -0
  37. package/dist/extension-reload.d.ts +37 -0
  38. package/dist/extension-reload.js +78 -0
  39. package/dist/fs-persistence.d.ts +63 -0
  40. package/dist/fs-persistence.js +102 -0
  41. package/dist/index.d.ts +57 -0
  42. package/dist/index.js +35 -0
  43. package/dist/logger.d.ts +21 -0
  44. package/dist/logger.js +66 -0
  45. package/dist/model-routing.d.ts +30 -0
  46. package/dist/model-routing.js +50 -0
  47. package/dist/model-spec.d.ts +29 -0
  48. package/dist/model-spec.js +252 -0
  49. package/dist/model-tier-config.d.ts +133 -0
  50. package/dist/model-tier-config.js +249 -0
  51. package/dist/run-persistence.d.ts +180 -0
  52. package/dist/run-persistence.js +294 -0
  53. package/dist/saved-commands.d.ts +28 -0
  54. package/dist/saved-commands.js +100 -0
  55. package/dist/shared-store.d.ts +98 -0
  56. package/dist/shared-store.js +212 -0
  57. package/dist/structured-output.d.ts +19 -0
  58. package/dist/structured-output.js +30 -0
  59. package/dist/task-panel.d.ts +61 -0
  60. package/dist/task-panel.js +422 -0
  61. package/dist/usage-limit-scheduler.d.ts +145 -0
  62. package/dist/usage-limit-scheduler.js +368 -0
  63. package/dist/web-tools.d.ts +20 -0
  64. package/dist/web-tools.js +120 -0
  65. package/dist/workflow-authoring-coverage.d.ts +70 -0
  66. package/dist/workflow-authoring-coverage.js +421 -0
  67. package/dist/workflow-authoring-reference.d.ts +20 -0
  68. package/dist/workflow-authoring-reference.js +156 -0
  69. package/dist/workflow-capability-contract.d.ts +131 -0
  70. package/dist/workflow-capability-contract.js +604 -0
  71. package/dist/workflow-commands.d.ts +18 -0
  72. package/dist/workflow-commands.js +260 -0
  73. package/dist/workflow-comprehension.d.ts +133 -0
  74. package/dist/workflow-comprehension.js +1321 -0
  75. package/dist/workflow-context-measurement.d.ts +72 -0
  76. package/dist/workflow-context-measurement.js +213 -0
  77. package/dist/workflow-control-tool.d.ts +30 -0
  78. package/dist/workflow-control-tool.js +176 -0
  79. package/dist/workflow-delivery-choice.d.ts +20 -0
  80. package/dist/workflow-delivery-choice.js +48 -0
  81. package/dist/workflow-editor.d.ts +93 -0
  82. package/dist/workflow-editor.js +363 -0
  83. package/dist/workflow-manager.d.ts +492 -0
  84. package/dist/workflow-manager.js +1124 -0
  85. package/dist/workflow-paths.d.ts +22 -0
  86. package/dist/workflow-paths.js +46 -0
  87. package/dist/workflow-release-gate.d.ts +39 -0
  88. package/dist/workflow-release-gate.js +309 -0
  89. package/dist/workflow-saved.d.ts +38 -0
  90. package/dist/workflow-saved.js +126 -0
  91. package/dist/workflow-settings.d.ts +70 -0
  92. package/dist/workflow-settings.js +131 -0
  93. package/dist/workflow-tool.d.ts +71 -0
  94. package/dist/workflow-tool.js +367 -0
  95. package/dist/workflow-ui.d.ts +182 -0
  96. package/dist/workflow-ui.js +1587 -0
  97. package/dist/workflow.d.ts +333 -0
  98. package/dist/workflow.js +1151 -0
  99. package/dist/workflows-models-command.d.ts +31 -0
  100. package/dist/workflows-models-command.js +156 -0
  101. package/dist/worktree.d.ts +25 -0
  102. package/dist/worktree.js +61 -0
  103. package/extensions/workflow.ts +151 -0
  104. package/package.json +104 -0
  105. package/skills/workflow-authoring/SKILL.md +30 -0
  106. package/skills/workflow-authoring/examples/adversarial-verification.js +63 -0
  107. package/skills/workflow-authoring/examples/bounded-semantic-retry.js +56 -0
  108. package/skills/workflow-authoring/examples/classify-and-act.js +67 -0
  109. package/skills/workflow-authoring/examples/fan-out-and-synthesize.js +47 -0
  110. package/skills/workflow-authoring/examples/generate-and-filter.js +68 -0
  111. package/skills/workflow-authoring/examples/loop-until-done.js +68 -0
  112. package/skills/workflow-authoring/examples/phased-budgets.js +75 -0
  113. package/skills/workflow-authoring/examples/saved-nested-workflows.js +44 -0
  114. package/skills/workflow-authoring/examples/structured-output.js +37 -0
  115. package/skills/workflow-authoring/examples/tournament.js +81 -0
  116. package/skills/workflow-authoring/examples/validated-gate.js +63 -0
  117. package/skills/workflow-authoring/references/capabilities.md +41 -0
  118. package/skills/workflow-authoring/references/capability-details.md +357 -0
  119. package/skills/workflow-authoring/references/common-helpers.md +4 -0
  120. package/skills/workflow-authoring/references/debugging.md +27 -0
  121. package/skills/workflow-authoring/references/focused-recipes.md +11 -0
  122. package/skills/workflow-authoring/references/helpers.md +9 -0
  123. package/skills/workflow-authoring/references/lifecycle.md +33 -0
  124. package/skills/workflow-authoring/references/pattern-selection.md +15 -0
  125. package/skills/workflow-authoring/references/quality-helpers.md +8 -0
  126. package/skills/workflow-authoring/references/registry-ownership.md +15 -0
  127. package/skills/workflow-authoring/references/retry-helper.md +5 -0
  128. package/skills/workflow-authoring/references/review.md +43 -0
  129. package/skills/workflow-authoring/references/runtime.md +27 -0
  130. package/skills/workflow-authoring/references/specialized-helpers.md +19 -0
  131. package/skills/workflow-authoring/references/versions.md +13 -0
  132. package/skills/workflow-patterns/SKILL.md +51 -0
  133. package/src/accept-workflow-guidance.ts +71 -0
  134. package/src/adversarial-review.ts +120 -0
  135. package/src/agent-history.ts +157 -0
  136. package/src/agent-registry.ts +221 -0
  137. package/src/agent.ts +929 -0
  138. package/src/builtin-commands.ts +286 -0
  139. package/src/builtin-workflows.ts +155 -0
  140. package/src/code-review.ts +183 -0
  141. package/src/config.ts +55 -0
  142. package/src/deep-research.ts +135 -0
  143. package/src/display.ts +367 -0
  144. package/src/effort-command.ts +87 -0
  145. package/src/enums.ts +77 -0
  146. package/src/errors.ts +199 -0
  147. package/src/extension-reload.ts +100 -0
  148. package/src/fs-persistence.ts +124 -0
  149. package/src/index.ts +176 -0
  150. package/src/logger.ts +88 -0
  151. package/src/model-routing.ts +73 -0
  152. package/src/model-spec.ts +309 -0
  153. package/src/model-tier-config.ts +296 -0
  154. package/src/run-persistence.ts +484 -0
  155. package/src/saved-commands.ts +115 -0
  156. package/src/shared-store.ts +228 -0
  157. package/src/structured-output.ts +47 -0
  158. package/src/task-panel.ts +490 -0
  159. package/src/usage-limit-scheduler.ts +432 -0
  160. package/src/web-tools.ts +124 -0
  161. package/src/workflow-authoring-coverage.ts +486 -0
  162. package/src/workflow-authoring-reference.ts +186 -0
  163. package/src/workflow-capability-contract.ts +806 -0
  164. package/src/workflow-commands.ts +287 -0
  165. package/src/workflow-comprehension.ts +1673 -0
  166. package/src/workflow-context-measurement.ts +262 -0
  167. package/src/workflow-control-tool.ts +238 -0
  168. package/src/workflow-delivery-choice.ts +69 -0
  169. package/src/workflow-editor.ts +444 -0
  170. package/src/workflow-manager.ts +1405 -0
  171. package/src/workflow-paths.ts +63 -0
  172. package/src/workflow-release-gate.ts +529 -0
  173. package/src/workflow-saved.ts +180 -0
  174. package/src/workflow-settings.ts +194 -0
  175. package/src/workflow-tool.ts +464 -0
  176. package/src/workflow-ui.ts +1789 -0
  177. package/src/workflow.ts +1615 -0
  178. package/src/workflows-models-command.ts +211 -0
  179. package/src/worktree.ts +76 -0
@@ -0,0 +1,364 @@
1
+ import { type CreateAgentSessionOptions, ModelRegistry, ModelRuntime, type ToolDefinition } from "@earendil-works/pi-coding-agent";
2
+ import type { Static, TSchema } from "typebox";
3
+ import { type AgentHistoryEntry } from "./agent-history.js";
4
+ import { type ModelTierConfig, type RankableModel } from "./model-tier-config.js";
5
+ import { type StructuredOutputCapture } from "./structured-output.js";
6
+ /**
7
+ * Last-resort structured-output recovery: extract a JSON block from prose, coerce
8
+ * it toward the schema, and accept it only if it then validates. Never fabricates
9
+ * — returns undefined unless the parsed value genuinely satisfies the schema.
10
+ */
11
+ export declare function extractValidated<T>(text: string, schema: TSchema): T | undefined;
12
+ /**
13
+ * The last assistant message's terminal metadata (stopReason/errorMessage). The pi
14
+ * SDK does NOT throw provider usage/quota limits — it records them as an assistant
15
+ * message with stopReason "error" and an errorMessage. This is the only place that
16
+ * metadata is observable to the workflow layer.
17
+ */
18
+ export declare function lastAssistantError(messages: unknown[]): {
19
+ stopReason?: string;
20
+ errorMessage?: string;
21
+ } | undefined;
22
+ /**
23
+ * If the subagent's turn ended in a provider usage/quota/rate-limit error, throw a
24
+ * PROVIDER_USAGE_LIMIT WorkflowError carrying the real provider message + reset hint.
25
+ * Gated on stopReason === "error" so a successful turn whose text merely mentions
26
+ * "rate limit" is never misclassified. recoverable:false so the run checkpoints
27
+ * (paused) rather than being retried into the same wall or collapsed to a silent null.
28
+ */
29
+ export declare function throwIfProviderLimit(messages: unknown[], label?: string): void;
30
+ /** Minimal session surface resolveStructuredOutput needs (real session or a test double). */
31
+ export interface StructuredSession {
32
+ prompt(text: string): Promise<void>;
33
+ setActiveToolsByName?(names: string[]): void;
34
+ messages: unknown[];
35
+ }
36
+ /**
37
+ * Resolve a schema agent's result. If the tool was called, return the captured
38
+ * value. Otherwise re-prompt up to maxSchemaRetries (tools restricted to
39
+ * structured_output), then try strict schema-validated prose extraction, else
40
+ * throw SCHEMA_NONCOMPLIANCE (non-recoverable — surfaced, never a silent null).
41
+ * Module-level with an injected `lastText` so it is unit-testable.
42
+ */
43
+ export declare function resolveStructuredOutput<T>(session: StructuredSession, capture: StructuredOutputCapture<T>, schema: TSchema, options: {
44
+ maxSchemaRetries?: number;
45
+ signal?: AbortSignal;
46
+ label?: string;
47
+ }, lastText: (messages: unknown[]) => string): Promise<T>;
48
+ /**
49
+ * Resolve which concrete model spec a subagent should use. Precedence, most
50
+ * specific first:
51
+ * 1. options.model — an explicit per-agent model (also carries agentType /
52
+ * phase model, which the workflow layer folds into options.model).
53
+ * 2. options.tier — resolved via the model-tiers config, falling back to the
54
+ * session's main model when the tier has no configured entry.
55
+ * 3. DEFAULT TIER — when neither is set but the user has a model-tiers config,
56
+ * untagged agents default to the "medium" tier so a configured tier set
57
+ * actually affects the whole workflow (not just agents the script tagged).
58
+ * Fresh-install medium == the session model, so this is a no-op until the
59
+ * user customizes tiers via /workflows-models.
60
+ * Returns undefined when nothing applies, so the session default is used.
61
+ *
62
+ * `loadConfig` is injectable for testing; it defaults to reading from disk.
63
+ */
64
+ export declare function resolveAgentModelSpec(options: {
65
+ model?: string;
66
+ tier?: string;
67
+ }, mainModel: string | undefined, loadConfig?: () => ModelTierConfig | null, onTierWithoutConfig?: (tier: string) => void): string | undefined;
68
+ export interface WorkflowAgentOptions {
69
+ cwd?: string;
70
+ /** Extra tools available to the subagent in addition to the structured output tool. */
71
+ tools?: ToolDefinition[];
72
+ /**
73
+ * Extra tool NAMES to deny in the subagent session, on top of the always-on
74
+ * defaults ({@link DEFAULT_EXCLUDED_SUBAGENT_TOOLS}). Lets the host exclude
75
+ * other recursive-orchestration tools it registers (e.g. a pi-subagents tool)
76
+ * so a workflow subagent can't fan out through them either (#107).
77
+ */
78
+ excludeTools?: string[];
79
+ /** Override any createAgentSession option (model, modelRuntime, resourceLoader, etc.). */
80
+ session?: Partial<CreateAgentSessionOptions>;
81
+ /** Extra system guidance prepended to every subagent task. */
82
+ instructions?: string;
83
+ /**
84
+ * The session's main model (`provider/modelId`). Used as a fallback when
85
+ * resolving opts.tier and no model-tiers.json config exists. Without this,
86
+ * a workflow using `{ tier: "small" }` would log a warning and fall through
87
+ * to the session default when no config is saved yet.
88
+ */
89
+ mainModel?: string;
90
+ /**
91
+ * Shared model registry from the host Pi session. When provided, subagents
92
+ * resolve tier/model specs against the same registry the main session uses,
93
+ * including dynamically-registered providers such as ollama-cloud. Without
94
+ * this, the agent builds an isolated registry from disk and may miss models
95
+ * that are only available via extension registration.
96
+ */
97
+ modelRegistry?: ModelRegistry;
98
+ /**
99
+ * Persist each subagent transcript as a real pi session file under the
100
+ * standard sessions directory (keyed by the runner's project cwd), instead
101
+ * of the default in-memory session that is discarded when the run ends.
102
+ * Default: false (current behavior).
103
+ */
104
+ persistAgentSessions?: boolean;
105
+ }
106
+ /**
107
+ * The ModelRuntime behind a registry facade. pi's ModelRegistry does not expose
108
+ * its runtime publicly, so reach into the private field (stable since 0.80.8);
109
+ * subagent sessions need it to share the host session's exact catalog and auth
110
+ * (createAgentSession takes modelRuntime, not a registry, since 0.80.8).
111
+ *
112
+ * Exported so the test suite can pin this pi-internals contract: the cast means
113
+ * neither tsc nor mock-based tests would notice pi renaming the field, and the
114
+ * runtime consequence is silent (subagents fall back to a default runtime and
115
+ * extension-registered providers vanish from routing).
116
+ */
117
+ export declare function runtimeOf(registry: ModelRegistry): ModelRuntime | undefined;
118
+ /**
119
+ * List the user's currently available models (those with auth configured) with
120
+ * the minimal fields tier ranking needs: canonical spec, output price, and
121
+ * context window. This is the single place the SDK `Model` is projected into
122
+ * the SDK-agnostic `RankableModel`. Best-effort: returns [] if the registry
123
+ * can't be built (or while the disk-backed fallback is still initializing).
124
+ */
125
+ export declare function listAvailableModels(registry?: ModelRegistry): RankableModel[];
126
+ /**
127
+ * List the user's currently available models as `provider/modelId` specs. Used
128
+ * to tell the workflow author which models it may route agents to. Best-effort:
129
+ * returns [] if the registry can't be built.
130
+ */
131
+ export declare function listAvailableModelSpecs(registry?: ModelRegistry): string[];
132
+ /** Real token/cost usage for a single subagent run, read from the SDK session. */
133
+ export interface AgentUsage {
134
+ input: number;
135
+ output: number;
136
+ cacheRead: number;
137
+ cacheWrite: number;
138
+ total: number;
139
+ cost: number;
140
+ }
141
+ /**
142
+ * Map session stats to an AgentUsage, or undefined when the provider reported
143
+ * no usage at all (all-zero stats). Returning undefined — instead of a zero
144
+ * breakdown — lets displays fall back to their scalar token count, so setups
145
+ * on non-reporting providers render the same as before the split existed.
146
+ */
147
+ export declare function usageFromStats(stats: {
148
+ tokens: {
149
+ input: number;
150
+ output: number;
151
+ cacheRead: number;
152
+ cacheWrite: number;
153
+ total: number;
154
+ };
155
+ cost: number;
156
+ }): AgentUsage | undefined;
157
+ export interface AgentRunOptions<TSchemaDef extends TSchema | undefined = undefined> {
158
+ label?: string;
159
+ /**
160
+ * Display name recorded on the persisted session (session_info entry) when
161
+ * `persistAgentSessions` is enabled, so transcripts are identifiable in
162
+ * session pickers (e.g. `workflow:<runId> <label>`). Ignored for in-memory
163
+ * sessions or when an explicit session.sessionManager override is injected.
164
+ */
165
+ sessionName?: string;
166
+ schema?: TSchemaDef;
167
+ tools?: ToolDefinition[];
168
+ instructions?: string;
169
+ signal?: AbortSignal;
170
+ /**
171
+ * Called once with this subagent's real usage, read from the session right
172
+ * before disposal. Fires on both the success and error paths so partial
173
+ * usage is never lost — but NOT when the provider reported no usage at all
174
+ * (all-zero stats), so consumers keep their scalar fallback.
175
+ */
176
+ onUsage?: (usage: AgentUsage) => void;
177
+ /**
178
+ * Model spec for this subagent: either `provider/modelId` (unambiguous) or a
179
+ * bare `modelId`. When it can't be resolved, the session default is used and
180
+ * a warning is logged. When omitted, the session default applies.
181
+ */
182
+ model?: string;
183
+ /**
184
+ * Model tier name (e.g. "small", "medium", "big"). When set (and no explicit
185
+ * `model` is given), the model is resolved from the user's model-tiers.json
186
+ * config before `run()` starts, falling back to the session's main model when
187
+ * the tier has no configured entry. An explicit `model` always takes priority,
188
+ * so workflow scripts can use `{ tier: "small" }` for coarse routing without
189
+ * caring which concrete model backs that tier.
190
+ */
191
+ tier?: string;
192
+ /** Called with the resolved model id once known (for display/telemetry). */
193
+ onModelResolved?: (modelId: string) => void;
194
+ /** Called when `model`/`tier`/phase resolved to a spec that wasn't found (fell back to session default). */
195
+ onModelFallback?: (requestedSpec: string) => void;
196
+ /** Called with a compact snapshot of this subagent's message/tool history. */
197
+ onHistory?: (history: AgentHistoryEntry[]) => void;
198
+ /** Run this agent in a different working directory (e.g. an isolated worktree). */
199
+ cwd?: string;
200
+ /**
201
+ * Restrict the subagent's coding tools to these names (an agentType
202
+ * definition's `tools` allowlist). Undefined = all coding tools. The
203
+ * structured_output tool is always added after this filter, so a schema
204
+ * still works under a restrictive allowlist.
205
+ */
206
+ toolNames?: string[];
207
+ /** Remove these coding-tool names after the allowlist (an agentType `disallowedTools` denylist). */
208
+ disallowedToolNames?: string[];
209
+ /**
210
+ * With `schema`: how many extra repair turns to allow if the model finishes
211
+ * without calling structured_output. Each retry re-prompts (tools restricted to
212
+ * structured_output) before falling back to strict prose extraction. Default 2.
213
+ */
214
+ maxSchemaRetries?: number;
215
+ /**
216
+ * Tools that are always injected AFTER the tool-policy filter (`toolNames` /
217
+ * `disallowedToolNames`), so they are available even under a restrictive
218
+ * allowlist. Used by the workflow runtime to inject shared-store tools into
219
+ * every agent regardless of its agentType definition.
220
+ */
221
+ systemTools?: ToolDefinition[];
222
+ /**
223
+ * Per-run model registry override. Takes precedence over the constructor's
224
+ * `modelRegistry` (WorkflowAgentOptions.modelRegistry) for both model
225
+ * resolution and the `createAgentSession` call this run makes. Falls back to
226
+ * the constructor's shared registry, then a lazily-built disk registry, when
227
+ * omitted.
228
+ */
229
+ modelRegistry?: ModelRegistry;
230
+ }
231
+ export type AgentRunResult<TSchemaDef extends TSchema | undefined> = TSchemaDef extends TSchema ? Static<TSchemaDef> : string;
232
+ /**
233
+ * Orchestration tools ALWAYS denied to workflow subagents. The `workflow` and
234
+ * `workflow_control` tools are registered globally by the extension, so — unless
235
+ * excluded — a subagent's session sees them and can start its own independent
236
+ * background workflows. Those nested runs recursively fan out and are NOT bounded
237
+ * by the parent run's maxAgents / concurrency / progress / accounting, and can
238
+ * drain a shared provider quota and pile up paused runs (#107). Callers may deny
239
+ * additional tool names via WorkflowAgentOptions.excludeTools.
240
+ */
241
+ export declare const DEFAULT_EXCLUDED_SUBAGENT_TOOLS: string[];
242
+ /**
243
+ * The full subagent tool denylist: the always-on defaults plus any names the
244
+ * caller added (via WorkflowAgentOptions.excludeTools) or set on the injected
245
+ * session options. Extracted so the merge — and its order — is unit-testable;
246
+ * a spread-order regression that dropped the defaults would slip past a test
247
+ * that only asserts the constant. The SDK dedupes, so overlap is harmless.
248
+ */
249
+ export declare function subagentExcludedTools(extra?: string[], sessionExclude?: string[]): string[];
250
+ export declare class WorkflowAgent {
251
+ private readonly cwd;
252
+ private readonly baseTools;
253
+ /** Extra subagent tool-name denylist, merged with the always-on defaults. */
254
+ private readonly excludeTools;
255
+ private readonly sessionOptions;
256
+ private readonly persistAgentSessions;
257
+ private readonly instructions?;
258
+ private readonly mainModel?;
259
+ /** Shared registry from the host session, when provided. */
260
+ private readonly sharedRegistry?;
261
+ /** Lazily built once; shares the SDK's agentDir/auth so resolved models are authed. */
262
+ private registry?;
263
+ /**
264
+ * Memoized model-tiers.json snapshot, boxed so a legitimately-null config
265
+ * (file absent/invalid) is distinguishable from "not loaded yet". See
266
+ * loadTierConfig() below for why this is scoped per-instance.
267
+ */
268
+ private tierConfigBox?;
269
+ /**
270
+ * Shared resource loader for every subagent of this run, built once. See
271
+ * getSharedResourceLoader — this is the #109 memory mitigation.
272
+ */
273
+ private sharedResourceLoaderPromise?;
274
+ constructor(options?: WorkflowAgentOptions);
275
+ /**
276
+ * A resource loader shared by every subagent of this run, built once (#109).
277
+ *
278
+ * Without a resourceLoader, createAgentSession() builds a fresh
279
+ * DefaultResourceLoader per subagent and reloads it — re-running EVERY installed
280
+ * extension factory each time (verified: N subagents → N factory runs). Each
281
+ * such factory that arms a load-time timer/listener then roots its subagent
282
+ * session forever, because AgentSession.dispose() emits no session_shutdown to
283
+ * run the cleanup — the dominant #109 leak, and one our own extension
284
+ * (UsageLimitScheduler) can trigger.
285
+ *
286
+ * `noExtensions: true` skips loading host extensions; skills, prompts, and
287
+ * AGENTS.md context still load. The subagent keeps the tools this workflow
288
+ * hands it via `customTools` (coding tools + any toolset like web-research) —
289
+ * those are unaffected. What it loses is HOST EXTENSION-REGISTERED tools (MCP
290
+ * bridges, browser tools, anything a host extension added via ctx.registerTool):
291
+ * pre-change a subagent session inherited those from the full host extension
292
+ * set, now it does not, so an agentType `tools` allowlist naming one matches
293
+ * nothing. This is a deliberate trade-off — it also structurally kills recursive
294
+ * orchestration in subagents (no extension runtime at all), beyond the name-level
295
+ * #107 denylist — and must be release-noted. `createAgentSession` with a shared
296
+ * resourceLoader is a supported embedding pattern. runWorkflow builds one
297
+ * WorkflowAgent per run, so this loader's lifetime is exactly one run: built
298
+ * once, reused by all its subagents, then dropped with the agent.
299
+ */
300
+ private getSharedResourceLoader;
301
+ /**
302
+ * Resolve the registry for a run: an explicit per-run registry wins, then the
303
+ * constructor's shared registry, then a lazily-built disk registry (shared
304
+ * across calls once built). Async because pi >= 0.80.8 builds registries from
305
+ * an async-created ModelRuntime.
306
+ */
307
+ private getRegistry;
308
+ /**
309
+ * Read+parse ~/.pi/workflows/model-tiers.json at most once for this
310
+ * instance's lifetime, instead of on every run() call. `resolveAgentModelSpec`
311
+ * previously received `loadModelTierConfig` directly (sync existsSync +
312
+ * readFileSync + JSON.parse from disk), which it calls unconditionally for
313
+ * any agent without an explicit options.model — so a large fan-out did N
314
+ * redundant synchronous disk reads that blocked the event loop and stalled
315
+ * concurrent agents' I/O.
316
+ *
317
+ * `runWorkflow()` constructs a fresh `WorkflowAgent` per run (see
318
+ * `new WorkflowAgent(options)` in workflow.ts, unless a caller injects its
319
+ * own `options.agent` runner — a test-only escape hatch per
320
+ * WorkflowManagerOptions.agent's doc comment), so a WorkflowAgent instance's
321
+ * lifetime is one run in production. Memoizing on `this` therefore has the
322
+ * same scope and lifetime as the agentRegistry snapshot workflow.ts already
323
+ * takes once per run "for determinism" — the config file isn't expected to
324
+ * change mid-run, and two different runs (= two different WorkflowAgent
325
+ * instances) each get their own fresh read of whatever is on disk at the
326
+ * time, so this does not leak stale config across runs or break tests that
327
+ * construct fresh agents with different configs.
328
+ *
329
+ * `loader` is injectable for tests (defaults to the real disk read); it is
330
+ * only ever consulted once, on the first call, regardless of what is passed
331
+ * on later calls.
332
+ */
333
+ private loadTierConfig;
334
+ /**
335
+ * Session manager for one subagent run. File-backed (persisted under the
336
+ * standard sessions dir, keyed by the runner's project cwd — never a
337
+ * per-call worktree cwd) when persistAgentSessions is on; in-memory otherwise.
338
+ *
339
+ * SessionManager.create() only creates the session directory — the SDK writes
340
+ * the session file lazily (synchronous fs calls, uncaught) on the first
341
+ * assistant message, deep inside session.prompt(). A failure there would
342
+ * otherwise throw mid-run and abort this subagent. Probe writability up front
343
+ * so any create/write failure (permissions, disk full) degrades this single
344
+ * agent to an in-memory session instead — the run continues, just without a
345
+ * persisted transcript.
346
+ */
347
+ private createSessionManager;
348
+ /** Best-effort write probe: throws if the session directory isn't actually writable. */
349
+ private assertSessionDirWritable;
350
+ run<TSchemaDef extends TSchema | undefined = undefined>(prompt: string, options?: AgentRunOptions<TSchemaDef>): Promise<AgentRunResult<TSchemaDef>>;
351
+ private buildPrompt;
352
+ private lastAssistantText;
353
+ /**
354
+ * The unstructured agent's FINAL answer: assistant text that appears after the
355
+ * last tool result. Text before the final tool result is stale progress (the
356
+ * agent's last real action was a tool call, not answering), so returning it
357
+ * would mask an incomplete run and suppress AGENT_EMPTY_OUTPUT retries (#111).
358
+ *
359
+ * Distinct from lastAssistantText(), which stays deliberately lenient — the
360
+ * schema path's prose-JSON recovery (resolveStructuredOutput) may need to read
361
+ * the structured payload out of any assistant message, not only the terminal one.
362
+ */
363
+ private finalAssistantText;
364
+ }