@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,9 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { Slot } from '../../types/memory.js';
|
|
3
|
+
import { SteeringAction } from '../../types/steering.js';
|
|
4
|
+
import { createMessage, estimateTokens } from '../../util/message-helpers.js';
|
|
5
|
+
import { FlowSchema, flowDepth } from '../flow-schema.js';
|
|
6
|
+
import { layerData, layerFn } from '../layer-provides.js';
|
|
7
7
|
//#region Constants
|
|
8
8
|
const MAX_PRD_LENGTH = 5e4;
|
|
9
9
|
const MAX_TREE_DEPTH = 5;
|
|
@@ -14,7 +14,12 @@ const ALLOWED_TOOLS_IN_PLAN_MODE = new Set([
|
|
|
14
14
|
'Grep',
|
|
15
15
|
'Find',
|
|
16
16
|
'Ls',
|
|
17
|
+
'AskUserQuestion',
|
|
17
18
|
'activateSkill',
|
|
19
|
+
'agent',
|
|
20
|
+
'checkAgent',
|
|
21
|
+
'sendMessage',
|
|
22
|
+
'requestPlanApproval',
|
|
18
23
|
'plan/enterPlanMode',
|
|
19
24
|
'plan/updatePrd',
|
|
20
25
|
'plan/setPlanTree',
|
|
@@ -63,15 +68,15 @@ function trimExecutionLog(log) {
|
|
|
63
68
|
function recallPlanning(state, additionalInstructions) {
|
|
64
69
|
const sections = [
|
|
65
70
|
'<plan_mode>',
|
|
66
|
-
'You are in PLAN MODE. You may only use read-only tools (Read, Grep, Find, Ls) to explore the codebase.',
|
|
71
|
+
'You are in PLAN MODE. You may only use read-only tools (Read, Grep, Find, Ls), AskUserQuestion, skill activation, sub-agent coordination tools, and requestPlanApproval to explore the codebase and request execution approval.',
|
|
67
72
|
'Your goal is to produce a PRD document and (optionally) a structured execution plan.',
|
|
68
73
|
'',
|
|
69
74
|
'## Workflow (5 phases)',
|
|
70
75
|
'',
|
|
71
|
-
'1. **Initial Understanding** — Read code and gather context. To parallelise exploration,
|
|
72
|
-
'2. **Design** — Synthesise findings. Optionally
|
|
76
|
+
'1. **Initial Understanding** — Read code and gather context. To parallelise exploration, use the `agent` tool to spawn bounded read-only sub-agents; up to 3 in parallel. Each sub-agent returns a focused report.',
|
|
77
|
+
'2. **Design** — Synthesise findings. Optionally spawn planning sub-agents (1–3 in parallel) to draft alternative implementation approaches and surface trade-offs.',
|
|
73
78
|
'3. **Review** — Read the critical files identified by your subagents directly so you understand them first-hand. If anything is ambiguous, ask the user a focused question.',
|
|
74
|
-
'4. **Final Plan** — Write the PRD via `plan/updatePrd`. Lead with a **Context** section (why this change), then your single recommended approach, the paths of files to modify, existing functions/utilities to reuse, and a **Verification** section.
|
|
79
|
+
'4. **Final Plan** — Write the PRD via `plan/updatePrd`. Lead with a **Context** section (why this change), then your single recommended approach, the paths of files to modify, existing functions/utilities to reuse, and a **Verification** section. Then call `plan/setPlanTree` with a JSON noetic flow built from the existing step primitives (`step.llm`, `step.branch`, `step.fork`, `step.spawn`, `step.loop`) — tool refs by name string.',
|
|
75
80
|
'5. **Exit** — Call `plan/exitPlanMode` with `{ action: "execute" }` to request approval. The user must accept before execution begins; if they reject, you stay in Plan Mode and may revise.',
|
|
76
81
|
'',
|
|
77
82
|
'## Available actions',
|
|
@@ -81,7 +86,7 @@ function recallPlanning(state, additionalInstructions) {
|
|
|
81
86
|
'- `plan/exitPlanMode` `{ action: "cancel" }` — discard plan and return to idle',
|
|
82
87
|
'',
|
|
83
88
|
'## Constraints',
|
|
84
|
-
'- DO NOT create, modify, or delete files (other than via `plan/updatePrd`).',
|
|
89
|
+
'- DO NOT create, modify, or delete files (other than via `plan/updatePrd` and `plan/setPlanTree`).',
|
|
85
90
|
'- DO NOT run mutating shell commands. Read-only exploration only.',
|
|
86
91
|
'- End each turn either by asking the user a focused clarifying question or by calling `plan/exitPlanMode`.',
|
|
87
92
|
];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MemoryScope } from '../../types/memory';
|
|
1
|
+
import type { MemoryScope } from '../../types/memory.js';
|
|
2
2
|
interface StaticContentOpts {
|
|
3
3
|
id?: string;
|
|
4
4
|
slot?: number;
|
|
@@ -21,7 +21,7 @@ export declare function staticContent(opts: StaticContentOpts): {
|
|
|
21
21
|
init(): Promise<{
|
|
22
22
|
state: string;
|
|
23
23
|
}>;
|
|
24
|
-
recall({ state }: import("
|
|
24
|
+
recall({ state }: import("../../index.js").RecallParams<string>): Promise<string | null>;
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
27
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { MemoryScope } from '../../types/memory';
|
|
2
|
-
import type { AfterModelCallParams, BeforeToolCallParams, LedgerEntry, SteeringConfig, SteeringDecision, SteeringState } from '../../types/steering';
|
|
1
|
+
import type { MemoryScope } from '../../types/memory.js';
|
|
2
|
+
import type { AfterModelCallParams, BeforeToolCallParams, LedgerEntry, SteeringConfig, SteeringDecision, SteeringState } from '../../types/steering.js';
|
|
3
3
|
/**
|
|
4
4
|
* Creates a steering memory layer that evaluates rules before tool calls and after model calls.
|
|
5
5
|
*
|
|
@@ -21,11 +21,11 @@ export declare function steering(config: SteeringConfig): {
|
|
|
21
21
|
afterModelCall: number;
|
|
22
22
|
};
|
|
23
23
|
hooks: {
|
|
24
|
-
init({ storage }: import("
|
|
24
|
+
init({ storage }: import("../../index.js").InitParams): Promise<{
|
|
25
25
|
state: SteeringState;
|
|
26
26
|
}>;
|
|
27
|
-
recall({ state }: import("
|
|
28
|
-
items: import("
|
|
27
|
+
recall({ state }: import("../../index.js").RecallParams<SteeringState>): Promise<{
|
|
28
|
+
items: import("../../index.js").InputMessageItem[];
|
|
29
29
|
tokenCount: number;
|
|
30
30
|
state: SteeringState;
|
|
31
31
|
} | null>;
|
|
@@ -38,13 +38,13 @@ export declare function steering(config: SteeringConfig): {
|
|
|
38
38
|
decision: SteeringDecision;
|
|
39
39
|
state: SteeringState;
|
|
40
40
|
}>;
|
|
41
|
-
onSpawn({ parentState }: import("
|
|
41
|
+
onSpawn({ parentState }: import("../../index.js").SpawnParams<SteeringState>): Promise<{
|
|
42
42
|
childState: {
|
|
43
43
|
ledger: LedgerEntry[];
|
|
44
44
|
pendingAsync: never[];
|
|
45
45
|
};
|
|
46
46
|
}>;
|
|
47
|
-
onComplete({ state, outcome }: import("
|
|
47
|
+
onComplete({ state, outcome }: import("../../index.js").CompleteParams<SteeringState>): Promise<{
|
|
48
48
|
state: SteeringState;
|
|
49
49
|
}>;
|
|
50
50
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { NoeticConfigError } from '../../errors/noetic-config-error';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { mostRestrictive } from '../layer-lifecycle';
|
|
1
|
+
import { NoeticConfigError } from '../../errors/noetic-config-error.js';
|
|
2
|
+
import { Slot } from '../../types/memory.js';
|
|
3
|
+
import { LedgerEntryKind, SteeringAction } from '../../types/steering.js';
|
|
4
|
+
import { createMessage, estimateTokens, extractAssistantText } from '../../util/message-helpers.js';
|
|
5
|
+
import { mostRestrictive } from '../layer-lifecycle.js';
|
|
6
6
|
//#region Constants
|
|
7
7
|
const DEFAULT_MAX_LEDGER_ENTRIES = 100;
|
|
8
8
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { MemoryLayer } from '../../types/memory.js';
|
|
2
|
+
import type { Tool } from '../../types/tool.js';
|
|
3
3
|
interface ToolMemoryLayerOpts {
|
|
4
4
|
slot?: number;
|
|
5
5
|
}
|
|
@@ -23,21 +23,21 @@ export declare function workingMemory(config?: WorkingMemoryConfig): {
|
|
|
23
23
|
max: number;
|
|
24
24
|
};
|
|
25
25
|
provides: {
|
|
26
|
-
snapshot: import("
|
|
27
|
-
update: import("
|
|
26
|
+
snapshot: import("../../index.js").LayerDataDecl<WorkingMemoryState, WorkingMemoryState>;
|
|
27
|
+
update: import("../../index.js").LayerFunctionDecl<Record<string, unknown>, void, WorkingMemoryState>;
|
|
28
28
|
};
|
|
29
29
|
hooks: {
|
|
30
|
-
init({ storage }: import("
|
|
30
|
+
init({ storage }: import("../../index.js").InitParams): Promise<{
|
|
31
31
|
state: WorkingMemoryState;
|
|
32
32
|
}>;
|
|
33
|
-
recall({ state }: import("
|
|
34
|
-
items: import("
|
|
33
|
+
recall({ state }: import("../../index.js").RecallParams<WorkingMemoryState>): Promise<{
|
|
34
|
+
items: import("../../index.js").InputMessageItem[];
|
|
35
35
|
tokenCount: number;
|
|
36
36
|
} | null>;
|
|
37
|
-
store({ newItems, state }: import("
|
|
37
|
+
store({ newItems, state }: import("../../index.js").StoreParams<WorkingMemoryState>): Promise<{
|
|
38
38
|
state: WorkingMemoryState;
|
|
39
39
|
} | undefined>;
|
|
40
|
-
onSpawn({ parentState }: import("
|
|
40
|
+
onSpawn({ parentState }: import("../../index.js").SpawnParams<WorkingMemoryState>): Promise<{
|
|
41
41
|
childState: WorkingMemoryState;
|
|
42
42
|
} | null>;
|
|
43
43
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
3
|
-
import { createMessage, estimateTokens } from '../../
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { Slot } from '../../types/memory.js';
|
|
3
|
+
import { createMessage, estimateTokens } from '../../util/message-helpers.js';
|
|
4
|
+
import { findFunctionCall } from '../function-call-utils.js';
|
|
5
|
+
import { layerData, layerFn } from '../layer-provides.js';
|
|
6
6
|
function safeMerge(state, args) {
|
|
7
7
|
const { __proto__: _p, constructor: _c, ...safeArgs } = args;
|
|
8
8
|
if (typeof state === 'object' && state !== null) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Item } from '../types/items';
|
|
2
|
-
import type { ProjectionPolicy } from '../types/memory';
|
|
1
|
+
import type { Item } from '../types/items.js';
|
|
2
|
+
import type { ProjectionPolicy } from '../types/memory.js';
|
|
3
3
|
interface AssembleViewParams {
|
|
4
4
|
systemPromptItems: Item[];
|
|
5
5
|
layerOutputItems: Item[];
|
package/dist/memory/scope.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { ExecutionContext, MemoryScope, ScopedStorage, StorageAdapter } from '../types/memory';
|
|
1
|
+
import type { ExecutionContext, MemoryScope, ScopedStorage, StorageAdapter } from '../types/memory.js';
|
|
2
2
|
export declare function resolveScopeKey(scope: MemoryScope, ctx: ExecutionContext): string;
|
|
3
3
|
export declare function createScopedStorage(storage: StorageAdapter, layerId: string, scopeKey: string): ScopedStorage;
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
* session-resume path to drop dangling pairs left by a crash, and by the
|
|
9
9
|
* `historyWindow` memory layer to clean orphans at the slice boundary.
|
|
10
10
|
*/
|
|
11
|
-
import type { Item } from '../types/items';
|
|
11
|
+
import type { Item } from '../types/items.js';
|
|
12
12
|
/** @public */
|
|
13
13
|
export declare function stripUnresolvedToolCalls(items: ReadonlyArray<Item>): Item[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Span, TraceExporter } from '../types/observability';
|
|
2
|
-
import { SpanImpl } from './span-impl';
|
|
1
|
+
import type { Span, TraceExporter } from '../types/observability.js';
|
|
2
|
+
import { SpanImpl } from './span-impl.js';
|
|
3
3
|
/** @public No-op trace exporter that silently discards all spans. */
|
|
4
4
|
export declare class NoopExporter implements TraceExporter {
|
|
5
5
|
export(_spans: Span[]): Promise<void>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern that lets an LLM generate a workflow as JSON during execution,
|
|
3
|
+
* then hydrates and runs it within the same harness session.
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '../types/context.js';
|
|
6
|
+
import type { ContextMemory } from '../types/memory.js';
|
|
7
|
+
import type { AgentHarnessContract } from '../types/runtime.js';
|
|
8
|
+
import type { Step } from '../types/step.js';
|
|
9
|
+
import type { Tool } from '../types/tool.js';
|
|
10
|
+
/** @public Options for creating a dynamic workflow step. */
|
|
11
|
+
export interface DynamicWorkflowOpts {
|
|
12
|
+
model?: string;
|
|
13
|
+
instructions?: string;
|
|
14
|
+
tools: Tool[];
|
|
15
|
+
maxDepth?: number;
|
|
16
|
+
maxRevisions?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Creates a step that uses an LLM to generate a workflow as JSON, then
|
|
20
|
+
* hydrates and executes it. The entire plan-and-execute cycle happens
|
|
21
|
+
* within a single harness run.
|
|
22
|
+
*
|
|
23
|
+
* @public
|
|
24
|
+
* @param opts.model - Model for the planner LLM. Default: `openai/gpt-4o`.
|
|
25
|
+
* @param opts.instructions - Additional instructions prepended to the planner prompt.
|
|
26
|
+
* @param opts.tools - Tools the generated workflow may reference by name.
|
|
27
|
+
* @param opts.maxDepth - Maximum workflow tree depth. Default: 5.
|
|
28
|
+
* @param opts.maxRevisions - Retries with error feedback on validation failure. Default: 3.
|
|
29
|
+
* @returns A `Step` that dynamically plans and executes.
|
|
30
|
+
*/
|
|
31
|
+
export declare function dynamicWorkflow(opts: DynamicWorkflowOpts): Step<ContextMemory, string, string>;
|
|
32
|
+
/** @public Options for `parseAndRunWorkflow`. */
|
|
33
|
+
export interface ParseAndRunWorkflowOpts {
|
|
34
|
+
json: unknown;
|
|
35
|
+
harness: AgentHarnessContract;
|
|
36
|
+
ctx: Context;
|
|
37
|
+
tools: Tool[];
|
|
38
|
+
input?: string;
|
|
39
|
+
maxDepth?: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Parses raw JSON into a `WorkflowDocument`, hydrates it into a live step
|
|
43
|
+
* tree, and executes it via the harness.
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
* @param opts.json - Raw JSON (string or parsed object) representing a workflow.
|
|
47
|
+
* @param opts.harness - The agent harness to execute the workflow with.
|
|
48
|
+
* @param opts.ctx - Execution context.
|
|
49
|
+
* @param opts.tools - Available tools the workflow may reference.
|
|
50
|
+
* @param opts.maxDepth - Maximum workflow tree depth. Default: 5.
|
|
51
|
+
* @returns The string output of the executed workflow.
|
|
52
|
+
* @throws `NoeticConfigError` with code `WORKFLOW_VALIDATION_FAILED` if JSON is invalid.
|
|
53
|
+
* @throws `NoeticConfigError` with code `UNKNOWN_TOOL_REFERENCE` if a tool reference cannot be resolved.
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseAndRunWorkflow(opts: ParseAndRunWorkflowOpts): Promise<string>;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern that lets an LLM generate a workflow as JSON during execution,
|
|
3
|
+
* then hydrates and runs it within the same harness session.
|
|
4
|
+
*/
|
|
5
|
+
import { step } from '../builders/step-builders.js';
|
|
6
|
+
import { hydrateWorkflow } from '../builders/workflow-hydrator.js';
|
|
7
|
+
import { NoeticConfigError } from '../errors/noetic-config-error.js';
|
|
8
|
+
import { WorkflowDocumentSchema, workflowDepth } from '../schemas/workflow.js';
|
|
9
|
+
import { frameworkCast } from '../util/framework-cast.js';
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region Constants
|
|
12
|
+
const DEFAULT_MAX_DEPTH = 5;
|
|
13
|
+
const DEFAULT_MAX_REVISIONS = 3;
|
|
14
|
+
const DEFAULT_MODEL = 'openai/gpt-4o';
|
|
15
|
+
const PLANNER_INSTRUCTIONS = `You are a workflow planner. Given a task, generate a JSON workflow document that describes how to accomplish it.
|
|
16
|
+
|
|
17
|
+
The workflow document must be valid JSON with this structure:
|
|
18
|
+
{
|
|
19
|
+
"version": 1,
|
|
20
|
+
"root": <WorkflowNode>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
A WorkflowNode is one of:
|
|
24
|
+
- { "kind": "llm", "id": "<unique>", "instructions": "<prompt>", "model": "<optional>", "tools": ["<tool-name>", ...] }
|
|
25
|
+
- { "kind": "tool", "id": "<unique>", "toolName": "<name>", "args": { ... } }
|
|
26
|
+
- { "kind": "sequence", "id": "<unique>", "steps": [<WorkflowNode>, ...] }
|
|
27
|
+
- { "kind": "fork", "id": "<unique>", "mode": "all"|"race"|"settle", "paths": [<WorkflowNode>, ...], "merge": "last"|"first"|"concat" }
|
|
28
|
+
- { "kind": "loop", "id": "<unique>", "body": <WorkflowNode>, "until": { "kind": "maxSteps", "n": <number> } }
|
|
29
|
+
- { "kind": "branch", "id": "<unique>", "routes": [{ "match": "<substring>", "target": <WorkflowNode> }], "default": <WorkflowNode> }
|
|
30
|
+
- { "kind": "spawn", "id": "<unique>", "child": <WorkflowNode> }
|
|
31
|
+
|
|
32
|
+
Until predicates: maxSteps, maxCost, maxDuration, noToolCalls, outputContains, outputEquals, converged, any, all.
|
|
33
|
+
|
|
34
|
+
Respond with ONLY the JSON document, no markdown fences or explanation.`;
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region Public API
|
|
37
|
+
/**
|
|
38
|
+
* Creates a step that uses an LLM to generate a workflow as JSON, then
|
|
39
|
+
* hydrates and executes it. The entire plan-and-execute cycle happens
|
|
40
|
+
* within a single harness run.
|
|
41
|
+
*
|
|
42
|
+
* @public
|
|
43
|
+
* @param opts.model - Model for the planner LLM. Default: `openai/gpt-4o`.
|
|
44
|
+
* @param opts.instructions - Additional instructions prepended to the planner prompt.
|
|
45
|
+
* @param opts.tools - Tools the generated workflow may reference by name.
|
|
46
|
+
* @param opts.maxDepth - Maximum workflow tree depth. Default: 5.
|
|
47
|
+
* @param opts.maxRevisions - Retries with error feedback on validation failure. Default: 3.
|
|
48
|
+
* @returns A `Step` that dynamically plans and executes.
|
|
49
|
+
*/
|
|
50
|
+
export function dynamicWorkflow(opts) {
|
|
51
|
+
const model = opts.model ?? DEFAULT_MODEL;
|
|
52
|
+
const maxDepth = opts.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
53
|
+
const maxRevisions = opts.maxRevisions ?? DEFAULT_MAX_REVISIONS;
|
|
54
|
+
const toolMap = buildToolMap(opts.tools);
|
|
55
|
+
return step.run({
|
|
56
|
+
id: 'dynamic-workflow',
|
|
57
|
+
execute: async (input, ctx) => {
|
|
58
|
+
const harness = ctx.harness;
|
|
59
|
+
if (!harness) {
|
|
60
|
+
throw new NoeticConfigError({
|
|
61
|
+
code: 'MISSING_HARNESS_CONTEXT',
|
|
62
|
+
message: 'dynamicWorkflow requires a harness on the execution context.',
|
|
63
|
+
hint: 'Execute this step via AgentHarness.run() or ensure ctx.harness is set.',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const toolList = opts.tools.map((t) => `- ${t.name}: ${t.description}`).join('\n');
|
|
67
|
+
const basePrompt = [
|
|
68
|
+
opts.instructions,
|
|
69
|
+
PLANNER_INSTRUCTIONS,
|
|
70
|
+
`\nAvailable tools:\n${toolList}`,
|
|
71
|
+
`\nTask: ${input}`,
|
|
72
|
+
]
|
|
73
|
+
.filter(Boolean)
|
|
74
|
+
.join('\n\n');
|
|
75
|
+
let lastError;
|
|
76
|
+
for (let revision = 0; revision < maxRevisions; revision++) {
|
|
77
|
+
const prompt = lastError
|
|
78
|
+
? `${basePrompt}\n\nPrevious attempt failed with error: ${lastError}\nPlease fix the workflow and try again.`
|
|
79
|
+
: basePrompt;
|
|
80
|
+
const plannerStep = step.llm({
|
|
81
|
+
id: `dynamic-workflow-planner-${revision}`,
|
|
82
|
+
model,
|
|
83
|
+
instructions: prompt,
|
|
84
|
+
});
|
|
85
|
+
const executeStep = frameworkCast(harness.run.bind(harness));
|
|
86
|
+
const rawOutput = await executeStep(plannerStep, input, ctx);
|
|
87
|
+
const text = coerceToString(rawOutput);
|
|
88
|
+
const parseResult = tryParseWorkflow(text, maxDepth);
|
|
89
|
+
if (!parseResult.ok) {
|
|
90
|
+
lastError = parseResult.error;
|
|
91
|
+
if (revision === maxRevisions - 1) {
|
|
92
|
+
throw new NoeticConfigError({
|
|
93
|
+
code: 'WORKFLOW_VALIDATION_FAILED',
|
|
94
|
+
message: `Failed to generate valid workflow after ${maxRevisions} attempts: ${lastError}`,
|
|
95
|
+
hint: 'The planner model may need clearer instructions or a more capable model.',
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const hydrationCtx = {
|
|
101
|
+
tools: toolMap,
|
|
102
|
+
executeStep,
|
|
103
|
+
};
|
|
104
|
+
const hydrated = hydrateWorkflow(parseResult.doc, hydrationCtx);
|
|
105
|
+
return frameworkCast(await executeStep(hydrated, input, ctx));
|
|
106
|
+
}
|
|
107
|
+
throw new NoeticConfigError({
|
|
108
|
+
code: 'WORKFLOW_VALIDATION_FAILED',
|
|
109
|
+
message: `Failed to generate valid workflow after ${maxRevisions} attempts.`,
|
|
110
|
+
hint: 'The planner model may need clearer instructions or a more capable model.',
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Parses raw JSON into a `WorkflowDocument`, hydrates it into a live step
|
|
117
|
+
* tree, and executes it via the harness.
|
|
118
|
+
*
|
|
119
|
+
* @public
|
|
120
|
+
* @param opts.json - Raw JSON (string or parsed object) representing a workflow.
|
|
121
|
+
* @param opts.harness - The agent harness to execute the workflow with.
|
|
122
|
+
* @param opts.ctx - Execution context.
|
|
123
|
+
* @param opts.tools - Available tools the workflow may reference.
|
|
124
|
+
* @param opts.maxDepth - Maximum workflow tree depth. Default: 5.
|
|
125
|
+
* @returns The string output of the executed workflow.
|
|
126
|
+
* @throws `NoeticConfigError` with code `WORKFLOW_VALIDATION_FAILED` if JSON is invalid.
|
|
127
|
+
* @throws `NoeticConfigError` with code `UNKNOWN_TOOL_REFERENCE` if a tool reference cannot be resolved.
|
|
128
|
+
*/
|
|
129
|
+
export async function parseAndRunWorkflow(opts) {
|
|
130
|
+
const parseResult = tryParseWorkflow(opts.json, opts.maxDepth ?? DEFAULT_MAX_DEPTH);
|
|
131
|
+
if (!parseResult.ok) {
|
|
132
|
+
throw new NoeticConfigError({
|
|
133
|
+
code: 'WORKFLOW_VALIDATION_FAILED',
|
|
134
|
+
message: `Invalid workflow document: ${parseResult.error}`,
|
|
135
|
+
hint: 'Ensure the JSON matches the WorkflowDocumentSchema.',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
const executeStep = frameworkCast(opts.harness.run.bind(opts.harness));
|
|
139
|
+
const hydrationCtx = {
|
|
140
|
+
tools: buildToolMap(opts.tools),
|
|
141
|
+
executeStep,
|
|
142
|
+
};
|
|
143
|
+
const hydrated = hydrateWorkflow(parseResult.doc, hydrationCtx);
|
|
144
|
+
const result = await executeStep(hydrated, opts.input ?? '', opts.ctx);
|
|
145
|
+
return coerceToString(result);
|
|
146
|
+
}
|
|
147
|
+
function buildToolMap(tools) {
|
|
148
|
+
return new Map(tools.map((t) => [
|
|
149
|
+
t.name,
|
|
150
|
+
t,
|
|
151
|
+
]));
|
|
152
|
+
}
|
|
153
|
+
function coerceToString(value) {
|
|
154
|
+
if (typeof value === 'string') {
|
|
155
|
+
return value;
|
|
156
|
+
}
|
|
157
|
+
return String(value ?? '');
|
|
158
|
+
}
|
|
159
|
+
function tryParseWorkflow(raw, maxDepth) {
|
|
160
|
+
const parsed = typeof raw === 'string' ? safeParse(raw) : raw;
|
|
161
|
+
if (parsed === null) {
|
|
162
|
+
return {
|
|
163
|
+
ok: false,
|
|
164
|
+
error: 'Input is not valid JSON.',
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
const result = WorkflowDocumentSchema.safeParse(parsed);
|
|
168
|
+
if (!result.success) {
|
|
169
|
+
return {
|
|
170
|
+
ok: false,
|
|
171
|
+
error: result.error.message,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const depth = workflowDepth(result.data.root);
|
|
175
|
+
if (depth > maxDepth) {
|
|
176
|
+
return {
|
|
177
|
+
ok: false,
|
|
178
|
+
error: `Workflow tree depth ${depth} exceeds maximum ${maxDepth}.`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
ok: true,
|
|
183
|
+
doc: result.data,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function safeParse(text) {
|
|
187
|
+
try {
|
|
188
|
+
return JSON.parse(text);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
//#endregion
|
package/dist/patterns/flow.d.ts
CHANGED
|
@@ -1,52 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* A "flow" is a JSON-serialisable subset of noetic's `Step` shape that the model
|
|
5
|
-
* may emit during plan mode. The runtime expands each node into a concrete `Step`
|
|
6
|
-
* via the existing builders (`step.llm`, `fork`, `spawn`) at execute time.
|
|
7
|
-
*
|
|
8
|
-
* Tool references inside `llm` nodes are name strings — they get resolved against
|
|
9
|
-
* the harness's live tool registry when the flow runs.
|
|
10
|
-
*/
|
|
11
|
-
import { z } from 'zod';
|
|
12
|
-
interface NodeBase {
|
|
13
|
-
id: string;
|
|
14
|
-
subPlanRef?: string;
|
|
15
|
-
}
|
|
16
|
-
export interface LlmFlowNode extends NodeBase {
|
|
17
|
-
kind: 'llm';
|
|
18
|
-
model?: string;
|
|
19
|
-
instructions: string;
|
|
20
|
-
tools?: string[];
|
|
21
|
-
}
|
|
22
|
-
export interface SubagentFlowNode extends NodeBase {
|
|
23
|
-
kind: 'subagent';
|
|
24
|
-
preset: string;
|
|
25
|
-
prompt: string;
|
|
26
|
-
}
|
|
27
|
-
export interface ForkFlowNode extends NodeBase {
|
|
28
|
-
kind: 'fork';
|
|
29
|
-
mode: 'all' | 'race' | 'settle';
|
|
30
|
-
paths: FlowNode[];
|
|
31
|
-
}
|
|
32
|
-
export interface SpawnFlowNode extends NodeBase {
|
|
33
|
-
kind: 'spawn';
|
|
34
|
-
child: FlowNode;
|
|
35
|
-
}
|
|
36
|
-
export interface SequenceFlowNode extends NodeBase {
|
|
37
|
-
kind: 'sequence';
|
|
38
|
-
steps: FlowNode[];
|
|
39
|
-
}
|
|
40
|
-
export type FlowNode = LlmFlowNode | SubagentFlowNode | ForkFlowNode | SpawnFlowNode | SequenceFlowNode;
|
|
41
|
-
/** Top-level flow document — a single root node. */
|
|
42
|
-
export declare const FlowSchema: z.ZodType<FlowNode, unknown, z.core.$ZodTypeInternals<FlowNode, unknown>>;
|
|
43
|
-
/** Validates a candidate flow document. Throws `ZodError` on invalid input. */
|
|
44
|
-
export declare function validateFlow(input: unknown): FlowNode;
|
|
45
|
-
/** Walks a flow tree depth-first, yielding each node. */
|
|
46
|
-
export declare function walkFlow(root: FlowNode): Iterable<FlowNode>;
|
|
47
|
-
/**
|
|
48
|
-
* Returns the maximum depth of a flow tree. A leaf (llm/subagent) is depth 0.
|
|
49
|
-
* Structural nodes (sequence/fork/spawn) contribute +1 over their deepest child.
|
|
50
|
-
*/
|
|
51
|
-
export declare function flowDepth(node: FlowNode): number;
|
|
52
|
-
export {};
|
|
1
|
+
export type { FlowNode, ForkFlowNode, LlmFlowNode, SequenceFlowNode, SpawnFlowNode, SubagentFlowNode, } from '../memory/flow-schema.js';
|
|
2
|
+
export { FlowSchema, flowDepth, validateFlow, walkFlow } from '../memory/flow-schema.js';
|
package/dist/patterns/flow.js
CHANGED
|
@@ -1,103 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Zod schema for plan-mode flow JSON.
|
|
3
|
-
*
|
|
4
|
-
* A "flow" is a JSON-serialisable subset of noetic's `Step` shape that the model
|
|
5
|
-
* may emit during plan mode. The runtime expands each node into a concrete `Step`
|
|
6
|
-
* via the existing builders (`step.llm`, `fork`, `spawn`) at execute time.
|
|
7
|
-
*
|
|
8
|
-
* Tool references inside `llm` nodes are name strings — they get resolved against
|
|
9
|
-
* the harness's live tool registry when the flow runs.
|
|
10
|
-
*/
|
|
11
|
-
import { z } from 'zod';
|
|
12
|
-
//#endregion
|
|
13
|
-
//#region Schema
|
|
14
|
-
const FlowNodeRef = z.lazy(() => FlowNodeSchema);
|
|
15
|
-
const SHARED_FIELDS = {
|
|
16
|
-
id: z.string().min(1),
|
|
17
|
-
subPlanRef: z.string().optional(),
|
|
18
|
-
};
|
|
19
|
-
const LlmNodeSchema = z.object({
|
|
20
|
-
kind: z.literal('llm'),
|
|
21
|
-
...SHARED_FIELDS,
|
|
22
|
-
model: z.string().optional(),
|
|
23
|
-
instructions: z.string(),
|
|
24
|
-
tools: z.array(z.string()).optional(),
|
|
25
|
-
});
|
|
26
|
-
const SubagentNodeSchema = z.object({
|
|
27
|
-
kind: z.literal('subagent'),
|
|
28
|
-
...SHARED_FIELDS,
|
|
29
|
-
preset: z.string().min(1),
|
|
30
|
-
prompt: z.string(),
|
|
31
|
-
});
|
|
32
|
-
const ForkNodeSchema = z.object({
|
|
33
|
-
kind: z.literal('fork'),
|
|
34
|
-
...SHARED_FIELDS,
|
|
35
|
-
mode: z.enum([
|
|
36
|
-
'all',
|
|
37
|
-
'race',
|
|
38
|
-
'settle',
|
|
39
|
-
]),
|
|
40
|
-
paths: z.array(FlowNodeRef).min(1),
|
|
41
|
-
});
|
|
42
|
-
const SpawnNodeSchema = z.object({
|
|
43
|
-
kind: z.literal('spawn'),
|
|
44
|
-
...SHARED_FIELDS,
|
|
45
|
-
child: FlowNodeRef,
|
|
46
|
-
});
|
|
47
|
-
const SequenceNodeSchema = z.object({
|
|
48
|
-
kind: z.literal('sequence'),
|
|
49
|
-
...SHARED_FIELDS,
|
|
50
|
-
steps: z.array(FlowNodeRef).min(1),
|
|
51
|
-
});
|
|
52
|
-
const FlowNodeSchema = z.discriminatedUnion('kind', [
|
|
53
|
-
LlmNodeSchema,
|
|
54
|
-
SubagentNodeSchema,
|
|
55
|
-
ForkNodeSchema,
|
|
56
|
-
SpawnNodeSchema,
|
|
57
|
-
SequenceNodeSchema,
|
|
58
|
-
]);
|
|
59
|
-
/** Top-level flow document — a single root node. */
|
|
60
|
-
export const FlowSchema = FlowNodeSchema;
|
|
61
|
-
//#endregion
|
|
62
|
-
//#region Public API
|
|
63
|
-
/** Validates a candidate flow document. Throws `ZodError` on invalid input. */
|
|
64
|
-
export function validateFlow(input) {
|
|
65
|
-
return FlowSchema.parse(input);
|
|
66
|
-
}
|
|
67
|
-
/** Walks a flow tree depth-first, yielding each node. */
|
|
68
|
-
export function* walkFlow(root) {
|
|
69
|
-
yield root;
|
|
70
|
-
if (root.kind === 'fork') {
|
|
71
|
-
for (const path of root.paths) {
|
|
72
|
-
yield* walkFlow(path);
|
|
73
|
-
}
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (root.kind === 'sequence') {
|
|
77
|
-
for (const step of root.steps) {
|
|
78
|
-
yield* walkFlow(step);
|
|
79
|
-
}
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (root.kind === 'spawn') {
|
|
83
|
-
yield* walkFlow(root.child);
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Returns the maximum depth of a flow tree. A leaf (llm/subagent) is depth 0.
|
|
89
|
-
* Structural nodes (sequence/fork/spawn) contribute +1 over their deepest child.
|
|
90
|
-
*/
|
|
91
|
-
export function flowDepth(node) {
|
|
92
|
-
if (node.kind === 'sequence') {
|
|
93
|
-
return 1 + Math.max(0, ...node.steps.map(flowDepth));
|
|
94
|
-
}
|
|
95
|
-
if (node.kind === 'fork') {
|
|
96
|
-
return 1 + Math.max(0, ...node.paths.map(flowDepth));
|
|
97
|
-
}
|
|
98
|
-
if (node.kind === 'spawn') {
|
|
99
|
-
return 1 + flowDepth(node.child);
|
|
100
|
-
}
|
|
101
|
-
return 0;
|
|
102
|
-
}
|
|
103
|
-
//#endregion
|
|
1
|
+
export { FlowSchema, flowDepth, validateFlow, walkFlow } from '../memory/flow-schema.js';
|