@noetic-tools/core 5.3.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +8 -6
  2. package/dist/adapters/in-memory-subprocess/step-completion.js +1 -1
  3. package/dist/adapters/openrouter.d.ts +12 -1
  4. package/dist/adapters/openrouter.js +79 -5
  5. package/dist/builders/control-flow-builders.d.ts +13 -13
  6. package/dist/builders/control-flow-builders.js +11 -11
  7. package/dist/{patterns → builders}/dynamic-workflow.d.ts +1 -1
  8. package/dist/{patterns → builders}/dynamic-workflow.js +18 -12
  9. package/dist/builders/every.d.ts +14 -14
  10. package/dist/builders/every.js +16 -16
  11. package/dist/builders/layer-provides-builders.d.ts +1 -1
  12. package/dist/builders/layer-provides-builders.js +1 -1
  13. package/dist/builders/provide-builder.d.ts +5 -12
  14. package/dist/builders/provide-builder.js +9 -10
  15. package/dist/builders/spawn-builder.d.ts +0 -2
  16. package/dist/builders/spawn-builder.js +2 -3
  17. package/dist/builders/step-builders.d.ts +66 -55
  18. package/dist/builders/step-builders.js +118 -111
  19. package/dist/builders/tool-builder.d.ts +18 -22
  20. package/dist/builders/tool-builder.js +6 -4
  21. package/dist/builders/workflow-hydrator.d.ts +3 -3
  22. package/dist/builders/workflow-hydrator.js +59 -63
  23. package/dist/builders/workflow-step.d.ts +13 -25
  24. package/dist/builders/workflow-step.js +13 -18
  25. package/dist/conditions/conditions.d.ts +2 -2
  26. package/dist/conditions/conditions.js +1 -1
  27. package/dist/harness/agent-harness.d.ts +54 -40
  28. package/dist/harness/agent-harness.js +44 -33
  29. package/dist/harness/deps/types.d.ts +1 -1
  30. package/dist/harness/model-call.d.ts +1 -1
  31. package/dist/harness/model-call.js +23 -18
  32. package/dist/index.d.ts +21 -33
  33. package/dist/index.js +10 -26
  34. package/dist/interpreter/action-types.d.ts +1 -1
  35. package/dist/interpreter/collect-tools.js +7 -7
  36. package/dist/interpreter/execute-action.d.ts +5 -5
  37. package/dist/interpreter/execute-action.js +284 -218
  38. package/dist/interpreter/execute-control.d.ts +9 -9
  39. package/dist/interpreter/execute-control.js +27 -27
  40. package/dist/interpreter/execute-sub-harness.d.ts +1 -1
  41. package/dist/interpreter/execute-sub-harness.js +7 -26
  42. package/dist/interpreter/execute.d.ts +1 -1
  43. package/dist/interpreter/execute.js +26 -25
  44. package/dist/interpreter/step-dispatcher.d.ts +1 -1
  45. package/dist/interpreter/step-dispatcher.js +3 -3
  46. package/dist/interpreter/structured-output.d.ts +14 -0
  47. package/dist/interpreter/structured-output.js +40 -0
  48. package/dist/interpreter/typeguards.d.ts +1 -1
  49. package/dist/interpreter/typeguards.js +1 -1
  50. package/dist/portable/builders.d.ts +3 -3
  51. package/dist/portable/builders.js +6 -5
  52. package/dist/portable/context-layers.d.ts +1 -1
  53. package/dist/portable/context-layers.js +1 -1
  54. package/dist/runtime/broadcaster-utils.d.ts +1 -1
  55. package/dist/runtime/broadcaster-utils.js +1 -1
  56. package/dist/runtime/context-impl.d.ts +8 -10
  57. package/dist/runtime/context-impl.js +8 -12
  58. package/dist/runtime/durable/step-ledger.d.ts +2 -2
  59. package/dist/runtime/durable/step-ledger.js +3 -3
  60. package/dist/runtime/session-runner.d.ts +12 -1
  61. package/dist/runtime/session-runner.js +33 -1
  62. package/dist/runtime/tool-context.js +0 -2
  63. package/dist/schemas/workflow.d.ts +3 -3
  64. package/dist/schemas/workflow.js +2 -2
  65. package/dist/types/checkpoint.d.ts +11 -2
  66. package/dist/types/checkpoint.js +10 -1
  67. package/dist/{runtime → util}/detached-handle.js +1 -1
  68. package/package.json +6 -4
  69. package/schema/noetic-workflow.schema.json +24 -11
  70. package/dist/builders/context-option.d.ts +0 -23
  71. package/dist/builders/context-option.js +0 -22
  72. package/dist/deprecated.d.ts +0 -30
  73. package/dist/deprecated.js +0 -28
  74. package/dist/patterns/interview.d.ts +0 -53
  75. package/dist/patterns/interview.js +0 -113
  76. package/dist/patterns/plans.d.ts +0 -44
  77. package/dist/patterns/plans.js +0 -125
  78. package/dist/patterns/ralph-wiggum.d.ts +0 -19
  79. package/dist/patterns/ralph-wiggum.js +0 -37
  80. package/dist/patterns/react.d.ts +0 -19
  81. package/dist/patterns/react.js +0 -41
  82. /package/dist/{runtime → util}/detached-handle.d.ts +0 -0
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Control-flow step handlers: branch, fork, loop, every.
2
+ * Control-flow step handlers: conditional, inParallel, loop, schedule.
3
3
  */
4
4
  import { createMessage, frameworkCast, isNoeticError, NoeticErrorImpl } from '@noetic-tools/types';
5
5
  import { ContextImpl } from '../runtime/context-impl.js';
@@ -7,18 +7,18 @@ import { snapshotCwdState } from '../runtime/cwd-helpers.js';
7
7
  import { contextToExecCtx, returnLayers, spawnLayers } from './action-deps.js';
8
8
  import { cloneWithGuard } from './clone-guard.js';
9
9
  import { getContextChannelStore, isContextImpl, isMutableContext } from './typeguards.js';
10
- //#region branch
11
- export async function executeBranch(step, input, ctx, executeStep) {
10
+ //#region conditional
11
+ export async function executeConditional(step, input, ctx, executeStep) {
12
12
  const selected = await step.route(input, ctx);
13
13
  if (selected === null) {
14
- // Requires I assignable to O for null route — when no branch is selected,
14
+ // Requires I assignable to O for null route — when no route is selected,
15
15
  // the input passes through. Callers must ensure I is compatible with O.
16
16
  return frameworkCast(input);
17
17
  }
18
18
  return executeStep(selected, input, ctx);
19
19
  }
20
20
  //#endregion
21
- //#region fork
21
+ //#region inParallel
22
22
  function createChildContexts(ctx, count, stepId) {
23
23
  const threadId = isContextImpl(ctx) ? ctx.threadId : crypto.randomUUID();
24
24
  const resourceId = isContextImpl(ctx) ? ctx.resourceId : undefined;
@@ -43,8 +43,8 @@ function createChildContexts(ctx, count, stepId) {
43
43
  resourceId,
44
44
  channelStore,
45
45
  cwdState: snapshotCwdState(ctx),
46
- // Layers and the harness tool pool cross the fork boundary: without
47
- // them an `llm` step inside a path would run with no context
46
+ // Layers and the harness tool pool cross the inParallel boundary: without
47
+ // them a `callModel` step inside a path would run with no context
48
48
  // projection and no layer tools, and a nested `spawn` would have no
49
49
  // parent layers to inherit. Per-path layer STATE is still isolated —
50
50
  // see `createForkLayerBridge`.
@@ -93,7 +93,7 @@ function createForkLayerBridge({ ctx, childContexts, opts, }) {
93
93
  }
94
94
  /**
95
95
  * Wraps the interpreter's `executeStep` so every forked path runs inside the
96
- * layer child boundary. Contexts that are not one of this fork's children
96
+ * layer child boundary. Contexts that are not one of this inParallel's children
97
97
  * (nested steps within a path) pass straight through.
98
98
  */
99
99
  function withForkLayers(executeStep, childContexts, bridge) {
@@ -119,7 +119,7 @@ function withForkLayers(executeStep, childContexts, bridge) {
119
119
  }
120
120
  };
121
121
  }
122
- export async function executeFork(step, input, ctx, rawExecuteStep, opts) {
122
+ export async function executeInParallel(step, input, ctx, rawExecuteStep, opts) {
123
123
  const baseCtx = frameworkCast(ctx);
124
124
  const paths = step.paths(input, ctx);
125
125
  if (paths.length === 0) {
@@ -156,7 +156,7 @@ export async function executeFork(step, input, ctx, rawExecuteStep, opts) {
156
156
  throw new NoeticErrorImpl({
157
157
  kind: 'step_failed',
158
158
  stepId: 'unknown',
159
- cause: new Error('Unknown fork mode'),
159
+ cause: new Error('Unknown inParallel mode'),
160
160
  retriesExhausted: false,
161
161
  });
162
162
  }
@@ -242,7 +242,7 @@ async function executeAll(step, paths, _input, ctx, childContexts, executeStep,
242
242
  if (firstFailureSeen) {
243
243
  throw new NoeticErrorImpl({
244
244
  kind: 'cancelled',
245
- reason: `fork '${step.id}' sibling failed`,
245
+ reason: `inParallel '${step.id}' sibling failed`,
246
246
  });
247
247
  }
248
248
  try {
@@ -254,7 +254,7 @@ async function executeAll(step, paths, _input, ctx, childContexts, executeStep,
254
254
  firstFailureSeen = true;
255
255
  for (let j = 0; j < childContexts.length; j++) {
256
256
  if (j !== i) {
257
- childContexts[j].abort(`fork '${step.id}' sibling failed`);
257
+ childContexts[j].abort(`inParallel '${step.id}' sibling failed`);
258
258
  }
259
259
  }
260
260
  }
@@ -263,7 +263,7 @@ async function executeAll(step, paths, _input, ctx, childContexts, executeStep,
263
263
  });
264
264
  const settled = await runWithConcurrency(tasks, concurrency);
265
265
  const { succeeded, failed } = classifyResults(settled, paths);
266
- // If the PARENT context was aborted mid-fork, the whole fork is cancelled —
266
+ // If the PARENT context was aborted mid-inParallel, the whole inParallel is cancelled —
267
267
  // surface 'cancelled', not a partial-failure shape (spec 09, item 3).
268
268
  if (ctx.aborted) {
269
269
  throw new NoeticErrorImpl({
@@ -344,7 +344,7 @@ async function executeRace(step, paths, input, ctx, childContexts, executeStep,
344
344
  async function executeSettle(step, paths, input, ctx, childContexts, executeStep, concurrency) {
345
345
  const tasks = paths.map((path, i) => () => executeStep(path, input, frameworkCast(childContexts[i])));
346
346
  const settled = await runWithConcurrency(tasks, concurrency);
347
- // Parent aborted mid-fork: the fork is cancelled, merge never runs
347
+ // Parent aborted mid-inParallel: the inParallel is cancelled, merge never runs
348
348
  // (spec 09, Cancellation item 3 — same rule as mode 'all').
349
349
  if (ctx.aborted) {
350
350
  throw new NoeticErrorImpl({
@@ -454,7 +454,7 @@ export async function executeLoop(step, input, ctx, executeStep) {
454
454
  }
455
455
  // Cancellation is not a retriable error (spec 09): it must terminate
456
456
  // the loop promptly rather than be consumed by 'retry'/'skip'. Same
457
- // guard as executeEvery's 'continue' policy below.
457
+ // guard as executeSchedule's 'continue' policy below.
458
458
  if (e.noeticError.kind === 'cancelled') {
459
459
  throw e;
460
460
  }
@@ -554,7 +554,7 @@ function nextParkMs(ms, jitter) {
554
554
  return value;
555
555
  }
556
556
  /**
557
- * Parks for `ms` ms, returning early if `wakeOn` receives a message or the
557
+ * Parks for `ms` ms, returning early if `inbox` receives a message or the
558
558
  * context is aborted. Always resolves; never throws (cancellation surfaces on
559
559
  * the next iteration's abort check).
560
560
  */
@@ -591,7 +591,7 @@ function park(parkCtx) {
591
591
  settle();
592
592
  }
593
593
  }, 5);
594
- if (!parkCtx.wakeOn) {
594
+ if (!parkCtx.inbox) {
595
595
  return;
596
596
  }
597
597
  const { channelStore } = parkCtx;
@@ -599,13 +599,13 @@ function park(parkCtx) {
599
599
  // Non-consuming subscription so the body still observes the message that
600
600
  // woke us — `recv()` would dequeue queue-mode messages and leave the
601
601
  // body's drain loop empty.
602
- wakeUnsub = channelStore.subscribeWake(parkCtx.wakeOn, settle);
602
+ wakeUnsub = channelStore.subscribeWake(parkCtx.inbox, settle);
603
603
  return;
604
604
  }
605
605
  // Contexts without a ContextImpl/channel store have no body draining the
606
606
  // channel anyway; the destructive `recv` is acceptable in that edge case.
607
607
  parkCtx.ctx
608
- .recv(parkCtx.wakeOn, {
608
+ .recv(parkCtx.inbox, {
609
609
  timeout: Math.max(duration, 1) + 1e2,
610
610
  })
611
611
  .then(settle)
@@ -617,7 +617,7 @@ function park(parkCtx) {
617
617
  function recordIterationError(ctx, error) {
618
618
  const message = error instanceof Error ? error.message : String(error);
619
619
  const stack = error instanceof Error && error.stack ? error.stack : '';
620
- ctx.span.addEvent('every.iteration.error', {
620
+ ctx.span.addEvent('schedule.iteration.error', {
621
621
  message,
622
622
  stack,
623
623
  });
@@ -629,18 +629,18 @@ function throwCancelled(reason) {
629
629
  });
630
630
  }
631
631
  /**
632
- * Executes an `every` step: runs the body step forever, paced by `ms ± jitter`,
633
- * woken early by `wakeOn`. Throws `cancelled` when the context is aborted.
632
+ * Executes a `schedule` step: runs the body step forever, paced by `ms ± jitter`,
633
+ * woken early by `inbox`. Throws `cancelled` when the context is aborted.
634
634
  *
635
635
  * On body throw, behavior depends on `onError`:
636
- * - `'continue'` (default): emit `every.iteration.error` span event and proceed
636
+ * - `'continue'` (default): emit `schedule.iteration.error` span event and proceed
637
637
  * to the park step as if no error occurred.
638
638
  * - `'fail'`: re-throw, terminating the operator.
639
639
  *
640
- * The body's output is discarded — `every` runs forever and does not accumulate
640
+ * The body's output is discarded — `schedule` runs forever and does not accumulate
641
641
  * iteration outputs. Only ever returns by throwing on cancellation or `fail`.
642
642
  */
643
- export async function executeEvery(step, input, ctx, executeStep) {
643
+ export async function executeSchedule(step, input, ctx, executeStep) {
644
644
  const onError = step.onError ?? 'continue';
645
645
  const jitter = step.jitter ?? 0;
646
646
  // Resolve once — the channel store reference is stable for the lifetime
@@ -668,9 +668,9 @@ export async function executeEvery(step, input, ctx, executeStep) {
668
668
  throwCancelled(ctx.abortReason);
669
669
  }
670
670
  await park({
671
- ms: step.ms,
671
+ ms: step.interval,
672
672
  jitter,
673
- wakeOn: step.wakeOn,
673
+ inbox: step.inbox,
674
674
  ctx,
675
675
  channelStore,
676
676
  });
@@ -2,7 +2,7 @@
2
2
  * SubHarness step handler: drives an external coding-agent harness
3
3
  * (Claude Code, Codex, opencode, pi) for one agentic turn and folds its output
4
4
  * back into the Noetic execution context — the harness analogue of
5
- * `executeLLM`.
5
+ * `executeCallModel`.
6
6
  */
7
7
  import type { Context, StepSubHarness } from '@noetic-tools/types';
8
8
  export declare function executeSubHarness<TContext, I, O>(step: StepSubHarness<TContext, I, O>, input: I, ctx: Context<TContext>): Promise<O>;
@@ -2,12 +2,12 @@
2
2
  * SubHarness step handler: drives an external coding-agent harness
3
3
  * (Claude Code, Codex, opencode, pi) for one agentic turn and folds its output
4
4
  * back into the Noetic execution context — the harness analogue of
5
- * `executeLLM`.
5
+ * `executeCallModel`.
6
6
  */
7
7
  import { createMessage, extractAssistantText, frameworkCast, NoeticConfigError, NoeticErrorImpl, } from '@noetic-tools/types';
8
- import { ZodError } from 'zod';
9
8
  import { resolveLazy } from './execute-action.js';
10
9
  import { trackUsage } from './message-helpers.js';
10
+ import { parseStructuredOutput } from './structured-output.js';
11
11
  import { SubHarnessEventBridge } from './sub-harness-events.js';
12
12
  import { isContextImpl, isFunctionCall, isMutableContext } from './typeguards.js';
13
13
  //#endregion
@@ -211,30 +211,11 @@ export async function executeSubHarness(step, input, ctx) {
211
211
  await finalizeSession(resolution, step.session, baseCtx);
212
212
  const lastText = result.text.length > 0 ? result.text : extractAssistantText(result.items);
213
213
  if (step.output) {
214
- try {
215
- const parsed = JSON.parse(lastText);
216
- return step.output.parse(parsed);
217
- }
218
- catch (e) {
219
- if (e instanceof SyntaxError || e instanceof ZodError) {
220
- throw new NoeticErrorImpl({
221
- kind: 'llm_parse_error',
222
- stepId: step.id,
223
- raw: lastText,
224
- schema: step.output,
225
- zodError: e instanceof ZodError
226
- ? e
227
- : new ZodError([
228
- {
229
- code: 'custom',
230
- message: `Invalid JSON: ${e.message}`,
231
- path: [],
232
- },
233
- ]),
234
- });
235
- }
236
- throw e;
237
- }
214
+ return parseStructuredOutput({
215
+ schema: step.output,
216
+ rawText: lastText,
217
+ stepId: step.id,
218
+ });
238
219
  }
239
220
  return frameworkCast(lastText);
240
221
  }
@@ -4,7 +4,7 @@ import type { Context, Step } from '@noetic-tools/types';
4
4
  * @internal
5
5
  * Dispatch a step at the per-kind handler level without adapter routing.
6
6
  *
7
- * Used as the top-level `_localExecutor` for `StepRun` / `StepSpawn`
7
+ * Used as the top-level `_localExecutor` for `StepRunCode` / `StepSpawn`
8
8
  * dispatches: the outer adapter call already recorded the request, so
9
9
  * running the handler directly avoids a re-entrant adapter round-trip
10
10
  * inside the same logical step. Nested step dispatches (e.g. `executeSpawn`
@@ -1,9 +1,9 @@
1
1
  import { frameworkCast, NoeticErrorImpl } from '@noetic-tools/types';
2
2
  import { emitFrameworkEvent, getBroadcaster, shouldEmit } from '../runtime/broadcaster-utils.js';
3
3
  import { ContextImpl } from '../runtime/context-impl.js';
4
- import { DetachedHandleImpl } from '../runtime/detached-handle.js';
5
- import { executeLLM, executeProvide, executeRun, executeSpawn, executeTool, } from './execute-action.js';
6
- import { executeBranch, executeEvery, executeFork, executeLoop } from './execute-control.js';
4
+ import { DetachedHandleImpl } from '../util/detached-handle.js';
5
+ import { executeCallModel, executeInvokeTool, executeRunCode, executeSpawn, executeWithContext, } from './execute-action.js';
6
+ import { executeConditional, executeInParallel, executeLoop, executeSchedule, } from './execute-control.js';
7
7
  import { executeSubHarness } from './execute-sub-harness.js';
8
8
  import { isMutableContext } from './typeguards.js';
9
9
  //#region Constants
@@ -31,11 +31,11 @@ function buildSpawnOpts(ctx) {
31
31
  };
32
32
  }
33
33
  /**
34
- * Resolve the per-step framework-event emit option. Both `llm` and the harness
34
+ * Resolve the per-step framework-event emit option. Both `callModel` and the harness
35
35
  * step kinds carry an `emit` field; every other kind defaults to enabled.
36
36
  */
37
37
  function resolveStepEmit(step) {
38
- if (step.kind === 'llm' ||
38
+ if (step.kind === 'callModel' ||
39
39
  step.kind === 'claude-code' ||
40
40
  step.kind === 'codex' ||
41
41
  step.kind === 'opencode' ||
@@ -50,7 +50,7 @@ function resolveStepEmit(step) {
50
50
  * `detachedSpawn` overrides layer above this in the harness itself.
51
51
  */
52
52
  function resolveStepAdapter(step, ctx) {
53
- if ((step.kind === 'run' || step.kind === 'spawn') && step.subprocess) {
53
+ if ((step.kind === 'runCode' || step.kind === 'spawn') && step.subprocess) {
54
54
  return step.subprocess;
55
55
  }
56
56
  return ctx.harness.subprocess;
@@ -90,7 +90,7 @@ async function dispatchViaAdapter(step, input, ctx, executor) {
90
90
  * @internal
91
91
  * Dispatch a step at the per-kind handler level without adapter routing.
92
92
  *
93
- * Used as the top-level `_localExecutor` for `StepRun` / `StepSpawn`
93
+ * Used as the top-level `_localExecutor` for `StepRunCode` / `StepSpawn`
94
94
  * dispatches: the outer adapter call already recorded the request, so
95
95
  * running the handler directly avoids a re-entrant adapter round-trip
96
96
  * inside the same logical step. Nested step dispatches (e.g. `executeSpawn`
@@ -100,13 +100,14 @@ async function dispatchViaAdapter(step, input, ctx, executor) {
100
100
  */
101
101
  export async function executeNoAdapter(step, input, ctx) {
102
102
  switch (step.kind) {
103
- case 'run':
104
- return executeRun(step, input, ctx);
103
+ case 'runCode':
104
+ return executeRunCode(step, input, ctx);
105
105
  case 'spawn':
106
106
  return executeSpawn(step, input, ctx, (s, i, c) => execute(s, i, c), buildSpawnOpts(ctx));
107
107
  default:
108
- // Kinds that don't currently route through the adapter (llm, tool,
109
- // branch, fork, provide, loop, every). Delegate back to `execute()`
108
+ // Kinds that don't currently route through the adapter (callModel,
109
+ // invokeTool, conditional, inParallel, withContext, loop, schedule).
110
+ // Delegate back to `execute()`
110
111
  // so they exercise the normal dispatch table, framework-event emits,
111
112
  // abort checks, and depth guard.
112
113
  return execute(step, input, ctx);
@@ -251,11 +252,11 @@ export async function execute(step, input, ctx) {
251
252
  let result;
252
253
  try {
253
254
  switch (step.kind) {
254
- case 'run':
255
- result = await dispatchViaAdapter(step, input, ctx, () => executeRun(step, input, ctx));
255
+ case 'runCode':
256
+ result = await dispatchViaAdapter(step, input, ctx, () => executeRunCode(step, input, ctx));
256
257
  break;
257
- case 'llm':
258
- result = await executeLLM(step, input, ctx, baseCtx.layers);
258
+ case 'callModel':
259
+ result = await executeCallModel(step, input, ctx, baseCtx.layers);
259
260
  break;
260
261
  case 'claude-code':
261
262
  case 'codex':
@@ -263,14 +264,14 @@ export async function execute(step, input, ctx) {
263
264
  case 'pi':
264
265
  result = await executeSubHarness(step, input, ctx);
265
266
  break;
266
- case 'tool':
267
- result = await executeTool(step, input, ctx, baseCtx.harness);
267
+ case 'invokeTool':
268
+ result = await executeInvokeTool(step, input, ctx, baseCtx.harness);
268
269
  break;
269
- case 'branch':
270
- result = await executeBranch(step, input, ctx, (s, i, c) => execute(s, i, c));
270
+ case 'conditional':
271
+ result = await executeConditional(step, input, ctx, (s, i, c) => execute(s, i, c));
271
272
  break;
272
- case 'fork':
273
- result = await executeFork(step, input, ctx, (s, i, c) => execute(s, i, c), {
273
+ case 'inParallel':
274
+ result = await executeInParallel(step, input, ctx, (s, i, c) => execute(s, i, c), {
274
275
  // Fork paths are child executions: the layer store lets their
275
276
  // `onSpawn`/`onReturn` boundary run (see `createForkLayerBridge`).
276
277
  layerStore: harnessWithLayerStore(baseCtx).layerStateStore,
@@ -280,14 +281,14 @@ export async function execute(step, input, ctx) {
280
281
  case 'spawn':
281
282
  result = await dispatchViaAdapter(step, input, ctx, () => executeSpawn(step, input, ctx, (s, i, c) => execute(s, i, c), buildSpawnOpts(ctx)));
282
283
  break;
283
- case 'provide':
284
- result = await executeProvide(step, input, ctx, (s, i, c) => execute(s, i, c));
284
+ case 'withContext':
285
+ result = await executeWithContext(step, input, ctx, (s, i, c) => execute(s, i, c));
285
286
  break;
286
287
  case 'loop':
287
288
  result = await executeLoop(step, input, ctx, (s, i, c) => execute(s, i, c));
288
289
  break;
289
- case 'every':
290
- result = await executeEvery(step, input, ctx, (s, i, c) => execute(s, i, c));
290
+ case 'schedule':
291
+ result = await executeSchedule(step, input, ctx, (s, i, c) => execute(s, i, c));
291
292
  break;
292
293
  default: {
293
294
  const _exhaustive = step;
@@ -4,7 +4,7 @@ import type { Context, DetachedHandle, Step, SubprocessAdapter } from '@noetic-t
4
4
  * Resolve the subprocess adapter used for a given step dispatch.
5
5
  *
6
6
  * Precedence: `detachedSpawn-overrides.subprocess ?? step.subprocess ??
7
- * harness.subprocess`. Only `StepRun` and `StepSpawn` currently carry a
7
+ * harness.subprocess`. Only `StepRunCode` and `StepSpawn` currently carry a
8
8
  * `subprocess` field — other variants always fall through to the harness
9
9
  * default.
10
10
  *
@@ -1,11 +1,11 @@
1
- import { DetachedHandleImpl } from '../runtime/detached-handle.js';
1
+ import { DetachedHandleImpl } from '../util/detached-handle.js';
2
2
  import { executeNoAdapter } from './execute.js';
3
3
  //#region Adapter resolution
4
4
  /**
5
5
  * Resolve the subprocess adapter used for a given step dispatch.
6
6
  *
7
7
  * Precedence: `detachedSpawn-overrides.subprocess ?? step.subprocess ??
8
- * harness.subprocess`. Only `StepRun` and `StepSpawn` currently carry a
8
+ * harness.subprocess`. Only `StepRunCode` and `StepSpawn` currently carry a
9
9
  * `subprocess` field — other variants always fall through to the harness
10
10
  * default.
11
11
  *
@@ -15,7 +15,7 @@ export function resolveStepAdapter(step, callOverride, fallback) {
15
15
  if (callOverride) {
16
16
  return callOverride;
17
17
  }
18
- if ((step.kind === 'run' || step.kind === 'spawn') && step.subprocess) {
18
+ if ((step.kind === 'runCode' || step.kind === 'spawn') && step.subprocess) {
19
19
  return step.subprocess;
20
20
  }
21
21
  return fallback;
@@ -0,0 +1,14 @@
1
+ import type { StandardSchemaV1 } from '@noetic-tools/types';
2
+ /**
3
+ * JSON-parse + validate assistant text against a Standard Schema, raising
4
+ * `model_parse_error`. Shared by the LLM step and sub-harness step handlers.
5
+ *
6
+ * Zod schemas keep the original `safeParse` error; other vendors' Standard
7
+ * Schema issues are adapted into a synthetic `ZodError` of `custom` issues so
8
+ * `model_parse_error.zodError` stays a single error surface.
9
+ */
10
+ export declare function parseStructuredOutput<O>(params: {
11
+ schema: StandardSchemaV1;
12
+ rawText: string;
13
+ stepId: string;
14
+ }): Promise<O>;
@@ -0,0 +1,40 @@
1
+ import { frameworkCast, NoeticErrorImpl, standardIssuesToZodError, validateSchema, } from '@noetic-tools/types';
2
+ /**
3
+ * JSON-parse + validate assistant text against a Standard Schema, raising
4
+ * `model_parse_error`. Shared by the LLM step and sub-harness step handlers.
5
+ *
6
+ * Zod schemas keep the original `safeParse` error; other vendors' Standard
7
+ * Schema issues are adapted into a synthetic `ZodError` of `custom` issues so
8
+ * `model_parse_error.zodError` stays a single error surface.
9
+ */
10
+ export async function parseStructuredOutput(params) {
11
+ const { schema, rawText, stepId } = params;
12
+ let parsed;
13
+ try {
14
+ parsed = JSON.parse(rawText);
15
+ }
16
+ catch (e) {
17
+ throw new NoeticErrorImpl({
18
+ kind: 'model_parse_error',
19
+ stepId,
20
+ raw: rawText,
21
+ schema,
22
+ zodError: standardIssuesToZodError([
23
+ {
24
+ message: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`,
25
+ },
26
+ ]),
27
+ });
28
+ }
29
+ const result = await validateSchema(schema, parsed);
30
+ if (!result.success) {
31
+ throw new NoeticErrorImpl({
32
+ kind: 'model_parse_error',
33
+ stepId,
34
+ raw: rawText,
35
+ schema,
36
+ zodError: result.zodError,
37
+ });
38
+ }
39
+ return frameworkCast(result.value);
40
+ }
@@ -9,7 +9,7 @@ export declare function isContextImpl(ctx: Context<ContextData>): ctx is Context
9
9
  /**
10
10
  * Co-located with `isContextImpl` so the import of `ContextImpl` flows through
11
11
  * the same module other interpreters pull it from, sidestepping a circular
12
- * TDZ when this helper is used by `executeEvery` in `execute-control.ts`.
12
+ * TDZ when this helper is used by `executeSchedule` in `execute-control.ts`.
13
13
  */
14
14
  export declare function getContextChannelStore<TContext>(ctx: Context<TContext>): ChannelStore | undefined;
15
15
  export declare function isFunctionCall(item: Item): item is FunctionCallItem;
@@ -16,7 +16,7 @@ export function isContextImpl(ctx) {
16
16
  /**
17
17
  * Co-located with `isContextImpl` so the import of `ContextImpl` flows through
18
18
  * the same module other interpreters pull it from, sidestepping a circular
19
- * TDZ when this helper is used by `executeEvery` in `execute-control.ts`.
19
+ * TDZ when this helper is used by `executeSchedule` in `execute-control.ts`.
20
20
  */
21
21
  export function getContextChannelStore(ctx) {
22
22
  if (ctx instanceof ContextImpl) {
@@ -1,12 +1,12 @@
1
1
  /** @public */
2
- export { branch, fork } from '../builders/control-flow-builders.js';
2
+ export { conditional, inParallel } from '../builders/control-flow-builders.js';
3
3
  /** @public */
4
- export { layerData, layerFn } from '../builders/layer-provides-builders.js';
4
+ export { layerData, layerFunction } from '../builders/layer-provides-builders.js';
5
5
  /** @public */
6
6
  export { loop } from '../builders/loop-builder.js';
7
7
  /** @public */
8
8
  export { spawn } from '../builders/spawn-builder.js';
9
9
  /** @public */
10
- export { step } from '../builders/step-builders.js';
10
+ export { callModel, invokeTool, runCode, step } from '../builders/step-builders.js';
11
11
  /** @public */
12
12
  export { tool, toolWithGenerator } from '../builders/tool-builder.js';
@@ -1,14 +1,15 @@
1
1
  /** @public */
2
- export { branch, fork } from '../builders/control-flow-builders.js';
2
+ export { conditional, inParallel } from '../builders/control-flow-builders.js';
3
3
  /** @public */
4
- export { layerData, layerFn } from '../builders/layer-provides-builders.js';
4
+ export { layerData, layerFunction } from '../builders/layer-provides-builders.js';
5
5
  /** @public */
6
6
  export { loop } from '../builders/loop-builder.js';
7
7
  /** @public */
8
8
  export { spawn } from '../builders/spawn-builder.js';
9
- // The base namespace, without `step.workflow` — the portable surface stays
10
- // free of the hydrator so restricted runtimes don't pull it in.
9
+ // The base builders plus the sub-harness `step` namespace, without
10
+ // `workflow` — the portable surface stays free of the hydrator so
11
+ // restricted runtimes don't pull it in.
11
12
  /** @public */
12
- export { step } from '../builders/step-builders.js';
13
+ export { callModel, invokeTool, runCode, step } from '../builders/step-builders.js';
13
14
  /** @public */
14
15
  export { tool, toolWithGenerator } from '../builders/tool-builder.js';
@@ -5,4 +5,4 @@
5
5
  /** @public */
6
6
  /** @public */
7
7
  /** @public */
8
- export { durableTaskState, historyWindow, observationalContext, planContext, temporalContext, toolContextLayer, workingMemoryContext, } from '@noetic-tools/context';
8
+ export { history, observations, plan, scratchpad, taskState, temporal, toolCalls, } from '@noetic-tools/context';
@@ -5,4 +5,4 @@
5
5
  /** @public */
6
6
  /** @public */
7
7
  /** @public */
8
- export { durableTaskState, historyWindow, observationalContext, planContext, temporalContext, toolContextLayer, workingMemoryContext, } from '@noetic-tools/context';
8
+ export { history, observations, plan, scratchpad, taskState, temporal, toolCalls, } from '@noetic-tools/context';
@@ -7,7 +7,7 @@ export type EmitOption = boolean | ((eventType: string, data: Record<string, unk
7
7
  *
8
8
  * When `emit` is `undefined` (the default for non-LLM steps where the
9
9
  * field does not exist on the Step type), events are always emitted.
10
- * Only StepLLM exposes `emit` for opt-out or filtering.
10
+ * Only StepCallModel exposes `emit` for opt-out or filtering.
11
11
  *
12
12
  * @internal
13
13
  */
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * When `emit` is `undefined` (the default for non-LLM steps where the
7
7
  * field does not exist on the Step type), events are always emitted.
8
- * Only StepLLM exposes `emit` for opt-out or filtering.
8
+ * Only StepCallModel exposes `emit` for opt-out or filtering.
9
9
  *
10
10
  * @internal
11
11
  */
@@ -31,8 +31,8 @@ export declare class ContextImpl implements Context<ContextData> {
31
31
  private readonly _createdAt;
32
32
  /**
33
33
  * Shared channel store for cross-context communication. Inherited by
34
- * `fork` / `spawn` children so channels published by a sibling are visible
35
- * to peers — see `executeFork` and `executeSpawn` in `interpreter/execute-action.ts`
34
+ * `inParallel` / `spawn` children so channels published by a sibling are visible
35
+ * to peers — see `executeInParallel` and `executeSpawn` in `interpreter/execute-action.ts`
36
36
  * and `interpreter/execute-control.ts`.
37
37
  * @internal
38
38
  */
@@ -46,14 +46,14 @@ export declare class ContextImpl implements Context<ContextData> {
46
46
  * Per-context abort fan-out. `abort()` fires it so operations blocked on
47
47
  * this context (channel `recv` waiters, parked back-pressure senders)
48
48
  * reject promptly with `{ kind: 'cancelled' }` instead of hanging until
49
- * their timeout (spec 09, Cancellation item 2). Each fork/spawn child
49
+ * their timeout (spec 09, Cancellation item 2). Each inParallel/spawn child
50
50
  * constructs its own ContextImpl and therefore its own controller —
51
51
  * aborting a child never rejects the parent's waiters, while aborting a
52
52
  * parent DOES cascade down to every live child (see `_children`).
53
53
  */
54
54
  private readonly _abortController;
55
55
  /**
56
- * Live child contexts (fork paths, spawn children) registered for the abort
56
+ * Live child contexts (inParallel paths, spawn children) registered for the abort
57
57
  * cascade. A child adds itself at construction and removes itself via
58
58
  * `detachFromParent()` when its execution settles, so a long-lived parent
59
59
  * driving a loop of spawns does not accumulate finished children.
@@ -77,7 +77,7 @@ export declare class ContextImpl implements Context<ContextData> {
77
77
  */
78
78
  private readonly _segments;
79
79
  /**
80
- * Path this context's steps hang under. Empty on a root context; a fork/spawn child
80
+ * Path this context's steps hang under. Empty on a root context; an inParallel/spawn child
81
81
  * inherits its parent's current path plus a discriminator, so a path key stays unique
82
82
  * across the whole step tree rather than restarting per child context.
83
83
  * @internal
@@ -91,7 +91,7 @@ export declare class ContextImpl implements Context<ContextData> {
91
91
  private readonly _occurrences;
92
92
  /**
93
93
  * Completion ledger for the execution this context belongs to. Shared by reference
94
- * with fork/spawn children — one execution, one ledger.
94
+ * with inParallel/spawn children — one execution, one ledger.
95
95
  * @internal
96
96
  */
97
97
  readonly ledger?: StepLedger;
@@ -105,7 +105,7 @@ export declare class ContextImpl implements Context<ContextData> {
105
105
  span?: Span;
106
106
  channelStore?: ChannelStore;
107
107
  checkpointFn?: (ctx: Context) => Promise<void>;
108
- /** Path this context's steps hang under (fork/spawn children inherit one). */
108
+ /** Path this context's steps hang under (inParallel/spawn children inherit one). */
109
109
  pathPrefix?: string;
110
110
  /** The execution's completion ledger, shared with children by reference. */
111
111
  ledger?: StepLedger;
@@ -134,7 +134,7 @@ export declare class ContextImpl implements Context<ContextData> {
134
134
  /**
135
135
  * @internal
136
136
  * Leave the parent's abort cascade. Called by the interpreter when a spawn
137
- * child or fork path settles — a finished child has nothing left to cancel,
137
+ * child or inParallel path settles — a finished child has nothing left to cancel,
138
138
  * and holding it would leak for the remaining life of the parent.
139
139
  */
140
140
  detachFromParent(): void;
@@ -150,8 +150,6 @@ export declare class ContextImpl implements Context<ContextData> {
150
150
  get shell(): AgentHarnessContract['shell'];
151
151
  get subprocess(): AgentHarnessContract['subprocess'];
152
152
  get context(): ContextData;
153
- /** @deprecated Renamed to `context`. Returns the same object. */
154
- get memory(): ContextData;
155
153
  recv<T>(ch: Channel<T>, opts?: {
156
154
  timeout?: number;
157
155
  }): Promise<T>;