@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
@@ -1,10 +1,11 @@
1
1
  import type * as OpenRouterAgent from '@openrouter/agent';
2
- import type { LLMResponse, Tool } from '../types/common';
3
- import type { Context } from '../types/context';
4
- import type { EmbedFn } from '../types/embed';
5
- import type { Item } from '../types/items';
6
- import type { MemoryLayer } from '../types/memory';
7
- import type { AgentHarnessContract } from '../types/runtime';
2
+ import type { LLMResponse } from '../types/common.js';
3
+ import type { Context } from '../types/context.js';
4
+ import type { EmbedFn } from '../types/embed.js';
5
+ import type { Item } from '../types/items.js';
6
+ import type { MemoryLayer } from '../types/memory.js';
7
+ import type { AgentHarnessContract } from '../types/runtime.js';
8
+ import type { Tool } from '../types/tool.js';
8
9
  type ProviderOutputItem = OpenRouterAgent.OpenResponsesResult['output'][number];
9
10
  type OpenRouterInputItem = OpenRouterAgent.EasyInputMessage | OpenRouterAgent.FunctionCallItem | OpenRouterAgent.FunctionCallOutputItem | ProviderOutputItem;
10
11
  /** @internal */
@@ -28,6 +29,14 @@ export declare function itemsToInput(items: ReadonlyArray<Item>): OpenRouterInpu
28
29
  export declare function extractOutputItems(response: OpenRouterAgent.OpenResponsesResult): Item[];
29
30
  /** @internal */
30
31
  export declare function extractUsage(usage: OpenRouterAgent.Usage | null | undefined): LLMResponse['usage'];
32
+ /**
33
+ * Provider APIs (Anthropic via OpenRouter) enforce tool names match
34
+ * `^[a-zA-Z0-9_-]{1,64}$`. Noetic's internal layer-tool names use `layerId/fn`
35
+ * which contains a forbidden `/`. We translate to a wire-safe form only at
36
+ * the SDK boundary; internal tool-name identity (and every codebase reference
37
+ * to names like `plan/updatePrd`) is preserved.
38
+ */
39
+ export declare function sanitizeToolNameForWire(name: string): string;
31
40
  /** @internal */
32
41
  export declare function convertTools({ tools }: ConvertToolsParams): SdkTool[];
33
42
  /** @internal */
@@ -53,5 +62,5 @@ export declare function executeToolCall(params: ExecuteToolCallParams): Promise<
53
62
  * @param embeddingModel - Model identifier (default: `'openai/text-embedding-3-small'`).
54
63
  * @returns An `EmbedFn` that produces embedding vectors for the given texts.
55
64
  */
56
- export declare function createOpenRouterEmbed(apiKey: string, embeddingModel?: string): EmbedFn;
65
+ export declare function createOpenRouterEmbed(apiKey?: string, embeddingModel?: string): EmbedFn;
57
66
  export {};
@@ -1,8 +1,9 @@
1
1
  import { z } from 'zod';
2
- import { frameworkCast } from '../interpreter/framework-cast';
3
- import { isAssistantMessage } from '../interpreter/typeguards';
4
- import { buildToolExecutionContext } from '../runtime/tool-memory';
5
- import { SteeringAction } from '../types/steering';
2
+ import { NoeticConfigError } from '../errors/noetic-config-error.js';
3
+ import { buildToolExecutionContext } from '../runtime/tool-memory.js';
4
+ import { SteeringAction } from '../types/steering.js';
5
+ import { frameworkCast } from '../util/framework-cast.js';
6
+ import { isAssistantMessage } from '../util/message-helpers.js';
6
7
  const EmbeddingsResponseSchema = z.object({
7
8
  data: z.array(z.object({
8
9
  embedding: z.array(z.number()),
@@ -20,6 +21,44 @@ function contentPartsToText(parts) {
20
21
  .map((p) => p.text)
21
22
  .join('');
22
23
  }
24
+ function inputTextPartToProvider(part) {
25
+ return {
26
+ type: 'input_text',
27
+ text: part.text,
28
+ };
29
+ }
30
+ function inputImagePartToProvider(part) {
31
+ return {
32
+ type: 'input_image',
33
+ imageUrl: part.imageUrl,
34
+ detail: part.detail ?? 'auto',
35
+ };
36
+ }
37
+ function inputFilePartToProvider(part) {
38
+ return {
39
+ type: 'input_file',
40
+ filename: part.filename,
41
+ fileData: part.fileData,
42
+ fileUrl: part.fileUrl,
43
+ fileId: part.fileId,
44
+ };
45
+ }
46
+ function inputContentPartToProvider(part) {
47
+ if (part.type === 'input_text') {
48
+ return inputTextPartToProvider(part);
49
+ }
50
+ if (part.type === 'input_image') {
51
+ return inputImagePartToProvider(part);
52
+ }
53
+ return inputFilePartToProvider(part);
54
+ }
55
+ function contentPartsToProviderContent(parts) {
56
+ const hasStructuredInput = parts.some((part) => part.type === 'input_image' || part.type === 'input_file');
57
+ if (!hasStructuredInput) {
58
+ return contentPartsToText(parts);
59
+ }
60
+ return frameworkCast(parts).map(inputContentPartToProvider);
61
+ }
23
62
  //#endregion
24
63
  //#region Item → OpenRouter Input Conversion
25
64
  /** @internal Extracts system messages from items and returns them as a single instructions string. */
@@ -51,7 +90,7 @@ function itemToInputItem(item) {
51
90
  // because the SDK's input union does not accept ResponsesOutputMessage directly.
52
91
  return {
53
92
  role: item.role,
54
- content: contentPartsToText(item.content),
93
+ content: contentPartsToProviderContent(item.content),
55
94
  };
56
95
  }
57
96
  if (item.type === 'function_call') {
@@ -141,12 +180,22 @@ export function extractUsage(usage) {
141
180
  // This prevents the SDK from handling tool calls internally, which would
142
181
  // make tool interactions invisible to Noetic's itemLog, token tracking,
143
182
  // and observability. Instead, the AgentHarness manages the tool loop.
183
+ /**
184
+ * Provider APIs (Anthropic via OpenRouter) enforce tool names match
185
+ * `^[a-zA-Z0-9_-]{1,64}$`. Noetic's internal layer-tool names use `layerId/fn`
186
+ * which contains a forbidden `/`. We translate to a wire-safe form only at
187
+ * the SDK boundary; internal tool-name identity (and every codebase reference
188
+ * to names like `plan/updatePrd`) is preserved.
189
+ */
190
+ export function sanitizeToolNameForWire(name) {
191
+ return name.replace(/[^a-zA-Z0-9_-]/g, '_');
192
+ }
144
193
  /** @internal */
145
194
  export function convertTools({ tools }) {
146
195
  return tools.map((t) => frameworkCast({
147
196
  type: 'function',
148
197
  function: {
149
- name: t.name,
198
+ name: sanitizeToolNameForWire(t.name),
150
199
  description: t.description,
151
200
  inputSchema: t.input,
152
201
  },
@@ -171,7 +220,12 @@ async function consumeGenerator(generator) {
171
220
  }
172
221
  /** @internal Execute a single tool call with steering checks. */
173
222
  export async function executeToolCall(params) {
174
- const matchedTool = params.tools.find((t) => t.name === params.toolName);
223
+ // Model sees sanitised tool names (see `sanitizeToolNameForWire`). Match
224
+ // against both the original and sanitised name so internal identity (e.g.
225
+ // `plan/updatePrd` used by steering whitelists, skill docs, and the
226
+ // `planMemory.beforeToolCall` hook) stays intact while the wire name is
227
+ // provider-compliant.
228
+ const matchedTool = params.tools.find((t) => t.name === params.toolName || sanitizeToolNameForWire(t.name) === params.toolName);
175
229
  if (!matchedTool) {
176
230
  return {
177
231
  output: `Error: unknown tool '${params.toolName}'`,
@@ -223,6 +277,13 @@ export async function executeToolCall(params) {
223
277
  * @returns An `EmbedFn` that produces embedding vectors for the given texts.
224
278
  */
225
279
  export function createOpenRouterEmbed(apiKey, embeddingModel) {
280
+ if (!apiKey) {
281
+ throw new NoeticConfigError({
282
+ code: 'MISSING_API_KEY',
283
+ message: 'createOpenRouterEmbed() requires an OpenRouter API key.',
284
+ hint: 'Pass the key explicitly, e.g. createOpenRouterEmbed(process.env.OPENROUTER_API_KEY).',
285
+ });
286
+ }
226
287
  const model = embeddingModel ?? 'openai/text-embedding-3-small';
227
288
  return async (texts) => {
228
289
  const response = await fetch('https://openrouter.ai/api/v1/embeddings', {
@@ -1,5 +1,5 @@
1
1
  import type { ZodType } from 'zod';
2
- import type { Channel, ExternalChannel } from '../types/channel';
2
+ import type { Channel, ExternalChannel } from '../types/channel.js';
3
3
  /**
4
4
  * Creates a typed communication channel writable from outside the execution tree.
5
5
  *
@@ -1,6 +1,6 @@
1
- import type { Context } from '../types/context';
2
- import type { ContextMemory } from '../types/memory';
3
- import type { SettleResult, Step, StepBranch, StepForkAll, StepForkRace, StepForkSettle } from '../types/step';
1
+ import type { Context } from '../types/context.js';
2
+ import type { ContextMemory } from '../types/memory.js';
3
+ import type { SettleResult, Step, StepBranch, StepForkAll, StepForkRace, StepForkSettle } from '../types/step.js';
4
4
  /**
5
5
  * Creates a parallel execution step that races paths and returns the first result.
6
6
  *
@@ -1,5 +1,6 @@
1
- import { NoeticConfigError } from '../errors/noetic-config-error';
2
- import { frameworkCast } from '../interpreter/framework-cast';
1
+ import { NoeticConfigError } from '../errors/noetic-config-error.js';
2
+ import { getDefaultRegistrar } from '../types/step-registrar.js';
3
+ import { frameworkCast } from '../util/framework-cast.js';
3
4
  export function fork(opts) {
4
5
  if (!opts.id || opts.id.trim() === '') {
5
6
  throw new NoeticConfigError({
@@ -15,10 +16,12 @@ export function fork(opts) {
15
16
  hint: 'Provide a merge function that combines path results into a single output.',
16
17
  });
17
18
  }
18
- return frameworkCast({
19
+ const built = frameworkCast({
19
20
  kind: 'fork',
20
21
  ...opts,
21
22
  });
23
+ getDefaultRegistrar().register(built);
24
+ return built;
22
25
  }
23
26
  /**
24
27
  * Creates a conditional routing step that selects the next step at runtime.
@@ -46,8 +49,10 @@ export function branch(opts) {
46
49
  hint: 'Provide a route function that selects the next step at runtime.',
47
50
  });
48
51
  }
49
- return {
52
+ const built = {
50
53
  kind: 'branch',
51
54
  ...opts,
52
55
  };
56
+ getDefaultRegistrar().register(built);
57
+ return built;
53
58
  }
@@ -1,6 +1,6 @@
1
- import type { Channel } from '../types/channel';
2
- import type { ContextMemory } from '../types/memory';
3
- import type { EveryErrorPolicy, Step, StepEvery } from '../types/step';
1
+ import type { Channel } from '../types/channel.js';
2
+ import type { ContextMemory } from '../types/memory.js';
3
+ import type { EveryErrorPolicy, Step, StepEvery } from '../types/step.js';
4
4
  /**
5
5
  * Configuration options accepted by the `every()` builder, excluding the `kind`
6
6
  * discriminant. `every()` schedules a body step on a fixed-interval, optionally
@@ -1,4 +1,5 @@
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';
2
3
  /**
3
4
  * Creates an `every` step that runs a body step on a fixed-interval schedule.
4
5
  *
@@ -48,7 +49,7 @@ export function every(opts) {
48
49
  hint: 'Pass a non-negative number of milliseconds for jitter, or omit it.',
49
50
  });
50
51
  }
51
- return {
52
+ const built = {
52
53
  kind: 'every',
53
54
  id: opts.id,
54
55
  step: opts.step,
@@ -57,4 +58,6 @@ export function every(opts) {
57
58
  onError: opts.onError ?? 'continue',
58
59
  jitter: opts.jitter ?? 0,
59
60
  };
61
+ getDefaultRegistrar().register(built);
62
+ return built;
60
63
  }
@@ -1,32 +1 @@
1
- import type { ZodType } from 'zod';
2
- import type { ExecutionContext, LayerDataDecl, LayerFunctionDecl } from '../types/memory';
3
- /**
4
- * Creates a read-only data declaration for a memory layer's `provides` map.
5
- *
6
- * @public
7
- * @param opts.read - Function that projects a value from the layer's current state.
8
- * @returns A `LayerDataDecl` to include in a layer's `provides`.
9
- */
10
- export declare function layerData<T, TState>(opts: {
11
- read: (state: TState) => T;
12
- }): LayerDataDecl<T, TState>;
13
- /**
14
- * Creates a callable function declaration for a memory layer's `provides` map.
15
- * Functions are accessible via `ctx.memory['layerId'].fn()` and automatically exposed as LLM tools.
16
- *
17
- * @public
18
- * @param opts.description - Human-readable description (used as tool description for LLM).
19
- * @param opts.input - Zod schema validating input arguments.
20
- * @param opts.output - Zod schema validating the return value.
21
- * @param opts.execute - Async function receiving args, current state, and execution context.
22
- * @returns A `LayerFunctionDecl` to include in a layer's `provides`.
23
- */
24
- export declare function layerFn<TInput, TOutput, TState>(opts: {
25
- description: string;
26
- input: ZodType<TInput>;
27
- output: ZodType<TOutput>;
28
- execute: (args: TInput, state: TState, ctx: ExecutionContext) => Promise<{
29
- result: TOutput;
30
- state?: TState;
31
- }>;
32
- }): LayerFunctionDecl<TInput, TOutput, TState>;
1
+ export { layerData, layerFn } from '../memory/layer-provides.js';
@@ -1,33 +1 @@
1
- /**
2
- * Creates a read-only data declaration for a memory layer's `provides` map.
3
- *
4
- * @public
5
- * @param opts.read - Function that projects a value from the layer's current state.
6
- * @returns A `LayerDataDecl` to include in a layer's `provides`.
7
- */
8
- export function layerData(opts) {
9
- return {
10
- kind: 'data',
11
- read: opts.read,
12
- };
13
- }
14
- /**
15
- * Creates a callable function declaration for a memory layer's `provides` map.
16
- * Functions are accessible via `ctx.memory['layerId'].fn()` and automatically exposed as LLM tools.
17
- *
18
- * @public
19
- * @param opts.description - Human-readable description (used as tool description for LLM).
20
- * @param opts.input - Zod schema validating input arguments.
21
- * @param opts.output - Zod schema validating the return value.
22
- * @param opts.execute - Async function receiving args, current state, and execution context.
23
- * @returns A `LayerFunctionDecl` to include in a layer's `provides`.
24
- */
25
- export function layerFn(opts) {
26
- return {
27
- kind: 'function',
28
- description: opts.description,
29
- input: opts.input,
30
- output: opts.output,
31
- execute: opts.execute,
32
- };
33
- }
1
+ export { layerData, layerFn } from '../memory/layer-provides.js';
@@ -1,5 +1,5 @@
1
- import type { ContextMemory } from '../types/memory';
2
- import type { StepLoop } from '../types/step';
1
+ import type { ContextMemory } from '../types/memory.js';
2
+ import type { StepLoop } from '../types/step.js';
3
3
  /** @public Configuration options accepted by the `loop()` builder, excluding the `kind` discriminant. */
4
4
  export type LoopConfig<TMemory = ContextMemory, I = unknown, O = unknown> = Omit<StepLoop<TMemory, I, O>, 'kind'>;
5
5
  /**
@@ -1,4 +1,5 @@
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';
2
3
  /**
3
4
  * Creates a loop step that iterates a body step until a termination predicate is satisfied.
4
5
  *
@@ -39,8 +40,10 @@ export function loop(opts) {
39
40
  hint: 'Provide an until predicate, e.g. until.maxSteps(10).',
40
41
  });
41
42
  }
42
- return {
43
+ const built = {
43
44
  kind: 'loop',
44
45
  ...opts,
45
46
  };
47
+ getDefaultRegistrar().register(built);
48
+ return built;
46
49
  }
@@ -1,4 +1,4 @@
1
- import type { MemoryConfig, MemoryLayer } from '../types/memory';
1
+ import type { MemoryConfig, MemoryLayer } from '../types/memory.js';
2
2
  /**
3
3
  * Creates a type-safe memory configuration from a tuple of memory layers.
4
4
  * The returned config preserves literal layer types for compile-time inference
@@ -1,4 +1,4 @@
1
- import { frameworkCast } from '../interpreter/framework-cast';
1
+ import { frameworkCast } from '../util/framework-cast.js';
2
2
  /**
3
3
  * Creates a type-safe memory configuration from a tuple of memory layers.
4
4
  * The returned config preserves literal layer types for compile-time inference
@@ -1,5 +1,5 @@
1
- import type { ContextMemory, MemoryConfig, MemoryLayer } from '../types/memory';
2
- import type { Step, StepProvide } from '../types/step';
1
+ import type { ContextMemory, MemoryConfig, MemoryLayer } from '../types/memory.js';
2
+ import type { Step, StepProvide } from '../types/step.js';
3
3
  /**
4
4
  * Creates a provide step that attaches memory layers to its child without creating an isolated context.
5
5
  * Like React's Context.Provider — layers are available to all descendant steps.
@@ -1,4 +1,5 @@
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';
2
3
  /**
3
4
  * Creates a provide step that attaches memory layers to its child without creating an isolated context.
4
5
  * Like React's Context.Provider — layers are available to all descendant steps.
@@ -27,8 +28,10 @@ export function provide(opts) {
27
28
  hint: 'Provide a child step to execute with the provided memory layers.',
28
29
  });
29
30
  }
30
- return {
31
+ const built = {
31
32
  kind: 'provide',
32
33
  ...opts,
33
34
  };
35
+ getDefaultRegistrar().register(built);
36
+ return built;
34
37
  }
@@ -1,5 +1,18 @@
1
- import type { ContextMemory, MemoryConfig, MemoryLayer } from '../types/memory';
2
- import type { Step, StepSpawn } from '../types/step';
1
+ import type { ContextMemory, MemoryConfig, MemoryLayer } from '../types/memory.js';
2
+ import type { Step, StepSpawn } from '../types/step.js';
3
+ import type { SubprocessAdapter } from '../types/subprocess-adapter.js';
4
+ interface SpawnOpts<TMemory, I, O> {
5
+ id: string;
6
+ child: Step<TMemory, I, O>;
7
+ memory?: MemoryConfig | MemoryLayer[];
8
+ timeout?: number;
9
+ /**
10
+ * Optional per-step subprocess adapter override. The interpreter routes
11
+ * this spawn through the given adapter instead of the harness default.
12
+ * See spec 04 for the `overrides ?? step ?? harness` precedence rule.
13
+ */
14
+ subprocess?: SubprocessAdapter;
15
+ }
3
16
  /**
4
17
  * Creates a spawn step that executes a child step in an isolated context boundary.
5
18
  *
@@ -8,13 +21,13 @@ import type { Step, StepSpawn } from '../types/step';
8
21
  * @param opts.child - Step to execute in the isolated child context.
9
22
  * @param opts.memory - Optional memory config or layers for the child context (replaces parent layers entirely).
10
23
  * @param opts.timeout - Optional execution timeout in ms; the child is aborted if it exceeds this.
11
- * @returns A `StepSpawn` step.
24
+ * @param opts.subprocess - Optional per-step subprocess adapter override.
25
+ * @returns A `StepSpawn` step. The spawn step and its `child` step are both
26
+ * auto-registered in the shared step registry so the subprocess adapter
27
+ * can dispatch either by id.
12
28
  * @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
13
29
  * @throws `NoeticConfigError` with code `MISSING_CHILD_STEP` if `child` is not provided.
30
+ * @throws `NoeticConfigError` with code `DUPLICATE_STEP_ID` if another step with the same id is already registered.
14
31
  */
15
- export declare function spawn<TMemory = ContextMemory, I = unknown, O = unknown>(opts: {
16
- id: string;
17
- child: Step<TMemory, I, O>;
18
- memory?: MemoryConfig | MemoryLayer[];
19
- timeout?: number;
20
- }): StepSpawn<TMemory, I, O>;
32
+ export declare function spawn<TMemory = ContextMemory, I = unknown, O = unknown>(opts: SpawnOpts<TMemory, I, O>): StepSpawn<TMemory, I, O>;
33
+ export {};
@@ -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 Public API
2
5
  /**
3
6
  * Creates a spawn step that executes a child step in an isolated context boundary.
4
7
  *
@@ -7,9 +10,13 @@ import { NoeticConfigError } from '../errors/noetic-config-error';
7
10
  * @param opts.child - Step to execute in the isolated child context.
8
11
  * @param opts.memory - Optional memory config or layers for the child context (replaces parent layers entirely).
9
12
  * @param opts.timeout - Optional execution timeout in ms; the child is aborted if it exceeds this.
10
- * @returns A `StepSpawn` step.
13
+ * @param opts.subprocess - Optional per-step subprocess adapter override.
14
+ * @returns A `StepSpawn` step. The spawn step and its `child` step are both
15
+ * auto-registered in the shared step registry so the subprocess adapter
16
+ * can dispatch either by id.
11
17
  * @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
12
18
  * @throws `NoeticConfigError` with code `MISSING_CHILD_STEP` if `child` is not provided.
19
+ * @throws `NoeticConfigError` with code `DUPLICATE_STEP_ID` if another step with the same id is already registered.
13
20
  */
14
21
  export function spawn(opts) {
15
22
  if (!opts.id?.trim()) {
@@ -26,8 +33,15 @@ export function spawn(opts) {
26
33
  hint: 'Provide a child step to execute in the isolated child context.',
27
34
  });
28
35
  }
29
- return {
36
+ const built = {
30
37
  kind: 'spawn',
31
38
  ...opts,
32
39
  };
40
+ getDefaultRegistrar().register(built);
41
+ // Ensure the child is addressable by id — builders for `run`/`llm`/`tool`
42
+ // self-register, but a caller can construct a step literal and pass it as
43
+ // `child` without going through a builder.
44
+ getDefaultRegistrar().register(opts.child);
45
+ return built;
33
46
  }
47
+ //#endregion
@@ -1,8 +1,38 @@
1
1
  import type { ZodType } from 'zod';
2
- import type { ModelParams, RetryPolicy, Tool } from '../types/common';
3
- import type { Context } from '../types/context';
4
- import type { ContextMemory } from '../types/memory';
5
- import type { StepLLM, StepRun, StepTool } from '../types/step';
2
+ import type { ModelParams, RetryPolicy } from '../types/common.js';
3
+ import type { Context } from '../types/context.js';
4
+ import type { ContextMemory } from '../types/memory.js';
5
+ import type { Lazy, StepLLM, StepRun, StepTool } from '../types/step.js';
6
+ import type { SubprocessAdapter } from '../types/subprocess-adapter.js';
7
+ import type { Tool } from '../types/tool.js';
8
+ interface StepRunOpts<TMemory, I, O> {
9
+ id: string;
10
+ execute: (input: I, ctx: Context<TMemory>) => Promise<O>;
11
+ retry?: RetryPolicy;
12
+ /**
13
+ * Optional subprocess adapter override. When set, `execute()` is routed
14
+ * through this adapter instead of the harness default. See spec 04 for
15
+ * precedence rules.
16
+ */
17
+ subprocess?: SubprocessAdapter;
18
+ }
19
+ interface StepLLMOpts<TMemory, O> {
20
+ id: string;
21
+ /** Model id. Eager string or `(ctx) => string` getter (resolved at step execution). */
22
+ model: Lazy<string, TMemory>;
23
+ /** Optional instructions; eager string or `(ctx) => string | undefined` getter. */
24
+ instructions?: Lazy<string | undefined, TMemory>;
25
+ /** Optional tools; eager array or `(ctx) => Tool[] | undefined` getter. */
26
+ tools?: Lazy<Tool[] | undefined, TMemory>;
27
+ output?: ZodType<O>;
28
+ params?: ModelParams;
29
+ emit?: boolean | ((eventType: string, data: Record<string, unknown>) => boolean);
30
+ }
31
+ interface StepToolOpts<I, O> {
32
+ id: string;
33
+ tool: Tool<ZodType<I>, ZodType<O>>;
34
+ args?: Partial<I>;
35
+ }
6
36
  export declare const step: {
7
37
  /**
8
38
  * Creates a pure async computation step.
@@ -11,38 +41,31 @@ export declare const step: {
11
41
  * @param opts.id - Unique step identifier used in traces and error messages.
12
42
  * @param opts.execute - Async function `(input, ctx) => output` that performs the work.
13
43
  * @param opts.retry - Optional retry policy controlling attempts, backoff, and delay.
14
- * @returns A `StepRun` that can be composed into larger pipelines.
44
+ * @param opts.subprocess - Optional per-step subprocess adapter override.
45
+ * @returns A `StepRun` that can be composed into larger pipelines. The step
46
+ * is auto-registered in the shared step registry so the subprocess
47
+ * adapter can dispatch it by id.
15
48
  * @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
16
49
  * @throws `NoeticConfigError` with code `MISSING_EXECUTE_FUNCTION` if `execute` is not provided.
50
+ * @throws `NoeticConfigError` with code `DUPLICATE_STEP_ID` if another step with the same id is already registered with a different body.
17
51
  */
18
- run<TMemory = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: {
19
- id: string;
20
- execute: (input: I, ctx: Context<TMemory>) => Promise<O>;
21
- retry?: RetryPolicy;
22
- }): StepRun<TMemory, I, O>;
52
+ run<TMemory = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: StepRunOpts<TMemory, I, O>): StepRun<TMemory, I, O>;
23
53
  /**
24
54
  * Creates an LLM model call step with optional tools and structured output.
25
55
  *
26
56
  * @public
27
57
  * @param opts.id - Unique step identifier used in traces and error messages.
28
- * @param opts.model - Model identifier string (e.g. `'anthropic/claude-sonnet-4-20250514'`).
29
- * @param opts.instructions - Optional system prompt / instructions for the model.
30
- * @param opts.tools - Optional tools available to the model during this call.
58
+ * @param opts.model - Model identifier, eager string or `(ctx) => string` getter (resolved at step execution time).
59
+ * @param opts.instructions - Optional system prompt; eager string or `(ctx) => string | undefined` getter.
60
+ * @param opts.tools - Optional tools; eager array or `(ctx) => Tool[] | undefined` getter.
31
61
  * @param opts.output - Optional Zod schema enabling structured output parsing.
32
62
  * @param opts.params - Optional model parameters (temperature, topP, maxTokens, stopSequences).
33
- * @returns A `StepLLM` that can be composed into larger pipelines.
63
+ * @returns A `StepLLM` that can be composed into larger pipelines. The step
64
+ * is auto-registered in the shared step registry.
34
65
  * @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
35
- * @throws `NoeticConfigError` with code `MISSING_MODEL` if `model` is empty.
66
+ * @throws `NoeticConfigError` with code `MISSING_MODEL` if an eager `model` string is empty. Function-form models are validated at step execution.
36
67
  */
37
- llm<TMemory = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: {
38
- id: string;
39
- model: string;
40
- instructions?: string;
41
- tools?: Tool[];
42
- output?: ZodType<O>;
43
- params?: ModelParams;
44
- emit?: boolean | ((eventType: string, data: Record<string, unknown>) => boolean);
45
- }): StepLLM<TMemory, I, O>;
68
+ llm<TMemory = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: StepLLMOpts<TMemory, O>): StepLLM<TMemory, I, O>;
46
69
  /**
47
70
  * Creates a tool execution step that invokes a typed tool definition.
48
71
  *
@@ -50,13 +73,11 @@ export declare const step: {
50
73
  * @param opts.id - Unique step identifier used in traces and error messages.
51
74
  * @param opts.tool - The tool definition with typed input/output schemas.
52
75
  * @param opts.args - Optional partial args that override or supplement LLM-provided arguments.
53
- * @returns A `StepTool` that can be composed into larger pipelines.
76
+ * @returns A `StepTool` that can be composed into larger pipelines. The step
77
+ * is auto-registered in the shared step registry.
54
78
  * @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
55
79
  * @throws `NoeticConfigError` with code `MISSING_TOOL` if `tool` is not provided.
56
80
  */
57
- tool<TMemory = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: {
58
- id: string;
59
- tool: Tool<ZodType<I>, ZodType<O>>;
60
- args?: Partial<I>;
61
- }): StepTool<TMemory, I, O>;
81
+ tool<TMemory = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: StepToolOpts<I, O>): StepTool<TMemory, I, O>;
62
82
  };
83
+ export {};