@noetic-tools/core 5.2.0 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/dist/adapters/in-memory-subprocess/step-completion.js +1 -1
- package/dist/adapters/openrouter.d.ts +20 -2
- package/dist/adapters/openrouter.js +102 -6
- package/dist/builders/control-flow-builders.d.ts +13 -13
- package/dist/builders/control-flow-builders.js +11 -11
- package/dist/{patterns → builders}/dynamic-workflow.d.ts +1 -1
- package/dist/{patterns → builders}/dynamic-workflow.js +18 -12
- package/dist/builders/every.d.ts +14 -14
- package/dist/builders/every.js +16 -16
- package/dist/builders/layer-provides-builders.d.ts +1 -1
- package/dist/builders/layer-provides-builders.js +1 -1
- package/dist/builders/provide-builder.d.ts +5 -12
- package/dist/builders/provide-builder.js +9 -10
- package/dist/builders/spawn-builder.d.ts +0 -2
- package/dist/builders/spawn-builder.js +2 -3
- package/dist/builders/step-builders.d.ts +66 -55
- package/dist/builders/step-builders.js +118 -111
- package/dist/builders/tool-builder.d.ts +18 -22
- package/dist/builders/tool-builder.js +6 -4
- package/dist/builders/workflow-hydrator.d.ts +3 -3
- package/dist/builders/workflow-hydrator.js +59 -63
- package/dist/builders/workflow-step.d.ts +13 -25
- package/dist/builders/workflow-step.js +13 -18
- package/dist/conditions/conditions.d.ts +2 -2
- package/dist/conditions/conditions.js +1 -1
- package/dist/harness/agent-harness.d.ts +58 -40
- package/dist/harness/agent-harness.js +125 -51
- package/dist/harness/deps/context.d.ts +1 -1
- package/dist/harness/deps/context.js +1 -1
- package/dist/harness/deps/interpreter.d.ts +1 -0
- package/dist/harness/deps/interpreter.js +1 -0
- package/dist/harness/deps/types.d.ts +2 -2
- package/dist/harness/model-call.d.ts +1 -1
- package/dist/harness/model-call.js +45 -23
- package/dist/index.d.ts +23 -35
- package/dist/index.js +10 -26
- package/dist/interpreter/action-deps.d.ts +2 -2
- package/dist/interpreter/action-deps.js +1 -1
- package/dist/interpreter/action-types.d.ts +1 -1
- package/dist/interpreter/collect-tools.js +7 -7
- package/dist/interpreter/context-assembly.d.ts +50 -0
- package/dist/interpreter/context-assembly.js +547 -0
- package/dist/interpreter/execute-action.d.ts +5 -5
- package/dist/interpreter/execute-action.js +337 -208
- package/dist/interpreter/execute-control.d.ts +9 -9
- package/dist/interpreter/execute-control.js +27 -27
- package/dist/interpreter/execute-sub-harness.d.ts +1 -1
- package/dist/interpreter/execute-sub-harness.js +7 -26
- package/dist/interpreter/execute.d.ts +1 -1
- package/dist/interpreter/execute.js +26 -25
- package/dist/interpreter/step-dispatcher.d.ts +1 -1
- package/dist/interpreter/step-dispatcher.js +3 -3
- package/dist/interpreter/structured-output.d.ts +14 -0
- package/dist/interpreter/structured-output.js +40 -0
- package/dist/interpreter/typeguards.d.ts +1 -1
- package/dist/interpreter/typeguards.js +1 -1
- package/dist/observability/genai-attributes.d.ts +20 -0
- package/dist/observability/genai-attributes.js +20 -0
- package/dist/portable/builders.d.ts +3 -3
- package/dist/portable/builders.js +6 -5
- package/dist/portable/context-layers.d.ts +1 -1
- package/dist/portable/context-layers.js +1 -1
- package/dist/runtime/broadcaster-utils.d.ts +1 -1
- package/dist/runtime/broadcaster-utils.js +1 -1
- package/dist/runtime/context-impl.d.ts +8 -10
- package/dist/runtime/context-impl.js +8 -12
- package/dist/runtime/durable/step-ledger.d.ts +2 -2
- package/dist/runtime/durable/step-ledger.js +3 -3
- package/dist/runtime/session-runner.d.ts +12 -1
- package/dist/runtime/session-runner.js +33 -1
- package/dist/runtime/tool-context.js +0 -2
- package/dist/schemas/workflow.d.ts +3 -3
- package/dist/schemas/workflow.js +2 -2
- package/dist/types/checkpoint.d.ts +11 -2
- package/dist/types/checkpoint.js +10 -1
- package/dist/{runtime → util}/detached-handle.js +1 -1
- package/package.json +6 -4
- package/schema/noetic-workflow.schema.json +24 -11
- package/dist/builders/context-option.d.ts +0 -23
- package/dist/builders/context-option.js +0 -22
- package/dist/deprecated.d.ts +0 -30
- package/dist/deprecated.js +0 -28
- package/dist/patterns/interview.d.ts +0 -53
- package/dist/patterns/interview.js +0 -113
- package/dist/patterns/plans.d.ts +0 -44
- package/dist/patterns/plans.js +0 -125
- package/dist/patterns/ralph-wiggum.d.ts +0 -19
- package/dist/patterns/ralph-wiggum.js +0 -37
- package/dist/patterns/react.d.ts +0 -19
- package/dist/patterns/react.js +0 -41
- /package/dist/{runtime → util}/detached-handle.d.ts +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ContextConfig, ContextData, ContextLayer } from '@noetic-tools/context';
|
|
2
|
-
import type { Step,
|
|
2
|
+
import type { Step, StepWithContext } from '@noetic-tools/types';
|
|
3
3
|
/**
|
|
4
4
|
* Creates a provide step that attaches context layers to its child without creating an isolated context.
|
|
5
5
|
* Like React's Context.Provider — layers are available to all descendant steps.
|
|
@@ -9,19 +9,12 @@ import type { Step, StepProvide } from '@noetic-tools/types';
|
|
|
9
9
|
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
10
10
|
* @param opts.child - Step to execute with the provided layers.
|
|
11
11
|
* @param opts.context - Context layers to provide to descendant steps.
|
|
12
|
-
* @returns A `
|
|
12
|
+
* @returns A `StepWithContext` step.
|
|
13
13
|
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
14
14
|
* @throws `NoeticConfigError` with code `MISSING_CHILD_STEP` if `child` is not provided.
|
|
15
15
|
*/
|
|
16
|
-
export declare function
|
|
16
|
+
export declare function withContext<TContext = ContextData, I = unknown, O = unknown>(opts: {
|
|
17
17
|
id: string;
|
|
18
18
|
child: Step<TContext, I, O>;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* valid way to supply the layers. Exactly one of the two is required — the
|
|
22
|
-
* runtime enforces it, the same way `id` and `child` are enforced.
|
|
23
|
-
*/
|
|
24
|
-
context?: ContextConfig | ContextLayer[];
|
|
25
|
-
/** @deprecated Renamed to `context`. */
|
|
26
|
-
memory?: ContextConfig | ContextLayer[];
|
|
27
|
-
}): StepProvide<TContext, I, O>;
|
|
19
|
+
context: ContextConfig | ContextLayer[];
|
|
20
|
+
}): StepWithContext<TContext, I, O>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { NoeticConfigError } from '@noetic-tools/types';
|
|
2
2
|
import { getDefaultRegistrar } from '../types/step-registrar.js';
|
|
3
|
-
import { resolveContextOption } from './context-option.js';
|
|
4
3
|
/**
|
|
5
4
|
* Creates a provide step that attaches context layers to its child without creating an isolated context.
|
|
6
5
|
* Like React's Context.Provider — layers are available to all descendant steps.
|
|
@@ -10,35 +9,35 @@ import { resolveContextOption } from './context-option.js';
|
|
|
10
9
|
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
11
10
|
* @param opts.child - Step to execute with the provided layers.
|
|
12
11
|
* @param opts.context - Context layers to provide to descendant steps.
|
|
13
|
-
* @returns A `
|
|
12
|
+
* @returns A `StepWithContext` step.
|
|
14
13
|
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
15
14
|
* @throws `NoeticConfigError` with code `MISSING_CHILD_STEP` if `child` is not provided.
|
|
16
15
|
*/
|
|
17
|
-
export function
|
|
16
|
+
export function withContext(opts) {
|
|
18
17
|
if (!opts.id?.trim()) {
|
|
19
18
|
throw new NoeticConfigError({
|
|
20
19
|
code: 'EMPTY_STEP_ID',
|
|
21
|
-
message: '
|
|
22
|
-
hint: 'Pass a unique string as the id field, e.g.
|
|
20
|
+
message: 'withContext() requires a non-empty id.',
|
|
21
|
+
hint: 'Pass a unique string as the id field, e.g. withContext({ id: "my-provider", ... }).',
|
|
23
22
|
});
|
|
24
23
|
}
|
|
25
24
|
if (!opts.child) {
|
|
26
25
|
throw new NoeticConfigError({
|
|
27
26
|
code: 'MISSING_CHILD_STEP',
|
|
28
|
-
message: '
|
|
27
|
+
message: 'withContext() requires a child step.',
|
|
29
28
|
hint: 'Provide a child step to execute with the provided context layers.',
|
|
30
29
|
});
|
|
31
30
|
}
|
|
32
|
-
const layers =
|
|
31
|
+
const layers = opts.context;
|
|
33
32
|
if (!layers) {
|
|
34
33
|
throw new NoeticConfigError({
|
|
35
34
|
code: 'MISSING_CONTEXT_LAYERS',
|
|
36
|
-
message: '
|
|
37
|
-
hint: 'Pass context: [
|
|
35
|
+
message: 'withContext() requires context layers.',
|
|
36
|
+
hint: 'Pass context: [scratchpad()].',
|
|
38
37
|
});
|
|
39
38
|
}
|
|
40
39
|
const built = {
|
|
41
|
-
kind: '
|
|
40
|
+
kind: 'withContext',
|
|
42
41
|
id: opts.id,
|
|
43
42
|
child: opts.child,
|
|
44
43
|
context: layers,
|
|
@@ -4,8 +4,6 @@ interface SpawnOpts<TContext, I, O> {
|
|
|
4
4
|
id: string;
|
|
5
5
|
child: Step<TContext, I, O>;
|
|
6
6
|
context?: ContextConfig | ContextLayer[];
|
|
7
|
-
/** @deprecated Renamed to `context`. */
|
|
8
|
-
memory?: ContextConfig | ContextLayer[];
|
|
9
7
|
timeout?: number;
|
|
10
8
|
/**
|
|
11
9
|
* Optional per-step subprocess adapter override. The interpreter routes
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { NoeticConfigError } from '@noetic-tools/types';
|
|
2
2
|
import { getDefaultRegistrar } from '../types/step-registrar.js';
|
|
3
|
-
import { resolveContextOption } from './context-option.js';
|
|
4
3
|
//#endregion
|
|
5
4
|
//#region Public API
|
|
6
5
|
/**
|
|
@@ -38,12 +37,12 @@ export function spawn(opts) {
|
|
|
38
37
|
kind: 'spawn',
|
|
39
38
|
id: opts.id,
|
|
40
39
|
child: opts.child,
|
|
41
|
-
context:
|
|
40
|
+
context: opts.context,
|
|
42
41
|
timeout: opts.timeout,
|
|
43
42
|
subprocess: opts.subprocess,
|
|
44
43
|
};
|
|
45
44
|
getDefaultRegistrar().register(built);
|
|
46
|
-
// Ensure the child is addressable by id — builders for `
|
|
45
|
+
// Ensure the child is addressable by id — builders for `runCode`/`callModel`/`invokeTool`
|
|
47
46
|
// self-register, but a caller can construct a step literal and pass it as
|
|
48
47
|
// `child` without going through a builder.
|
|
49
48
|
getDefaultRegistrar().register(opts.child);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { ContextData } from '@noetic-tools/context';
|
|
2
|
-
import type { Context, Lazy, ModelParams, OutputCodec, RetryPolicy, ServerToolSpec,
|
|
3
|
-
|
|
4
|
-
export interface StepRunOpts<TContext, I, O> {
|
|
2
|
+
import type { Context, Lazy, ModelParams, OutputCodec, RetryPolicy, ServerToolSpec, StandardSchemaV1, StepCallModel, StepInvokeTool, StepRunCode, StepSubHarness, SubHarness, SubHarnessSessionPolicy, SubHarnessSettings, SubprocessAdapter, Tool } from '@noetic-tools/types';
|
|
3
|
+
export interface RunCodeOpts<TContext, I, O> {
|
|
5
4
|
id: string;
|
|
6
5
|
execute: (input: I, ctx: Context<TContext>) => Promise<O>;
|
|
7
6
|
retry?: RetryPolicy;
|
|
@@ -12,7 +11,7 @@ export interface StepRunOpts<TContext, I, O> {
|
|
|
12
11
|
*/
|
|
13
12
|
subprocess?: SubprocessAdapter;
|
|
14
13
|
}
|
|
15
|
-
export interface
|
|
14
|
+
export interface CallModelOpts<TContext, O> {
|
|
16
15
|
id: string;
|
|
17
16
|
/** Model id. Eager string or `(ctx) => string` getter (resolved at step execution). */
|
|
18
17
|
model: Lazy<string, TContext>;
|
|
@@ -24,14 +23,19 @@ export interface StepLLMOpts<TContext, O> {
|
|
|
24
23
|
* server tool the provider executes, e.g. web search/fetch).
|
|
25
24
|
*/
|
|
26
25
|
tools?: Lazy<(Tool | ServerToolSpec)[] | undefined, TContext>;
|
|
27
|
-
/** Structured output: a Zod
|
|
28
|
-
output?:
|
|
26
|
+
/** Structured output: a Standard Schema (Zod, Valibot, …) or a streaming `OutputCodec` (e.g. OpenUI Lang). */
|
|
27
|
+
output?: StandardSchemaV1<unknown, O> | OutputCodec<O>;
|
|
28
|
+
/**
|
|
29
|
+
* Explicit raw JSON Schema override sent to the model. For non-Zod schemas,
|
|
30
|
+
* it takes precedence over StandardJSONSchemaV1 conversion.
|
|
31
|
+
*/
|
|
32
|
+
outputJsonSchema?: Record<string, unknown>;
|
|
29
33
|
params?: ModelParams;
|
|
30
34
|
emit?: boolean | ((eventType: string, data: Record<string, unknown>) => boolean);
|
|
31
35
|
}
|
|
32
|
-
export interface
|
|
36
|
+
export interface InvokeToolOpts<I, O> {
|
|
33
37
|
id: string;
|
|
34
|
-
tool: Tool<
|
|
38
|
+
tool: Tool<StandardSchemaV1<unknown, I>, StandardSchemaV1<unknown, O>>;
|
|
35
39
|
args?: Partial<I>;
|
|
36
40
|
}
|
|
37
41
|
export interface StepSubHarnessOpts<TContext, O> {
|
|
@@ -44,58 +48,65 @@ export interface StepSubHarnessOpts<TContext, O> {
|
|
|
44
48
|
settings?: SubHarnessSettings;
|
|
45
49
|
/** System instructions applied on the first message of a fresh session. */
|
|
46
50
|
instructions?: Lazy<string | undefined, TContext>;
|
|
47
|
-
/** Optional
|
|
48
|
-
output?:
|
|
51
|
+
/** Optional Standard Schema; when set the assistant text is JSON-parsed and validated. */
|
|
52
|
+
output?: StandardSchemaV1<unknown, O>;
|
|
49
53
|
/** Session reuse + teardown policy across steps. */
|
|
50
54
|
session?: SubHarnessSessionPolicy;
|
|
51
55
|
emit?: boolean | ((eventType: string, data: Record<string, unknown>) => boolean);
|
|
52
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Creates a pure async computation step.
|
|
59
|
+
*
|
|
60
|
+
* @public
|
|
61
|
+
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
62
|
+
* @param opts.execute - Async function `(input, ctx) => output` that performs the work.
|
|
63
|
+
* @param opts.retry - Optional retry policy controlling attempts, backoff, and delay.
|
|
64
|
+
* @param opts.subprocess - Optional per-step subprocess adapter override.
|
|
65
|
+
* @returns A `StepRunCode` that can be composed into larger pipelines. The step
|
|
66
|
+
* is auto-registered in the shared step registry so the subprocess
|
|
67
|
+
* adapter can dispatch it by id.
|
|
68
|
+
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
69
|
+
* @throws `NoeticConfigError` with code `MISSING_EXECUTE_FUNCTION` if `execute` is not provided.
|
|
70
|
+
* @throws `NoeticConfigError` with code `DUPLICATE_STEP_ID` if another step with the same id is already registered with a different body.
|
|
71
|
+
*/
|
|
72
|
+
export declare function runCode<TContext = ContextData, I = unknown, O = unknown>(opts: RunCodeOpts<TContext, I, O>): StepRunCode<TContext, I, O>;
|
|
73
|
+
/**
|
|
74
|
+
* Creates a model call step with optional tools and structured output.
|
|
75
|
+
*
|
|
76
|
+
* @public
|
|
77
|
+
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
78
|
+
* @param opts.model - Model identifier, eager string or `(ctx) => string` getter (resolved at step execution time).
|
|
79
|
+
* @param opts.instructions - Optional system prompt; eager string or `(ctx) => string | undefined` getter.
|
|
80
|
+
* @param opts.tools - Optional tools; eager array or `(ctx) => Tool[] | undefined` getter.
|
|
81
|
+
* @param opts.output - Optional Zod schema enabling structured output parsing.
|
|
82
|
+
* @param opts.params - Optional model parameters (temperature, topP, maxTokens, stopSequences).
|
|
83
|
+
* @returns A `StepCallModel` that can be composed into larger pipelines. The step
|
|
84
|
+
* is auto-registered in the shared step registry.
|
|
85
|
+
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
86
|
+
* @throws `NoeticConfigError` with code `MISSING_MODEL` if an eager `model` string is empty. Function-form models are validated at step execution.
|
|
87
|
+
*/
|
|
88
|
+
export declare function callModel<TContext = ContextData, I = unknown, O = unknown>(opts: CallModelOpts<TContext, O>): StepCallModel<TContext, I, O>;
|
|
89
|
+
/**
|
|
90
|
+
* Creates a tool execution step that invokes a typed tool definition.
|
|
91
|
+
*
|
|
92
|
+
* @public
|
|
93
|
+
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
94
|
+
* @param opts.tool - The tool definition with typed input/output schemas.
|
|
95
|
+
* @param opts.args - Optional partial args that override or supplement model-provided arguments.
|
|
96
|
+
* @returns A `StepInvokeTool` that can be composed into larger pipelines. The step
|
|
97
|
+
* is auto-registered in the shared step registry.
|
|
98
|
+
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
99
|
+
* @throws `NoeticConfigError` with code `MISSING_TOOL` if `tool` is not provided.
|
|
100
|
+
*/
|
|
101
|
+
export declare function invokeTool<TContext = ContextData, I = unknown, O = unknown>(opts: InvokeToolOpts<I, O>): StepInvokeTool<TContext, I, O>;
|
|
102
|
+
/**
|
|
103
|
+
* The sub-harness step builder namespace. Unlike the flattened base builders
|
|
104
|
+
* (`runCode`, `callModel`, `invokeTool`), the coding-agent harness builders
|
|
105
|
+
* stay grouped under `step` — their `step.<harness>()` API is unchanged.
|
|
106
|
+
*
|
|
107
|
+
* @public
|
|
108
|
+
*/
|
|
53
109
|
export declare const step: {
|
|
54
|
-
/**
|
|
55
|
-
* Creates a pure async computation step.
|
|
56
|
-
*
|
|
57
|
-
* @public
|
|
58
|
-
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
59
|
-
* @param opts.execute - Async function `(input, ctx) => output` that performs the work.
|
|
60
|
-
* @param opts.retry - Optional retry policy controlling attempts, backoff, and delay.
|
|
61
|
-
* @param opts.subprocess - Optional per-step subprocess adapter override.
|
|
62
|
-
* @returns A `StepRun` that can be composed into larger pipelines. The step
|
|
63
|
-
* is auto-registered in the shared step registry so the subprocess
|
|
64
|
-
* adapter can dispatch it by id.
|
|
65
|
-
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
66
|
-
* @throws `NoeticConfigError` with code `MISSING_EXECUTE_FUNCTION` if `execute` is not provided.
|
|
67
|
-
* @throws `NoeticConfigError` with code `DUPLICATE_STEP_ID` if another step with the same id is already registered with a different body.
|
|
68
|
-
*/
|
|
69
|
-
run<TContext = ContextData, I = unknown, O = unknown>(opts: StepRunOpts<TContext, I, O>): StepRun<TContext, I, O>;
|
|
70
|
-
/**
|
|
71
|
-
* Creates an LLM model call step with optional tools and structured output.
|
|
72
|
-
*
|
|
73
|
-
* @public
|
|
74
|
-
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
75
|
-
* @param opts.model - Model identifier, eager string or `(ctx) => string` getter (resolved at step execution time).
|
|
76
|
-
* @param opts.instructions - Optional system prompt; eager string or `(ctx) => string | undefined` getter.
|
|
77
|
-
* @param opts.tools - Optional tools; eager array or `(ctx) => Tool[] | undefined` getter.
|
|
78
|
-
* @param opts.output - Optional Zod schema enabling structured output parsing.
|
|
79
|
-
* @param opts.params - Optional model parameters (temperature, topP, maxTokens, stopSequences).
|
|
80
|
-
* @returns A `StepLLM` that can be composed into larger pipelines. The step
|
|
81
|
-
* is auto-registered in the shared step registry.
|
|
82
|
-
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
83
|
-
* @throws `NoeticConfigError` with code `MISSING_MODEL` if an eager `model` string is empty. Function-form models are validated at step execution.
|
|
84
|
-
*/
|
|
85
|
-
llm<TContext = ContextData, I = unknown, O = unknown>(opts: StepLLMOpts<TContext, O>): StepLLM<TContext, I, O>;
|
|
86
|
-
/**
|
|
87
|
-
* Creates a tool execution step that invokes a typed tool definition.
|
|
88
|
-
*
|
|
89
|
-
* @public
|
|
90
|
-
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
91
|
-
* @param opts.tool - The tool definition with typed input/output schemas.
|
|
92
|
-
* @param opts.args - Optional partial args that override or supplement LLM-provided arguments.
|
|
93
|
-
* @returns A `StepTool` that can be composed into larger pipelines. The step
|
|
94
|
-
* is auto-registered in the shared step registry.
|
|
95
|
-
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
96
|
-
* @throws `NoeticConfigError` with code `MISSING_TOOL` if `tool` is not provided.
|
|
97
|
-
*/
|
|
98
|
-
tool<TContext = ContextData, I = unknown, O = unknown>(opts: StepToolOpts<I, O>): StepTool<TContext, I, O>;
|
|
99
110
|
/**
|
|
100
111
|
* Creates a step that delegates a turn to the Claude Code harness.
|
|
101
112
|
*
|
|
@@ -41,118 +41,125 @@ function buildSubHarnessStep(kind, builderName, opts) {
|
|
|
41
41
|
}
|
|
42
42
|
//#endregion
|
|
43
43
|
//#region Builders
|
|
44
|
+
/**
|
|
45
|
+
* Creates a pure async computation step.
|
|
46
|
+
*
|
|
47
|
+
* @public
|
|
48
|
+
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
49
|
+
* @param opts.execute - Async function `(input, ctx) => output` that performs the work.
|
|
50
|
+
* @param opts.retry - Optional retry policy controlling attempts, backoff, and delay.
|
|
51
|
+
* @param opts.subprocess - Optional per-step subprocess adapter override.
|
|
52
|
+
* @returns A `StepRunCode` that can be composed into larger pipelines. The step
|
|
53
|
+
* is auto-registered in the shared step registry so the subprocess
|
|
54
|
+
* adapter can dispatch it by id.
|
|
55
|
+
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
56
|
+
* @throws `NoeticConfigError` with code `MISSING_EXECUTE_FUNCTION` if `execute` is not provided.
|
|
57
|
+
* @throws `NoeticConfigError` with code `DUPLICATE_STEP_ID` if another step with the same id is already registered with a different body.
|
|
58
|
+
*/
|
|
59
|
+
export function runCode(opts) {
|
|
60
|
+
if (!opts.id || opts.id.trim() === '') {
|
|
61
|
+
throw new NoeticConfigError({
|
|
62
|
+
code: 'EMPTY_STEP_ID',
|
|
63
|
+
message: 'runCode() requires a non-empty id.',
|
|
64
|
+
hint: 'Pass a unique string as the id field, e.g. runCode({ id: "my-step", ... }).',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (!opts.execute) {
|
|
68
|
+
throw new NoeticConfigError({
|
|
69
|
+
code: 'MISSING_EXECUTE_FUNCTION',
|
|
70
|
+
message: 'runCode() requires an execute function.',
|
|
71
|
+
hint: 'Provide an async execute function, e.g. execute: async (input, ctx) => result.',
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const built = {
|
|
75
|
+
kind: 'runCode',
|
|
76
|
+
...opts,
|
|
77
|
+
};
|
|
78
|
+
getDefaultRegistrar().register(built);
|
|
79
|
+
return built;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Creates a model call step with optional tools and structured output.
|
|
83
|
+
*
|
|
84
|
+
* @public
|
|
85
|
+
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
86
|
+
* @param opts.model - Model identifier, eager string or `(ctx) => string` getter (resolved at step execution time).
|
|
87
|
+
* @param opts.instructions - Optional system prompt; eager string or `(ctx) => string | undefined` getter.
|
|
88
|
+
* @param opts.tools - Optional tools; eager array or `(ctx) => Tool[] | undefined` getter.
|
|
89
|
+
* @param opts.output - Optional Zod schema enabling structured output parsing.
|
|
90
|
+
* @param opts.params - Optional model parameters (temperature, topP, maxTokens, stopSequences).
|
|
91
|
+
* @returns A `StepCallModel` that can be composed into larger pipelines. The step
|
|
92
|
+
* is auto-registered in the shared step registry.
|
|
93
|
+
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
94
|
+
* @throws `NoeticConfigError` with code `MISSING_MODEL` if an eager `model` string is empty. Function-form models are validated at step execution.
|
|
95
|
+
*/
|
|
96
|
+
export function callModel(opts) {
|
|
97
|
+
if (!opts.id || opts.id.trim() === '') {
|
|
98
|
+
throw new NoeticConfigError({
|
|
99
|
+
code: 'EMPTY_STEP_ID',
|
|
100
|
+
message: 'callModel() requires a non-empty id.',
|
|
101
|
+
hint: 'Pass a unique string as the id field, e.g. callModel({ id: "my-llm", ... }).',
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// Only validate eager models here. Function-form models are validated
|
|
105
|
+
// post-resolution in executeCallModel so the same MISSING_MODEL error surfaces
|
|
106
|
+
// whether the caller passes a string or a getter.
|
|
107
|
+
if (typeof opts.model === 'string' && opts.model.trim() === '') {
|
|
108
|
+
throw new NoeticConfigError({
|
|
109
|
+
code: 'MISSING_MODEL',
|
|
110
|
+
message: 'callModel() requires a non-empty model.',
|
|
111
|
+
hint: "Pass a model identifier, e.g. model: 'anthropic/claude-sonnet-4-20250514'.",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const built = {
|
|
115
|
+
kind: 'callModel',
|
|
116
|
+
...opts,
|
|
117
|
+
};
|
|
118
|
+
getDefaultRegistrar().register(built);
|
|
119
|
+
return built;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Creates a tool execution step that invokes a typed tool definition.
|
|
123
|
+
*
|
|
124
|
+
* @public
|
|
125
|
+
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
126
|
+
* @param opts.tool - The tool definition with typed input/output schemas.
|
|
127
|
+
* @param opts.args - Optional partial args that override or supplement model-provided arguments.
|
|
128
|
+
* @returns A `StepInvokeTool` that can be composed into larger pipelines. The step
|
|
129
|
+
* is auto-registered in the shared step registry.
|
|
130
|
+
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
131
|
+
* @throws `NoeticConfigError` with code `MISSING_TOOL` if `tool` is not provided.
|
|
132
|
+
*/
|
|
133
|
+
export function invokeTool(opts) {
|
|
134
|
+
if (!opts.id || opts.id.trim() === '') {
|
|
135
|
+
throw new NoeticConfigError({
|
|
136
|
+
code: 'EMPTY_STEP_ID',
|
|
137
|
+
message: 'invokeTool() requires a non-empty id.',
|
|
138
|
+
hint: 'Pass a unique string as the id field, e.g. invokeTool({ id: "my-tool", ... }).',
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (!opts.tool) {
|
|
142
|
+
throw new NoeticConfigError({
|
|
143
|
+
code: 'MISSING_TOOL',
|
|
144
|
+
message: 'invokeTool() requires a tool.',
|
|
145
|
+
hint: 'Provide a tool definition created with the tool() builder.',
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
const built = {
|
|
149
|
+
kind: 'invokeTool',
|
|
150
|
+
...opts,
|
|
151
|
+
};
|
|
152
|
+
getDefaultRegistrar().register(built);
|
|
153
|
+
return built;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The sub-harness step builder namespace. Unlike the flattened base builders
|
|
157
|
+
* (`runCode`, `callModel`, `invokeTool`), the coding-agent harness builders
|
|
158
|
+
* stay grouped under `step` — their `step.<harness>()` API is unchanged.
|
|
159
|
+
*
|
|
160
|
+
* @public
|
|
161
|
+
*/
|
|
44
162
|
export const step = {
|
|
45
|
-
/**
|
|
46
|
-
* Creates a pure async computation step.
|
|
47
|
-
*
|
|
48
|
-
* @public
|
|
49
|
-
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
50
|
-
* @param opts.execute - Async function `(input, ctx) => output` that performs the work.
|
|
51
|
-
* @param opts.retry - Optional retry policy controlling attempts, backoff, and delay.
|
|
52
|
-
* @param opts.subprocess - Optional per-step subprocess adapter override.
|
|
53
|
-
* @returns A `StepRun` that can be composed into larger pipelines. The step
|
|
54
|
-
* is auto-registered in the shared step registry so the subprocess
|
|
55
|
-
* adapter can dispatch it by id.
|
|
56
|
-
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
57
|
-
* @throws `NoeticConfigError` with code `MISSING_EXECUTE_FUNCTION` if `execute` is not provided.
|
|
58
|
-
* @throws `NoeticConfigError` with code `DUPLICATE_STEP_ID` if another step with the same id is already registered with a different body.
|
|
59
|
-
*/
|
|
60
|
-
run(opts) {
|
|
61
|
-
if (!opts.id || opts.id.trim() === '') {
|
|
62
|
-
throw new NoeticConfigError({
|
|
63
|
-
code: 'EMPTY_STEP_ID',
|
|
64
|
-
message: 'step.run() requires a non-empty id.',
|
|
65
|
-
hint: 'Pass a unique string as the id field, e.g. step.run({ id: "my-step", ... }).',
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
if (!opts.execute) {
|
|
69
|
-
throw new NoeticConfigError({
|
|
70
|
-
code: 'MISSING_EXECUTE_FUNCTION',
|
|
71
|
-
message: 'step.run() requires an execute function.',
|
|
72
|
-
hint: 'Provide an async execute function, e.g. execute: async (input, ctx) => result.',
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
const built = {
|
|
76
|
-
kind: 'run',
|
|
77
|
-
...opts,
|
|
78
|
-
};
|
|
79
|
-
getDefaultRegistrar().register(built);
|
|
80
|
-
return built;
|
|
81
|
-
},
|
|
82
|
-
/**
|
|
83
|
-
* Creates an LLM model call step with optional tools and structured output.
|
|
84
|
-
*
|
|
85
|
-
* @public
|
|
86
|
-
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
87
|
-
* @param opts.model - Model identifier, eager string or `(ctx) => string` getter (resolved at step execution time).
|
|
88
|
-
* @param opts.instructions - Optional system prompt; eager string or `(ctx) => string | undefined` getter.
|
|
89
|
-
* @param opts.tools - Optional tools; eager array or `(ctx) => Tool[] | undefined` getter.
|
|
90
|
-
* @param opts.output - Optional Zod schema enabling structured output parsing.
|
|
91
|
-
* @param opts.params - Optional model parameters (temperature, topP, maxTokens, stopSequences).
|
|
92
|
-
* @returns A `StepLLM` that can be composed into larger pipelines. The step
|
|
93
|
-
* is auto-registered in the shared step registry.
|
|
94
|
-
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
95
|
-
* @throws `NoeticConfigError` with code `MISSING_MODEL` if an eager `model` string is empty. Function-form models are validated at step execution.
|
|
96
|
-
*/
|
|
97
|
-
llm(opts) {
|
|
98
|
-
if (!opts.id || opts.id.trim() === '') {
|
|
99
|
-
throw new NoeticConfigError({
|
|
100
|
-
code: 'EMPTY_STEP_ID',
|
|
101
|
-
message: 'step.llm() requires a non-empty id.',
|
|
102
|
-
hint: 'Pass a unique string as the id field, e.g. step.llm({ id: "my-llm", ... }).',
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
// Only validate eager models here. Function-form models are validated
|
|
106
|
-
// post-resolution in executeLLM so the same MISSING_MODEL error surfaces
|
|
107
|
-
// whether the caller passes a string or a getter.
|
|
108
|
-
if (typeof opts.model === 'string' && opts.model.trim() === '') {
|
|
109
|
-
throw new NoeticConfigError({
|
|
110
|
-
code: 'MISSING_MODEL',
|
|
111
|
-
message: 'step.llm() requires a non-empty model.',
|
|
112
|
-
hint: "Pass a model identifier, e.g. model: 'anthropic/claude-sonnet-4-20250514'.",
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
const built = {
|
|
116
|
-
kind: 'llm',
|
|
117
|
-
...opts,
|
|
118
|
-
};
|
|
119
|
-
getDefaultRegistrar().register(built);
|
|
120
|
-
return built;
|
|
121
|
-
},
|
|
122
|
-
/**
|
|
123
|
-
* Creates a tool execution step that invokes a typed tool definition.
|
|
124
|
-
*
|
|
125
|
-
* @public
|
|
126
|
-
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
127
|
-
* @param opts.tool - The tool definition with typed input/output schemas.
|
|
128
|
-
* @param opts.args - Optional partial args that override or supplement LLM-provided arguments.
|
|
129
|
-
* @returns A `StepTool` that can be composed into larger pipelines. The step
|
|
130
|
-
* is auto-registered in the shared step registry.
|
|
131
|
-
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
132
|
-
* @throws `NoeticConfigError` with code `MISSING_TOOL` if `tool` is not provided.
|
|
133
|
-
*/
|
|
134
|
-
tool(opts) {
|
|
135
|
-
if (!opts.id || opts.id.trim() === '') {
|
|
136
|
-
throw new NoeticConfigError({
|
|
137
|
-
code: 'EMPTY_STEP_ID',
|
|
138
|
-
message: 'step.tool() requires a non-empty id.',
|
|
139
|
-
hint: 'Pass a unique string as the id field, e.g. step.tool({ id: "my-tool", ... }).',
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
if (!opts.tool) {
|
|
143
|
-
throw new NoeticConfigError({
|
|
144
|
-
code: 'MISSING_TOOL',
|
|
145
|
-
message: 'step.tool() requires a tool.',
|
|
146
|
-
hint: 'Provide a tool definition created with the tool() builder.',
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
const built = {
|
|
150
|
-
kind: 'tool',
|
|
151
|
-
...opts,
|
|
152
|
-
};
|
|
153
|
-
getDefaultRegistrar().register(built);
|
|
154
|
-
return built;
|
|
155
|
-
},
|
|
156
163
|
/**
|
|
157
164
|
* Creates a step that delegates a turn to the Claude Code harness.
|
|
158
165
|
*
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { FunctionCallItem, FunctionCallOutputItem, Item, ItemSchemaExtensions, Tool, ToolContextDeclaration, ToolExecutionContext, ToolResultExtensionItem, ToolUiDeclaration } from '@noetic-tools/types';
|
|
2
|
-
|
|
3
|
-
interface ToolConfig<I extends ZodTypeAny, O extends ZodTypeAny> {
|
|
1
|
+
import type { FunctionCallItem, FunctionCallOutputItem, InferSchemaOutput, InputSchemaConfig, Item, ItemSchemaExtensions, StandardSchemaV1, Tool, ToolContextDeclaration, ToolExecutionContext, ToolResultExtensionItem, ToolUiDeclaration } from '@noetic-tools/types';
|
|
2
|
+
type ToolConfig<I extends StandardSchemaV1, O extends StandardSchemaV1> = {
|
|
4
3
|
name: string;
|
|
5
4
|
description: string;
|
|
6
5
|
input: I;
|
|
@@ -9,21 +8,19 @@ interface ToolConfig<I extends ZodTypeAny, O extends ZodTypeAny> {
|
|
|
9
8
|
decorateResultItem?: (params: {
|
|
10
9
|
baseItem: FunctionCallOutputItem;
|
|
11
10
|
callItem: FunctionCallItem;
|
|
12
|
-
args:
|
|
13
|
-
result:
|
|
11
|
+
args: InferSchemaOutput<I>;
|
|
12
|
+
result: InferSchemaOutput<O> | undefined;
|
|
14
13
|
output: string;
|
|
15
14
|
error?: boolean;
|
|
16
15
|
}) => Item | ToolResultExtensionItem;
|
|
17
|
-
execute: (args:
|
|
16
|
+
execute: (args: InferSchemaOutput<I>, toolCtx: ToolExecutionContext) => Promise<InferSchemaOutput<O>>;
|
|
18
17
|
needsApproval?: boolean;
|
|
19
|
-
/** Optional context declaration — the runtime generates a ContextLayer from this via
|
|
18
|
+
/** Optional context declaration — the runtime generates a ContextLayer from this via toolCalls(). */
|
|
20
19
|
context?: ToolContextDeclaration;
|
|
21
|
-
/** @deprecated Renamed to `context`. */
|
|
22
|
-
memory?: ToolContextDeclaration;
|
|
23
20
|
/** Optional UI declaration — the runtime emits the rendered fragments at call/progress/result points. */
|
|
24
21
|
ui?: ToolUiDeclaration<I, O>;
|
|
25
|
-
}
|
|
26
|
-
|
|
22
|
+
} & InputSchemaConfig<I>;
|
|
23
|
+
type GeneratorToolConfig<I extends StandardSchemaV1, E extends StandardSchemaV1, O extends StandardSchemaV1> = {
|
|
27
24
|
name: string;
|
|
28
25
|
description: string;
|
|
29
26
|
input: I;
|
|
@@ -33,30 +30,29 @@ interface GeneratorToolConfig<I extends ZodTypeAny, E extends ZodTypeAny, O exte
|
|
|
33
30
|
decorateResultItem?: (params: {
|
|
34
31
|
baseItem: FunctionCallOutputItem;
|
|
35
32
|
callItem: FunctionCallItem;
|
|
36
|
-
args:
|
|
37
|
-
result:
|
|
33
|
+
args: InferSchemaOutput<I>;
|
|
34
|
+
result: InferSchemaOutput<O> | undefined;
|
|
38
35
|
output: string;
|
|
39
36
|
error?: boolean;
|
|
40
37
|
}) => Item | ToolResultExtensionItem;
|
|
41
|
-
execute: (args:
|
|
38
|
+
execute: (args: InferSchemaOutput<I>, toolCtx: ToolExecutionContext) => AsyncGenerator<InferSchemaOutput<E>, InferSchemaOutput<O>>;
|
|
42
39
|
needsApproval?: boolean;
|
|
43
|
-
/** Optional context declaration — the runtime generates a ContextLayer from this via
|
|
40
|
+
/** Optional context declaration — the runtime generates a ContextLayer from this via toolCalls(). */
|
|
44
41
|
context?: ToolContextDeclaration;
|
|
45
|
-
/** @deprecated Renamed to `context`. */
|
|
46
|
-
memory?: ToolContextDeclaration;
|
|
47
42
|
/** Optional UI declaration — the runtime emits the rendered fragments at call/progress/result points. */
|
|
48
|
-
ui?: ToolUiDeclaration<I, O,
|
|
49
|
-
}
|
|
43
|
+
ui?: ToolUiDeclaration<I, O, InferSchemaOutput<E>>;
|
|
44
|
+
} & InputSchemaConfig<I>;
|
|
50
45
|
/**
|
|
51
|
-
* Creates a typed Tool with
|
|
46
|
+
* Creates a typed Tool with Standard Schema inference for input and output.
|
|
47
|
+
* Accepts Zod, Valibot, or any Standard Schema v1 implementation.
|
|
52
48
|
*
|
|
53
49
|
* @public
|
|
54
50
|
*/
|
|
55
|
-
export declare function tool<I extends
|
|
51
|
+
export declare function tool<I extends StandardSchemaV1, O extends StandardSchemaV1>(config: ToolConfig<I, O>): Tool<I, O>;
|
|
56
52
|
/**
|
|
57
53
|
* Creates a typed Tool that can stream progress events before returning a final output.
|
|
58
54
|
*
|
|
59
55
|
* @public
|
|
60
56
|
*/
|
|
61
|
-
export declare function toolWithGenerator<I extends
|
|
57
|
+
export declare function toolWithGenerator<I extends StandardSchemaV1, E extends StandardSchemaV1, O extends StandardSchemaV1>(config: GeneratorToolConfig<I, E, O>): Tool<I, O>;
|
|
62
58
|
export {};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { NoeticConfigError } from '@noetic-tools/types';
|
|
2
|
-
import { resolveContextOption } from './context-option.js';
|
|
3
2
|
//#endregion
|
|
4
3
|
//#region Helpers
|
|
5
4
|
function validateToolConfig(name, execute) {
|
|
@@ -21,7 +20,8 @@ function validateToolConfig(name, execute) {
|
|
|
21
20
|
//#endregion
|
|
22
21
|
//#region Public API
|
|
23
22
|
/**
|
|
24
|
-
* Creates a typed Tool with
|
|
23
|
+
* Creates a typed Tool with Standard Schema inference for input and output.
|
|
24
|
+
* Accepts Zod, Valibot, or any Standard Schema v1 implementation.
|
|
25
25
|
*
|
|
26
26
|
* @public
|
|
27
27
|
*/
|
|
@@ -32,11 +32,12 @@ export function tool(config) {
|
|
|
32
32
|
description: config.description,
|
|
33
33
|
input: config.input,
|
|
34
34
|
output: config.output,
|
|
35
|
+
inputJsonSchema: config.inputJsonSchema,
|
|
35
36
|
itemSchemas: config.itemSchemas,
|
|
36
37
|
decorateResultItem: config.decorateResultItem,
|
|
37
38
|
execute: config.execute,
|
|
38
39
|
needsApproval: config.needsApproval,
|
|
39
|
-
context:
|
|
40
|
+
context: config.context,
|
|
40
41
|
ui: config.ui,
|
|
41
42
|
};
|
|
42
43
|
}
|
|
@@ -53,11 +54,12 @@ export function toolWithGenerator(config) {
|
|
|
53
54
|
input: config.input,
|
|
54
55
|
event: config.event,
|
|
55
56
|
output: config.output,
|
|
57
|
+
inputJsonSchema: config.inputJsonSchema,
|
|
56
58
|
itemSchemas: config.itemSchemas,
|
|
57
59
|
decorateResultItem: config.decorateResultItem,
|
|
58
60
|
execute: config.execute,
|
|
59
61
|
needsApproval: config.needsApproval,
|
|
60
|
-
context:
|
|
62
|
+
context: config.context,
|
|
61
63
|
ui: config.ui,
|
|
62
64
|
};
|
|
63
65
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Converts a validated `WorkflowDocument` into a live `Step` tree.
|
|
3
3
|
*
|
|
4
|
-
* Each node kind maps to the corresponding builder (`
|
|
4
|
+
* Each node kind maps to the corresponding builder (`callModel`, `inParallel`,
|
|
5
5
|
* `loop`, etc.) so hydrated steps are indistinguishable from programmatic
|
|
6
6
|
* ones — they register in the step registry, carry retry policies, etc.
|
|
7
7
|
*/
|
|
@@ -16,14 +16,14 @@ export interface HydrationContext {
|
|
|
16
16
|
/** SubHarness adapters keyed by harness id, resolving `claude-code`/`codex`/… nodes. */
|
|
17
17
|
subHarnesses?: ReadonlyMap<SubHarnessKind, SubHarness>;
|
|
18
18
|
/**
|
|
19
|
-
* Output codecs keyed by the `library` ref
|
|
19
|
+
* Output codecs keyed by the `library` ref a `callModel` node's `output` codec
|
|
20
20
|
* reference names — the live codec built from a component library, e.g.
|
|
21
21
|
* `new Map([['dashboard-lib', openUi(dashboardLibrary)]])` from
|
|
22
22
|
* `@noetic-tools/openui`. Resolved the same way sub-harness adapters are.
|
|
23
23
|
*/
|
|
24
24
|
uiLibraries?: ReadonlyMap<string, OutputCodec>;
|
|
25
25
|
/**
|
|
26
|
-
* Resolves a named subprocess adapter ref declared on a `
|
|
26
|
+
* Resolves a named subprocess adapter ref declared on a `runCode` node's
|
|
27
27
|
* `subprocess` field. When a node omits the ref, the step falls back to
|
|
28
28
|
* `ctx.subprocess` at execution time.
|
|
29
29
|
*/
|