@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.
Files changed (254) hide show
  1. package/README.md +31 -11
  2. package/dist/adapters/in-memory-fs-adapter.d.ts +1 -1
  3. package/dist/adapters/in-memory-fs-adapter.js +1 -1
  4. package/dist/adapters/in-memory-shell-adapter.d.ts +1 -1
  5. package/dist/adapters/in-memory-subprocess/manifest-persistence.d.ts +8 -0
  6. package/dist/adapters/in-memory-subprocess/manifest-persistence.js +56 -0
  7. package/dist/adapters/in-memory-subprocess/metadata.d.ts +12 -0
  8. package/dist/adapters/in-memory-subprocess/metadata.js +58 -0
  9. package/dist/adapters/in-memory-subprocess/step-completion.d.ts +3 -0
  10. package/dist/adapters/in-memory-subprocess/step-completion.js +86 -0
  11. package/dist/adapters/in-memory-subprocess/types.d.ts +88 -0
  12. package/dist/adapters/in-memory-subprocess/types.js +2 -0
  13. package/dist/adapters/in-memory-subprocess-adapter.d.ts +12 -4
  14. package/dist/adapters/in-memory-subprocess-adapter.js +164 -55
  15. package/dist/adapters/openrouter.d.ts +16 -7
  16. package/dist/adapters/openrouter.js +68 -7
  17. package/dist/builders/channel-builder.d.ts +1 -1
  18. package/dist/builders/control-flow-builders.d.ts +3 -3
  19. package/dist/builders/control-flow-builders.js +9 -4
  20. package/dist/builders/every.d.ts +3 -3
  21. package/dist/builders/every.js +5 -2
  22. package/dist/builders/layer-provides-builders.d.ts +1 -32
  23. package/dist/builders/layer-provides-builders.js +1 -33
  24. package/dist/builders/loop-builder.d.ts +2 -2
  25. package/dist/builders/loop-builder.js +5 -2
  26. package/dist/builders/memory-builder.d.ts +1 -1
  27. package/dist/builders/memory-builder.js +1 -1
  28. package/dist/builders/provide-builder.d.ts +2 -2
  29. package/dist/builders/provide-builder.js +5 -2
  30. package/dist/builders/spawn-builder.d.ts +22 -9
  31. package/dist/builders/spawn-builder.js +17 -3
  32. package/dist/builders/step-builders.d.ts +51 -30
  33. package/dist/builders/step-builders.js +31 -12
  34. package/dist/builders/tool-builder.d.ts +7 -3
  35. package/dist/builders/tool-builder.js +3 -1
  36. package/dist/builders/workflow-hydrator.d.ts +38 -0
  37. package/dist/builders/workflow-hydrator.js +336 -0
  38. package/dist/conditions/conditions.d.ts +4 -4
  39. package/dist/conditions/conditions.js +2 -2
  40. package/dist/errors/noetic-error.d.ts +1 -1
  41. package/dist/errors/noetic-error.js +2 -0
  42. package/dist/{runtime → harness}/agent-harness.d.ts +65 -45
  43. package/dist/harness/agent-harness.js +576 -0
  44. package/dist/harness/deps/adapters.d.ts +4 -0
  45. package/dist/harness/deps/adapters.js +4 -0
  46. package/dist/harness/deps/interpreter.d.ts +5 -0
  47. package/dist/harness/deps/interpreter.js +4 -0
  48. package/dist/harness/deps/memory.d.ts +5 -0
  49. package/dist/harness/deps/memory.js +4 -0
  50. package/dist/harness/deps/runtime.d.ts +10 -0
  51. package/dist/harness/deps/runtime.js +7 -0
  52. package/dist/harness/deps/types.d.ts +17 -0
  53. package/dist/harness/deps/types.js +1 -0
  54. package/dist/harness/model-call.d.ts +50 -0
  55. package/dist/harness/model-call.js +694 -0
  56. package/dist/harness/model-schema.d.ts +19 -0
  57. package/dist/harness/model-schema.js +46 -0
  58. package/dist/harness/step-bootstrap.d.ts +25 -0
  59. package/dist/harness/step-bootstrap.js +170 -0
  60. package/dist/index.d.ts +114 -76
  61. package/dist/index.js +74 -50
  62. package/dist/internal-test.d.ts +4 -4
  63. package/dist/internal-test.js +4 -4
  64. package/dist/interpreter/action-deps.d.ts +12 -0
  65. package/dist/interpreter/action-deps.js +10 -0
  66. package/dist/interpreter/action-types.d.ts +8 -0
  67. package/dist/interpreter/action-types.js +1 -0
  68. package/dist/interpreter/collect-tools.d.ts +2 -2
  69. package/dist/interpreter/collect-tools.js +6 -2
  70. package/dist/interpreter/execute-action.d.ts +22 -0
  71. package/dist/interpreter/execute-action.js +527 -0
  72. package/dist/interpreter/{execute-every.d.ts → execute-control.d.ts} +8 -2
  73. package/dist/interpreter/execute-control.js +530 -0
  74. package/dist/interpreter/execute.d.ts +16 -3
  75. package/dist/interpreter/execute.js +154 -51
  76. package/dist/interpreter/message-helpers.d.ts +1 -9
  77. package/dist/interpreter/message-helpers.js +1 -42
  78. package/dist/interpreter/step-dispatcher.d.ts +61 -0
  79. package/dist/interpreter/step-dispatcher.js +67 -0
  80. package/dist/interpreter/typeguards.d.ts +8 -15
  81. package/dist/interpreter/typeguards.js +4 -21
  82. package/dist/memory/budget.d.ts +2 -2
  83. package/dist/memory/budget.js +1 -1
  84. package/dist/{runtime → memory}/exec-context-factory.d.ts +2 -2
  85. package/dist/{runtime → memory}/exec-context-factory.js +1 -1
  86. package/dist/memory/flow-schema.d.ts +52 -0
  87. package/dist/memory/flow-schema.js +102 -0
  88. package/dist/memory/function-call-utils.d.ts +1 -1
  89. package/dist/memory/function-call-utils.js +4 -2
  90. package/dist/memory/layer-api.d.ts +4 -4
  91. package/dist/memory/layer-api.js +2 -2
  92. package/dist/memory/layer-lifecycle.d.ts +6 -6
  93. package/dist/memory/layer-lifecycle.js +6 -6
  94. package/dist/memory/layer-provides.d.ts +32 -0
  95. package/dist/memory/layer-provides.js +33 -0
  96. package/dist/memory/layer-usage.d.ts +4 -3
  97. package/dist/memory/layer-usage.js +9 -3
  98. package/dist/memory/layers/durable-task-state.d.ts +8 -8
  99. package/dist/memory/layers/durable-task-state.js +2 -2
  100. package/dist/memory/layers/file-reference.d.ts +1 -1
  101. package/dist/memory/layers/file-reference.js +303 -247
  102. package/dist/memory/layers/history-window.d.ts +1 -1
  103. package/dist/memory/layers/history-window.js +4 -4
  104. package/dist/memory/layers/observational-memory.d.ts +5 -5
  105. package/dist/memory/layers/observational-memory.js +2 -3
  106. package/dist/memory/layers/plan.d.ts +2 -2
  107. package/dist/memory/layers/plan.js +15 -10
  108. package/dist/memory/layers/static-content.d.ts +2 -2
  109. package/dist/memory/layers/static-content.js +1 -1
  110. package/dist/memory/layers/steering.d.ts +7 -7
  111. package/dist/memory/layers/steering.js +5 -5
  112. package/dist/memory/layers/tool-memory-layer.d.ts +2 -2
  113. package/dist/memory/layers/tool-memory-layer.js +1 -1
  114. package/dist/memory/layers/working-memory.d.ts +7 -7
  115. package/dist/memory/layers/working-memory.js +4 -4
  116. package/dist/memory/projector.d.ts +2 -2
  117. package/dist/memory/scope.d.ts +1 -1
  118. package/dist/memory/strip-unresolved.d.ts +1 -1
  119. package/dist/observability/span-impl.d.ts +1 -1
  120. package/dist/observability/trace-exporter.d.ts +2 -2
  121. package/dist/observability/trace-exporter.js +1 -1
  122. package/dist/patterns/dynamic-workflow.d.ts +55 -0
  123. package/dist/patterns/dynamic-workflow.js +194 -0
  124. package/dist/patterns/flow.d.ts +2 -52
  125. package/dist/patterns/flow.js +1 -103
  126. package/dist/patterns/interview.d.ts +2 -2
  127. package/dist/patterns/interview.js +5 -5
  128. package/dist/patterns/plans.d.ts +6 -6
  129. package/dist/patterns/plans.js +4 -4
  130. package/dist/patterns/ralph-wiggum.d.ts +4 -4
  131. package/dist/patterns/ralph-wiggum.js +5 -5
  132. package/dist/patterns/react.d.ts +3 -3
  133. package/dist/patterns/react.js +5 -5
  134. package/dist/portable/adapters.d.ts +6 -0
  135. package/dist/portable/adapters.js +6 -0
  136. package/dist/portable/ask-user.d.ts +4 -0
  137. package/dist/portable/ask-user.js +2 -0
  138. package/dist/portable/builders.d.ts +12 -0
  139. package/dist/portable/builders.js +12 -0
  140. package/dist/portable/memory-layers.d.ts +12 -0
  141. package/dist/portable/memory-layers.js +12 -0
  142. package/dist/portable/runtime.d.ts +4 -0
  143. package/dist/portable/runtime.js +4 -0
  144. package/dist/portable/until.d.ts +4 -0
  145. package/dist/portable/until.js +4 -0
  146. package/dist/portable.d.ts +8 -26
  147. package/dist/portable.js +8 -34
  148. package/dist/runtime/broadcaster-utils.d.ts +7 -3
  149. package/dist/runtime/broadcaster-utils.js +11 -6
  150. package/dist/runtime/channel-store.d.ts +1 -1
  151. package/dist/runtime/channel-store.js +2 -2
  152. package/dist/runtime/context-deps.d.ts +4 -0
  153. package/dist/runtime/context-deps.js +2 -0
  154. package/dist/runtime/context-impl.d.ts +42 -12
  155. package/dist/runtime/context-impl.js +52 -5
  156. package/dist/runtime/context-type-deps.d.ts +14 -0
  157. package/dist/runtime/context-type-deps.js +1 -0
  158. package/dist/runtime/cwd-helpers.d.ts +1 -1
  159. package/dist/runtime/detached-handle.d.ts +52 -4
  160. package/dist/runtime/detached-handle.js +218 -14
  161. package/dist/runtime/durable/checkpoint-store.d.ts +38 -0
  162. package/dist/runtime/durable/checkpoint-store.js +101 -0
  163. package/dist/runtime/durable/detached-signal.d.ts +37 -0
  164. package/dist/runtime/durable/detached-signal.js +52 -0
  165. package/dist/runtime/durable/harness-checkpoints.d.ts +51 -0
  166. package/dist/runtime/durable/harness-checkpoints.js +104 -0
  167. package/dist/runtime/durable/index.d.ts +10 -0
  168. package/dist/runtime/durable/index.js +5 -0
  169. package/dist/runtime/durable/runnable-loop.d.ts +100 -0
  170. package/dist/runtime/durable/runnable-loop.js +90 -0
  171. package/dist/runtime/durable/session-seed.d.ts +28 -0
  172. package/dist/runtime/durable/session-seed.js +27 -0
  173. package/dist/runtime/durable/stall-nudge.d.ts +82 -0
  174. package/dist/runtime/durable/stall-nudge.js +87 -0
  175. package/dist/runtime/event-broadcaster.d.ts +1 -1
  176. package/dist/runtime/in-memory-storage.d.ts +1 -1
  177. package/dist/runtime/in-memory-storage.js +1 -1
  178. package/dist/runtime/item-log-impl.d.ts +3 -3
  179. package/dist/runtime/item-log-impl.js +1 -1
  180. package/dist/runtime/message-queue.d.ts +2 -2
  181. package/dist/runtime/session-runner.d.ts +7 -7
  182. package/dist/runtime/session-runner.js +3 -3
  183. package/dist/runtime/session-streams.d.ts +3 -3
  184. package/dist/runtime/session-streams.js +1 -1
  185. package/dist/runtime/step-registry.d.ts +42 -0
  186. package/dist/runtime/step-registry.js +77 -0
  187. package/dist/runtime/tool-memory.d.ts +3 -3
  188. package/dist/schemas/item.d.ts +1 -1
  189. package/dist/schemas/workflow.d.ts +139 -0
  190. package/dist/schemas/workflow.js +232 -0
  191. package/dist/types/ask-user-types.d.ts +57 -0
  192. package/dist/types/ask-user-types.js +74 -0
  193. package/dist/types/checkpoint.d.ts +98 -0
  194. package/dist/types/checkpoint.js +81 -0
  195. package/dist/types/common.d.ts +1 -50
  196. package/dist/types/context-parts/item-log.d.ts +6 -0
  197. package/dist/types/context-parts/item-log.js +1 -0
  198. package/dist/types/context-parts/layer-usage.d.ts +18 -0
  199. package/dist/types/context-parts/layer-usage.js +1 -0
  200. package/dist/types/context.d.ts +140 -31
  201. package/dist/types/error.d.ts +15 -0
  202. package/dist/types/harness-result.d.ts +2 -2
  203. package/dist/types/items.d.ts +18 -2
  204. package/dist/types/memory-context.d.ts +39 -0
  205. package/dist/types/memory-context.js +1 -0
  206. package/dist/types/memory.d.ts +38 -68
  207. package/dist/types/mutable-context.d.ts +3 -3
  208. package/dist/types/runtime.d.ts +14 -13
  209. package/dist/types/steering.d.ts +2 -2
  210. package/dist/types/step-registrar.d.ts +46 -0
  211. package/dist/types/step-registrar.js +56 -0
  212. package/dist/types/step.d.ts +34 -9
  213. package/dist/types/subprocess-adapter.d.ts +119 -3
  214. package/dist/types/subprocess-adapter.js +2 -0
  215. package/dist/types/tool-context.d.ts +6 -6
  216. package/dist/types/tool.d.ts +64 -0
  217. package/dist/types/tool.js +1 -0
  218. package/dist/unstable.d.ts +9 -9
  219. package/dist/unstable.js +7 -7
  220. package/dist/until/combinators.d.ts +1 -1
  221. package/dist/until/never.d.ts +1 -1
  222. package/dist/until/predicates.d.ts +13 -4
  223. package/dist/until/predicates.js +16 -2
  224. package/dist/util/message-helpers.d.ts +17 -0
  225. package/dist/util/message-helpers.js +64 -0
  226. package/package.json +6 -4
  227. package/dist/adapters/local-fs-adapter.d.ts +0 -3
  228. package/dist/adapters/local-fs-adapter.js +0 -43
  229. package/dist/adapters/local-shell-adapter.d.ts +0 -51
  230. package/dist/adapters/local-shell-adapter.js +0 -167
  231. package/dist/adapters/local-subprocess-adapter.d.ts +0 -16
  232. package/dist/adapters/local-subprocess-adapter.js +0 -187
  233. package/dist/conditions/index.d.ts +0 -3
  234. package/dist/conditions/index.js +0 -2
  235. package/dist/interpreter/execute-branch.d.ts +0 -3
  236. package/dist/interpreter/execute-branch.js +0 -10
  237. package/dist/interpreter/execute-every.js +0 -143
  238. package/dist/interpreter/execute-fork.d.ts +0 -3
  239. package/dist/interpreter/execute-fork.js +0 -215
  240. package/dist/interpreter/execute-llm.d.ts +0 -4
  241. package/dist/interpreter/execute-llm.js +0 -217
  242. package/dist/interpreter/execute-loop.d.ts +0 -3
  243. package/dist/interpreter/execute-loop.js +0 -171
  244. package/dist/interpreter/execute-provide.d.ts +0 -10
  245. package/dist/interpreter/execute-provide.js +0 -64
  246. package/dist/interpreter/execute-run.d.ts +0 -3
  247. package/dist/interpreter/execute-run.js +0 -39
  248. package/dist/interpreter/execute-spawn.d.ts +0 -11
  249. package/dist/interpreter/execute-spawn.js +0 -113
  250. package/dist/interpreter/execute-tool.d.ts +0 -5
  251. package/dist/interpreter/execute-tool.js +0 -81
  252. package/dist/runtime/agent-harness.js +0 -1170
  253. /package/dist/{interpreter → util}/framework-cast.d.ts +0 -0
  254. /package/dist/{interpreter → util}/framework-cast.js +0 -0
@@ -0,0 +1,42 @@
1
+ import type { ContextMemory } from '../types/memory.js';
2
+ import type { Step } from '../types/step.js';
3
+ /** Registry-wide step type — stored at the widest generic parameters so
4
+ * callers can register steps with narrower input/output types without
5
+ * fighting variance. The public `Step` default already uses `unknown` for
6
+ * the input and output parameters, matching this shape. */
7
+ type RegisteredStep = Step<ContextMemory, unknown, unknown>;
8
+ /**
9
+ * @public
10
+ * Registers a step so the subprocess adapter can look it up by id.
11
+ *
12
+ * Called automatically by the step builders when a `Step` is constructed.
13
+ * Policy: **latest registration wins**. Dispatch-and-lookup happen in the
14
+ * same tick, so the live entry is always the one the caller just built;
15
+ * cross-test pollution from bun's per-file process model (describe blocks
16
+ * rebuild the same step id) is not a safety concern here. Strict
17
+ * "reject duplicate id with a different body" detection + a test-side
18
+ * `clearRegistry` wiring is deferred — see the tracked follow-up task on
19
+ * the team's board (strict-registry-plus-test-clear).
20
+ */
21
+ export declare function registerStep<TMemory, I, O>(step: Step<TMemory, I, O>): void;
22
+ /**
23
+ * @public
24
+ * Looks up a registered step by id. Returns `null` when the id is not known
25
+ * — callers (e.g. the in-memory adapter's step dispatch path) translate the
26
+ * miss into a typed configuration error.
27
+ */
28
+ export declare function lookupStep(id: string): RegisteredStep | null;
29
+ /**
30
+ * @public
31
+ * Returns a read-only view over the registry. Primarily for tests and
32
+ * debugging; production callers should use `lookupStep`.
33
+ */
34
+ export declare function getRegistry(): ReadonlyMap<string, RegisteredStep>;
35
+ /**
36
+ * @public
37
+ * Clears the registry. Test-only helper — exported because several suites
38
+ * need a clean registry between describe blocks. Not part of the public API
39
+ * surface consumed by agent authors.
40
+ */
41
+ export declare function clearRegistry(): void;
42
+ export {};
@@ -0,0 +1,77 @@
1
+ import { NoeticConfigError } from '../errors/noetic-config-error.js';
2
+ import { setDefaultRegistrar } from '../types/step-registrar.js';
3
+ import { frameworkCast } from '../util/framework-cast.js';
4
+ //#endregion
5
+ //#region Module state
6
+ const registry = new Map();
7
+ //#endregion
8
+ //#region Public API
9
+ /**
10
+ * @public
11
+ * Registers a step so the subprocess adapter can look it up by id.
12
+ *
13
+ * Called automatically by the step builders when a `Step` is constructed.
14
+ * Policy: **latest registration wins**. Dispatch-and-lookup happen in the
15
+ * same tick, so the live entry is always the one the caller just built;
16
+ * cross-test pollution from bun's per-file process model (describe blocks
17
+ * rebuild the same step id) is not a safety concern here. Strict
18
+ * "reject duplicate id with a different body" detection + a test-side
19
+ * `clearRegistry` wiring is deferred — see the tracked follow-up task on
20
+ * the team's board (strict-registry-plus-test-clear).
21
+ */
22
+ export function registerStep(step) {
23
+ if (!step.id || step.id.trim() === '') {
24
+ throw new NoeticConfigError({
25
+ code: 'EMPTY_STEP_ID',
26
+ message: 'registerStep() requires a step with a non-empty id.',
27
+ hint: 'Set `id` on the step before constructing it.',
28
+ });
29
+ }
30
+ // `frameworkCast` is the approved single-point escape for generic variance:
31
+ // narrowing I/O from specific types to the registry's widened `unknown`
32
+ // shape is structurally safe at runtime because the registry only holds
33
+ // references and dispatches them through the same `execute()` pipeline.
34
+ const widened = frameworkCast(step);
35
+ registry.set(step.id, widened);
36
+ }
37
+ /**
38
+ * @public
39
+ * Looks up a registered step by id. Returns `null` when the id is not known
40
+ * — callers (e.g. the in-memory adapter's step dispatch path) translate the
41
+ * miss into a typed configuration error.
42
+ */
43
+ export function lookupStep(id) {
44
+ return registry.get(id) ?? null;
45
+ }
46
+ /**
47
+ * @public
48
+ * Returns a read-only view over the registry. Primarily for tests and
49
+ * debugging; production callers should use `lookupStep`.
50
+ */
51
+ export function getRegistry() {
52
+ return registry;
53
+ }
54
+ /**
55
+ * @public
56
+ * Clears the registry. Test-only helper — exported because several suites
57
+ * need a clean registry between describe blocks. Not part of the public API
58
+ * surface consumed by agent authors.
59
+ */
60
+ export function clearRegistry() {
61
+ registry.clear();
62
+ }
63
+ //#endregion
64
+ //#region Default-registrar installation
65
+ /**
66
+ * Install this module's `registerStep` as the runtime default registrar.
67
+ * Executes on first import — which happens transitively from
68
+ * `agent-harness.ts` and from anywhere that imports `@noetic-tools/core`'s
69
+ * top-level barrel. Builders call `getDefaultRegistrar().register(step)`
70
+ * from `../types/step-registrar` and get this concrete implementation
71
+ * without depending on `core-runtime` themselves (fixes the
72
+ * `core-primitives → core-runtime` layer_direction violations).
73
+ */
74
+ setDefaultRegistrar({
75
+ register: registerStep,
76
+ });
77
+ //#endregion
@@ -1,6 +1,6 @@
1
1
  import type { TurnContext } from '@openrouter/agent';
2
- import type { Context } from '../types/context';
3
- import type { AgentHarnessContract } from '../types/runtime';
4
- import type { ToolExecutionContext, ToolMemory } from '../types/tool-context';
2
+ import type { Context } from '../types/context.js';
3
+ import type { AgentHarnessContract } from '../types/runtime.js';
4
+ import type { ToolExecutionContext, ToolMemory } from '../types/tool-context.js';
5
5
  export declare function buildToolMemory(harness: AgentHarnessContract, ctx: Context): ToolMemory;
6
6
  export declare function buildToolExecutionContext(ctx: Context, harness: AgentHarnessContract, turnContext?: TurnContext): ToolExecutionContext;
@@ -13,7 +13,7 @@
13
13
  * don't need to re-validate every provider field TypeScript already types.
14
14
  */
15
15
  import { z } from 'zod';
16
- import type { Item, ItemSchemaExtensions } from '../types/items';
16
+ import type { Item, ItemSchemaExtensions } from '../types/items.js';
17
17
  /** @public Structural validator for `Item`. Asserts non-empty string `type` discriminant. */
18
18
  export declare const ItemSchema: z.ZodCustom<Item, Item>;
19
19
  type ItemSchemaCategory = keyof Required<ItemSchemaExtensions>;
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Zod schemas for JSON-serialisable workflow definitions.
3
+ *
4
+ * A `WorkflowDocument` is a portable, JSON-safe representation of a noetic
5
+ * step tree. It covers every step kind except `run` (which carries arbitrary
6
+ * closures). The hydrator in `builders/workflow-hydrator.ts` converts a
7
+ * validated document back into live `Step` objects via the existing builders.
8
+ */
9
+ import { z } from 'zod';
10
+ interface UntilAnyPredicate {
11
+ kind: 'any';
12
+ predicates: UntilPredicate[];
13
+ }
14
+ interface UntilAllPredicate {
15
+ kind: 'all';
16
+ predicates: UntilPredicate[];
17
+ }
18
+ /** @public Discriminated union of named until predicates usable in JSON workflows. */
19
+ export type UntilPredicate = {
20
+ kind: 'maxSteps';
21
+ n: number;
22
+ } | {
23
+ kind: 'maxCost';
24
+ usd: number;
25
+ } | {
26
+ kind: 'maxDuration';
27
+ ms: number;
28
+ } | {
29
+ kind: 'noToolCalls';
30
+ } | {
31
+ kind: 'outputContains';
32
+ marker: string;
33
+ } | {
34
+ kind: 'outputEquals';
35
+ sentinel: string;
36
+ } | {
37
+ kind: 'converged';
38
+ threshold?: number;
39
+ } | UntilAnyPredicate | UntilAllPredicate;
40
+ /** @public Zod schema validating a named `until` predicate (including `any`/`all` combinators). */
41
+ export declare const UntilPredicateSchema: z.ZodType<UntilPredicate>;
42
+ /** @public ESM literal enum for merge strategies. */
43
+ export declare const MergeStrategy: {
44
+ readonly Last: "last";
45
+ readonly First: "first";
46
+ readonly Concat: "concat";
47
+ };
48
+ /** @public Named merge strategy for fork nodes. */
49
+ export type MergeStrategy = (typeof MergeStrategy)[keyof typeof MergeStrategy];
50
+ /** @public Zod schema for the named merge strategy used by `fork` nodes. */
51
+ export declare const MergeStrategySchema: z.ZodEnum<{
52
+ concat: "concat";
53
+ last: "last";
54
+ first: "first";
55
+ }>;
56
+ declare const ModelParamsSchema: z.ZodObject<{
57
+ temperature: z.ZodOptional<z.ZodNumber>;
58
+ topP: z.ZodOptional<z.ZodNumber>;
59
+ maxTokens: z.ZodOptional<z.ZodNumber>;
60
+ stopSequences: z.ZodOptional<z.ZodArray<z.ZodString>>;
61
+ }, z.core.$strip>;
62
+ interface WorkflowNodeBase {
63
+ id: string;
64
+ }
65
+ export interface LlmWorkflowNode extends WorkflowNodeBase {
66
+ kind: 'llm';
67
+ model?: string;
68
+ instructions: string;
69
+ tools?: string[];
70
+ params?: z.infer<typeof ModelParamsSchema>;
71
+ }
72
+ export interface ToolWorkflowNode extends WorkflowNodeBase {
73
+ kind: 'tool';
74
+ toolName: string;
75
+ args?: Record<string, unknown>;
76
+ }
77
+ export interface BranchRoute {
78
+ match: string;
79
+ target: WorkflowNode;
80
+ }
81
+ export interface BranchWorkflowNode extends WorkflowNodeBase {
82
+ kind: 'branch';
83
+ routes: BranchRoute[];
84
+ default?: WorkflowNode;
85
+ }
86
+ export interface ForkWorkflowNode extends WorkflowNodeBase {
87
+ kind: 'fork';
88
+ mode: 'race' | 'all' | 'settle';
89
+ paths: WorkflowNode[];
90
+ merge?: MergeStrategy;
91
+ concurrency?: number;
92
+ }
93
+ export interface SpawnWorkflowNode extends WorkflowNodeBase {
94
+ kind: 'spawn';
95
+ child: WorkflowNode;
96
+ timeout?: number;
97
+ }
98
+ export interface ProvideWorkflowNode extends WorkflowNodeBase {
99
+ kind: 'provide';
100
+ child: WorkflowNode;
101
+ layers: string[];
102
+ }
103
+ export interface LoopWorkflowNode extends WorkflowNodeBase {
104
+ kind: 'loop';
105
+ body: WorkflowNode;
106
+ until: UntilPredicate;
107
+ maxIterations?: number;
108
+ }
109
+ export interface SequenceWorkflowNode extends WorkflowNodeBase {
110
+ kind: 'sequence';
111
+ steps: WorkflowNode[];
112
+ }
113
+ export interface EveryWorkflowNode extends WorkflowNodeBase {
114
+ kind: 'every';
115
+ step: WorkflowNode;
116
+ ms: number;
117
+ onError?: 'continue' | 'fail';
118
+ }
119
+ /** @public Discriminated union of all JSON-serialisable workflow node kinds. */
120
+ export type WorkflowNode = LlmWorkflowNode | ToolWorkflowNode | BranchWorkflowNode | ForkWorkflowNode | SpawnWorkflowNode | ProvideWorkflowNode | LoopWorkflowNode | SequenceWorkflowNode | EveryWorkflowNode;
121
+ /** @public Zod schema validating a single `WorkflowNode` (any of the 9 JSON-safe kinds). */
122
+ export declare const WorkflowNodeSchema: z.ZodType<WorkflowNode>;
123
+ /** @public Top-level envelope for a JSON workflow definition. */
124
+ export interface WorkflowDocument {
125
+ version: 1;
126
+ root: WorkflowNode;
127
+ }
128
+ /** @public Zod schema validating a complete `WorkflowDocument`. */
129
+ export declare const WorkflowDocumentSchema: z.ZodType<WorkflowDocument>;
130
+ /** Validates a candidate workflow document. Throws `ZodError` on invalid input. */
131
+ export declare function validateWorkflow(input: unknown): WorkflowDocument;
132
+ /** Walks a workflow tree depth-first, yielding each node. */
133
+ export declare function walkWorkflow(node: WorkflowNode): Iterable<WorkflowNode>;
134
+ /**
135
+ * Returns the maximum depth of a workflow tree.
136
+ * Leaf nodes (`llm`, `tool`) have depth 0. Structural nodes add +1.
137
+ */
138
+ export declare function workflowDepth(node: WorkflowNode): number;
139
+ export {};
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Zod schemas for JSON-serialisable workflow definitions.
3
+ *
4
+ * A `WorkflowDocument` is a portable, JSON-safe representation of a noetic
5
+ * step tree. It covers every step kind except `run` (which carries arbitrary
6
+ * closures). The hydrator in `builders/workflow-hydrator.ts` converts a
7
+ * validated document back into live `Step` objects via the existing builders.
8
+ */
9
+ import { z } from 'zod';
10
+ //#endregion
11
+ //#region Until Predicate Schemas
12
+ const MaxStepsPredicateSchema = z.object({
13
+ kind: z.literal('maxSteps'),
14
+ n: z.number().int().positive(),
15
+ });
16
+ const MaxCostPredicateSchema = z.object({
17
+ kind: z.literal('maxCost'),
18
+ usd: z.number().positive(),
19
+ });
20
+ const MaxDurationPredicateSchema = z.object({
21
+ kind: z.literal('maxDuration'),
22
+ ms: z.number().positive(),
23
+ });
24
+ const NoToolCallsPredicateSchema = z.object({
25
+ kind: z.literal('noToolCalls'),
26
+ });
27
+ const OutputContainsPredicateSchema = z.object({
28
+ kind: z.literal('outputContains'),
29
+ marker: z.string().min(1),
30
+ });
31
+ const OutputEqualsPredicateSchema = z.object({
32
+ kind: z.literal('outputEquals'),
33
+ sentinel: z.string().min(1),
34
+ });
35
+ const ConvergedPredicateSchema = z.object({
36
+ kind: z.literal('converged'),
37
+ threshold: z.number().min(0).max(1).optional(),
38
+ });
39
+ const UntilPredicateRef = z.lazy(() => UntilPredicateSchema);
40
+ const AnyPredicateSchema = z.object({
41
+ kind: z.literal('any'),
42
+ predicates: z.array(UntilPredicateRef).min(1),
43
+ });
44
+ const AllPredicateSchema = z.object({
45
+ kind: z.literal('all'),
46
+ predicates: z.array(UntilPredicateRef).min(1),
47
+ });
48
+ /** @public Zod schema validating a named `until` predicate (including `any`/`all` combinators). */
49
+ export const UntilPredicateSchema = z.union([
50
+ MaxStepsPredicateSchema,
51
+ MaxCostPredicateSchema,
52
+ MaxDurationPredicateSchema,
53
+ NoToolCallsPredicateSchema,
54
+ OutputContainsPredicateSchema,
55
+ OutputEqualsPredicateSchema,
56
+ ConvergedPredicateSchema,
57
+ AnyPredicateSchema,
58
+ AllPredicateSchema,
59
+ ]);
60
+ //#endregion
61
+ //#region Merge Strategy
62
+ /** @public ESM literal enum for merge strategies. */
63
+ export const MergeStrategy = {
64
+ Last: 'last',
65
+ First: 'first',
66
+ Concat: 'concat',
67
+ };
68
+ /** @public Zod schema for the named merge strategy used by `fork` nodes. */
69
+ export const MergeStrategySchema = z.enum([
70
+ 'last',
71
+ 'first',
72
+ 'concat',
73
+ ]);
74
+ //#endregion
75
+ //#region Model Params
76
+ const ModelParamsSchema = z.object({
77
+ temperature: z.number().min(0).optional(),
78
+ topP: z.number().min(0).max(1).optional(),
79
+ maxTokens: z.number().int().positive().optional(),
80
+ stopSequences: z.array(z.string()).optional(),
81
+ });
82
+ //#endregion
83
+ //#region Workflow Node Schema
84
+ const WorkflowNodeRef = z.lazy(() => WorkflowNodeSchema);
85
+ const SHARED_FIELDS = {
86
+ id: z.string().min(1),
87
+ };
88
+ const LlmNodeSchema = z.object({
89
+ kind: z.literal('llm'),
90
+ ...SHARED_FIELDS,
91
+ model: z.string().optional(),
92
+ instructions: z.string(),
93
+ tools: z.array(z.string()).optional(),
94
+ params: ModelParamsSchema.optional(),
95
+ });
96
+ const ToolNodeSchema = z.object({
97
+ kind: z.literal('tool'),
98
+ ...SHARED_FIELDS,
99
+ toolName: z.string().min(1),
100
+ args: z.record(z.string(), z.unknown()).optional(),
101
+ });
102
+ const BranchRouteSchema = z.object({
103
+ match: z.string().min(1),
104
+ target: z.lazy(() => WorkflowNodeSchema),
105
+ });
106
+ const BranchNodeSchema = z.object({
107
+ kind: z.literal('branch'),
108
+ ...SHARED_FIELDS,
109
+ routes: z.array(BranchRouteSchema).min(1),
110
+ default: WorkflowNodeRef.optional(),
111
+ });
112
+ const ForkNodeSchema = z.object({
113
+ kind: z.literal('fork'),
114
+ ...SHARED_FIELDS,
115
+ mode: z.enum([
116
+ 'race',
117
+ 'all',
118
+ 'settle',
119
+ ]),
120
+ paths: z.array(WorkflowNodeRef).min(1),
121
+ merge: MergeStrategySchema.optional(),
122
+ concurrency: z.number().int().positive().optional(),
123
+ });
124
+ const SpawnNodeSchema = z.object({
125
+ kind: z.literal('spawn'),
126
+ ...SHARED_FIELDS,
127
+ child: WorkflowNodeRef,
128
+ timeout: z.number().positive().optional(),
129
+ });
130
+ const ProvideNodeSchema = z.object({
131
+ kind: z.literal('provide'),
132
+ ...SHARED_FIELDS,
133
+ child: WorkflowNodeRef,
134
+ layers: z.array(z.string().min(1)).min(1),
135
+ });
136
+ const LoopNodeSchema = z.object({
137
+ kind: z.literal('loop'),
138
+ ...SHARED_FIELDS,
139
+ body: WorkflowNodeRef,
140
+ until: UntilPredicateSchema,
141
+ maxIterations: z.number().int().positive().optional(),
142
+ });
143
+ const SequenceNodeSchema = z.object({
144
+ kind: z.literal('sequence'),
145
+ ...SHARED_FIELDS,
146
+ steps: z.array(WorkflowNodeRef).min(1),
147
+ });
148
+ const EveryNodeSchema = z.object({
149
+ kind: z.literal('every'),
150
+ ...SHARED_FIELDS,
151
+ step: WorkflowNodeRef,
152
+ ms: z.number().nonnegative(),
153
+ onError: z
154
+ .enum([
155
+ 'continue',
156
+ 'fail',
157
+ ])
158
+ .optional(),
159
+ });
160
+ /** @public Zod schema validating a single `WorkflowNode` (any of the 9 JSON-safe kinds). */
161
+ export const WorkflowNodeSchema = z.discriminatedUnion('kind', [
162
+ LlmNodeSchema,
163
+ ToolNodeSchema,
164
+ BranchNodeSchema,
165
+ ForkNodeSchema,
166
+ SpawnNodeSchema,
167
+ ProvideNodeSchema,
168
+ LoopNodeSchema,
169
+ SequenceNodeSchema,
170
+ EveryNodeSchema,
171
+ ]);
172
+ /** @public Zod schema validating a complete `WorkflowDocument`. */
173
+ export const WorkflowDocumentSchema = z.object({
174
+ version: z.literal(1),
175
+ root: WorkflowNodeSchema,
176
+ });
177
+ //#endregion
178
+ //#region Helpers
179
+ /** Returns the direct child nodes of a workflow node. Leaf nodes return an empty array. */
180
+ function childNodes(node) {
181
+ switch (node.kind) {
182
+ case 'sequence':
183
+ return node.steps;
184
+ case 'fork':
185
+ return node.paths;
186
+ case 'spawn':
187
+ case 'provide':
188
+ return [
189
+ node.child,
190
+ ];
191
+ case 'loop':
192
+ return [
193
+ node.body,
194
+ ];
195
+ case 'every':
196
+ return [
197
+ node.step,
198
+ ];
199
+ case 'branch': {
200
+ const children = node.routes.map((r) => r.target);
201
+ if (node.default) {
202
+ children.push(node.default);
203
+ }
204
+ return children;
205
+ }
206
+ default:
207
+ return [];
208
+ }
209
+ }
210
+ /** Validates a candidate workflow document. Throws `ZodError` on invalid input. */
211
+ export function validateWorkflow(input) {
212
+ return WorkflowDocumentSchema.parse(input);
213
+ }
214
+ /** Walks a workflow tree depth-first, yielding each node. */
215
+ export function* walkWorkflow(node) {
216
+ yield node;
217
+ for (const child of childNodes(node)) {
218
+ yield* walkWorkflow(child);
219
+ }
220
+ }
221
+ /**
222
+ * Returns the maximum depth of a workflow tree.
223
+ * Leaf nodes (`llm`, `tool`) have depth 0. Structural nodes add +1.
224
+ */
225
+ export function workflowDepth(node) {
226
+ const children = childNodes(node);
227
+ if (children.length === 0) {
228
+ return 0;
229
+ }
230
+ return 1 + Math.max(0, ...children.map(workflowDepth));
231
+ }
232
+ //#endregion
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Wire schemas + types for the ask-user pattern.
3
+ *
4
+ * The "ask-user" shape is a portable, tool-agnostic description of an
5
+ * interactive prompt (questions + options + answers) that any UI — in-process
6
+ * TUI modal, IPC-backed runner, future web renderer — can render and
7
+ * respond to. The schemas live in core so callers on either side of an
8
+ * adapter (tool author, TUI, IPC protocol) validate against the same
9
+ * definitions rather than each package maintaining a drift-prone copy.
10
+ *
11
+ * Kept separate from a concrete tool factory so the TUI can import the
12
+ * types without pulling in a tool that closes over an `AskUserService`.
13
+ */
14
+ import { z } from 'zod';
15
+ export declare const AskUserOptionSchema: z.ZodObject<{
16
+ label: z.ZodString;
17
+ description: z.ZodString;
18
+ preview: z.ZodOptional<z.ZodString>;
19
+ }, z.core.$strip>;
20
+ export declare const AskUserQuestionSchema: z.ZodObject<{
21
+ question: z.ZodString;
22
+ header: z.ZodString;
23
+ options: z.ZodArray<z.ZodObject<{
24
+ label: z.ZodString;
25
+ description: z.ZodString;
26
+ preview: z.ZodOptional<z.ZodString>;
27
+ }, z.core.$strip>>;
28
+ multiSelect: z.ZodDefault<z.ZodBoolean>;
29
+ }, z.core.$strip>;
30
+ export declare const AskUserInputSchema: z.ZodObject<{
31
+ questions: z.ZodArray<z.ZodObject<{
32
+ question: z.ZodString;
33
+ header: z.ZodString;
34
+ options: z.ZodArray<z.ZodObject<{
35
+ label: z.ZodString;
36
+ description: z.ZodString;
37
+ preview: z.ZodOptional<z.ZodString>;
38
+ }, z.core.$strip>>;
39
+ multiSelect: z.ZodDefault<z.ZodBoolean>;
40
+ }, z.core.$strip>>;
41
+ }, z.core.$strip>;
42
+ export declare const AskUserAnnotationSchema: z.ZodObject<{
43
+ notes: z.ZodOptional<z.ZodString>;
44
+ preview: z.ZodOptional<z.ZodString>;
45
+ }, z.core.$strip>;
46
+ export declare const AskUserOutputSchema: z.ZodObject<{
47
+ answers: z.ZodRecord<z.ZodString, z.ZodString>;
48
+ annotations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
49
+ notes: z.ZodOptional<z.ZodString>;
50
+ preview: z.ZodOptional<z.ZodString>;
51
+ }, z.core.$strip>>>;
52
+ }, z.core.$strip>;
53
+ export type AskUserOption = z.infer<typeof AskUserOptionSchema>;
54
+ export type AskUserQuestion = z.infer<typeof AskUserQuestionSchema>;
55
+ export type AskUserInput = z.infer<typeof AskUserInputSchema>;
56
+ export type AskUserAnnotation = z.infer<typeof AskUserAnnotationSchema>;
57
+ export type AskUserOutput = z.infer<typeof AskUserOutputSchema>;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Wire schemas + types for the ask-user pattern.
3
+ *
4
+ * The "ask-user" shape is a portable, tool-agnostic description of an
5
+ * interactive prompt (questions + options + answers) that any UI — in-process
6
+ * TUI modal, IPC-backed runner, future web renderer — can render and
7
+ * respond to. The schemas live in core so callers on either side of an
8
+ * adapter (tool author, TUI, IPC protocol) validate against the same
9
+ * definitions rather than each package maintaining a drift-prone copy.
10
+ *
11
+ * Kept separate from a concrete tool factory so the TUI can import the
12
+ * types without pulling in a tool that closes over an `AskUserService`.
13
+ */
14
+ import { z } from 'zod';
15
+ //#region Schemas
16
+ export const AskUserOptionSchema = z.object({
17
+ label: z.string().min(1).describe('The display text for this option. Concise (1–5 words).'),
18
+ description: z
19
+ .string()
20
+ .describe('Explanation of what this option means or what will happen if chosen.'),
21
+ preview: z
22
+ .string()
23
+ .optional()
24
+ .describe('Optional preview content rendered when this option is focused. Markdown (or HTML fragment) for side-by-side visual comparison.'),
25
+ });
26
+ export const AskUserQuestionSchema = z.object({
27
+ question: z
28
+ .string()
29
+ .min(1)
30
+ .describe('The complete question. Should be clear, specific, and end with a question mark.'),
31
+ header: z
32
+ .string()
33
+ .min(1)
34
+ .max(12)
35
+ .describe('Very short label displayed as a chip/tag (1–12 chars, inclusive).'),
36
+ options: z
37
+ .array(AskUserOptionSchema)
38
+ .min(2)
39
+ .max(4)
40
+ .describe('2–4 distinct choices. An "Other" option is added automatically.'),
41
+ multiSelect: z
42
+ .boolean()
43
+ .default(false)
44
+ .describe('When true, users may select multiple options for this question.'),
45
+ });
46
+ export const AskUserInputSchema = z.object({
47
+ questions: z
48
+ .array(AskUserQuestionSchema)
49
+ .min(1)
50
+ .max(4)
51
+ .describe('1–4 questions to ask the user.')
52
+ // Question text doubles as the answers-map key. Two questions with the
53
+ // same text would silently collapse, so reject duplicates at parse time.
54
+ .refine((qs) => new Set(qs.map((q) => q.question)).size === qs.length, {
55
+ message: 'Question texts must be unique — duplicates would collapse in the answers map.',
56
+ }),
57
+ });
58
+ export const AskUserAnnotationSchema = z.object({
59
+ notes: z.string().optional().describe('Free-text notes the user added to their selection.'),
60
+ preview: z
61
+ .string()
62
+ .optional()
63
+ .describe('The preview content of the selected option, if the question used previews.'),
64
+ });
65
+ export const AskUserOutputSchema = z.object({
66
+ answers: z
67
+ .record(z.string(), z.string())
68
+ .describe('Map from question text to the user\'s answer (label or custom "Other" text).'),
69
+ annotations: z
70
+ .record(z.string(), AskUserAnnotationSchema)
71
+ .optional()
72
+ .describe('Optional per-question annotations (preview content of selected option, notes).'),
73
+ });
74
+ //#endregion