agentweaver 0.1.16 → 0.1.18
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 +148 -27
- package/dist/artifacts.js +114 -3
- package/dist/doctor/checks/executors.js +2 -2
- package/dist/flow-state.js +138 -1
- package/dist/index.js +421 -82
- package/dist/interactive/controller.js +305 -36
- package/dist/interactive/ink/index.js +24 -3
- package/dist/interactive/state.js +1 -0
- package/dist/interactive/tree.js +2 -2
- package/dist/interactive/web/index.js +179 -0
- package/dist/interactive/web/protocol.js +154 -0
- package/dist/interactive/web/server.js +575 -0
- package/dist/interactive/web/static/app.js +709 -0
- package/dist/interactive/web/static/index.html +77 -0
- package/dist/interactive/web/static/styles.css +2 -0
- package/dist/interactive/web/static/styles.input.css +469 -0
- package/dist/pipeline/auto-flow.js +9 -6
- package/dist/pipeline/context.js +6 -5
- package/dist/pipeline/declarative-flows.js +39 -20
- package/dist/pipeline/flow-catalog.js +40 -14
- package/dist/pipeline/flow-specs/auto-common-guided.json +313 -0
- package/dist/pipeline/flow-specs/auto-common.json +4 -1
- package/dist/pipeline/flow-specs/auto-golang.json +27 -1
- package/dist/pipeline/flow-specs/design-review/design-review-loop.json +15 -1
- package/dist/pipeline/flow-specs/design-review.json +2 -0
- package/dist/pipeline/flow-specs/implement.json +3 -1
- package/dist/pipeline/flow-specs/plan.json +8 -2
- package/dist/pipeline/flow-specs/playbook-init.json +199 -0
- package/dist/pipeline/flow-specs/review/review-fix.json +3 -1
- package/dist/pipeline/flow-specs/review/review-loop.json +4 -0
- package/dist/pipeline/flow-specs/review/review.json +2 -0
- package/dist/pipeline/launch-profile-config.js +30 -18
- package/dist/pipeline/node-contract.js +1 -0
- package/dist/pipeline/node-registry.js +119 -5
- package/dist/pipeline/nodes/flow-run-node.js +200 -173
- package/dist/pipeline/nodes/llm-prompt-node.js +15 -33
- package/dist/pipeline/nodes/playbook-ensure-node.js +115 -0
- package/dist/pipeline/nodes/playbook-inventory-node.js +51 -0
- package/dist/pipeline/nodes/playbook-questions-form-node.js +166 -0
- package/dist/pipeline/nodes/playbook-write-node.js +243 -0
- package/dist/pipeline/nodes/project-guidance-node.js +69 -0
- package/dist/pipeline/plugin-loader.js +389 -0
- package/dist/pipeline/plugin-types.js +1 -0
- package/dist/pipeline/prompt-registry.js +4 -1
- package/dist/pipeline/prompt-runtime.js +6 -2
- package/dist/pipeline/registry.js +71 -4
- package/dist/pipeline/spec-compiler.js +1 -0
- package/dist/pipeline/spec-loader.js +14 -0
- package/dist/pipeline/spec-types.js +19 -0
- package/dist/pipeline/spec-validator.js +6 -0
- package/dist/pipeline/value-resolver.js +41 -2
- package/dist/playbook/practice-candidates.js +12 -0
- package/dist/playbook/repo-inventory.js +208 -0
- package/dist/plugin-sdk.js +1 -0
- package/dist/prompts.js +31 -0
- package/dist/runtime/artifact-registry.js +3 -0
- package/dist/runtime/execution-routing.js +25 -19
- package/dist/runtime/interactive-execution-routing.js +66 -57
- package/dist/runtime/playbook.js +485 -0
- package/dist/runtime/project-guidance.js +339 -0
- package/dist/structured-artifact-schema-registry.js +8 -0
- package/dist/structured-artifact-schemas.json +235 -0
- package/dist/structured-artifacts.js +7 -1
- package/docs/declarative-workflows.md +565 -0
- package/docs/example/.flows/examples/claude-example.json +50 -0
- package/docs/example/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/example/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/examples/.flows/claude-example.json +50 -0
- package/docs/examples/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/examples/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/features.md +77 -0
- package/docs/playbook.md +327 -0
- package/docs/plugin-sdk.md +731 -0
- package/package.json +13 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { flowRoutingGroups, flowRoutingKey } from "../pipeline/flow-catalog.js";
|
|
3
3
|
import { loadNamedDeclarativeFlow } from "../pipeline/declarative-flows.js";
|
|
4
|
+
import { createPipelineRegistryContext } from "../pipeline/plugin-loader.js";
|
|
4
5
|
import { EXECUTION_ROUTING_GROUPS, } from "../pipeline/execution-routing-config.js";
|
|
5
6
|
import { DEFAULT_LAUNCH_PROFILE, defaultModelForExecutor, isAllowedModelForExecutor, } from "../pipeline/launch-profile-config.js";
|
|
6
7
|
import { FlowInterruptedError, TaskRunnerError } from "../errors.js";
|
|
@@ -58,15 +59,9 @@ function executionPresetSelectionForm(flowEntry, flowDefaultAvailable, lastUsedA
|
|
|
58
59
|
],
|
|
59
60
|
};
|
|
60
61
|
}
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
{ value: "opencode", label: "opencode" },
|
|
65
|
-
];
|
|
66
|
-
}
|
|
67
|
-
function selectedExecutorFromValues(values, fieldId, fallbackExecutor) {
|
|
68
|
-
const candidate = values[fieldId];
|
|
69
|
-
return candidate === "codex" || candidate === "opencode" ? candidate : fallbackExecutor;
|
|
62
|
+
function selectedExecutorFromValues(values, fieldId, fallbackExecutor, registryContext) {
|
|
63
|
+
const candidate = typeof values[fieldId] === "string" ? values[fieldId] : "";
|
|
64
|
+
return registryContext.executors.getRouting(candidate)?.kind === "llm" ? candidate : fallbackExecutor;
|
|
70
65
|
}
|
|
71
66
|
function routingEditorDraftFromRouting(routing) {
|
|
72
67
|
return {
|
|
@@ -83,7 +78,11 @@ function routingEditorDraftFromRouting(routing) {
|
|
|
83
78
|
])),
|
|
84
79
|
};
|
|
85
80
|
}
|
|
86
|
-
function advancedRoutingEditorForm(activeGroups, draft, validationMessage) {
|
|
81
|
+
function advancedRoutingEditorForm(activeGroups, draft, registryContext, validationMessage) {
|
|
82
|
+
const executorOptions = registryContext.executors.llmExecutors().map((entry) => ({
|
|
83
|
+
value: entry.id,
|
|
84
|
+
label: entry.id,
|
|
85
|
+
}));
|
|
87
86
|
const fields = [
|
|
88
87
|
{
|
|
89
88
|
id: "default_route_executor",
|
|
@@ -91,7 +90,7 @@ function advancedRoutingEditorForm(activeGroups, draft, validationMessage) {
|
|
|
91
90
|
label: "Default route executor",
|
|
92
91
|
required: true,
|
|
93
92
|
default: draft.defaultRoute.executor,
|
|
94
|
-
options:
|
|
93
|
+
options: executorOptions,
|
|
95
94
|
},
|
|
96
95
|
{
|
|
97
96
|
id: "default_route_model",
|
|
@@ -100,8 +99,8 @@ function advancedRoutingEditorForm(activeGroups, draft, validationMessage) {
|
|
|
100
99
|
help: "Available models follow the selected default executor.",
|
|
101
100
|
required: true,
|
|
102
101
|
default: draft.defaultRoute.model,
|
|
103
|
-
options: modelOptionsForExecutor(draft.defaultRoute.executor),
|
|
104
|
-
optionsFromValues: (values) => modelOptionsForExecutor(selectedExecutorFromValues(values, "default_route_executor", draft.defaultRoute.executor)),
|
|
102
|
+
options: modelOptionsForExecutor(draft.defaultRoute.executor, registryContext.executors),
|
|
103
|
+
optionsFromValues: (values) => modelOptionsForExecutor(selectedExecutorFromValues(values, "default_route_executor", draft.defaultRoute.executor, registryContext), registryContext.executors),
|
|
105
104
|
},
|
|
106
105
|
...activeGroups.flatMap((group) => {
|
|
107
106
|
const route = draft.groups[group];
|
|
@@ -112,7 +111,7 @@ function advancedRoutingEditorForm(activeGroups, draft, validationMessage) {
|
|
|
112
111
|
label: `${routingGroupLabel(group)} executor`,
|
|
113
112
|
required: true,
|
|
114
113
|
default: route.executor,
|
|
115
|
-
options:
|
|
114
|
+
options: executorOptions,
|
|
116
115
|
},
|
|
117
116
|
{
|
|
118
117
|
id: `${group}_model`,
|
|
@@ -121,8 +120,8 @@ function advancedRoutingEditorForm(activeGroups, draft, validationMessage) {
|
|
|
121
120
|
help: `Available models follow the selected ${routingGroupLabel(group)} executor.`,
|
|
122
121
|
required: true,
|
|
123
122
|
default: route.model,
|
|
124
|
-
options: modelOptionsForExecutor(route.executor),
|
|
125
|
-
optionsFromValues: (values) => modelOptionsForExecutor(selectedExecutorFromValues(values, `${group}_executor`, route.executor)),
|
|
123
|
+
options: modelOptionsForExecutor(route.executor, registryContext.executors),
|
|
124
|
+
optionsFromValues: (values) => modelOptionsForExecutor(selectedExecutorFromValues(values, `${group}_executor`, route.executor, registryContext), registryContext.executors),
|
|
126
125
|
},
|
|
127
126
|
];
|
|
128
127
|
}),
|
|
@@ -202,8 +201,8 @@ function presetNameForm() {
|
|
|
202
201
|
],
|
|
203
202
|
};
|
|
204
203
|
}
|
|
205
|
-
function normalizeEditableRoute(label, route) {
|
|
206
|
-
if (isAllowedModelForExecutor(route.executor, route.model)) {
|
|
204
|
+
function normalizeEditableRoute(label, route, executors) {
|
|
205
|
+
if (isAllowedModelForExecutor(route.executor, route.model, executors)) {
|
|
207
206
|
return {
|
|
208
207
|
route: { ...route },
|
|
209
208
|
validationErrors: [],
|
|
@@ -212,20 +211,20 @@ function normalizeEditableRoute(label, route) {
|
|
|
212
211
|
return {
|
|
213
212
|
route: {
|
|
214
213
|
executor: route.executor,
|
|
215
|
-
model: defaultModelForExecutor(route.executor),
|
|
214
|
+
model: defaultModelForExecutor(route.executor, executors),
|
|
216
215
|
},
|
|
217
216
|
validationErrors: [
|
|
218
217
|
`${label} model '${route.model}' is not allowed for executor '${route.executor}'. Select a ${route.executor} model.`,
|
|
219
218
|
],
|
|
220
219
|
};
|
|
221
220
|
}
|
|
222
|
-
function normalizeEditableRoutingDraft(draft) {
|
|
223
|
-
const defaultRoute = normalizeEditableRoute("Default route", draft.defaultRoute);
|
|
221
|
+
function normalizeEditableRoutingDraft(draft, executors) {
|
|
222
|
+
const defaultRoute = normalizeEditableRoute("Default route", draft.defaultRoute, executors);
|
|
224
223
|
const groups = {};
|
|
225
224
|
const currentRunOverrides = {};
|
|
226
225
|
const validationErrors = [...defaultRoute.validationErrors];
|
|
227
226
|
for (const group of EXECUTION_ROUTING_GROUPS) {
|
|
228
|
-
const normalizedRoute = normalizeEditableRoute(routingGroupLabel(group), draft.groups[group]);
|
|
227
|
+
const normalizedRoute = normalizeEditableRoute(routingGroupLabel(group), draft.groups[group], executors);
|
|
229
228
|
groups[group] = normalizedRoute.route;
|
|
230
229
|
if (normalizedRoute.route.executor !== defaultRoute.route.executor
|
|
231
230
|
|| normalizedRoute.route.model !== defaultRoute.route.model) {
|
|
@@ -274,40 +273,47 @@ function formatAsciiTable(headers, rows, maxWidths) {
|
|
|
274
273
|
const separator = `|-${widths.map((width) => "-".repeat(width)).join("-|-")}-|`;
|
|
275
274
|
return [formatRow(headers), separator, ...rows.map((row) => formatRow(row))];
|
|
276
275
|
}
|
|
277
|
-
function collectEffectiveRoutedStepRows(flow, cwd, routing, prefixSegments = [], ancestry = []) {
|
|
276
|
+
function collectEffectiveRoutedStepRows(flow, cwd, routing, registryContext, prefixSegments = [], ancestry = []) {
|
|
278
277
|
if (ancestry.includes(flow.absolutePath)) {
|
|
279
|
-
return [];
|
|
278
|
+
return Promise.resolve([]);
|
|
280
279
|
}
|
|
281
280
|
const nextAncestry = [...ancestry, flow.absolutePath];
|
|
282
281
|
const rows = [];
|
|
283
|
-
|
|
284
|
-
for (const
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
282
|
+
const run = async () => {
|
|
283
|
+
for (const phase of flow.phases) {
|
|
284
|
+
for (const step of phase.steps) {
|
|
285
|
+
const stepRef = `${phase.id}.${step.id}`;
|
|
286
|
+
if (step.routingGroup) {
|
|
287
|
+
const route = routing.groups[step.routingGroup];
|
|
288
|
+
rows.push({
|
|
289
|
+
step: [...prefixSegments, stepRef].join(" > "),
|
|
290
|
+
group: routingGroupLabel(step.routingGroup),
|
|
291
|
+
executor: route.executor,
|
|
292
|
+
model: route.model,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
if (step.node !== "flow-run") {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
const nestedFlowName = step.params?.fileName;
|
|
299
|
+
if (!nestedFlowName || !("const" in nestedFlowName) || typeof nestedFlowName.const !== "string") {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const nestedFlow = await loadNamedDeclarativeFlow(nestedFlowName.const, cwd, {
|
|
303
|
+
...(registryContext ? { registryContext } : {}),
|
|
293
304
|
});
|
|
305
|
+
const nestedFlowLabel = path.basename(nestedFlow.fileName, path.extname(nestedFlow.fileName));
|
|
306
|
+
rows.push(...await collectEffectiveRoutedStepRows(nestedFlow, cwd, routing, registryContext, [...prefixSegments, stepRef, nestedFlowLabel], nextAncestry));
|
|
294
307
|
}
|
|
295
|
-
if (step.node !== "flow-run") {
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
const nestedFlowName = step.params?.fileName;
|
|
299
|
-
if (!nestedFlowName || !("const" in nestedFlowName) || typeof nestedFlowName.const !== "string") {
|
|
300
|
-
continue;
|
|
301
|
-
}
|
|
302
|
-
const nestedFlow = loadNamedDeclarativeFlow(nestedFlowName.const, cwd);
|
|
303
|
-
const nestedFlowLabel = path.basename(nestedFlow.fileName, path.extname(nestedFlow.fileName));
|
|
304
|
-
rows.push(...collectEffectiveRoutedStepRows(nestedFlow, cwd, routing, [...prefixSegments, stepRef, nestedFlowLabel], nextAncestry));
|
|
305
308
|
}
|
|
306
|
-
|
|
307
|
-
|
|
309
|
+
return rows;
|
|
310
|
+
};
|
|
311
|
+
return run();
|
|
308
312
|
}
|
|
309
|
-
export function describeEffectiveRoutingPreview(flowEntry, routing, cwd) {
|
|
310
|
-
const previewGroups = flowRoutingGroups(flowEntry, cwd
|
|
313
|
+
export async function describeEffectiveRoutingPreview(flowEntry, routing, cwd, registryContext) {
|
|
314
|
+
const previewGroups = await flowRoutingGroups(flowEntry, cwd, {
|
|
315
|
+
...(registryContext ? { registryContext } : {}),
|
|
316
|
+
});
|
|
311
317
|
const summaryRows = [
|
|
312
318
|
["Default", routing.defaultRoute.executor, routing.defaultRoute.model],
|
|
313
319
|
...previewGroups.map((group) => [
|
|
@@ -320,7 +326,7 @@ export function describeEffectiveRoutingPreview(flowEntry, routing, cwd) {
|
|
|
320
326
|
"Effective routes:",
|
|
321
327
|
...formatAsciiTable(["Scope", "Executor", "Model"], summaryRows, [18, 12, 36]),
|
|
322
328
|
];
|
|
323
|
-
const routedSteps = collapseRepeatedEffectiveRoutedStepRows(collectEffectiveRoutedStepRows(flowEntry.flow, cwd, routing));
|
|
329
|
+
const routedSteps = collapseRepeatedEffectiveRoutedStepRows(await collectEffectiveRoutedStepRows(flowEntry.flow, cwd, routing, registryContext));
|
|
324
330
|
if (routedSteps.length === 0) {
|
|
325
331
|
return lines.join("\n");
|
|
326
332
|
}
|
|
@@ -332,7 +338,8 @@ export function describeEffectiveRoutingPreview(flowEntry, routing, cwd) {
|
|
|
332
338
|
].join("\n");
|
|
333
339
|
}
|
|
334
340
|
export async function requestInteractiveExecutionRouting(flowEntry, requestUserInput) {
|
|
335
|
-
const
|
|
341
|
+
const registryContext = await createPipelineRegistryContext(process.cwd());
|
|
342
|
+
const previewGroups = await flowRoutingGroups(flowEntry, process.cwd(), { registryContext });
|
|
336
343
|
const flowKey = flowRoutingKey(flowEntry);
|
|
337
344
|
const namedPresets = getNamedExecutionPresets();
|
|
338
345
|
const flowDefault = getFlowDefaultExecutionRouting(flowKey);
|
|
@@ -346,14 +353,14 @@ export async function requestInteractiveExecutionRouting(flowEntry, requestUserI
|
|
|
346
353
|
throw new TaskRunnerError("Flow default routing is unavailable.");
|
|
347
354
|
}
|
|
348
355
|
selectedPreset = { kind: "flow-default", label: "Flow default" };
|
|
349
|
-
routing = resolveStoredExecutionRoutingSnapshot(flowDefault.routing);
|
|
356
|
+
routing = resolveStoredExecutionRoutingSnapshot(flowDefault.routing, registryContext.executors);
|
|
350
357
|
}
|
|
351
358
|
else if (selectedPresetValue === "last-used") {
|
|
352
359
|
if (!lastUsed) {
|
|
353
360
|
throw new TaskRunnerError("Last-used routing is unavailable.");
|
|
354
361
|
}
|
|
355
362
|
selectedPreset = { kind: "last-used", label: "Last used" };
|
|
356
|
-
routing = resolveStoredExecutionRoutingSnapshot(lastUsed.routing);
|
|
363
|
+
routing = resolveStoredExecutionRoutingSnapshot(lastUsed.routing, registryContext.executors);
|
|
357
364
|
}
|
|
358
365
|
else if (selectedPresetValue.startsWith("named:")) {
|
|
359
366
|
const presetName = selectedPresetValue.slice("named:".length);
|
|
@@ -362,7 +369,7 @@ export async function requestInteractiveExecutionRouting(flowEntry, requestUserI
|
|
|
362
369
|
throw new TaskRunnerError(`Named preset '${presetName}' is unavailable.`);
|
|
363
370
|
}
|
|
364
371
|
selectedPreset = { kind: "named", presetId: presetName, label: `Named preset: ${presetName}` };
|
|
365
|
-
routing = resolveStoredExecutionRoutingSnapshot(namedPreset.routing);
|
|
372
|
+
routing = resolveStoredExecutionRoutingSnapshot(namedPreset.routing, registryContext.executors);
|
|
366
373
|
}
|
|
367
374
|
else if (selectedPresetValue.startsWith("built-in:")) {
|
|
368
375
|
const presetId = selectedPresetValue.slice("built-in:".length);
|
|
@@ -371,11 +378,12 @@ export async function requestInteractiveExecutionRouting(flowEntry, requestUserI
|
|
|
371
378
|
throw new TaskRunnerError(`Unknown execution preset '${presetId}'.`);
|
|
372
379
|
}
|
|
373
380
|
selectedPreset = { kind: "built-in", presetId, label: preset.label };
|
|
374
|
-
routing = resolveExecutionRouting({ presetId });
|
|
381
|
+
routing = resolveExecutionRouting({ presetId, executors: registryContext.executors });
|
|
375
382
|
}
|
|
376
383
|
else {
|
|
377
384
|
selectedPreset = { kind: "custom", label: "Custom" };
|
|
378
385
|
routing = resolveExecutionRouting({
|
|
386
|
+
executors: registryContext.executors,
|
|
379
387
|
defaultRoute: {
|
|
380
388
|
executor: DEFAULT_LAUNCH_PROFILE.executor,
|
|
381
389
|
model: DEFAULT_LAUNCH_PROFILE.model,
|
|
@@ -385,7 +393,7 @@ export async function requestInteractiveExecutionRouting(flowEntry, requestUserI
|
|
|
385
393
|
let editorDraft = routingEditorDraftFromRouting(routing);
|
|
386
394
|
let editorValidationMessage;
|
|
387
395
|
for (;;) {
|
|
388
|
-
const previewText = `Preset: ${selectedPreset.label}\n${describeEffectiveRoutingPreview(flowEntry, routing, process.cwd())}`;
|
|
396
|
+
const previewText = `Preset: ${selectedPreset.label}\n${await describeEffectiveRoutingPreview(flowEntry, routing, process.cwd(), registryContext)}`;
|
|
389
397
|
const actionResult = await requestUserInput(routingActionForm(previewText));
|
|
390
398
|
const action = String(actionResult.values.action ?? "start");
|
|
391
399
|
if (action === "cancel") {
|
|
@@ -395,7 +403,7 @@ export async function requestInteractiveExecutionRouting(flowEntry, requestUserI
|
|
|
395
403
|
saveLastUsedExecutionRouting(flowKey, routing, selectedPreset);
|
|
396
404
|
return { routing, selectedPreset };
|
|
397
405
|
}
|
|
398
|
-
const routingFormResult = await requestUserInput(advancedRoutingEditorForm(previewGroups, editorDraft, editorValidationMessage));
|
|
406
|
+
const routingFormResult = await requestUserInput(advancedRoutingEditorForm(previewGroups, editorDraft, registryContext, editorValidationMessage));
|
|
399
407
|
const requestedDefaultRoute = {
|
|
400
408
|
executor: String(routingFormResult.values.default_route_executor ?? editorDraft.defaultRoute.executor),
|
|
401
409
|
model: String(routingFormResult.values.default_route_model ?? editorDraft.defaultRoute.model),
|
|
@@ -418,7 +426,7 @@ export async function requestInteractiveExecutionRouting(flowEntry, requestUserI
|
|
|
418
426
|
];
|
|
419
427
|
})),
|
|
420
428
|
};
|
|
421
|
-
const normalizedDraft = normalizeEditableRoutingDraft(requestedDraft);
|
|
429
|
+
const normalizedDraft = normalizeEditableRoutingDraft(requestedDraft, registryContext.executors);
|
|
422
430
|
editorDraft = normalizedDraft.draft;
|
|
423
431
|
if (normalizedDraft.validationErrors.length > 0) {
|
|
424
432
|
editorValidationMessage = normalizedDraft.validationErrors.join("\n");
|
|
@@ -426,6 +434,7 @@ export async function requestInteractiveExecutionRouting(flowEntry, requestUserI
|
|
|
426
434
|
}
|
|
427
435
|
try {
|
|
428
436
|
routing = resolveExecutionRouting({
|
|
437
|
+
executors: registryContext.executors,
|
|
429
438
|
defaultRoute: {
|
|
430
439
|
executor: normalizedDraft.draft.defaultRoute.executor,
|
|
431
440
|
model: normalizedDraft.draft.defaultRoute.model,
|