@noetic-tools/core 0.0.1 → 0.1.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.
- package/README.md +31 -11
- package/dist/adapters/in-memory-fs-adapter.d.ts +1 -1
- package/dist/adapters/in-memory-fs-adapter.js +1 -1
- package/dist/adapters/in-memory-shell-adapter.d.ts +1 -1
- package/dist/adapters/in-memory-subprocess/manifest-persistence.d.ts +8 -0
- package/dist/adapters/in-memory-subprocess/manifest-persistence.js +56 -0
- package/dist/adapters/in-memory-subprocess/metadata.d.ts +12 -0
- package/dist/adapters/in-memory-subprocess/metadata.js +58 -0
- package/dist/adapters/in-memory-subprocess/step-completion.d.ts +3 -0
- package/dist/adapters/in-memory-subprocess/step-completion.js +86 -0
- package/dist/adapters/in-memory-subprocess/types.d.ts +88 -0
- package/dist/adapters/in-memory-subprocess/types.js +2 -0
- package/dist/adapters/in-memory-subprocess-adapter.d.ts +12 -4
- package/dist/adapters/in-memory-subprocess-adapter.js +164 -55
- package/dist/adapters/openrouter.d.ts +16 -7
- package/dist/adapters/openrouter.js +68 -7
- package/dist/builders/channel-builder.d.ts +1 -1
- package/dist/builders/control-flow-builders.d.ts +3 -3
- package/dist/builders/control-flow-builders.js +9 -4
- package/dist/builders/every.d.ts +3 -3
- package/dist/builders/every.js +5 -2
- package/dist/builders/layer-provides-builders.d.ts +1 -32
- package/dist/builders/layer-provides-builders.js +1 -33
- package/dist/builders/loop-builder.d.ts +2 -2
- package/dist/builders/loop-builder.js +5 -2
- package/dist/builders/memory-builder.d.ts +1 -1
- package/dist/builders/memory-builder.js +1 -1
- package/dist/builders/provide-builder.d.ts +2 -2
- package/dist/builders/provide-builder.js +5 -2
- package/dist/builders/spawn-builder.d.ts +22 -9
- package/dist/builders/spawn-builder.js +17 -3
- package/dist/builders/step-builders.d.ts +51 -30
- package/dist/builders/step-builders.js +31 -12
- package/dist/builders/tool-builder.d.ts +7 -3
- package/dist/builders/tool-builder.js +3 -1
- package/dist/builders/workflow-hydrator.d.ts +38 -0
- package/dist/builders/workflow-hydrator.js +336 -0
- package/dist/conditions/conditions.d.ts +4 -4
- package/dist/conditions/conditions.js +2 -2
- package/dist/errors/noetic-error.d.ts +1 -1
- package/dist/errors/noetic-error.js +2 -0
- package/dist/{runtime → harness}/agent-harness.d.ts +65 -45
- package/dist/harness/agent-harness.js +576 -0
- package/dist/harness/deps/adapters.d.ts +4 -0
- package/dist/harness/deps/adapters.js +4 -0
- package/dist/harness/deps/interpreter.d.ts +5 -0
- package/dist/harness/deps/interpreter.js +4 -0
- package/dist/harness/deps/memory.d.ts +5 -0
- package/dist/harness/deps/memory.js +4 -0
- package/dist/harness/deps/runtime.d.ts +10 -0
- package/dist/harness/deps/runtime.js +7 -0
- package/dist/harness/deps/types.d.ts +17 -0
- package/dist/harness/deps/types.js +1 -0
- package/dist/harness/model-call.d.ts +50 -0
- package/dist/harness/model-call.js +694 -0
- package/dist/harness/model-schema.d.ts +19 -0
- package/dist/harness/model-schema.js +46 -0
- package/dist/harness/step-bootstrap.d.ts +25 -0
- package/dist/harness/step-bootstrap.js +170 -0
- package/dist/index.d.ts +114 -76
- package/dist/index.js +74 -50
- package/dist/internal-test.d.ts +4 -4
- package/dist/internal-test.js +4 -4
- package/dist/interpreter/action-deps.d.ts +12 -0
- package/dist/interpreter/action-deps.js +10 -0
- package/dist/interpreter/action-types.d.ts +8 -0
- package/dist/interpreter/action-types.js +1 -0
- package/dist/interpreter/collect-tools.d.ts +2 -2
- package/dist/interpreter/collect-tools.js +6 -2
- package/dist/interpreter/execute-action.d.ts +22 -0
- package/dist/interpreter/execute-action.js +527 -0
- package/dist/interpreter/{execute-every.d.ts → execute-control.d.ts} +8 -2
- package/dist/interpreter/execute-control.js +530 -0
- package/dist/interpreter/execute.d.ts +16 -3
- package/dist/interpreter/execute.js +154 -51
- package/dist/interpreter/message-helpers.d.ts +1 -9
- package/dist/interpreter/message-helpers.js +1 -42
- package/dist/interpreter/step-dispatcher.d.ts +61 -0
- package/dist/interpreter/step-dispatcher.js +67 -0
- package/dist/interpreter/typeguards.d.ts +8 -15
- package/dist/interpreter/typeguards.js +4 -21
- package/dist/memory/budget.d.ts +2 -2
- package/dist/memory/budget.js +1 -1
- package/dist/{runtime → memory}/exec-context-factory.d.ts +2 -2
- package/dist/{runtime → memory}/exec-context-factory.js +1 -1
- package/dist/memory/flow-schema.d.ts +52 -0
- package/dist/memory/flow-schema.js +102 -0
- package/dist/memory/function-call-utils.d.ts +1 -1
- package/dist/memory/function-call-utils.js +4 -2
- package/dist/memory/layer-api.d.ts +4 -4
- package/dist/memory/layer-api.js +2 -2
- package/dist/memory/layer-lifecycle.d.ts +6 -6
- package/dist/memory/layer-lifecycle.js +6 -6
- package/dist/memory/layer-provides.d.ts +32 -0
- package/dist/memory/layer-provides.js +33 -0
- package/dist/memory/layer-usage.d.ts +4 -3
- package/dist/memory/layer-usage.js +9 -3
- package/dist/memory/layers/durable-task-state.d.ts +8 -8
- package/dist/memory/layers/durable-task-state.js +2 -2
- package/dist/memory/layers/file-reference.d.ts +1 -1
- package/dist/memory/layers/file-reference.js +303 -247
- package/dist/memory/layers/history-window.d.ts +1 -1
- package/dist/memory/layers/history-window.js +4 -4
- package/dist/memory/layers/observational-memory.d.ts +5 -5
- package/dist/memory/layers/observational-memory.js +2 -3
- package/dist/memory/layers/plan.d.ts +2 -2
- package/dist/memory/layers/plan.js +15 -10
- package/dist/memory/layers/static-content.d.ts +2 -2
- package/dist/memory/layers/static-content.js +1 -1
- package/dist/memory/layers/steering.d.ts +7 -7
- package/dist/memory/layers/steering.js +5 -5
- package/dist/memory/layers/tool-memory-layer.d.ts +2 -2
- package/dist/memory/layers/tool-memory-layer.js +1 -1
- package/dist/memory/layers/working-memory.d.ts +7 -7
- package/dist/memory/layers/working-memory.js +4 -4
- package/dist/memory/projector.d.ts +2 -2
- package/dist/memory/scope.d.ts +1 -1
- package/dist/memory/strip-unresolved.d.ts +1 -1
- package/dist/observability/span-impl.d.ts +1 -1
- package/dist/observability/trace-exporter.d.ts +2 -2
- package/dist/observability/trace-exporter.js +1 -1
- package/dist/patterns/dynamic-workflow.d.ts +55 -0
- package/dist/patterns/dynamic-workflow.js +194 -0
- package/dist/patterns/flow.d.ts +2 -52
- package/dist/patterns/flow.js +1 -103
- package/dist/patterns/interview.d.ts +2 -2
- package/dist/patterns/interview.js +5 -5
- package/dist/patterns/plans.d.ts +6 -6
- package/dist/patterns/plans.js +4 -4
- package/dist/patterns/ralph-wiggum.d.ts +4 -4
- package/dist/patterns/ralph-wiggum.js +5 -5
- package/dist/patterns/react.d.ts +3 -3
- package/dist/patterns/react.js +5 -5
- package/dist/portable/adapters.d.ts +6 -0
- package/dist/portable/adapters.js +6 -0
- package/dist/portable/ask-user.d.ts +4 -0
- package/dist/portable/ask-user.js +2 -0
- package/dist/portable/builders.d.ts +12 -0
- package/dist/portable/builders.js +12 -0
- package/dist/portable/memory-layers.d.ts +12 -0
- package/dist/portable/memory-layers.js +12 -0
- package/dist/portable/runtime.d.ts +4 -0
- package/dist/portable/runtime.js +4 -0
- package/dist/portable/until.d.ts +4 -0
- package/dist/portable/until.js +4 -0
- package/dist/portable.d.ts +8 -26
- package/dist/portable.js +8 -34
- package/dist/runtime/broadcaster-utils.d.ts +7 -3
- package/dist/runtime/broadcaster-utils.js +11 -6
- package/dist/runtime/channel-store.d.ts +1 -1
- package/dist/runtime/channel-store.js +2 -2
- package/dist/runtime/context-deps.d.ts +4 -0
- package/dist/runtime/context-deps.js +2 -0
- package/dist/runtime/context-impl.d.ts +42 -12
- package/dist/runtime/context-impl.js +52 -5
- package/dist/runtime/context-type-deps.d.ts +14 -0
- package/dist/runtime/context-type-deps.js +1 -0
- package/dist/runtime/cwd-helpers.d.ts +1 -1
- package/dist/runtime/detached-handle.d.ts +52 -4
- package/dist/runtime/detached-handle.js +218 -14
- package/dist/runtime/durable/checkpoint-store.d.ts +38 -0
- package/dist/runtime/durable/checkpoint-store.js +101 -0
- package/dist/runtime/durable/detached-signal.d.ts +37 -0
- package/dist/runtime/durable/detached-signal.js +52 -0
- package/dist/runtime/durable/harness-checkpoints.d.ts +51 -0
- package/dist/runtime/durable/harness-checkpoints.js +104 -0
- package/dist/runtime/durable/index.d.ts +10 -0
- package/dist/runtime/durable/index.js +5 -0
- package/dist/runtime/durable/runnable-loop.d.ts +100 -0
- package/dist/runtime/durable/runnable-loop.js +90 -0
- package/dist/runtime/durable/session-seed.d.ts +28 -0
- package/dist/runtime/durable/session-seed.js +27 -0
- package/dist/runtime/durable/stall-nudge.d.ts +82 -0
- package/dist/runtime/durable/stall-nudge.js +87 -0
- package/dist/runtime/event-broadcaster.d.ts +1 -1
- package/dist/runtime/in-memory-storage.d.ts +1 -1
- package/dist/runtime/in-memory-storage.js +1 -1
- package/dist/runtime/item-log-impl.d.ts +3 -3
- package/dist/runtime/item-log-impl.js +1 -1
- package/dist/runtime/message-queue.d.ts +2 -2
- package/dist/runtime/session-runner.d.ts +7 -7
- package/dist/runtime/session-runner.js +3 -3
- package/dist/runtime/session-streams.d.ts +3 -3
- package/dist/runtime/session-streams.js +1 -1
- package/dist/runtime/step-registry.d.ts +42 -0
- package/dist/runtime/step-registry.js +77 -0
- package/dist/runtime/tool-memory.d.ts +3 -3
- package/dist/schemas/item.d.ts +1 -1
- package/dist/schemas/workflow.d.ts +139 -0
- package/dist/schemas/workflow.js +232 -0
- package/dist/types/ask-user-types.d.ts +57 -0
- package/dist/types/ask-user-types.js +74 -0
- package/dist/types/checkpoint.d.ts +98 -0
- package/dist/types/checkpoint.js +81 -0
- package/dist/types/common.d.ts +1 -50
- package/dist/types/context-parts/item-log.d.ts +6 -0
- package/dist/types/context-parts/item-log.js +1 -0
- package/dist/types/context-parts/layer-usage.d.ts +18 -0
- package/dist/types/context-parts/layer-usage.js +1 -0
- package/dist/types/context.d.ts +140 -31
- package/dist/types/error.d.ts +15 -0
- package/dist/types/harness-result.d.ts +2 -2
- package/dist/types/items.d.ts +18 -2
- package/dist/types/memory-context.d.ts +39 -0
- package/dist/types/memory-context.js +1 -0
- package/dist/types/memory.d.ts +38 -68
- package/dist/types/mutable-context.d.ts +3 -3
- package/dist/types/runtime.d.ts +14 -13
- package/dist/types/steering.d.ts +2 -2
- package/dist/types/step-registrar.d.ts +46 -0
- package/dist/types/step-registrar.js +56 -0
- package/dist/types/step.d.ts +34 -9
- package/dist/types/subprocess-adapter.d.ts +119 -3
- package/dist/types/subprocess-adapter.js +2 -0
- package/dist/types/tool-context.d.ts +6 -6
- package/dist/types/tool.d.ts +64 -0
- package/dist/types/tool.js +1 -0
- package/dist/unstable.d.ts +9 -9
- package/dist/unstable.js +7 -7
- package/dist/until/combinators.d.ts +1 -1
- package/dist/until/never.d.ts +1 -1
- package/dist/until/predicates.d.ts +13 -4
- package/dist/until/predicates.js +16 -2
- package/dist/util/message-helpers.d.ts +17 -0
- package/dist/util/message-helpers.js +64 -0
- package/package.json +6 -4
- package/dist/adapters/local-fs-adapter.d.ts +0 -3
- package/dist/adapters/local-fs-adapter.js +0 -43
- package/dist/adapters/local-shell-adapter.d.ts +0 -51
- package/dist/adapters/local-shell-adapter.js +0 -167
- package/dist/adapters/local-subprocess-adapter.d.ts +0 -16
- package/dist/adapters/local-subprocess-adapter.js +0 -187
- package/dist/conditions/index.d.ts +0 -3
- package/dist/conditions/index.js +0 -2
- package/dist/interpreter/execute-branch.d.ts +0 -3
- package/dist/interpreter/execute-branch.js +0 -10
- package/dist/interpreter/execute-every.js +0 -143
- package/dist/interpreter/execute-fork.d.ts +0 -3
- package/dist/interpreter/execute-fork.js +0 -215
- package/dist/interpreter/execute-llm.d.ts +0 -4
- package/dist/interpreter/execute-llm.js +0 -217
- package/dist/interpreter/execute-loop.d.ts +0 -3
- package/dist/interpreter/execute-loop.js +0 -171
- package/dist/interpreter/execute-provide.d.ts +0 -10
- package/dist/interpreter/execute-provide.js +0 -64
- package/dist/interpreter/execute-run.d.ts +0 -3
- package/dist/interpreter/execute-run.js +0 -39
- package/dist/interpreter/execute-spawn.d.ts +0 -11
- package/dist/interpreter/execute-spawn.js +0 -113
- package/dist/interpreter/execute-tool.d.ts +0 -5
- package/dist/interpreter/execute-tool.js +0 -81
- package/dist/runtime/agent-harness.js +0 -1170
- /package/dist/{interpreter → util}/framework-cast.d.ts +0 -0
- /package/dist/{interpreter → util}/framework-cast.js +0 -0
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { NoeticConfigError } from '../errors/noetic-config-error';
|
|
1
|
+
import { NoeticConfigError } from '../errors/noetic-config-error.js';
|
|
2
|
+
import { getDefaultRegistrar } from '../types/step-registrar.js';
|
|
3
|
+
//#endregion
|
|
4
|
+
//#region Builders
|
|
2
5
|
export const step = {
|
|
3
6
|
/**
|
|
4
7
|
* Creates a pure async computation step.
|
|
@@ -7,9 +10,13 @@ export const step = {
|
|
|
7
10
|
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
8
11
|
* @param opts.execute - Async function `(input, ctx) => output` that performs the work.
|
|
9
12
|
* @param opts.retry - Optional retry policy controlling attempts, backoff, and delay.
|
|
10
|
-
* @
|
|
13
|
+
* @param opts.subprocess - Optional per-step subprocess adapter override.
|
|
14
|
+
* @returns A `StepRun` that can be composed into larger pipelines. The step
|
|
15
|
+
* is auto-registered in the shared step registry so the subprocess
|
|
16
|
+
* adapter can dispatch it by id.
|
|
11
17
|
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
12
18
|
* @throws `NoeticConfigError` with code `MISSING_EXECUTE_FUNCTION` if `execute` is not provided.
|
|
19
|
+
* @throws `NoeticConfigError` with code `DUPLICATE_STEP_ID` if another step with the same id is already registered with a different body.
|
|
13
20
|
*/
|
|
14
21
|
run(opts) {
|
|
15
22
|
if (!opts.id || opts.id.trim() === '') {
|
|
@@ -26,24 +33,27 @@ export const step = {
|
|
|
26
33
|
hint: 'Provide an async execute function, e.g. execute: async (input, ctx) => result.',
|
|
27
34
|
});
|
|
28
35
|
}
|
|
29
|
-
|
|
36
|
+
const built = {
|
|
30
37
|
kind: 'run',
|
|
31
38
|
...opts,
|
|
32
39
|
};
|
|
40
|
+
getDefaultRegistrar().register(built);
|
|
41
|
+
return built;
|
|
33
42
|
},
|
|
34
43
|
/**
|
|
35
44
|
* Creates an LLM model call step with optional tools and structured output.
|
|
36
45
|
*
|
|
37
46
|
* @public
|
|
38
47
|
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
39
|
-
* @param opts.model - Model identifier string (
|
|
40
|
-
* @param opts.instructions - Optional system prompt
|
|
41
|
-
* @param opts.tools - Optional tools
|
|
48
|
+
* @param opts.model - Model identifier, eager string or `(ctx) => string` getter (resolved at step execution time).
|
|
49
|
+
* @param opts.instructions - Optional system prompt; eager string or `(ctx) => string | undefined` getter.
|
|
50
|
+
* @param opts.tools - Optional tools; eager array or `(ctx) => Tool[] | undefined` getter.
|
|
42
51
|
* @param opts.output - Optional Zod schema enabling structured output parsing.
|
|
43
52
|
* @param opts.params - Optional model parameters (temperature, topP, maxTokens, stopSequences).
|
|
44
|
-
* @returns A `StepLLM` that can be composed into larger pipelines.
|
|
53
|
+
* @returns A `StepLLM` that can be composed into larger pipelines. The step
|
|
54
|
+
* is auto-registered in the shared step registry.
|
|
45
55
|
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
46
|
-
* @throws `NoeticConfigError` with code `MISSING_MODEL` if `model` is empty.
|
|
56
|
+
* @throws `NoeticConfigError` with code `MISSING_MODEL` if an eager `model` string is empty. Function-form models are validated at step execution.
|
|
47
57
|
*/
|
|
48
58
|
llm(opts) {
|
|
49
59
|
if (!opts.id || opts.id.trim() === '') {
|
|
@@ -53,17 +63,22 @@ export const step = {
|
|
|
53
63
|
hint: 'Pass a unique string as the id field, e.g. step.llm({ id: "my-llm", ... }).',
|
|
54
64
|
});
|
|
55
65
|
}
|
|
56
|
-
|
|
66
|
+
// Only validate eager models here. Function-form models are validated
|
|
67
|
+
// post-resolution in executeLLM so the same MISSING_MODEL error surfaces
|
|
68
|
+
// whether the caller passes a string or a getter.
|
|
69
|
+
if (typeof opts.model === 'string' && opts.model.trim() === '') {
|
|
57
70
|
throw new NoeticConfigError({
|
|
58
71
|
code: 'MISSING_MODEL',
|
|
59
72
|
message: 'step.llm() requires a non-empty model.',
|
|
60
73
|
hint: "Pass a model identifier, e.g. model: 'anthropic/claude-sonnet-4-20250514'.",
|
|
61
74
|
});
|
|
62
75
|
}
|
|
63
|
-
|
|
76
|
+
const built = {
|
|
64
77
|
kind: 'llm',
|
|
65
78
|
...opts,
|
|
66
79
|
};
|
|
80
|
+
getDefaultRegistrar().register(built);
|
|
81
|
+
return built;
|
|
67
82
|
},
|
|
68
83
|
/**
|
|
69
84
|
* Creates a tool execution step that invokes a typed tool definition.
|
|
@@ -72,7 +87,8 @@ export const step = {
|
|
|
72
87
|
* @param opts.id - Unique step identifier used in traces and error messages.
|
|
73
88
|
* @param opts.tool - The tool definition with typed input/output schemas.
|
|
74
89
|
* @param opts.args - Optional partial args that override or supplement LLM-provided arguments.
|
|
75
|
-
* @returns A `StepTool` that can be composed into larger pipelines.
|
|
90
|
+
* @returns A `StepTool` that can be composed into larger pipelines. The step
|
|
91
|
+
* is auto-registered in the shared step registry.
|
|
76
92
|
* @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
|
|
77
93
|
* @throws `NoeticConfigError` with code `MISSING_TOOL` if `tool` is not provided.
|
|
78
94
|
*/
|
|
@@ -91,9 +107,12 @@ export const step = {
|
|
|
91
107
|
hint: 'Provide a tool definition created with the tool() builder.',
|
|
92
108
|
});
|
|
93
109
|
}
|
|
94
|
-
|
|
110
|
+
const built = {
|
|
95
111
|
kind: 'tool',
|
|
96
112
|
...opts,
|
|
97
113
|
};
|
|
114
|
+
getDefaultRegistrar().register(built);
|
|
115
|
+
return built;
|
|
98
116
|
},
|
|
99
117
|
};
|
|
118
|
+
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ZodTypeAny, z } from 'zod';
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type { ToolExecutionContext } from '../types/tool-context';
|
|
2
|
+
import type { FunctionCallItem, FunctionCallOutputItem, Item, ItemSchemaExtensions, ToolResultExtensionItem } from '../types/items.js';
|
|
3
|
+
import type { Tool, ToolMemoryDeclaration } from '../types/tool.js';
|
|
4
|
+
import type { ToolExecutionContext } from '../types/tool-context.js';
|
|
5
5
|
interface ToolConfig<I extends ZodTypeAny, O extends ZodTypeAny> {
|
|
6
6
|
name: string;
|
|
7
7
|
description: string;
|
|
@@ -18,6 +18,8 @@ interface ToolConfig<I extends ZodTypeAny, O extends ZodTypeAny> {
|
|
|
18
18
|
}) => Item | ToolResultExtensionItem;
|
|
19
19
|
execute: (args: z.infer<I>, toolCtx: ToolExecutionContext) => Promise<z.infer<O>>;
|
|
20
20
|
needsApproval?: boolean;
|
|
21
|
+
/** Optional memory declaration — the runtime generates a MemoryLayer from this via toolMemoryLayer(). */
|
|
22
|
+
memory?: ToolMemoryDeclaration;
|
|
21
23
|
}
|
|
22
24
|
interface GeneratorToolConfig<I extends ZodTypeAny, E extends ZodTypeAny, O extends ZodTypeAny> {
|
|
23
25
|
name: string;
|
|
@@ -36,6 +38,8 @@ interface GeneratorToolConfig<I extends ZodTypeAny, E extends ZodTypeAny, O exte
|
|
|
36
38
|
}) => Item | ToolResultExtensionItem;
|
|
37
39
|
execute: (args: z.infer<I>, toolCtx: ToolExecutionContext) => AsyncGenerator<z.infer<E>, z.infer<O>>;
|
|
38
40
|
needsApproval?: boolean;
|
|
41
|
+
/** Optional memory declaration — the runtime generates a MemoryLayer from this via toolMemoryLayer(). */
|
|
42
|
+
memory?: ToolMemoryDeclaration;
|
|
39
43
|
}
|
|
40
44
|
/**
|
|
41
45
|
* Creates a typed Tool with Zod schema inference for input and output.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NoeticConfigError } from '../errors/noetic-config-error';
|
|
1
|
+
import { NoeticConfigError } from '../errors/noetic-config-error.js';
|
|
2
2
|
//#endregion
|
|
3
3
|
//#region Helpers
|
|
4
4
|
function validateToolConfig(name, execute) {
|
|
@@ -35,6 +35,7 @@ export function tool(config) {
|
|
|
35
35
|
decorateResultItem: config.decorateResultItem,
|
|
36
36
|
execute: config.execute,
|
|
37
37
|
needsApproval: config.needsApproval,
|
|
38
|
+
memory: config.memory,
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
/**
|
|
@@ -54,6 +55,7 @@ export function toolWithGenerator(config) {
|
|
|
54
55
|
decorateResultItem: config.decorateResultItem,
|
|
55
56
|
execute: config.execute,
|
|
56
57
|
needsApproval: config.needsApproval,
|
|
58
|
+
memory: config.memory,
|
|
57
59
|
};
|
|
58
60
|
}
|
|
59
61
|
//#endregion
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a validated `WorkflowDocument` into a live `Step` tree.
|
|
3
|
+
*
|
|
4
|
+
* Each node kind maps to the corresponding builder (`step.llm`, `fork`,
|
|
5
|
+
* `loop`, etc.) so hydrated steps are indistinguishable from programmatic
|
|
6
|
+
* ones — they register in the step registry, carry retry policies, etc.
|
|
7
|
+
*/
|
|
8
|
+
import type { WorkflowDocument, WorkflowNode } from '../schemas/workflow.js';
|
|
9
|
+
import type { ContextMemory, MemoryLayer } from '../types/memory.js';
|
|
10
|
+
import type { ExecuteStepFn, Step } from '../types/step.js';
|
|
11
|
+
import type { Tool } from '../types/tool.js';
|
|
12
|
+
/** @public Context required to hydrate a JSON workflow into live steps. */
|
|
13
|
+
export interface HydrationContext {
|
|
14
|
+
tools: ReadonlyMap<string, Tool>;
|
|
15
|
+
executeStep: ExecuteStepFn;
|
|
16
|
+
layers?: ReadonlyMap<string, MemoryLayer>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Hydrates a single `WorkflowNode` into a live `Step`.
|
|
20
|
+
*
|
|
21
|
+
* @public
|
|
22
|
+
* @param node - Validated workflow node.
|
|
23
|
+
* @param ctx - Hydration context with tool registry and step executor.
|
|
24
|
+
* @returns A live `Step` ready for execution.
|
|
25
|
+
* @throws `NoeticConfigError` with code `UNKNOWN_NODE_KIND` if the node kind is unrecognised.
|
|
26
|
+
* @throws `NoeticConfigError` with code `UNKNOWN_TOOL_REFERENCE` if a tool name cannot be resolved.
|
|
27
|
+
* @throws `NoeticConfigError` with code `UNKNOWN_UNTIL_PREDICATE` if an until predicate kind is unrecognised.
|
|
28
|
+
*/
|
|
29
|
+
export declare function hydrateNode(node: WorkflowNode, ctx: HydrationContext): Step<ContextMemory, string, string>;
|
|
30
|
+
/**
|
|
31
|
+
* Hydrates a complete `WorkflowDocument` into a live `Step` tree.
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
* @param doc - Validated workflow document (version 1).
|
|
35
|
+
* @param ctx - Hydration context with tool registry and step executor.
|
|
36
|
+
* @returns The root `Step` of the hydrated workflow.
|
|
37
|
+
*/
|
|
38
|
+
export declare function hydrateWorkflow(doc: WorkflowDocument, ctx: HydrationContext): Step<ContextMemory, string, string>;
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a validated `WorkflowDocument` into a live `Step` tree.
|
|
3
|
+
*
|
|
4
|
+
* Each node kind maps to the corresponding builder (`step.llm`, `fork`,
|
|
5
|
+
* `loop`, etc.) so hydrated steps are indistinguishable from programmatic
|
|
6
|
+
* ones — they register in the step registry, carry retry policies, etc.
|
|
7
|
+
*/
|
|
8
|
+
import { NoeticConfigError } from '../errors/noetic-config-error.js';
|
|
9
|
+
import { all, any } from '../until/combinators.js';
|
|
10
|
+
import { until } from '../until/predicates.js';
|
|
11
|
+
import { frameworkCast } from '../util/framework-cast.js';
|
|
12
|
+
import { branch, fork } from './control-flow-builders.js';
|
|
13
|
+
import { every } from './every.js';
|
|
14
|
+
import { loop } from './loop-builder.js';
|
|
15
|
+
import { provide } from './provide-builder.js';
|
|
16
|
+
import { spawn } from './spawn-builder.js';
|
|
17
|
+
import { step } from './step-builders.js';
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region Until Predicate Hydration
|
|
20
|
+
function hydrateUntilPredicate(pred) {
|
|
21
|
+
switch (pred.kind) {
|
|
22
|
+
case 'maxSteps':
|
|
23
|
+
return until.maxSteps(pred.n);
|
|
24
|
+
case 'maxCost':
|
|
25
|
+
return until.maxCost(pred.usd);
|
|
26
|
+
case 'maxDuration':
|
|
27
|
+
return until.maxDuration(pred.ms);
|
|
28
|
+
case 'noToolCalls':
|
|
29
|
+
return until.noToolCalls();
|
|
30
|
+
case 'outputContains':
|
|
31
|
+
return until.outputContains(pred.marker);
|
|
32
|
+
case 'outputEquals':
|
|
33
|
+
return until.outputEquals(pred.sentinel);
|
|
34
|
+
case 'converged':
|
|
35
|
+
return until.converged({
|
|
36
|
+
threshold: pred.threshold,
|
|
37
|
+
});
|
|
38
|
+
case 'any':
|
|
39
|
+
return any(...pred.predicates.map(hydrateUntilPredicate));
|
|
40
|
+
case 'all':
|
|
41
|
+
return all(...pred.predicates.map(hydrateUntilPredicate));
|
|
42
|
+
default:
|
|
43
|
+
throw new NoeticConfigError({
|
|
44
|
+
code: 'UNKNOWN_UNTIL_PREDICATE',
|
|
45
|
+
message: `Unknown until predicate kind: '${frameworkCast(pred).kind}'.`,
|
|
46
|
+
hint: 'Supported kinds: maxSteps, maxCost, maxDuration, noToolCalls, outputContains, outputEquals, converged, any, all.',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region Node Hydrators
|
|
52
|
+
function hydrateLlmNode(node, ctx) {
|
|
53
|
+
if (node.kind !== 'llm') {
|
|
54
|
+
return frameworkCast(undefined);
|
|
55
|
+
}
|
|
56
|
+
const resolvedTools = resolveTools(node.tools, ctx.tools);
|
|
57
|
+
return step.llm({
|
|
58
|
+
id: node.id,
|
|
59
|
+
model: node.model ?? 'openai/gpt-4o',
|
|
60
|
+
instructions: node.instructions,
|
|
61
|
+
tools: resolvedTools.length > 0 ? resolvedTools : undefined,
|
|
62
|
+
params: node.params,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function hydrateToolNode(node, ctx) {
|
|
66
|
+
if (node.kind !== 'tool') {
|
|
67
|
+
return frameworkCast(undefined);
|
|
68
|
+
}
|
|
69
|
+
const resolved = ctx.tools.get(node.toolName);
|
|
70
|
+
if (!resolved) {
|
|
71
|
+
throw new NoeticConfigError({
|
|
72
|
+
code: 'UNKNOWN_TOOL_REFERENCE',
|
|
73
|
+
message: `Tool '${node.toolName}' referenced in workflow node '${node.id}' is not registered.`,
|
|
74
|
+
hint: `Available tools: ${[
|
|
75
|
+
...ctx.tools.keys(),
|
|
76
|
+
].join(', ') || '(none)'}`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return frameworkCast(step.run({
|
|
80
|
+
id: node.id,
|
|
81
|
+
execute: async (_input, execCtx) => {
|
|
82
|
+
const args = node.args ?? {};
|
|
83
|
+
const callId = `call-${node.id}-${Date.now()}`;
|
|
84
|
+
const callItem = {
|
|
85
|
+
id: callId,
|
|
86
|
+
type: 'function_call',
|
|
87
|
+
status: 'completed',
|
|
88
|
+
name: node.toolName,
|
|
89
|
+
callId,
|
|
90
|
+
arguments: JSON.stringify(args),
|
|
91
|
+
};
|
|
92
|
+
execCtx.itemLog.append(callItem);
|
|
93
|
+
const toolCtx = {
|
|
94
|
+
ctx: execCtx,
|
|
95
|
+
harness: execCtx.harness,
|
|
96
|
+
fs: execCtx.fs,
|
|
97
|
+
shell: execCtx.shell,
|
|
98
|
+
memory: {
|
|
99
|
+
get: (_layerId) => undefined,
|
|
100
|
+
set: (_layerId, _state) => { },
|
|
101
|
+
},
|
|
102
|
+
assembledView: execCtx.itemLog.items,
|
|
103
|
+
lastStepMeta: execCtx.lastStepMeta,
|
|
104
|
+
};
|
|
105
|
+
const result = await resolved.execute(args, toolCtx);
|
|
106
|
+
return stringifyResult(result);
|
|
107
|
+
},
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
function hydrateBranchNode(node, ctx) {
|
|
111
|
+
if (node.kind !== 'branch') {
|
|
112
|
+
return frameworkCast(undefined);
|
|
113
|
+
}
|
|
114
|
+
const hydratedRoutes = node.routes.map((r) => ({
|
|
115
|
+
match: r.match,
|
|
116
|
+
target: hydrateNode(r.target, ctx),
|
|
117
|
+
}));
|
|
118
|
+
const defaultTarget = node.default ? hydrateNode(node.default, ctx) : null;
|
|
119
|
+
const allTargets = hydratedRoutes.map((r) => r.target);
|
|
120
|
+
if (defaultTarget) {
|
|
121
|
+
allTargets.push(defaultTarget);
|
|
122
|
+
}
|
|
123
|
+
return branch({
|
|
124
|
+
id: node.id,
|
|
125
|
+
route: (input) => {
|
|
126
|
+
const trimmed = input.trim().toLowerCase();
|
|
127
|
+
for (const r of hydratedRoutes) {
|
|
128
|
+
if (trimmed.includes(r.match.toLowerCase())) {
|
|
129
|
+
return r.target;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return defaultTarget;
|
|
133
|
+
},
|
|
134
|
+
_optimizable: frameworkCast(allTargets),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function hydrateForkNode(node, ctx) {
|
|
138
|
+
if (node.kind !== 'fork') {
|
|
139
|
+
return frameworkCast(undefined);
|
|
140
|
+
}
|
|
141
|
+
const hydratedPaths = node.paths.map((p) => hydrateNode(p, ctx));
|
|
142
|
+
if (node.mode === 'race') {
|
|
143
|
+
return fork({
|
|
144
|
+
id: node.id,
|
|
145
|
+
mode: 'race',
|
|
146
|
+
paths: () => hydratedPaths,
|
|
147
|
+
concurrency: node.concurrency,
|
|
148
|
+
_optimizable: frameworkCast(hydratedPaths),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
const mergeFn = buildMerge(node.merge ?? 'last');
|
|
152
|
+
if (node.mode === 'settle') {
|
|
153
|
+
return fork({
|
|
154
|
+
id: node.id,
|
|
155
|
+
mode: 'settle',
|
|
156
|
+
paths: () => hydratedPaths,
|
|
157
|
+
merge: (results) => {
|
|
158
|
+
const values = results.filter((r) => r.status === 'fulfilled').map((r) => r.value ?? '');
|
|
159
|
+
return mergeFn(values);
|
|
160
|
+
},
|
|
161
|
+
concurrency: node.concurrency,
|
|
162
|
+
_optimizable: frameworkCast(hydratedPaths),
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return fork({
|
|
166
|
+
id: node.id,
|
|
167
|
+
mode: 'all',
|
|
168
|
+
paths: () => hydratedPaths,
|
|
169
|
+
merge: mergeFn,
|
|
170
|
+
concurrency: node.concurrency,
|
|
171
|
+
_optimizable: frameworkCast(hydratedPaths),
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
function hydrateSpawnNode(node, ctx) {
|
|
175
|
+
if (node.kind !== 'spawn') {
|
|
176
|
+
return frameworkCast(undefined);
|
|
177
|
+
}
|
|
178
|
+
return spawn({
|
|
179
|
+
id: node.id,
|
|
180
|
+
child: hydrateNode(node.child, ctx),
|
|
181
|
+
timeout: node.timeout,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function hydrateProvideNode(node, ctx) {
|
|
185
|
+
if (node.kind !== 'provide') {
|
|
186
|
+
return frameworkCast(undefined);
|
|
187
|
+
}
|
|
188
|
+
const resolvedLayers = ctx.layers
|
|
189
|
+
? node.layers.map((name) => {
|
|
190
|
+
const layer = ctx.layers?.get(name);
|
|
191
|
+
if (!layer) {
|
|
192
|
+
throw new NoeticConfigError({
|
|
193
|
+
code: 'UNKNOWN_LAYER_REFERENCE',
|
|
194
|
+
message: `Memory layer '${name}' referenced in provide node '${node.id}' is not registered.`,
|
|
195
|
+
hint: `Available layers: ${[
|
|
196
|
+
...(ctx.layers?.keys() ?? []),
|
|
197
|
+
].join(', ') || '(none)'}. Pass named layers via HydrationContext.layers.`,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return layer;
|
|
201
|
+
})
|
|
202
|
+
: [];
|
|
203
|
+
return provide({
|
|
204
|
+
id: node.id,
|
|
205
|
+
child: hydrateNode(node.child, ctx),
|
|
206
|
+
memory: resolvedLayers,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function hydrateLoopNode(node, ctx) {
|
|
210
|
+
if (node.kind !== 'loop') {
|
|
211
|
+
return frameworkCast(undefined);
|
|
212
|
+
}
|
|
213
|
+
return loop({
|
|
214
|
+
id: node.id,
|
|
215
|
+
steps: [
|
|
216
|
+
hydrateNode(node.body, ctx),
|
|
217
|
+
],
|
|
218
|
+
until: hydrateUntilPredicate(node.until),
|
|
219
|
+
maxIterations: node.maxIterations,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
function hydrateSequenceNode(node, ctx) {
|
|
223
|
+
if (node.kind !== 'sequence') {
|
|
224
|
+
return frameworkCast(undefined);
|
|
225
|
+
}
|
|
226
|
+
const children = node.steps.map((s) => hydrateNode(s, ctx));
|
|
227
|
+
return frameworkCast(step.run({
|
|
228
|
+
id: node.id,
|
|
229
|
+
execute: async (input, execCtx) => {
|
|
230
|
+
let current = input;
|
|
231
|
+
for (const child of children) {
|
|
232
|
+
const childInput = stringifyResult(current);
|
|
233
|
+
current = await ctx.executeStep(child, childInput, execCtx);
|
|
234
|
+
}
|
|
235
|
+
return stringifyResult(current);
|
|
236
|
+
},
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
function hydrateEveryNode(node, ctx) {
|
|
240
|
+
if (node.kind !== 'every') {
|
|
241
|
+
return frameworkCast(undefined);
|
|
242
|
+
}
|
|
243
|
+
return every({
|
|
244
|
+
id: node.id,
|
|
245
|
+
step: hydrateNode(node.step, ctx),
|
|
246
|
+
ms: node.ms,
|
|
247
|
+
onError: node.onError,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region Handler Registry
|
|
252
|
+
const NODE_HYDRATORS = {
|
|
253
|
+
llm: hydrateLlmNode,
|
|
254
|
+
tool: hydrateToolNode,
|
|
255
|
+
branch: hydrateBranchNode,
|
|
256
|
+
fork: hydrateForkNode,
|
|
257
|
+
spawn: hydrateSpawnNode,
|
|
258
|
+
provide: hydrateProvideNode,
|
|
259
|
+
loop: hydrateLoopNode,
|
|
260
|
+
sequence: hydrateSequenceNode,
|
|
261
|
+
every: hydrateEveryNode,
|
|
262
|
+
};
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region Helpers
|
|
265
|
+
function resolveTools(toolNames, registry) {
|
|
266
|
+
if (!toolNames || toolNames.length === 0) {
|
|
267
|
+
return [];
|
|
268
|
+
}
|
|
269
|
+
return toolNames.map((name) => {
|
|
270
|
+
const resolved = registry.get(name);
|
|
271
|
+
if (!resolved) {
|
|
272
|
+
throw new NoeticConfigError({
|
|
273
|
+
code: 'UNKNOWN_TOOL_REFERENCE',
|
|
274
|
+
message: `Tool '${name}' referenced in workflow is not registered.`,
|
|
275
|
+
hint: `Available tools: ${[
|
|
276
|
+
...registry.keys(),
|
|
277
|
+
].join(', ') || '(none)'}`,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return resolved;
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
function buildMerge(strategy) {
|
|
284
|
+
if (strategy === 'first') {
|
|
285
|
+
return (r) => r[0] ?? '';
|
|
286
|
+
}
|
|
287
|
+
if (strategy === 'concat') {
|
|
288
|
+
return (r) => r.join('\n');
|
|
289
|
+
}
|
|
290
|
+
return (r) => r[r.length - 1] ?? '';
|
|
291
|
+
}
|
|
292
|
+
function stringifyResult(value) {
|
|
293
|
+
if (typeof value === 'string') {
|
|
294
|
+
return value;
|
|
295
|
+
}
|
|
296
|
+
if (value === null || value === undefined) {
|
|
297
|
+
return '';
|
|
298
|
+
}
|
|
299
|
+
return JSON.stringify(value);
|
|
300
|
+
}
|
|
301
|
+
//#endregion
|
|
302
|
+
//#region Public API
|
|
303
|
+
/**
|
|
304
|
+
* Hydrates a single `WorkflowNode` into a live `Step`.
|
|
305
|
+
*
|
|
306
|
+
* @public
|
|
307
|
+
* @param node - Validated workflow node.
|
|
308
|
+
* @param ctx - Hydration context with tool registry and step executor.
|
|
309
|
+
* @returns A live `Step` ready for execution.
|
|
310
|
+
* @throws `NoeticConfigError` with code `UNKNOWN_NODE_KIND` if the node kind is unrecognised.
|
|
311
|
+
* @throws `NoeticConfigError` with code `UNKNOWN_TOOL_REFERENCE` if a tool name cannot be resolved.
|
|
312
|
+
* @throws `NoeticConfigError` with code `UNKNOWN_UNTIL_PREDICATE` if an until predicate kind is unrecognised.
|
|
313
|
+
*/
|
|
314
|
+
export function hydrateNode(node, ctx) {
|
|
315
|
+
const hydrator = NODE_HYDRATORS[node.kind];
|
|
316
|
+
if (!hydrator) {
|
|
317
|
+
throw new NoeticConfigError({
|
|
318
|
+
code: 'UNKNOWN_NODE_KIND',
|
|
319
|
+
message: `Unknown workflow node kind: '${node.kind}'.`,
|
|
320
|
+
hint: `Supported kinds: ${Object.keys(NODE_HYDRATORS).join(', ')}.`,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
return hydrator(node, ctx);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Hydrates a complete `WorkflowDocument` into a live `Step` tree.
|
|
327
|
+
*
|
|
328
|
+
* @public
|
|
329
|
+
* @param doc - Validated workflow document (version 1).
|
|
330
|
+
* @param ctx - Hydration context with tool registry and step executor.
|
|
331
|
+
* @returns The root `Step` of the hydrated workflow.
|
|
332
|
+
*/
|
|
333
|
+
export function hydrateWorkflow(doc, ctx) {
|
|
334
|
+
return hydrateNode(doc.root, ctx);
|
|
335
|
+
}
|
|
336
|
+
//#endregion
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Context } from '../types/context';
|
|
2
|
-
import type { EmbedFn } from '../types/embed';
|
|
3
|
-
import type { ContextMemory, StorageAdapter } from '../types/memory';
|
|
4
|
-
import type { Step } from '../types/step';
|
|
1
|
+
import type { Context } from '../types/context.js';
|
|
2
|
+
import type { EmbedFn } from '../types/embed.js';
|
|
3
|
+
import type { ContextMemory, StorageAdapter } from '../types/memory.js';
|
|
4
|
+
import type { Step } from '../types/step.js';
|
|
5
5
|
export type Condition<I> = (input: I, ctx: Context) => Promise<boolean>;
|
|
6
6
|
export interface WhenClause<TMemory = ContextMemory, I = unknown, O = unknown> {
|
|
7
7
|
readonly kind: 'when';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { createMessage, extractAssistantText, trackUsage } from '../
|
|
3
|
-
import { cosineSimilarity } from './cosine-similarity';
|
|
2
|
+
import { createMessage, extractAssistantText, trackUsage } from '../util/message-helpers.js';
|
|
3
|
+
import { cosineSimilarity } from './cosine-similarity.js';
|
|
4
4
|
//#endregion
|
|
5
5
|
//#region Helpers
|
|
6
6
|
function serializeInput(input) {
|
|
@@ -43,6 +43,8 @@ function formatMessage(error) {
|
|
|
43
43
|
return `Budget exceeded: ${error.field} limit ${error.limit}, actual ${error.actual}`;
|
|
44
44
|
case 'steering_denied':
|
|
45
45
|
return `Steering denied${error.guidance ? `: ${error.guidance}` : ''}`;
|
|
46
|
+
case 'handle_evicted':
|
|
47
|
+
return `Subprocess handle '${error.handleId}' evicted (step '${error.stepId}'): adapter returned null for ${error.gracePeriodMs}ms`;
|
|
46
48
|
default: {
|
|
47
49
|
const _exhaustive = error;
|
|
48
50
|
void _exhaustive;
|