@noetic-tools/types 3.2.0 → 3.2.2
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.
- package/README.md +3 -3
- package/dist/errors/noetic-error.js +7 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/schemas/workflow.d.ts +131 -61
- package/dist/schemas/workflow.js +129 -76
- package/dist/types/acp.d.ts +525 -0
- package/dist/types/acp.js +101 -0
- package/dist/types/common.d.ts +12 -0
- package/dist/types/context-harness.d.ts +172 -0
- package/dist/types/context.d.ts +7 -174
- package/dist/types/error.d.ts +5 -4
- package/dist/types/harness-result.d.ts +6 -0
- package/dist/types/observability.d.ts +2 -1
- package/dist/types/output-codec.d.ts +6 -6
- package/dist/types/output-codec.js +4 -4
- package/dist/types/runtime.d.ts +32 -11
- package/dist/types/steering.d.ts +2 -1
- package/dist/types/step.d.ts +68 -53
- package/dist/types/tool-context.d.ts +0 -7
- package/dist/util/message-helpers.js +8 -1
- package/package.json +2 -1
- package/dist/deprecated.d.ts +0 -39
- package/dist/types/sub-harness.d.ts +0 -273
- package/dist/types/sub-harness.js +0 -106
- /package/dist/{deprecated.js → types/context-harness.js} +0 -0
package/dist/schemas/workflow.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Zod schemas for JSON-serialisable workflow definitions.
|
|
3
3
|
*
|
|
4
4
|
* A `WorkflowDocument` is a portable, JSON-safe representation of a noetic
|
|
5
|
-
* step tree. It covers every step kind. The `
|
|
6
|
-
* code STRING (not an in-process closure) dispatched through a subprocess
|
|
5
|
+
* step tree. It covers every step kind. The `runCode` node carries its body as
|
|
6
|
+
* a code STRING (not an in-process closure) dispatched through a subprocess
|
|
7
7
|
* adapter, keeping the document JSON-safe. The hydrator in
|
|
8
8
|
* `@noetic-tools/core` (`builders/workflow-hydrator.ts`) converts a validated
|
|
9
9
|
* document back into live `Step` objects via the existing builders.
|
|
@@ -21,11 +21,14 @@ const MaxCostPredicateSchema = z.object({
|
|
|
21
21
|
});
|
|
22
22
|
const MaxDurationPredicateSchema = z.object({
|
|
23
23
|
kind: z.literal('maxDuration'),
|
|
24
|
-
|
|
24
|
+
duration: z.number().positive(),
|
|
25
25
|
});
|
|
26
26
|
const NoToolCallsPredicateSchema = z.object({
|
|
27
27
|
kind: z.literal('noToolCalls'),
|
|
28
28
|
});
|
|
29
|
+
const NeverPredicateSchema = z.object({
|
|
30
|
+
kind: z.literal('never'),
|
|
31
|
+
});
|
|
29
32
|
const OutputContainsPredicateSchema = z.object({
|
|
30
33
|
kind: z.literal('outputContains'),
|
|
31
34
|
marker: z.string().min(1),
|
|
@@ -54,6 +57,7 @@ export const UntilPredicateSchema = z
|
|
|
54
57
|
MaxCostPredicateSchema,
|
|
55
58
|
MaxDurationPredicateSchema,
|
|
56
59
|
NoToolCallsPredicateSchema,
|
|
60
|
+
NeverPredicateSchema,
|
|
57
61
|
OutputContainsPredicateSchema,
|
|
58
62
|
OutputEqualsPredicateSchema,
|
|
59
63
|
ConvergedPredicateSchema,
|
|
@@ -72,7 +76,7 @@ export const MergeStrategy = {
|
|
|
72
76
|
First: 'first',
|
|
73
77
|
Concat: 'concat',
|
|
74
78
|
};
|
|
75
|
-
/** @public Zod schema for the named merge strategy used by `
|
|
79
|
+
/** @public Zod schema for the named merge strategy used by `inParallel` nodes. */
|
|
76
80
|
export const MergeStrategySchema = z.enum([
|
|
77
81
|
'last',
|
|
78
82
|
'first',
|
|
@@ -89,7 +93,7 @@ const ModelParamsSchema = z.object({
|
|
|
89
93
|
//#endregion
|
|
90
94
|
//#region Tool Entries
|
|
91
95
|
/**
|
|
92
|
-
* A uniform tool entry on
|
|
96
|
+
* A uniform tool entry on a `callModel` node. Every entry is an object keyed by
|
|
93
97
|
* `type`:
|
|
94
98
|
* - A CLIENT tool is `{ type: "<registered-tool-name>" }`. The hydrator
|
|
95
99
|
* resolves `type` against the tool registry; `parameters` (if present) is
|
|
@@ -102,13 +106,13 @@ const ModelParamsSchema = z.object({
|
|
|
102
106
|
* Server vs client is decided by the `type` value (a reserved `openrouter:*`
|
|
103
107
|
* server-tool literal vs an arbitrary tool name), not by the entry's shape.
|
|
104
108
|
*/
|
|
105
|
-
const
|
|
109
|
+
const CallModelToolEntrySchema = z.object({
|
|
106
110
|
type: z.string().min(1),
|
|
107
111
|
parameters: z.record(z.string(), z.unknown()).optional(),
|
|
108
112
|
});
|
|
109
113
|
//#endregion
|
|
110
114
|
//#region Retry Policy
|
|
111
|
-
/** Retry policy for a `
|
|
115
|
+
/** Retry policy for a `runCode` node, mirroring `RetryPolicy` in `@noetic-tools/types`. */
|
|
112
116
|
const RetryPolicySchema = z.object({
|
|
113
117
|
maxAttempts: z.number().int().positive(),
|
|
114
118
|
backoff: z.enum([
|
|
@@ -120,30 +124,84 @@ const RetryPolicySchema = z.object({
|
|
|
120
124
|
maxDelay: z.number().nonnegative().optional(),
|
|
121
125
|
});
|
|
122
126
|
//#endregion
|
|
123
|
-
//#region
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
127
|
+
//#region ACP Agent Settings
|
|
128
|
+
/** ACP `ToolKind` — the agent's own classification of a tool call. */
|
|
129
|
+
const AcpToolKindSchema = z.enum([
|
|
130
|
+
'read',
|
|
131
|
+
'edit',
|
|
132
|
+
'delete',
|
|
133
|
+
'move',
|
|
134
|
+
'search',
|
|
135
|
+
'execute',
|
|
136
|
+
'think',
|
|
137
|
+
'fetch',
|
|
138
|
+
'switch_mode',
|
|
139
|
+
'other',
|
|
140
|
+
]);
|
|
141
|
+
const AcpPermissionDecisionSchema = z.enum([
|
|
142
|
+
'allow',
|
|
143
|
+
'deny',
|
|
144
|
+
'cancel',
|
|
145
|
+
]);
|
|
146
|
+
/**
|
|
147
|
+
* A permission rule. Both fields are optional matchers; an omitted field
|
|
148
|
+
* matches anything. `title` is a case-insensitive substring match here — the
|
|
149
|
+
* programmatic API additionally accepts a `RegExp`, which JSON cannot express.
|
|
150
|
+
*/
|
|
151
|
+
const AcpPermissionRuleSchema = z.object({
|
|
152
|
+
kind: AcpToolKindSchema.optional(),
|
|
153
|
+
title: z.string().min(1).optional(),
|
|
154
|
+
});
|
|
155
|
+
const AcpPermissionPolicySchema = z.object({
|
|
156
|
+
default: AcpPermissionDecisionSchema.optional(),
|
|
157
|
+
allow: z.array(AcpPermissionRuleSchema).optional(),
|
|
158
|
+
deny: z.array(AcpPermissionRuleSchema).optional(),
|
|
159
|
+
persist: z.boolean().optional(),
|
|
160
|
+
});
|
|
161
|
+
const AcpClientCapabilityConfigSchema = z.object({
|
|
162
|
+
readTextFile: z.boolean().optional(),
|
|
163
|
+
writeTextFile: z.boolean().optional(),
|
|
164
|
+
terminal: z.boolean().optional(),
|
|
165
|
+
});
|
|
166
|
+
const AcpNamedValueSchema = z.object({
|
|
167
|
+
name: z.string(),
|
|
168
|
+
value: z.string(),
|
|
137
169
|
});
|
|
138
|
-
|
|
170
|
+
/** ACP `McpServer`. Stdio is untagged and mandatory for every agent; http/sse are capability-gated. */
|
|
171
|
+
const AcpMcpServerSchema = z.union([
|
|
172
|
+
z.object({
|
|
173
|
+
type: z.literal('http'),
|
|
174
|
+
name: z.string().min(1),
|
|
175
|
+
url: z.string(),
|
|
176
|
+
headers: z.array(AcpNamedValueSchema),
|
|
177
|
+
}),
|
|
178
|
+
z.object({
|
|
179
|
+
type: z.literal('sse'),
|
|
180
|
+
name: z.string().min(1),
|
|
181
|
+
url: z.string(),
|
|
182
|
+
headers: z.array(AcpNamedValueSchema),
|
|
183
|
+
}),
|
|
184
|
+
z.object({
|
|
185
|
+
name: z.string().min(1),
|
|
186
|
+
command: z.string().min(1),
|
|
187
|
+
args: z.array(z.string()),
|
|
188
|
+
env: z.array(AcpNamedValueSchema),
|
|
189
|
+
}),
|
|
190
|
+
]);
|
|
191
|
+
const AcpSessionPolicySchema = z.object({
|
|
139
192
|
reuse: z.string().min(1).optional(),
|
|
140
|
-
|
|
193
|
+
/**
|
|
194
|
+
* How long the connection is kept alive. Defaults to `step`; `run` and
|
|
195
|
+
* `harness` are explicit opt-ins because a connection owns a live agent.
|
|
196
|
+
*/
|
|
197
|
+
keepAlive: z
|
|
141
198
|
.enum([
|
|
142
|
-
'
|
|
143
|
-
'
|
|
144
|
-
'
|
|
199
|
+
'step',
|
|
200
|
+
'run',
|
|
201
|
+
'harness',
|
|
145
202
|
])
|
|
146
203
|
.optional(),
|
|
204
|
+
load: z.string().min(1).optional(),
|
|
147
205
|
});
|
|
148
206
|
//#endregion
|
|
149
207
|
//#region Workflow Node Schema
|
|
@@ -155,41 +213,41 @@ const OutputCodecRefSchema = z.object({
|
|
|
155
213
|
codec: z.literal('openui'),
|
|
156
214
|
library: z.string().min(1),
|
|
157
215
|
});
|
|
158
|
-
const
|
|
159
|
-
kind: z.literal('
|
|
216
|
+
const CallModelNodeSchema = z.object({
|
|
217
|
+
kind: z.literal('callModel'),
|
|
160
218
|
...SHARED_FIELDS,
|
|
161
219
|
model: z.string().optional(),
|
|
162
220
|
instructions: z.string(),
|
|
163
|
-
tools: z.array(
|
|
221
|
+
tools: z.array(CallModelToolEntrySchema).optional(),
|
|
164
222
|
params: ModelParamsSchema.optional(),
|
|
165
223
|
output: OutputCodecRefSchema.optional(),
|
|
166
224
|
});
|
|
167
|
-
const
|
|
168
|
-
kind: z.literal('
|
|
225
|
+
const InvokeToolNodeSchema = z.object({
|
|
226
|
+
kind: z.literal('invokeTool'),
|
|
169
227
|
...SHARED_FIELDS,
|
|
170
228
|
toolName: z.string().min(1),
|
|
171
229
|
args: z.record(z.string(), z.unknown()).optional(),
|
|
172
230
|
});
|
|
173
|
-
const
|
|
174
|
-
kind: z.literal('
|
|
231
|
+
const RunCodeNodeSchema = z.object({
|
|
232
|
+
kind: z.literal('runCode'),
|
|
175
233
|
...SHARED_FIELDS,
|
|
176
234
|
execute: z.string().min(1),
|
|
177
235
|
retry: RetryPolicySchema.optional(),
|
|
178
236
|
subprocess: z.string().min(1).optional(),
|
|
179
237
|
});
|
|
180
|
-
const
|
|
238
|
+
const ConditionalRouteSchema = z.object({
|
|
181
239
|
match: z.string().min(1),
|
|
182
240
|
target: z.lazy(() => WorkflowNodeSchema),
|
|
183
241
|
});
|
|
184
|
-
const
|
|
185
|
-
kind: z.literal('
|
|
242
|
+
const ConditionalNodeSchema = z.object({
|
|
243
|
+
kind: z.literal('conditional'),
|
|
186
244
|
...SHARED_FIELDS,
|
|
187
|
-
routes: z.array(
|
|
245
|
+
routes: z.array(ConditionalRouteSchema).min(1),
|
|
188
246
|
default: WorkflowNodeRef.optional(),
|
|
189
247
|
});
|
|
190
|
-
const
|
|
248
|
+
const InParallelNodeSchema = z
|
|
191
249
|
.object({
|
|
192
|
-
kind: z.literal('
|
|
250
|
+
kind: z.literal('inParallel'),
|
|
193
251
|
...SHARED_FIELDS,
|
|
194
252
|
mode: z.enum([
|
|
195
253
|
'race',
|
|
@@ -203,7 +261,7 @@ const ForkNodeSchema = z
|
|
|
203
261
|
concurrency: z.number().int().positive().optional(),
|
|
204
262
|
})
|
|
205
263
|
.refine((node) => (node.paths === undefined) !== (node.each === undefined), {
|
|
206
|
-
message: "
|
|
264
|
+
message: "inParallel node requires exactly one of 'paths' (static) or 'each' (dynamic).",
|
|
207
265
|
});
|
|
208
266
|
const SpawnNodeSchema = z.object({
|
|
209
267
|
kind: z.literal('spawn'),
|
|
@@ -212,8 +270,8 @@ const SpawnNodeSchema = z.object({
|
|
|
212
270
|
timeout: z.number().positive().optional(),
|
|
213
271
|
layers: z.array(z.string().min(1)).min(1).optional(),
|
|
214
272
|
});
|
|
215
|
-
const
|
|
216
|
-
kind: z.literal('
|
|
273
|
+
const WithContextNodeSchema = z.object({
|
|
274
|
+
kind: z.literal('withContext'),
|
|
217
275
|
...SHARED_FIELDS,
|
|
218
276
|
child: WorkflowNodeRef,
|
|
219
277
|
layers: z.array(z.string().min(1)).min(1),
|
|
@@ -230,11 +288,11 @@ const SequenceNodeSchema = z.object({
|
|
|
230
288
|
...SHARED_FIELDS,
|
|
231
289
|
steps: z.array(WorkflowNodeRef).min(1),
|
|
232
290
|
});
|
|
233
|
-
const
|
|
234
|
-
kind: z.literal('
|
|
291
|
+
const ScheduleNodeSchema = z.object({
|
|
292
|
+
kind: z.literal('schedule'),
|
|
235
293
|
...SHARED_FIELDS,
|
|
236
294
|
step: WorkflowNodeRef,
|
|
237
|
-
|
|
295
|
+
interval: z.number().nonnegative(),
|
|
238
296
|
onError: z
|
|
239
297
|
.enum([
|
|
240
298
|
'continue',
|
|
@@ -254,39 +312,34 @@ const SubflowNodeSchema = z
|
|
|
254
312
|
.refine((node) => (node.document === undefined) !== (node.ref === undefined), {
|
|
255
313
|
message: "subflow node requires exactly one of 'document' (inline) or 'ref' (named).",
|
|
256
314
|
});
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const OpencodeNodeSchema = subHarnessNodeSchema('opencode');
|
|
271
|
-
const PiNodeSchema = subHarnessNodeSchema('pi');
|
|
315
|
+
const AcpAgentNodeSchema = z.object({
|
|
316
|
+
kind: z.literal('acp-agent'),
|
|
317
|
+
...SHARED_FIELDS,
|
|
318
|
+
agent: z.string().min(1),
|
|
319
|
+
prompt: z.string().min(1),
|
|
320
|
+
cwd: z.string().min(1).optional(),
|
|
321
|
+
mode: z.string().min(1).optional(),
|
|
322
|
+
model: z.string().min(1).optional(),
|
|
323
|
+
mcpServers: z.array(AcpMcpServerSchema).optional(),
|
|
324
|
+
permissions: AcpPermissionPolicySchema.optional(),
|
|
325
|
+
clientCapabilities: AcpClientCapabilityConfigSchema.optional(),
|
|
326
|
+
session: AcpSessionPolicySchema.optional(),
|
|
327
|
+
});
|
|
272
328
|
/** @public Zod schema validating a single `WorkflowNode` (any JSON-safe kind). */
|
|
273
329
|
export const WorkflowNodeSchema = z
|
|
274
330
|
.discriminatedUnion('kind', [
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
331
|
+
CallModelNodeSchema,
|
|
332
|
+
InvokeToolNodeSchema,
|
|
333
|
+
RunCodeNodeSchema,
|
|
334
|
+
ConditionalNodeSchema,
|
|
335
|
+
InParallelNodeSchema,
|
|
280
336
|
SpawnNodeSchema,
|
|
281
|
-
|
|
337
|
+
WithContextNodeSchema,
|
|
282
338
|
LoopNodeSchema,
|
|
283
339
|
SequenceNodeSchema,
|
|
284
|
-
|
|
340
|
+
ScheduleNodeSchema,
|
|
285
341
|
SubflowNodeSchema,
|
|
286
|
-
|
|
287
|
-
CodexNodeSchema,
|
|
288
|
-
OpencodeNodeSchema,
|
|
289
|
-
PiNodeSchema,
|
|
342
|
+
AcpAgentNodeSchema,
|
|
290
343
|
])
|
|
291
344
|
.meta({
|
|
292
345
|
id: 'WorkflowNode',
|
|
@@ -310,7 +363,7 @@ function childNodes(node) {
|
|
|
310
363
|
switch (node.kind) {
|
|
311
364
|
case 'sequence':
|
|
312
365
|
return node.steps;
|
|
313
|
-
case '
|
|
366
|
+
case 'inParallel':
|
|
314
367
|
if (node.each) {
|
|
315
368
|
return [
|
|
316
369
|
node.each,
|
|
@@ -318,7 +371,7 @@ function childNodes(node) {
|
|
|
318
371
|
}
|
|
319
372
|
return node.paths ?? [];
|
|
320
373
|
case 'spawn':
|
|
321
|
-
case '
|
|
374
|
+
case 'withContext':
|
|
322
375
|
return [
|
|
323
376
|
node.child,
|
|
324
377
|
];
|
|
@@ -326,11 +379,11 @@ function childNodes(node) {
|
|
|
326
379
|
return [
|
|
327
380
|
node.body,
|
|
328
381
|
];
|
|
329
|
-
case '
|
|
382
|
+
case 'schedule':
|
|
330
383
|
return [
|
|
331
384
|
node.step,
|
|
332
385
|
];
|
|
333
|
-
case '
|
|
386
|
+
case 'conditional': {
|
|
334
387
|
const children = node.routes.map((r) => r.target);
|
|
335
388
|
if (node.default) {
|
|
336
389
|
children.push(node.default);
|
|
@@ -388,7 +441,7 @@ export function workflowGraph(root) {
|
|
|
388
441
|
}
|
|
389
442
|
/**
|
|
390
443
|
* Returns the maximum depth of a workflow tree.
|
|
391
|
-
* Leaf nodes (`
|
|
444
|
+
* Leaf nodes (`callModel`, `invokeTool`) have depth 0. Structural nodes add +1.
|
|
392
445
|
* A `subflow` ref counts as a leaf — depth does not see through named refs.
|
|
393
446
|
*/
|
|
394
447
|
export function workflowDepth(node) {
|