@orkestrel/tool 0.0.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.
@@ -0,0 +1,1240 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _orkestrel_contract = require("@orkestrel/contract");
3
+ let _orkestrel_agent = require("@orkestrel/agent");
4
+ let _orkestrel_workflow = require("@orkestrel/workflow");
5
+ //#region src/core/constants.ts
6
+ /**
7
+ * The name {@link import('./factories.js').createAgentTool} advertises by default — the key a
8
+ * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
9
+ */
10
+ var AGENT_TOOL_NAME = "agent";
11
+ /**
12
+ * The maximum nesting depth a delegation chain (agent tool → sub-agent → agent tool → …) may
13
+ * reach — the bound {@link import('./factories.js').createAgentTool}'s depth/cycle guard
14
+ * enforces.
15
+ *
16
+ * @remarks
17
+ * Deliberately a SEPARATE constant from {@link MAX_WORKFLOW_DEPTH} (rather than the two guards
18
+ * sharing one reference): the two guards bound DIFFERENT chains (workflow nesting vs. agent
19
+ * delegation) that happen to share a value today, and keeping this bound decoupled means a
20
+ * future change to one never silently shifts the other. Same numeric value by convention, not
21
+ * by shared reference.
22
+ */
23
+ var AGENT_TOOL_DEPTH = 8;
24
+ /**
25
+ * The DESCRIPTION {@link import('./factories.js').createAgentTool} advertises — a short guide
26
+ * that teaches a model how to delegate a task to a sub-agent.
27
+ *
28
+ * @remarks
29
+ * Mirrors {@link WORKFLOW_TOOL_DESCRIPTION} / `WORKSPACE_TOOL_DESCRIPTION`'s teaching style: names
30
+ * the required `task` field, and documents the optional per-call `provider` / `tools` /
31
+ * `system` overrides.
32
+ */
33
+ /**
34
+ * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createAgentTool}
35
+ * advertises in place of {@link AGENT_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
36
+ * (`@orkestrel/agent`) advertises `summary ?? description`, so this one-sentence text stands in
37
+ * for the full teaching description; the full text stays retrievable via
38
+ * {@link import('./factories.js').createDescribeTool}.
39
+ */
40
+ var AGENT_TOOL_SUMMARY = "Delegate a task to a sub-agent and return its result; each call runs one sub-agent turn to completion. Call describe('agent') for the optional provider/tools/system overrides.";
41
+ var AGENT_TOOL_DESCRIPTION = [
42
+ "Delegate a task to a sub-agent and return its result. Every call runs ONE sub-agent turn to completion.",
43
+ "",
44
+ "Required:",
45
+ " task - the instructions the sub-agent should carry out.",
46
+ "Optional overrides (default to the values this tool was configured with):",
47
+ " provider - the registry key of the model/provider the sub-agent runs against.",
48
+ " tools - registry keys of the tools loaded into the sub-agent (replaces the default list, not merged).",
49
+ " system - a system prompt seeding the sub-agent's context (replaces the default).",
50
+ "Example:",
51
+ JSON.stringify({ task: "Summarize the attached notes in three bullet points." })
52
+ ].join("\n");
53
+ /**
54
+ * The maximum nesting depth a workflow → agent → workflow chain may reach — the bound
55
+ * {@link import('./factories.js').createAgentFunction} and
56
+ * {@link import('./factories.js').createWorkflowTool}'s depth/cycle guards enforce.
57
+ *
58
+ * @remarks
59
+ * OWNED here now (ported from `@orkestrel/workflow`, whose engine no longer uses it — only the
60
+ * tool-authoring guards this package now owns consume it). The limit lives in ONE place: an
61
+ * agent-function-wrapped agent running at this depth can no longer author + run a NESTED
62
+ * workflow through its bound workflow tool (that would be depth `MAX_WORKFLOW_DEPTH + 1`), so
63
+ * the over-deep invocation is REJECTED (a typed `DEPTH` `WorkflowError` throw, `@orkestrel/workflow`).
64
+ */
65
+ var MAX_WORKFLOW_DEPTH = 8;
66
+ /**
67
+ * The name {@link import('./factories.js').createWorkflowTool} advertises by default — the key a
68
+ * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under, and the name
69
+ * {@link import('./factories.js').createAgentFunction} binds the depth/cycle-aware workflow tool
70
+ * under onto a wrapped agent's `context.tools`.
71
+ *
72
+ * @remarks
73
+ * OWNED here now (ported from `@orkestrel/workflow`). The propagation seam's well-known key: when
74
+ * `createAgentFunction`'s `runner` option is supplied, it adds a `createWorkflowTool`-built tool
75
+ * under this name to the agent's `context.tools`, so it can author + run a NESTED workflow
76
+ * (bounded by {@link MAX_WORKFLOW_DEPTH}).
77
+ */
78
+ var WORKFLOW_TOOL_NAME = "workflow";
79
+ /**
80
+ * A complete FLAT authoring example — the PRIMARY way a small model authors a workflow through
81
+ * {@link import('./factories.js').createWorkflowTool}: `{ name, steps: [{ name }] }`.
82
+ *
83
+ * @remarks
84
+ * OWNED here now (ported from `@orkestrel/workflow`). Each step becomes a one-task phase, in
85
+ * order; a step's `name` is a REGISTERED behavior name (not a label) — the registry key its
86
+ * task's `run` resolves against. The tool expands this
87
+ * ({@link import('./helpers.js').expandSteps}) into a valid `WorkflowDefinition`
88
+ * (`@orkestrel/workflow`). It is embedded VERBATIM in {@link WORKFLOW_TOOL_DESCRIPTION}.
89
+ */
90
+ var WORKFLOW_TOOL_FLAT_EXAMPLE = Object.freeze({
91
+ name: "release",
92
+ steps: Object.freeze([Object.freeze({ name: "compile" }), Object.freeze({ name: "publish" })])
93
+ });
94
+ /**
95
+ * A minimal NESTED authoring example — the ADVANCED escape-hatch form a model may use instead of
96
+ * the flat shape: a full `WorkflowDefinition` (`@orkestrel/workflow`).
97
+ *
98
+ * @remarks
99
+ * OWNED here now (ported from `@orkestrel/workflow`). The full four-level form, documented in
100
+ * {@link WORKFLOW_TOOL_DESCRIPTION} as the advanced alternative. It is embedded VERBATIM.
101
+ */
102
+ var WORKFLOW_TOOL_NESTED_EXAMPLE = Object.freeze({
103
+ id: "release",
104
+ name: "Release",
105
+ phases: Object.freeze([Object.freeze({
106
+ id: "build",
107
+ name: "Build",
108
+ tasks: Object.freeze([Object.freeze({
109
+ id: "compile",
110
+ name: "Compile",
111
+ run: "compile"
112
+ })])
113
+ })])
114
+ });
115
+ /**
116
+ * The DESCRIPTION {@link import('./factories.js').createWorkflowTool} advertises — a multi-line
117
+ * guide that teaches a small model how to author a complete workflow tree.
118
+ *
119
+ * @remarks
120
+ * OWNED here now (ported from `@orkestrel/workflow`). Presents the SIMPLE flat shape
121
+ * (`{ name, steps: [{ name }] }`) as the PRIMARY way with one complete worked example
122
+ * ({@link WORKFLOW_TOOL_FLAT_EXAMPLE}), names that a step's `name` is a REGISTERED name (not a
123
+ * human label), and documents the full nested `WorkflowDefinition` as the ADVANCED form with a
124
+ * minimal example ({@link WORKFLOW_TOOL_NESTED_EXAMPLE}). The `parameters` the tool advertises
125
+ * are the FLAT shape's schema; the nested form is the documented escape-hatch (the tool accepts
126
+ * both).
127
+ */
128
+ /**
129
+ * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createWorkflowTool}
130
+ * advertises in place of {@link WORKFLOW_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
131
+ * (`@orkestrel/agent`) advertises `summary ?? description`, so this one-sentence text stands in
132
+ * for the full teaching description; the full text stays retrievable via
133
+ * {@link import('./factories.js').createDescribeTool}.
134
+ */
135
+ var WORKFLOW_TOOL_SUMMARY = "Author and run a multi-phase workflow in one call — phases run in sequence, tasks within a phase run concurrently. Call describe('workflow') for the full authoring schema and examples.";
136
+ var WORKFLOW_TOOL_DESCRIPTION = [
137
+ "Author and run a workflow (phases run sequentially, the tasks within a phase run concurrently) in one call.",
138
+ "",
139
+ "SIMPLEST way — a flat list of steps. Each step runs one registered behavior; steps run one after another:",
140
+ " { \"name\": \"<workflow name>\", \"steps\": [ { \"name\": \"<registered name>\" }, ... ] }",
141
+ "- a step's \"name\" is a REGISTERED behavior name (a registry key), NOT a human label.",
142
+ "- the top-level \"name\" (the workflow name) is optional. Ids are filled in for you.",
143
+ "Example:",
144
+ JSON.stringify(WORKFLOW_TOOL_FLAT_EXAMPLE),
145
+ "",
146
+ "ADVANCED — the full nested form, for multi-task phases or explicit ids. A workflow has phases; a phase has tasks; a task has a \"run\" (a registered behavior name):",
147
+ JSON.stringify(WORKFLOW_TOOL_NESTED_EXAMPLE),
148
+ "In the nested form you may omit any \"id\"/\"name\" and they are filled in positionally; a provided one is kept."
149
+ ].join("\n");
150
+ /**
151
+ * The name {@link import('./factories.js').createWorkspaceTool} advertises by default — the key a
152
+ * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
153
+ *
154
+ * @remarks
155
+ * OWNED here now (ported from `@orkestrel/agent`).
156
+ */
157
+ var WORKSPACE_TOOL_NAME = "workspace";
158
+ /**
159
+ * A valid `WorkspaceOperation` (`@orkestrel/agent`) object — the canonical example embedded
160
+ * VERBATIM in {@link WORKSPACE_TOOL_DESCRIPTION}.
161
+ *
162
+ * @remarks
163
+ * OWNED here now (ported from `@orkestrel/agent`). A `'write'` op (the most common authoring
164
+ * action): create or overwrite `notes.txt` with `hello`. Frozen so it cannot be mutated in
165
+ * place.
166
+ */
167
+ var WORKSPACE_TOOL_EXAMPLE = Object.freeze({
168
+ operation: "write",
169
+ path: "notes.txt",
170
+ content: "hello"
171
+ });
172
+ /**
173
+ * The DESCRIPTION {@link import('./factories.js').createWorkspaceTool} advertises — a multi-line
174
+ * guide that teaches a small model how to drive a workspace through the single
175
+ * `operation`-keyed tool.
176
+ *
177
+ * @remarks
178
+ * OWNED here now (ported from `@orkestrel/agent`). Mirrors {@link WORKFLOW_TOOL_DESCRIPTION}'s
179
+ * teaching style: names the `operation` discriminant field, enumerates all 13 operations with
180
+ * their FLAT fields, gives a worked example for the common ones, and embeds
181
+ * {@link WORKSPACE_TOOL_EXAMPLE} verbatim.
182
+ */
183
+ /**
184
+ * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createWorkspaceTool}
185
+ * advertises in place of {@link WORKSPACE_TOOL_DESCRIPTION} — a `ToolManagerInterface.definitions()`
186
+ * (`@orkestrel/agent`) advertises `summary ?? description`, so this one-sentence text stands in
187
+ * for the full teaching description; the full text stays retrievable via
188
+ * {@link import('./factories.js').createDescribeTool}.
189
+ */
190
+ var WORKSPACE_TOOL_SUMMARY = "Read and edit files in a workspace — one operation per call (read, write, list, search, replace, splice, move, remove, plus workspace switching), chosen by the 'operation' field. Call describe('workspace') for the full operation list and fields.";
191
+ var WORKSPACE_TOOL_DESCRIPTION = [
192
+ "Read and edit files in a workspace. Every call is ONE operation, chosen by the \"operation\" field.",
193
+ "All file operations act on the ACTIVE workspace; use \"workspaces\" then \"switch\" to move between workspaces.",
194
+ "",
195
+ "Operations (each takes the fields listed):",
196
+ "- read { \"operation\": \"read\", \"path\": \"<file>\" } — return the file's text.",
197
+ "- list { \"operation\": \"list\" } — list every file in the active workspace (path, state, size, lines, kind).",
198
+ "- has { \"operation\": \"has\", \"path\": \"<file>\" } — whether the file exists.",
199
+ "- search { \"operation\": \"search\", \"query\": \"<text>\", \"regex\"?: bool, \"exact\"?: bool, \"limit\"?: int } — find lines matching the query across all files.",
200
+ "- replace { \"operation\": \"replace\", \"query\": \"<text>\", \"replacement\": \"<text>\", \"regex\"?: bool, \"exact\"?: bool, \"limit\"?: int } — replace matches across all files.",
201
+ "- write { \"operation\": \"write\", \"path\": \"<file>\", \"content\": \"<text>\" } — create or overwrite the whole file.",
202
+ "- splice { \"operation\": \"splice\", \"path\": \"<file>\", \"content\": \"<text>\", \"fromLine\": int, \"fromColumn\": int, \"toLine\": int, \"toColumn\": int } — replace a 1-based range (from inclusive, to exclusive) with content.",
203
+ "- prepend { \"operation\": \"prepend\", \"path\": \"<file>\", \"content\": \"<text>\" } — add content to the start of the file.",
204
+ "- append { \"operation\": \"append\", \"path\": \"<file>\", \"content\": \"<text>\" } — add content to the end of the file.",
205
+ "- move { \"operation\": \"move\", \"from\": \"<file>\", \"to\": \"<file>\" } — rename / move a file.",
206
+ "- remove { \"operation\": \"remove\", \"path\": \"<file>\" } — delete a file.",
207
+ "- workspaces { \"operation\": \"workspaces\" } — list the workspaces you can switch between (each id, file count, active).",
208
+ "- switch { \"operation\": \"switch\", \"id\": \"<id>\" } — make the workspace with that id active (ids come from \"workspaces\").",
209
+ "",
210
+ "Notes: lines and columns are 1-based (column 1 is the first character). \"regex\" defaults to false (a literal substring), \"exact\" defaults to true (case-sensitive). \"search\"/\"replace\"/\"splice\" act only on text files. Editing with no active workspace auto-creates one.",
211
+ "",
212
+ "Example — write a file:",
213
+ JSON.stringify(WORKSPACE_TOOL_EXAMPLE)
214
+ ].join("\n");
215
+ /**
216
+ * The name {@link import('./factories.js').createDescribeTool} advertises by default — the key a
217
+ * model calls and the `ToolManagerInterface` (`@orkestrel/agent`) registers under.
218
+ *
219
+ * @remarks
220
+ * Net-new: pairs with the other three tools' lean {@link AGENT_TOOL_SUMMARY} /
221
+ * {@link WORKFLOW_TOOL_SUMMARY} / {@link WORKSPACE_TOOL_SUMMARY} — a model that reads only the
222
+ * advertised summary can call `describe` with that tool's registered name to get its full
223
+ * teaching description back.
224
+ */
225
+ var DESCRIBE_TOOL_NAME = "describe";
226
+ /**
227
+ * The lean {@link import('@orkestrel/agent').ToolInterface.summary} {@link import('./factories.js').createDescribeTool}
228
+ * advertises — this tool needs no teaching of its own, so its summary and description are both
229
+ * short.
230
+ */
231
+ var DESCRIBE_TOOL_SUMMARY = "Return the full description of a named registered tool.";
232
+ /**
233
+ * The DESCRIPTION {@link import('./factories.js').createDescribeTool} advertises.
234
+ *
235
+ * @remarks
236
+ * Deliberately short — unlike the workflow / workspace / agent tools, this one has no authoring
237
+ * schema or multi-step protocol to teach.
238
+ */
239
+ var DESCRIBE_TOOL_DESCRIPTION = "Return the full description of a registered tool by its name. Required: name - the registered tool name (see another tool listing for available names).";
240
+ //#endregion
241
+ //#region src/core/errors.ts
242
+ /**
243
+ * Thrown by {@link import('./factories.js').createAgentTool}'s and
244
+ * {@link import('./factories.js').createDescribeTool}'s handlers on every failure path — a
245
+ * malformed / unresolvable call or an unknown tool name (`TOOL`), or a delegation that would
246
+ * exceed the configured depth bound or re-enter an ancestor (`DEPTH`).
247
+ *
248
+ * @remarks
249
+ * Carries a machine-readable `code` (see {@link import('./types.js').AgentToolErrorCode}) and
250
+ * an optional `context` bag for structured diagnostics. The `ToolManagerInterface`
251
+ * (`@orkestrel/agent`) isolates every throw into the canonical tool result's top-level `error`
252
+ * (AGENTS §14) — nothing escapes the run.
253
+ *
254
+ * @example
255
+ * ```ts
256
+ * import { AgentToolError, isAgentToolError } from '@src/core'
257
+ *
258
+ * try {
259
+ * throw new AgentToolError('TOOL', 'task is required')
260
+ * } catch (error) {
261
+ * if (isAgentToolError(error)) console.log(error.code) // 'TOOL'
262
+ * }
263
+ * ```
264
+ */
265
+ var AgentToolError = class extends Error {
266
+ code;
267
+ context;
268
+ constructor(code, message, context) {
269
+ super(message);
270
+ this.name = "AgentToolError";
271
+ this.code = code;
272
+ this.context = context;
273
+ }
274
+ };
275
+ /**
276
+ * Type guard narrowing an unknown caught value to an {@link AgentToolError}.
277
+ *
278
+ * @param value - The value to test (typically a `catch` binding)
279
+ * @returns `true` when `value` is an {@link AgentToolError}
280
+ *
281
+ * @example
282
+ * ```ts
283
+ * import { isAgentToolError } from '@src/core'
284
+ *
285
+ * try {
286
+ * // ...
287
+ * } catch (error) {
288
+ * if (isAgentToolError(error)) console.log(error.code)
289
+ * }
290
+ * ```
291
+ */
292
+ function isAgentToolError(value) {
293
+ return value instanceof AgentToolError;
294
+ }
295
+ //#endregion
296
+ //#region src/core/shapers.ts
297
+ /**
298
+ * The shape of {@link import('./types.js').AgentToolArguments} —
299
+ * {@link import('./factories.js').createAgentTool}'s advertised `parameters`.
300
+ *
301
+ * @remarks
302
+ * `task` is the only required field (a non-empty string); `provider` / `tools` / `system`
303
+ * are per-call overrides of the tool's own configured defaults.
304
+ */
305
+ var agentToolShape = (0, _orkestrel_contract.objectShape)({
306
+ task: (0, _orkestrel_contract.stringShape)({
307
+ min: 1,
308
+ description: "The instructions the sub-agent should carry out."
309
+ }),
310
+ provider: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
311
+ min: 1,
312
+ description: "Registry key of the provider to run the sub-agent against (overrides the default)."
313
+ })),
314
+ tools: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.arrayShape)((0, _orkestrel_contract.stringShape)({ min: 1 }), { description: "Registry keys of the tools loaded into the sub-agent (replaces the default list)." })),
315
+ system: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({ description: "A system prompt seeding the sub-agent's context (overrides the default)." }))
316
+ });
317
+ /**
318
+ * The shape of {@link import('./types.js').DescribeToolArguments} —
319
+ * {@link import('./factories.js').createDescribeTool}'s advertised `parameters`.
320
+ *
321
+ * @remarks
322
+ * `name` is the only field (a non-empty string) — the registered tool name to look up.
323
+ */
324
+ var describeToolShape = (0, _orkestrel_contract.objectShape)({ name: (0, _orkestrel_contract.stringShape)({
325
+ min: 1,
326
+ description: "The registered name of the tool whose full description to return."
327
+ }) });
328
+ /**
329
+ * The shape of a {@link import('./types.js').TaskDraft} — identical to a strict task shape
330
+ * EXCEPT `id` and `name` are OPTIONAL.
331
+ */
332
+ var taskDraftShape = (0, _orkestrel_contract.objectShape)({
333
+ id: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
334
+ min: 1,
335
+ description: "Task id; auto-filled when omitted."
336
+ })),
337
+ name: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
338
+ min: 1,
339
+ description: "Task name; defaults to the id when omitted."
340
+ })),
341
+ description: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({ description: "Optional task description." })),
342
+ run: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
343
+ min: 1,
344
+ description: "The registered behavior name to invoke (a registry key, not a label); omitted has no handler."
345
+ })),
346
+ retries: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.integerShape)({
347
+ min: 0,
348
+ description: "Extra attempts after the first on failure; overrides the phase default. Omitted means none."
349
+ })),
350
+ timeout: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.integerShape)({
351
+ min: 0,
352
+ description: "Per-attempt deadline in milliseconds; overrides the phase default. Omitted means no deadline."
353
+ }))
354
+ });
355
+ /**
356
+ * The shape of a PHASE in a draft workflow — identical to a strict phase shape EXCEPT `id` and
357
+ * `name` are OPTIONAL, and its tasks are {@link taskDraftShape}s.
358
+ */
359
+ var phaseDraftShape = (0, _orkestrel_contract.objectShape)({
360
+ id: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
361
+ min: 1,
362
+ description: "Phase id; auto-filled when omitted."
363
+ })),
364
+ name: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
365
+ min: 1,
366
+ description: "Phase name; defaults to the id when omitted."
367
+ })),
368
+ description: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({ description: "Optional phase description." })),
369
+ tasks: (0, _orkestrel_contract.arrayShape)(taskDraftShape, { description: "The phase tasks; they run CONCURRENTLY." }),
370
+ concurrency: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.integerShape)({
371
+ min: 1,
372
+ description: "Max tasks in flight at once (a resource throttle); omitted means unbounded."
373
+ })),
374
+ bail: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.literalShape)([true, false], { description: "Per-phase failure-policy override; omitted inherits the workflow bail." }))
375
+ });
376
+ /**
377
+ * The shape of a DRAFT workflow — identical to a strict workflow shape EXCEPT `id` and `name`
378
+ * are OPTIONAL at all three levels (workflow / phase / task), so a small model can omit the six
379
+ * identity strings and let the tool synthesize them positionally.
380
+ *
381
+ * @remarks
382
+ * The lenient counterpart {@link import('./factories.js').createWorkflowDraftContract} compiles.
383
+ * `run` stays required on the strict form; a provided `id` / `name` still has `minLength: 1` (so
384
+ * an explicitly-empty `id: ''` is REJECTED, not auto-filled). After
385
+ * {@link import('./helpers.js').completeDraft} fills the missing ids/names, the result is
386
+ * validated against the STRICT `createWorkflowContract` (`@orkestrel/workflow`) gate before
387
+ * running.
388
+ */
389
+ var workflowDraftShape = (0, _orkestrel_contract.objectShape)({
390
+ id: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
391
+ min: 1,
392
+ description: "Workflow id; auto-filled when omitted."
393
+ })),
394
+ name: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
395
+ min: 1,
396
+ description: "Workflow name; defaults to the id when omitted."
397
+ })),
398
+ description: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({ description: "Optional workflow description." })),
399
+ phases: (0, _orkestrel_contract.arrayShape)(phaseDraftShape, { description: "The workflow phases; they run SEQUENTIALLY, in order." }),
400
+ bail: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.literalShape)([true, false], { description: "Failure policy: false (default) continues gracefully, true halts on the first failure." }))
401
+ });
402
+ /**
403
+ * The shape of ONE flat step — `{ name }` — the building block of {@link workflowStepsShape}.
404
+ *
405
+ * @remarks
406
+ * `name` is the REGISTERED behavior name the step runs (it becomes the task's `run`). The tool
407
+ * expands each step into a one-task phase, in order ({@link import('./helpers.js').expandSteps}).
408
+ */
409
+ var stepShape = (0, _orkestrel_contract.objectShape)({ name: (0, _orkestrel_contract.stringShape)({
410
+ min: 1,
411
+ description: "The registered behavior name this step runs (becomes the task run)."
412
+ }) });
413
+ /**
414
+ * The FLAT authoring shape {@link import('./factories.js').createWorkflowTool} advertises as its
415
+ * `parameters` — the simplest surface a small model can fill: `{ name?, steps: [{ name }] }`.
416
+ *
417
+ * @remarks
418
+ * A deliberately-reduced surface: a flat ordered list of steps, each a `{ name }`. The tool
419
+ * EXPANDS it ({@link import('./helpers.js').expandSteps}) into a full
420
+ * {@link import('./types.js').WorkflowDefinition} — one one-task phase per step, in order —
421
+ * then validates against the STRICT `createWorkflowContract` (`@orkestrel/workflow`) gate. The
422
+ * full nested form is STILL accepted by the tool (it branches on the args' shape) and is
423
+ * documented as the advanced escape-hatch in the tool's description — but THIS is what
424
+ * `parameters` advertises.
425
+ */
426
+ var workflowStepsShape = (0, _orkestrel_contract.objectShape)({
427
+ name: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.stringShape)({
428
+ min: 1,
429
+ description: "Optional workflow name."
430
+ })),
431
+ steps: (0, _orkestrel_contract.arrayShape)(stepShape, { description: "The ordered steps to run, one after another (each becomes a one-task phase)." })
432
+ });
433
+ /**
434
+ * The shape of a {@link import('./types.js').WorkspaceOperation} — a descriptive tagged union
435
+ * over the 13 workspace edit / read / navigation operations, discriminated by the `operation`
436
+ * literal (never a bare `kind`; AGENTS §4.4). Each variant leads with its `operation`
437
+ * discriminant then its FLAT fields, every field via `stringShape` / `optionalShape` /
438
+ * `integerShape({ min: 1 })` / `booleanShape`, each carrying a strong field-level `description`.
439
+ *
440
+ * @remarks
441
+ * The union compiles to an `anyOf` JSON Schema + a `unionOf` guard + a first-match parser
442
+ * automatically ({@link import('./factories.js').createWorkspaceTool} types the result to the
443
+ * hand-written {@link import('./types.js').WorkspaceOperation}). `limit` and the four `'splice'`
444
+ * caret components are POSITIVE integers (`integerShape({ min: 1 })`); `regex` / `exact` are
445
+ * `optionalShape(booleanShape(...))`. The two REGISTRY arms — `workspaces` (list the workspaces
446
+ * the model can move between) and `switch` (re-point the active one by `id`) — let a model
447
+ * DISCOVER then CHOOSE which workspace the edit / read arms target.
448
+ */
449
+ var workspaceToolShape = (0, _orkestrel_contract.unionShape)((0, _orkestrel_contract.objectShape)({
450
+ operation: (0, _orkestrel_contract.literalShape)(["read"], { description: "Read a whole text file's text by path." }),
451
+ path: (0, _orkestrel_contract.stringShape)({ description: "The path of the file to read." })
452
+ }), (0, _orkestrel_contract.objectShape)({ operation: (0, _orkestrel_contract.literalShape)(["list"], { description: "List every file in the workspace." }) }), (0, _orkestrel_contract.objectShape)({
453
+ operation: (0, _orkestrel_contract.literalShape)(["has"], { description: "Check whether a file exists at the path." }),
454
+ path: (0, _orkestrel_contract.stringShape)({ description: "The path to check for." })
455
+ }), (0, _orkestrel_contract.objectShape)({
456
+ operation: (0, _orkestrel_contract.literalShape)(["search"], { description: "Search every text file for a query, returning each hit." }),
457
+ query: (0, _orkestrel_contract.stringShape)({ description: "The text (or regular-expression source) to search for." }),
458
+ regex: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.booleanShape)({ description: "Treat the query as a regular expression. Defaults to false (a literal substring)." })),
459
+ exact: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.booleanShape)({ description: "Match case-sensitively. Defaults to true (set false for case-insensitive)." })),
460
+ limit: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.integerShape)({
461
+ min: 1,
462
+ description: "Stop after this many matches across all files. Omitted means unlimited."
463
+ }))
464
+ }), (0, _orkestrel_contract.objectShape)({
465
+ operation: (0, _orkestrel_contract.literalShape)(["replace"], { description: "Replace a query with a replacement across every text file." }),
466
+ query: (0, _orkestrel_contract.stringShape)({ description: "The text (or regular-expression source) to replace." }),
467
+ replacement: (0, _orkestrel_contract.stringShape)({ description: "The text to substitute for each match." }),
468
+ regex: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.booleanShape)({ description: "Treat the query as a regular expression. Defaults to false (a literal substring)." })),
469
+ exact: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.booleanShape)({ description: "Match case-sensitively. Defaults to true (set false for case-insensitive)." })),
470
+ limit: (0, _orkestrel_contract.optionalShape)((0, _orkestrel_contract.integerShape)({
471
+ min: 1,
472
+ description: "Stop after this many replacements across all files. Omitted means unlimited."
473
+ }))
474
+ }), (0, _orkestrel_contract.objectShape)({
475
+ operation: (0, _orkestrel_contract.literalShape)(["write"], { description: "Create or overwrite a whole file with content." }),
476
+ path: (0, _orkestrel_contract.stringShape)({ description: "The path of the file to write." }),
477
+ content: (0, _orkestrel_contract.stringShape)({ description: "The full new contents of the file." })
478
+ }), (0, _orkestrel_contract.objectShape)({
479
+ operation: (0, _orkestrel_contract.literalShape)(["splice"], { description: "Replace a 1-based range of an existing text file (from inclusive, to exclusive) with content." }),
480
+ path: (0, _orkestrel_contract.stringShape)({ description: "The path of the text file to edit." }),
481
+ content: (0, _orkestrel_contract.stringShape)({ description: "The text to splice in place of the range." }),
482
+ fromLine: (0, _orkestrel_contract.integerShape)({
483
+ min: 1,
484
+ description: "The 1-based start line of the range (inclusive)."
485
+ }),
486
+ fromColumn: (0, _orkestrel_contract.integerShape)({
487
+ min: 1,
488
+ description: "The 1-based start column of the range (inclusive; column 1 is the first character)."
489
+ }),
490
+ toLine: (0, _orkestrel_contract.integerShape)({
491
+ min: 1,
492
+ description: "The 1-based end line of the range (exclusive)."
493
+ }),
494
+ toColumn: (0, _orkestrel_contract.integerShape)({
495
+ min: 1,
496
+ description: "The 1-based end column of the range (exclusive)."
497
+ })
498
+ }), (0, _orkestrel_contract.objectShape)({
499
+ operation: (0, _orkestrel_contract.literalShape)(["prepend"], { description: "Add content to the start of a file (creating it when absent)." }),
500
+ path: (0, _orkestrel_contract.stringShape)({ description: "The path of the file to prepend to." }),
501
+ content: (0, _orkestrel_contract.stringShape)({ description: "The text to add at the start of the file." })
502
+ }), (0, _orkestrel_contract.objectShape)({
503
+ operation: (0, _orkestrel_contract.literalShape)(["append"], { description: "Add content to the end of a file (creating it when absent)." }),
504
+ path: (0, _orkestrel_contract.stringShape)({ description: "The path of the file to append to." }),
505
+ content: (0, _orkestrel_contract.stringShape)({ description: "The text to add at the end of the file." })
506
+ }), (0, _orkestrel_contract.objectShape)({
507
+ operation: (0, _orkestrel_contract.literalShape)(["move"], { description: "Rename or move a file (overwriting an occupied target)." }),
508
+ from: (0, _orkestrel_contract.stringShape)({ description: "The current path of the file." }),
509
+ to: (0, _orkestrel_contract.stringShape)({ description: "The new path for the file." })
510
+ }), (0, _orkestrel_contract.objectShape)({
511
+ operation: (0, _orkestrel_contract.literalShape)(["remove"], { description: "Delete a file from the workspace." }),
512
+ path: (0, _orkestrel_contract.stringShape)({ description: "The path of the file to remove." })
513
+ }), (0, _orkestrel_contract.objectShape)({ operation: (0, _orkestrel_contract.literalShape)(["workspaces"], { description: "List the workspaces you can move between (each id, file count, and whether it is active), so you can pick an id to switch to." }) }), (0, _orkestrel_contract.objectShape)({
514
+ operation: (0, _orkestrel_contract.literalShape)(["switch"], { description: "Switch the active workspace to the one with this id (get ids from the \"workspaces\" operation). Edit and read operations then target it." }),
515
+ id: (0, _orkestrel_contract.stringShape)({ description: "The id of the workspace to make active (from the \"workspaces\" listing)." })
516
+ }));
517
+ //#endregion
518
+ //#region src/core/helpers.ts
519
+ /**
520
+ * The ancestry identifier of a workflow in a run chain — `workflow:<id>`.
521
+ *
522
+ * @remarks
523
+ * Namespacing keeps a workflow id and an {@link agentTag} agent name in ONE set without
524
+ * collision, so re-entering a workflow OR an agent already in the chain is a single `includes`
525
+ * check.
526
+ *
527
+ * @param id - The workflow definition's `id`
528
+ * @returns The namespaced ancestry tag (`workflow:<id>`)
529
+ */
530
+ function workflowTag(id) {
531
+ return `workflow:${id}`;
532
+ }
533
+ /**
534
+ * The ancestry identifier of an agent in a run chain — `agent:<name>`.
535
+ *
536
+ * @remarks
537
+ * The agent counterpart of {@link workflowTag}: {@link import('./factories.js').createAgentFunction}
538
+ * / {@link import('./factories.js').createWorkflowTool} guard against re-entering an agent or
539
+ * workflow already in the chain (a typed `DEPTH` `WorkflowError`, `@orkestrel/workflow`). The
540
+ * `agent:` namespace keeps it distinct from a same-string workflow id.
541
+ *
542
+ * @param name - The agent's identifier / registry name
543
+ * @returns The namespaced ancestry tag (`agent:<name>`)
544
+ */
545
+ function agentTag(name) {
546
+ return `agent:${name}`;
547
+ }
548
+ /**
549
+ * Build the plain success summary {@link import('./factories.js').createWorkflowTool} returns on
550
+ * a completed run — the universal tool-handler contract (AGENTS §14): return a plain value on
551
+ * success, appearing identically over BOTH the agent loop and MCP.
552
+ *
553
+ * @remarks
554
+ * The summary is LEAN: the workflow's terminal `status` and the COUNT of settled task results —
555
+ * enough for a caller / model to react without serializing the whole live tree. (It carries no
556
+ * synthetic `id` / `name`: a tool handler has no call id; the `ToolManagerInterface`
557
+ * (`@orkestrel/agent`) supplies the canonical envelope's identity.)
558
+ *
559
+ * @param result - The terminal `WorkflowResult` (`@orkestrel/workflow`) the run produced
560
+ * @returns The plain success summary — `{ status, count }`
561
+ */
562
+ function workflowToolSummary(result) {
563
+ return {
564
+ status: result.status,
565
+ count: result.results.length
566
+ };
567
+ }
568
+ /**
569
+ * Complete a {@link WorkflowDraft} into a strict {@link WorkflowDefinition} — synthesize any
570
+ * MISSING `id` deterministically + positionally, and default any MISSING `name` to its
571
+ * (now-resolved) `id`.
572
+ *
573
+ * @remarks
574
+ * The positional id scheme is stable and human-legible: the workflow is `wf`, phase `i` is
575
+ * `phase-<i>`, and task `j` of that phase is `<phaseId>-task-<j>` (so a provided phase id flows
576
+ * into its tasks' synthesized ids). A PROVIDED `id` / `name` at any level is kept VERBATIM —
577
+ * synthesis touches only the omitted ones. A missing `name` defaults to the resolved `id` (never
578
+ * the other way round), so the result always has both. `run`, `description`, the per-phase
579
+ * `concurrency` / `bail`, the per-task `retries` / `timeout`, and the workflow `bail` carry over
580
+ * unchanged. The result is a complete {@link WorkflowDefinition}; the caller still validates it
581
+ * against the STRICT contract.
582
+ *
583
+ * @param draft - The draft workflow (id/name optional at all three levels)
584
+ * @returns A complete {@link WorkflowDefinition} with every id/name filled
585
+ */
586
+ function completeDraft(draft) {
587
+ const id = draft.id ?? "wf";
588
+ return {
589
+ id,
590
+ name: draft.name ?? id,
591
+ ...draft.description === void 0 ? {} : { description: draft.description },
592
+ phases: draft.phases.map((phase, index) => completePhaseDraft(phase, index)),
593
+ ...draft.bail === void 0 ? {} : { bail: draft.bail }
594
+ };
595
+ }
596
+ /**
597
+ * Complete one {@link PhaseDraft} into a strict phase definition — the per-phase step of
598
+ * {@link completeDraft} (phase `index` → `phase-<index>` when its id is omitted).
599
+ *
600
+ * @param phase - The draft phase
601
+ * @param index - The phase's positional index in the workflow
602
+ * @returns A complete phase definition
603
+ */
604
+ function completePhaseDraft(phase, index) {
605
+ const id = phase.id ?? `phase-${index}`;
606
+ return {
607
+ id,
608
+ name: phase.name ?? id,
609
+ ...phase.description === void 0 ? {} : { description: phase.description },
610
+ tasks: phase.tasks.map((task, taskIndex) => completeTaskDraft(task, id, taskIndex)),
611
+ ...phase.concurrency === void 0 ? {} : { concurrency: phase.concurrency },
612
+ ...phase.bail === void 0 ? {} : { bail: phase.bail }
613
+ };
614
+ }
615
+ /**
616
+ * Complete one {@link TaskDraft} into a strict task definition — the per-task leaf step of
617
+ * {@link completeDraft} (task `index` of phase `<phaseId>` → `<phaseId>-task-<index>` when its id
618
+ * is omitted).
619
+ *
620
+ * @param task - The draft task
621
+ * @param phaseId - The (resolved) parent phase id, so the synthesized task id nests under it
622
+ * @param index - The task's positional index within its phase
623
+ * @returns A complete task definition
624
+ */
625
+ function completeTaskDraft(task, phaseId, index) {
626
+ const id = task.id ?? `${phaseId}-task-${index}`;
627
+ return {
628
+ id,
629
+ name: task.name ?? id,
630
+ ...task.description === void 0 ? {} : { description: task.description },
631
+ ...task.run === void 0 ? {} : { run: task.run },
632
+ ...task.retries === void 0 ? {} : { retries: task.retries },
633
+ ...task.timeout === void 0 ? {} : { timeout: task.timeout }
634
+ };
635
+ }
636
+ /**
637
+ * Expand a flat {@link WorkflowSteps} blob into a strict {@link WorkflowDefinition} — each step
638
+ * becomes a one-task phase, IN ORDER.
639
+ *
640
+ * @remarks
641
+ * The expansion of the tool's ADVERTISED surface: the deliberately-reduced flat form. Each
642
+ * {@link import('./types.js').WorkflowStep} maps to a phase holding exactly one task: the step's
643
+ * `name` becomes the task's `run` (the behavior-registry key). Ids/names are auto-filled
644
+ * positionally — it builds an ids-omitted {@link WorkflowDraft} and delegates to
645
+ * {@link completeDraft}, so the two lenient surfaces share ONE synthesis path (step `i` → phase
646
+ * `phase-<i>`, its task `phase-<i>-task-0`). The optional `name` becomes the workflow's `name`.
647
+ * The result is a complete definition the caller validates against the STRICT contract before
648
+ * running.
649
+ *
650
+ * @param flat - The flat steps blob (`{ name?, steps: [{ name }] }`)
651
+ * @returns A complete {@link WorkflowDefinition} (one one-task phase per step)
652
+ */
653
+ function expandSteps(flat) {
654
+ return completeDraft({
655
+ ...flat.name === void 0 ? {} : { name: flat.name },
656
+ phases: flat.steps.map((step) => ({ tasks: [{ run: step.name }] }))
657
+ });
658
+ }
659
+ //#endregion
660
+ //#region src/core/factories.ts
661
+ /**
662
+ * Wrap a registered tool as a {@link WorkflowFunction} (`@orkestrel/workflow`) — the OPT-IN
663
+ * adapter that lets a `function`-form task run a `@orkestrel/agent` tool BY NAME.
664
+ *
665
+ * @remarks
666
+ * OWNED here now (ported from `@orkestrel/workflow`). Composes into a caller's
667
+ * `WorkflowOptions.functions` registry like any other behavior
668
+ * (`{ publish: createToolFunction(tools, 'publish') }`); the pure workflow runner has no
669
+ * knowledge of tools itself. The returned function executes `name` against `tools` with the
670
+ * task's `controller.input` as the call arguments, id-correlated to the task's own id. A
671
+ * `ToolManagerInterface.execute` (`@orkestrel/agent`) NEVER throws (a handler throw is isolated
672
+ * into `result.error`), so a failing tool is surfaced here as a THROWN `Error` carrying the
673
+ * original message as `cause` — the leaf `fail`s, honouring `bail`. An UNREGISTERED tool name is
674
+ * a programmer error (an explicit binding to a name that doesn't exist) — unlike the engine's
675
+ * own silent auto-complete of an unresolved task handler, this THROWS a typed `TOOL`
676
+ * `WorkflowError` (`@orkestrel/workflow`).
677
+ *
678
+ * @param tools - The `ToolManagerInterface` (`@orkestrel/agent`) the named tool is registered on
679
+ * @param name - The registered tool's name
680
+ * @returns A {@link WorkflowFunction} that runs the named tool
681
+ *
682
+ * @example
683
+ * ```ts
684
+ * import { createToolFunction } from '@src/core'
685
+ * import { createToolManager } from '@orkestrel/agent'
686
+ * import { createWorkflowRunner } from '@orkestrel/workflow'
687
+ *
688
+ * const tools = createToolManager()
689
+ * tools.add(myPublishTool)
690
+ * const runner = createWorkflowRunner()
691
+ * await runner.execute(definition, { functions: { publish: createToolFunction(tools, 'publish') } })
692
+ * ```
693
+ */
694
+ function createToolFunction(tools, name) {
695
+ return async (controller) => {
696
+ if (tools.tool(name) === void 0) throw new _orkestrel_workflow.WorkflowError("TOOL", `tool '${name}' is not registered`, { tool: name });
697
+ const result = await tools.execute({
698
+ id: controller.task.id,
699
+ name,
700
+ arguments: controller.input
701
+ });
702
+ if (result.error !== void 0) throw new Error(result.error, { cause: result.error });
703
+ return result.value;
704
+ };
705
+ }
706
+ /**
707
+ * Wrap a live `AgentInterface` (`@orkestrel/agent`) as a {@link WorkflowFunction}
708
+ * (`@orkestrel/workflow`) — the OPT-IN adapter that runs the agent to a settled result, folding
709
+ * a nested workflow-authoring depth / cycle guard into its own closure.
710
+ *
711
+ * @remarks
712
+ * OWNED here now (ported from `@orkestrel/workflow`). Composes into a caller's
713
+ * `WorkflowOptions.functions` registry like any other behavior; the pure workflow runner has no
714
+ * knowledge of agents itself. Before running the agent, the depth/cycle guard REJECTS the call
715
+ * (a THROWN typed `DEPTH` `WorkflowError`, which the leaf `fail`s) when running it would push a
716
+ * nested chain past {@link import('./constants.js').MAX_WORKFLOW_DEPTH}, OR when this agent is
717
+ * already an ancestor (a cycle). When {@link import('./types.js').AgentFunctionOptions.runner}
718
+ * is supplied, the adapter BINDS a depth/cycle-aware {@link createWorkflowTool} onto the agent's
719
+ * `context.tools` (the propagation seam) — closed over `depth` and the extended ancestry (the
720
+ * tool itself computes `depth + 1` internally) — so the agent can author + run a NESTED workflow
721
+ * through it; the wrapped default is the CURRENT task's own workflow id (used only on a no-args
722
+ * tool call). The task's cancellation folds into the agent run: an already-aborted
723
+ * `controller.signal` cancels the agent up front; otherwise a one-shot listener fires
724
+ * `agent.abort(reason)` when the task cancels, removed in `finally`. `agent.generate()` resolves
725
+ * a partial `AgentResult` on a cancel (never rejects), returned as the task's completed value.
726
+ *
727
+ * A bound agent is effectively SINGLE-RUN: `context.tools.add` binds one `ToolInterface` under
728
+ * the fixed {@link import('./constants.js').WORKFLOW_TOOL_NAME}, and `agent.generate()` /
729
+ * `agent.abort()` are per-agent state. Two CONCURRENT tasks sharing the SAME `agent` instance
730
+ * race on that one tool binding (last-write-wins) and on generate/abort — give each concurrent
731
+ * task its OWN agent instance.
732
+ *
733
+ * @param agent - The live `AgentInterface` to run
734
+ * @param options - The nested-workflow binding + depth/cycle bookkeeping (see {@link import('./types.js').AgentFunctionOptions})
735
+ * @returns A {@link WorkflowFunction} that runs `agent` to its settled result
736
+ *
737
+ * @example
738
+ * ```ts
739
+ * import { createAgentFunction } from '@src/core'
740
+ * import { createWorkflowRunner } from '@orkestrel/workflow'
741
+ *
742
+ * const runner = createWorkflowRunner()
743
+ * const review = createAgentFunction(myAgent, { runner })
744
+ * await runner.execute(definition, { functions: { review } })
745
+ * ```
746
+ */
747
+ function createAgentFunction(agent, options) {
748
+ return async (controller) => {
749
+ const depth = options?.depth ?? 0;
750
+ const ancestry = options?.ancestry ?? [];
751
+ if (depth + 1 > 8) throw new _orkestrel_workflow.WorkflowError("DEPTH", `agent '${agent.id}' exceeds max workflow depth`, {
752
+ agent: agent.id,
753
+ depth,
754
+ max: 8
755
+ });
756
+ const tag = agentTag(agent.id);
757
+ if (ancestry.includes(tag)) throw new _orkestrel_workflow.WorkflowError("DEPTH", `agent '${agent.id}' is already an ancestor (cycle)`, {
758
+ agent: agent.id,
759
+ ancestry: [...ancestry]
760
+ });
761
+ const runner = options?.runner;
762
+ if (runner !== void 0) {
763
+ const workflowId = controller.task.phase.workflow.id;
764
+ const wrapped = {
765
+ id: workflowId,
766
+ name: workflowId,
767
+ phases: []
768
+ };
769
+ agent.context.tools.add(createWorkflowTool(wrapped, runner, {
770
+ depth,
771
+ ancestry: [...ancestry, tag]
772
+ }));
773
+ }
774
+ const signal = controller.signal;
775
+ const onAbort = () => agent.abort(signal.reason);
776
+ if (signal.aborted) agent.abort(signal.reason);
777
+ else signal.addEventListener("abort", onAbort, { once: true });
778
+ try {
779
+ return await agent.generate();
780
+ } finally {
781
+ signal.removeEventListener("abort", onAbort);
782
+ }
783
+ };
784
+ }
785
+ /**
786
+ * Compile the LENIENT workflow DRAFT contract — identical to `createWorkflowContract`
787
+ * (`@orkestrel/workflow`) EXCEPT `id` and `name` are OPTIONAL at all three levels (workflow /
788
+ * phase / task), so a small model can omit the six identity strings.
789
+ *
790
+ * @remarks
791
+ * The widened authoring surface {@link createWorkflowTool} parses an authored blob through
792
+ * before {@link import('./helpers.js').completeDraft} fills the missing ids/names. It does NOT
793
+ * relax the canonical contract — `createWorkflowContract` (`@orkestrel/workflow`) stays
794
+ * byte-for-byte unchanged and STRICT, and the completed draft is re-validated against THAT
795
+ * strict gate before running (soundness preserved). A PROVIDED `id` / `name` still carries
796
+ * `minLength: 1`, so an explicitly-empty `id: ''` is REJECTED (parses to `undefined`), never
797
+ * auto-filled — keeping "garbage" distinct from "omitted". `run` stays optional (a plain name
798
+ * string).
799
+ *
800
+ * @returns The compiled {@link import('./types.js').WorkflowDraft} contract
801
+ *
802
+ * @example
803
+ * ```ts
804
+ * import { createWorkflowDraftContract, completeDraft } from '@src/core'
805
+ *
806
+ * const draft = createWorkflowDraftContract()
807
+ * const parsed = draft.parse({ phases: [{ tasks: [{ run: 'compile' }] }] })
808
+ * const definition = parsed && completeDraft(parsed) // ids/names filled positionally
809
+ * draft.parse({ id: '', phases: [] }) // undefined — an explicit empty id is rejected
810
+ * ```
811
+ */
812
+ function createWorkflowDraftContract() {
813
+ return (0, _orkestrel_contract.createContract)(workflowDraftShape);
814
+ }
815
+ /**
816
+ * Wrap a {@link WorkflowDefinition} as an LLM-callable tool — it ADVERTISES the SIMPLE flat
817
+ * authoring shape (`{ name?, steps: [{ name }] }`) as its `parameters` so even a small model can
818
+ * author a complete tree, and its handler EXPANDS / COMPLETES the authored blob, validates it
819
+ * against the STRICT contract, runs it through `runner`, and, when
820
+ * {@link import('./types.js').WorkflowToolOptions.store} is supplied, PERSISTS each executed
821
+ * workflow's final snapshot after the run settles.
822
+ *
823
+ * @remarks
824
+ * A plain `ToolManagerInterface`-compatible tool (`@orkestrel/agent`), reproducing
825
+ * `@orkestrel/workflow`'s former call contract exactly (flat / draft / full authoring forms, the
826
+ * strict soundness gate, the depth/cycle guard). It is ALSO the propagation carrier
827
+ * {@link createAgentFunction} binds onto a wrapped agent's `context.tools`: because a tool
828
+ * handler receives ONLY the model-supplied `args` (no ambient context, no signal), the run's
829
+ * depth + ancestry are CLOSED OVER at bind time via {@link import('./types.js').WorkflowToolOptions},
830
+ * and the handler enforces the SAME depth / cycle guard itself before running the nested
831
+ * workflow at `depth + 1` with the extended ancestry.
832
+ *
833
+ * **Widened authoring surface (additive — the canonical contract + runner stay STRICT and
834
+ * unchanged).** A 2B model reliably CALLS the tool but cannot reliably emit the full four-level
835
+ * nested {@link WorkflowDefinition} (six required `id`/`name` strings, an all-or-nothing tree).
836
+ * So the tool ACCEPTS three authoring forms and converges them on the SAME strict
837
+ * `createWorkflowContract` gate before running (soundness preserved):
838
+ * - the FLAT shape `{ name?, steps: [{ name }] }` — the ADVERTISED `parameters` (the simplest
839
+ * form, {@link import('./helpers.js').expandSteps}'d into one one-task phase per step);
840
+ * - a nested DRAFT with any `id`/`name` OMITTED — {@link createWorkflowDraftContract}-parsed then
841
+ * {@link import('./helpers.js').completeDraft}'d (missing ids synthesized positionally);
842
+ * - the full nested {@link WorkflowDefinition} — the advanced escape-hatch, accepted as the draft
843
+ * super-set.
844
+ *
845
+ * The universal tool-handler contract (AGENTS §14): returns the plain run summary
846
+ * (`{ status, count }`) on success, THROWS a typed `WorkflowError` (`@orkestrel/workflow`) on
847
+ * every failure path — malformed authored args (`TOOL`), or an over-deep / cyclic nested run
848
+ * (`DEPTH`). The `ToolManagerInterface` isolates every throw into the canonical tool result's
849
+ * top-level `error`, so nothing escapes the run. `options.depth` / `options.ancestry` are the
850
+ * propagation carrier across a workflow → agent → workflow chain; `options.store` is this
851
+ * package's ADDITION — the persisted snapshot is retrievable via the store afterwards (a caller
852
+ * restores it through `@orkestrel/workflow`'s own `Workflow.restore` / store-backed factories).
853
+ *
854
+ * @param definition - The workflow the tool runs when called with no authored args
855
+ * @param runner - The `WorkflowRunnerInterface` (`@orkestrel/workflow`) that executes the (nested) workflow
856
+ * @param options - Depth/ancestry bookkeeping plus the optional durable store (see {@link import('./types.js').WorkflowToolOptions})
857
+ * @returns A `ToolInterface` (named {@link import('./constants.js').WORKFLOW_TOOL_NAME}) whose
858
+ * `parameters` advertise the flat authoring schema
859
+ *
860
+ * @example
861
+ * ```ts
862
+ * import { createWorkflowTool } from '@src/core'
863
+ * import { createWorkflowRunner, createMemoryWorkflowStore } from '@orkestrel/workflow'
864
+ * import { createToolManager } from '@orkestrel/agent'
865
+ *
866
+ * const runner = createWorkflowRunner()
867
+ * const store = createMemoryWorkflowStore()
868
+ * const tool = createWorkflowTool(definition, runner, { store })
869
+ * const tools = createToolManager()
870
+ * tools.add(tool) // authored runs are now persisted to `store` on settle
871
+ * ```
872
+ */
873
+ function createWorkflowTool(definition, runner, options) {
874
+ const strict = (0, _orkestrel_workflow.createWorkflowContract)();
875
+ const draft = createWorkflowDraftContract();
876
+ const steps = (0, _orkestrel_contract.createContract)(workflowStepsShape);
877
+ const depth = options?.depth ?? 0;
878
+ const ancestry = options?.ancestry ?? [];
879
+ const store = options?.store;
880
+ return (0, _orkestrel_agent.createTool)({
881
+ name: WORKFLOW_TOOL_NAME,
882
+ description: WORKFLOW_TOOL_DESCRIPTION,
883
+ summary: WORKFLOW_TOOL_SUMMARY,
884
+ parameters: (0, _orkestrel_contract.schemaToParameters)(steps.schema),
885
+ execute: async (args) => {
886
+ let target;
887
+ if (Object.keys(args).length === 0) target = definition;
888
+ else if (Array.isArray(args.steps)) {
889
+ const flat = steps.parse(args);
890
+ target = flat === void 0 ? void 0 : expandSteps(flat);
891
+ } else {
892
+ const parsed = draft.parse(args);
893
+ target = parsed === void 0 ? void 0 : completeDraft(parsed);
894
+ }
895
+ if (target === void 0 || !strict.is(target)) throw new _orkestrel_workflow.WorkflowError("TOOL", "malformed workflow definition", { workflow: definition.id });
896
+ if (depth + 1 > 8) throw new _orkestrel_workflow.WorkflowError("DEPTH", `nested workflow exceeds max depth 8`, {
897
+ workflow: target.id,
898
+ depth,
899
+ max: 8
900
+ });
901
+ const tag = workflowTag(target.id);
902
+ if (ancestry.includes(tag)) throw new _orkestrel_workflow.WorkflowError("DEPTH", `workflow '${target.id}' is already an ancestor (cycle)`, {
903
+ workflow: target.id,
904
+ ancestry: [...ancestry]
905
+ });
906
+ const result = await runner.execute(target);
907
+ if (store !== void 0) await store.set(result.workflow.snapshot());
908
+ return workflowToolSummary(result);
909
+ }
910
+ });
911
+ }
912
+ /**
913
+ * Build an LLM-callable workspace-editing tool — it ADVERTISES the `operation`-discriminated
914
+ * 13-op union ({@link import('./shapers.js').workspaceToolShape}) as its `parameters`, and its
915
+ * handler PARSES the model-supplied args against that contract and DISPATCHES the matched
916
+ * operation against the manager's ACTIVE workspace (the registry ops drive the manager itself),
917
+ * returning the plain result (throwing a typed `WorkspaceError`, `@orkestrel/agent`, on
918
+ * failure). EITHER drives a caller-supplied {@link WorkspaceToolOptions.manager} directly, OR
919
+ * constructs a fresh `WorkspaceManagerInterface` (`@orkestrel/agent`) over
920
+ * {@link import('./types.js').WorkspaceToolOptions.store} (via `@orkestrel/agent`'s
921
+ * `createWorkspaceManager`); neither given constructs a manager backed by `@orkestrel/agent`'s
922
+ * in-memory store default.
923
+ *
924
+ * @remarks
925
+ * MANAGER-DRIVEN: every edit / read op (read / list / has / search / replace / write / splice /
926
+ * prepend / append / move / remove) targets `manager.active`, so the model edits whichever
927
+ * workspace is active and a host can re-point it (`WorkspaceManagerInterface.switch`) between
928
+ * turns. Two REGISTRY ops make the model self-sufficient: `workspaces` LISTS the registered
929
+ * workspaces (each `{ id, files, active }`) so it can discover an id, and `switch` re-points the
930
+ * active workspace by id (lenient — an unknown id is a no-op reporting `switched: false`, never a
931
+ * throw).
932
+ *
933
+ * NO-ACTIVE RULE (the ergonomic seam): a WRITING op (write / splice / prepend / append / move /
934
+ * remove / replace) run when `manager.active` is `undefined` AUTO-CREATES + activates a default
935
+ * workspace (`manager.add()`) so the model can just start writing; a pure-READ op (read / list /
936
+ * has / search) against no active workspace returns the EMPTY result (`undefined` / `[]` /
937
+ * `false`), never creating one and never throwing.
938
+ *
939
+ * The handler conforms to the universal tool-handler contract (AGENTS §14): it `contract.parse`s
940
+ * the args, THROWS a `TOOL` `WorkspaceError` when no operation arm matched (a malformed / unknown
941
+ * operation), else `switch`es on `op.operation` and RETURNS the plain result — letting a
942
+ * `WorkspaceError` raised by the live workspace (`MODALITY` / `PATTERN` / `RANGE`) PROPAGATE
943
+ * uncaught. The range edit is the FLAT `'splice'` op: its four flat caret integers are
944
+ * reassembled into a `Range` (`@orkestrel/agent`) by `rangeOf` and fed to the workspace's ranged
945
+ * `write`.
946
+ *
947
+ * @param options - `manager` (drive directly) OR `store` (build a manager over it); neither ⇒
948
+ * an in-memory-backed manager (see {@link import('./types.js').WorkspaceToolOptions})
949
+ * @returns A `ToolInterface` (named {@link import('./constants.js').WORKSPACE_TOOL_NAME} by default)
950
+ *
951
+ * @example
952
+ * ```ts
953
+ * import { createWorkspaceTool } from '@src/core'
954
+ * import { createToolManager } from '@orkestrel/agent'
955
+ *
956
+ * const tool = createWorkspaceTool() // in-memory workspace, no persistence
957
+ * const tools = createToolManager()
958
+ * tools.add(tool)
959
+ * ```
960
+ */
961
+ function createWorkspaceTool(options) {
962
+ const manager = options?.manager ?? (0, _orkestrel_agent.createWorkspaceManager)(options?.store === void 0 ? void 0 : { store: options.store });
963
+ const contract = (0, _orkestrel_contract.createContract)(workspaceToolShape);
964
+ const parameters = (0, _orkestrel_contract.schemaToParameters)(contract.schema);
965
+ return (0, _orkestrel_agent.createTool)({
966
+ name: options?.name ?? "workspace",
967
+ description: options?.description ?? WORKSPACE_TOOL_DESCRIPTION,
968
+ summary: WORKSPACE_TOOL_SUMMARY,
969
+ parameters,
970
+ execute: (args) => {
971
+ const op = contract.parse(args);
972
+ if (op === void 0) throw new _orkestrel_agent.WorkspaceError("TOOL", `unknown or malformed operation`, { args });
973
+ if (op.operation === "workspaces") {
974
+ const activeId = manager.active?.id;
975
+ return manager.workspaces().map((workspace) => ({
976
+ id: workspace.id,
977
+ files: workspace.count,
978
+ active: workspace.id === activeId
979
+ }));
980
+ }
981
+ if (op.operation === "switch") {
982
+ const switched = manager.switch(op.id);
983
+ return switched === void 0 ? {
984
+ id: op.id,
985
+ switched: false
986
+ } : {
987
+ id: switched.id,
988
+ switched: true,
989
+ files: switched.count
990
+ };
991
+ }
992
+ const active = manager.active;
993
+ switch (op.operation) {
994
+ case "read": return active?.read(op.path);
995
+ case "list": return (active?.files() ?? []).map((file) => ({
996
+ path: file.path,
997
+ state: file.state,
998
+ size: file.size,
999
+ lines: file.lines,
1000
+ kind: (0, _orkestrel_agent.isText)(file.content) ? "text" : "binary"
1001
+ }));
1002
+ case "has": return active?.has(op.path) ?? false;
1003
+ case "search": return active?.search(op.query, {
1004
+ regex: op.regex,
1005
+ exact: op.exact,
1006
+ limit: op.limit
1007
+ }) ?? [];
1008
+ case "replace": return (active ?? manager.add()).replace(op.query, op.replacement, {
1009
+ regex: op.regex,
1010
+ exact: op.exact,
1011
+ limit: op.limit
1012
+ });
1013
+ case "write": {
1014
+ const workspace = active ?? manager.add();
1015
+ workspace.write(op.path, op.content);
1016
+ return {
1017
+ path: op.path,
1018
+ state: workspace.file(op.path)?.state
1019
+ };
1020
+ }
1021
+ case "splice": {
1022
+ const workspace = active ?? manager.add();
1023
+ workspace.write(op.path, op.content, (0, _orkestrel_agent.rangeOf)(op.fromLine, op.fromColumn, op.toLine, op.toColumn));
1024
+ return {
1025
+ path: op.path,
1026
+ state: workspace.file(op.path)?.state
1027
+ };
1028
+ }
1029
+ case "prepend": {
1030
+ const workspace = active ?? manager.add();
1031
+ workspace.prepend(op.path, op.content);
1032
+ return {
1033
+ path: op.path,
1034
+ state: workspace.file(op.path)?.state
1035
+ };
1036
+ }
1037
+ case "append": {
1038
+ const workspace = active ?? manager.add();
1039
+ workspace.append(op.path, op.content);
1040
+ return {
1041
+ path: op.path,
1042
+ state: workspace.file(op.path)?.state
1043
+ };
1044
+ }
1045
+ case "move": {
1046
+ const workspace = active ?? manager.add();
1047
+ return {
1048
+ from: op.from,
1049
+ to: op.to,
1050
+ moved: workspace.move(op.from, op.to)
1051
+ };
1052
+ }
1053
+ case "remove": {
1054
+ const workspace = active ?? manager.add();
1055
+ return {
1056
+ path: op.path,
1057
+ removed: workspace.remove(op.path)
1058
+ };
1059
+ }
1060
+ }
1061
+ }
1062
+ });
1063
+ }
1064
+ /**
1065
+ * Build an LLM-callable sub-agent delegation tool — resolves a live, seeded `AgentInterface`
1066
+ * from `registry` and runs it to completion for ONE delegated `task`.
1067
+ *
1068
+ * @remarks
1069
+ * The universal tool-handler contract (AGENTS §14): validates the call args against
1070
+ * {@link import('./shapers.js').agentToolShape}, assembles an `AgentJobInput` (`task` seeds the
1071
+ * sub-agent's conversation as a single `user` message; `provider` / `tools` / `system` fall
1072
+ * back to the tool's own {@link import('./types.js').AgentToolOptions} defaults), rehydrates the sub-agent via
1073
+ * `registry.build`, runs it with `agent.generate()`, and returns the settled
1074
+ * `AgentResult.content` string (the sub-agent's final text). A missing / unresolvable `provider`, or a malformed call, THROWS a typed `TOOL`
1075
+ * {@link import('./errors.js').AgentToolError}; a delegation that would exceed
1076
+ * {@link import('./constants.js').AGENT_TOOL_DEPTH}, or re-enter an already-delegated agent (a
1077
+ * cycle), THROWS a typed `DEPTH` {@link import('./errors.js').AgentToolError} — both isolated
1078
+ * by the `ToolManagerInterface` into the canonical tool result's top-level `error`.
1079
+ *
1080
+ * `AgentInterface` (`@orkestrel/agent`) exposes no teardown method — a bound sub-agent's
1081
+ * lifetime is the single `generate()` call this handler awaits; there is nothing to release
1082
+ * afterwards (unlike a store-backed resource, its state lives entirely in the resolved
1083
+ * `AgentContextInterface`, owned by the caller's registry).
1084
+ *
1085
+ * @param registry - The `AgentRegistryInterface` a delegated job resolves against (providers,
1086
+ * tools, authorities, schedulers, and the `build` rehydration seam)
1087
+ * @param options - Delegation defaults, depth/ancestry bookkeeping, and advertised overrides
1088
+ * (see {@link import('./types.js').AgentToolOptions})
1089
+ * @returns A `ToolInterface` (named {@link import('./constants.js').AGENT_TOOL_NAME} by default)
1090
+ *
1091
+ * @example
1092
+ * ```ts
1093
+ * import { createAgentTool } from '@src/core'
1094
+ * import { createAgentRegistry, createToolManager } from '@orkestrel/agent'
1095
+ *
1096
+ * const registry = createAgentRegistry({ providers: { openai: myProvider } })
1097
+ * const tool = createAgentTool(registry, { provider: 'openai' })
1098
+ * const tools = createToolManager()
1099
+ * tools.add(tool) // a model can now delegate a task to a sub-agent
1100
+ * ```
1101
+ */
1102
+ function createAgentTool(registry, options) {
1103
+ const contract = (0, _orkestrel_contract.createContract)(agentToolShape);
1104
+ const parameters = (0, _orkestrel_contract.schemaToParameters)(contract.schema);
1105
+ const depth = options?.depth ?? 0;
1106
+ const ancestry = options?.ancestry ?? [];
1107
+ return (0, _orkestrel_agent.createTool)({
1108
+ name: options?.name ?? "agent",
1109
+ description: options?.description ?? AGENT_TOOL_DESCRIPTION,
1110
+ summary: AGENT_TOOL_SUMMARY,
1111
+ parameters,
1112
+ execute: async (args) => {
1113
+ const call = contract.parse(args);
1114
+ if (call === void 0) throw new AgentToolError("TOOL", "malformed agent-delegation call", { args });
1115
+ const provider = call.provider ?? options?.provider;
1116
+ if (provider === void 0) throw new AgentToolError("TOOL", "no provider resolved for the delegated agent", { task: call.task });
1117
+ if (depth + 1 > 8) throw new AgentToolError("DEPTH", `delegation exceeds max agent depth 8`, {
1118
+ provider,
1119
+ depth,
1120
+ max: 8
1121
+ });
1122
+ const tag = agentTag(provider);
1123
+ if (ancestry.includes(tag)) throw new AgentToolError("DEPTH", `agent '${provider}' is already an ancestor (cycle)`, {
1124
+ provider,
1125
+ ancestry: [...ancestry]
1126
+ });
1127
+ const tools = call.tools ?? options?.tools;
1128
+ const system = call.system ?? options?.system;
1129
+ const agent = registry.build({
1130
+ provider,
1131
+ messages: [{
1132
+ role: "user",
1133
+ content: call.task
1134
+ }],
1135
+ ...system === void 0 ? {} : { system },
1136
+ ...tools === void 0 ? {} : { tools }
1137
+ });
1138
+ const result = await agent.generate();
1139
+ if (options?.store !== void 0) {
1140
+ const active = agent.context.conversations.active;
1141
+ if (active !== void 0) await options.store.set(active.snapshot());
1142
+ }
1143
+ return result.content;
1144
+ }
1145
+ });
1146
+ }
1147
+ /**
1148
+ * Build an LLM-callable tool that returns the FULL `description` of another registered tool by
1149
+ * name — the counterpart to the lean `summary` the other tools in this package advertise
1150
+ * (`AGENT_TOOL_SUMMARY` / `WORKFLOW_TOOL_SUMMARY` / `WORKSPACE_TOOL_SUMMARY`).
1151
+ *
1152
+ * @remarks
1153
+ * `ToolManagerInterface.definitions()` (`@orkestrel/agent`) advertises `tool.summary ??
1154
+ * tool.description` — a lean one-sentence summary stands in for a tool's full teaching
1155
+ * description when `summary` is set, keeping the advertised tool list compact for a small model.
1156
+ * This tool is the on-demand expansion seam: given a registered tool's `name`, it looks the tool
1157
+ * up via `tools.tool(name)` and returns its full `description` (falling back to `summary` when a
1158
+ * tool has no `description` of its own, then a placeholder when it has neither).
1159
+ *
1160
+ * The universal tool-handler contract (AGENTS §14): validates the call args against
1161
+ * {@link import('./shapers.js').describeToolShape}, RETURNS the plain description string on
1162
+ * success, THROWS a typed `TOOL` {@link import('./errors.js').AgentToolError} on a malformed call
1163
+ * or an unknown tool name.
1164
+ *
1165
+ * @param tools - The `ToolManagerInterface` (`@orkestrel/agent`) whose registered tools this
1166
+ * tool can describe
1167
+ * @returns A `ToolInterface` (named {@link import('./constants.js').DESCRIBE_TOOL_NAME})
1168
+ *
1169
+ * @example
1170
+ * ```ts
1171
+ * import { createDescribeTool, createWorkflowTool } from '@src/core'
1172
+ * import { createToolManager } from '@orkestrel/agent'
1173
+ *
1174
+ * const tools = createToolManager()
1175
+ * tools.add(createWorkflowTool(definition, runner))
1176
+ * tools.add(createDescribeTool(tools))
1177
+ * const full = await tools.execute({ id: '1', name: 'describe', arguments: { name: 'workflow' } })
1178
+ * full.value // the workflow tool's full teaching description
1179
+ * ```
1180
+ */
1181
+ function createDescribeTool(tools) {
1182
+ const contract = (0, _orkestrel_contract.createContract)(describeToolShape);
1183
+ return (0, _orkestrel_agent.createTool)({
1184
+ name: DESCRIBE_TOOL_NAME,
1185
+ description: DESCRIBE_TOOL_DESCRIPTION,
1186
+ summary: DESCRIBE_TOOL_SUMMARY,
1187
+ parameters: (0, _orkestrel_contract.schemaToParameters)(contract.schema),
1188
+ execute: async (args) => {
1189
+ const call = contract.parse(args);
1190
+ if (call === void 0) throw new AgentToolError("TOOL", "malformed describe call", { args });
1191
+ const tool = tools.tool(call.name);
1192
+ if (tool === void 0) throw new AgentToolError("TOOL", `unknown tool '${call.name}'`, { name: call.name });
1193
+ return tool.description ?? tool.summary ?? "<no description>";
1194
+ }
1195
+ });
1196
+ }
1197
+ //#endregion
1198
+ exports.AGENT_TOOL_DEPTH = AGENT_TOOL_DEPTH;
1199
+ exports.AGENT_TOOL_DESCRIPTION = AGENT_TOOL_DESCRIPTION;
1200
+ exports.AGENT_TOOL_NAME = AGENT_TOOL_NAME;
1201
+ exports.AGENT_TOOL_SUMMARY = AGENT_TOOL_SUMMARY;
1202
+ exports.AgentToolError = AgentToolError;
1203
+ exports.DESCRIBE_TOOL_DESCRIPTION = DESCRIBE_TOOL_DESCRIPTION;
1204
+ exports.DESCRIBE_TOOL_NAME = DESCRIBE_TOOL_NAME;
1205
+ exports.DESCRIBE_TOOL_SUMMARY = DESCRIBE_TOOL_SUMMARY;
1206
+ exports.MAX_WORKFLOW_DEPTH = MAX_WORKFLOW_DEPTH;
1207
+ exports.WORKFLOW_TOOL_DESCRIPTION = WORKFLOW_TOOL_DESCRIPTION;
1208
+ exports.WORKFLOW_TOOL_FLAT_EXAMPLE = WORKFLOW_TOOL_FLAT_EXAMPLE;
1209
+ exports.WORKFLOW_TOOL_NAME = WORKFLOW_TOOL_NAME;
1210
+ exports.WORKFLOW_TOOL_NESTED_EXAMPLE = WORKFLOW_TOOL_NESTED_EXAMPLE;
1211
+ exports.WORKFLOW_TOOL_SUMMARY = WORKFLOW_TOOL_SUMMARY;
1212
+ exports.WORKSPACE_TOOL_DESCRIPTION = WORKSPACE_TOOL_DESCRIPTION;
1213
+ exports.WORKSPACE_TOOL_EXAMPLE = WORKSPACE_TOOL_EXAMPLE;
1214
+ exports.WORKSPACE_TOOL_NAME = WORKSPACE_TOOL_NAME;
1215
+ exports.WORKSPACE_TOOL_SUMMARY = WORKSPACE_TOOL_SUMMARY;
1216
+ exports.agentTag = agentTag;
1217
+ exports.agentToolShape = agentToolShape;
1218
+ exports.completeDraft = completeDraft;
1219
+ exports.completePhaseDraft = completePhaseDraft;
1220
+ exports.completeTaskDraft = completeTaskDraft;
1221
+ exports.createAgentFunction = createAgentFunction;
1222
+ exports.createAgentTool = createAgentTool;
1223
+ exports.createDescribeTool = createDescribeTool;
1224
+ exports.createToolFunction = createToolFunction;
1225
+ exports.createWorkflowDraftContract = createWorkflowDraftContract;
1226
+ exports.createWorkflowTool = createWorkflowTool;
1227
+ exports.createWorkspaceTool = createWorkspaceTool;
1228
+ exports.describeToolShape = describeToolShape;
1229
+ exports.expandSteps = expandSteps;
1230
+ exports.isAgentToolError = isAgentToolError;
1231
+ exports.phaseDraftShape = phaseDraftShape;
1232
+ exports.stepShape = stepShape;
1233
+ exports.taskDraftShape = taskDraftShape;
1234
+ exports.workflowDraftShape = workflowDraftShape;
1235
+ exports.workflowStepsShape = workflowStepsShape;
1236
+ exports.workflowTag = workflowTag;
1237
+ exports.workflowToolSummary = workflowToolSummary;
1238
+ exports.workspaceToolShape = workspaceToolShape;
1239
+
1240
+ //# sourceMappingURL=index.cjs.map