@noetic-tools/core 3.2.0 → 5.0.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 (96) hide show
  1. package/dist/adapters/in-memory-subprocess/manifest-persistence.d.ts +1 -1
  2. package/dist/adapters/in-memory-subprocess/types.d.ts +1 -1
  3. package/dist/adapters/openrouter.d.ts +2 -2
  4. package/dist/adapters/openrouter.js +2 -2
  5. package/dist/builders/context-builder.d.ts +11 -0
  6. package/dist/builders/context-builder.js +15 -0
  7. package/dist/builders/context-option.d.ts +23 -0
  8. package/dist/builders/context-option.js +22 -0
  9. package/dist/builders/control-flow-builders.d.ts +19 -19
  10. package/dist/builders/every.d.ts +4 -4
  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/loop-builder.d.ts +3 -3
  14. package/dist/builders/provide-builder.d.ts +14 -7
  15. package/dist/builders/provide-builder.js +15 -4
  16. package/dist/builders/spawn-builder.d.ts +8 -6
  17. package/dist/builders/spawn-builder.js +7 -2
  18. package/dist/builders/step-builders.d.ts +19 -20
  19. package/dist/builders/tool-builder.d.ts +9 -5
  20. package/dist/builders/tool-builder.js +3 -2
  21. package/dist/builders/workflow-hydrator.d.ts +17 -4
  22. package/dist/builders/workflow-hydrator.js +87 -8
  23. package/dist/builders/workflow-step.d.ts +61 -0
  24. package/dist/builders/workflow-step.js +126 -0
  25. package/dist/conditions/conditions.d.ts +17 -17
  26. package/dist/conditions/conditions.js +1 -1
  27. package/dist/deprecated.d.ts +30 -0
  28. package/dist/deprecated.js +28 -0
  29. package/dist/harness/agent-harness.d.ts +42 -26
  30. package/dist/harness/agent-harness.js +68 -21
  31. package/dist/harness/deps/{memory.d.ts → context.d.ts} +2 -2
  32. package/dist/harness/deps/{memory.js → context.js} +1 -1
  33. package/dist/harness/deps/types.d.ts +1 -1
  34. package/dist/harness/model-schema.d.ts +2 -2
  35. package/dist/index.d.ts +21 -17
  36. package/dist/index.js +14 -8
  37. package/dist/interpreter/action-deps.d.ts +3 -3
  38. package/dist/interpreter/action-deps.js +2 -2
  39. package/dist/interpreter/action-types.d.ts +1 -1
  40. package/dist/interpreter/collect-tools.d.ts +1 -1
  41. package/dist/interpreter/execute-action.d.ts +10 -10
  42. package/dist/interpreter/execute-action.js +13 -13
  43. package/dist/interpreter/execute-control.d.ts +4 -4
  44. package/dist/interpreter/execute-control.js +1 -1
  45. package/dist/interpreter/execute-sub-harness.d.ts +1 -1
  46. package/dist/interpreter/execute.d.ts +3 -3
  47. package/dist/interpreter/execute.js +78 -31
  48. package/dist/interpreter/step-dispatcher.d.ts +3 -3
  49. package/dist/interpreter/sub-harness-events.d.ts +2 -2
  50. package/dist/interpreter/typeguards.d.ts +4 -4
  51. package/dist/patterns/dynamic-workflow.d.ts +7 -4
  52. package/dist/patterns/dynamic-workflow.js +2 -0
  53. package/dist/patterns/interview.d.ts +2 -2
  54. package/dist/patterns/plans.d.ts +5 -5
  55. package/dist/patterns/ralph-wiggum.d.ts +2 -2
  56. package/dist/patterns/react.d.ts +7 -5
  57. package/dist/patterns/react.js +6 -4
  58. package/dist/portable/builders.js +2 -0
  59. package/dist/portable/context-layers.d.ts +8 -0
  60. package/dist/portable/context-layers.js +8 -0
  61. package/dist/portable.d.ts +2 -2
  62. package/dist/portable.js +2 -2
  63. package/dist/runtime/channel-store.d.ts +33 -0
  64. package/dist/runtime/channel-store.js +297 -11
  65. package/dist/runtime/context-deps.d.ts +2 -2
  66. package/dist/runtime/context-deps.js +1 -1
  67. package/dist/runtime/context-impl.d.ts +10 -8
  68. package/dist/runtime/context-impl.js +11 -7
  69. package/dist/runtime/context-type-deps.d.ts +1 -1
  70. package/dist/runtime/durable/checkpoint-store.d.ts +1 -1
  71. package/dist/runtime/durable/harness-checkpoints.d.ts +2 -3
  72. package/dist/runtime/durable/harness-checkpoints.js +2 -3
  73. package/dist/runtime/durable/step-ledger.d.ts +1 -1
  74. package/dist/runtime/durable/step-ledger.js +1 -1
  75. package/dist/runtime/in-memory-storage.d.ts +1 -1
  76. package/dist/runtime/session-runner.d.ts +1 -1
  77. package/dist/runtime/step-registry.d.ts +3 -3
  78. package/dist/runtime/{tool-memory.d.ts → tool-context.d.ts} +1 -2
  79. package/dist/runtime/{tool-memory.js → tool-context.js} +5 -2
  80. package/dist/runtime/tool-ui.d.ts +1 -1
  81. package/dist/runtime/tool-ui.js +1 -1
  82. package/dist/schemas/workflow.d.ts +5 -279
  83. package/dist/schemas/workflow.js +4 -376
  84. package/dist/types/mutable-context.d.ts +2 -2
  85. package/dist/types/step-registrar.d.ts +1 -1
  86. package/dist/unstable.d.ts +5 -5
  87. package/dist/unstable.js +3 -3
  88. package/dist/until/predicates.d.ts +1 -1
  89. package/package.json +4 -4
  90. package/schema/noetic-workflow.schema.json +28 -0
  91. package/dist/builders/memory-builder.d.ts +0 -11
  92. package/dist/builders/memory-builder.js +0 -15
  93. package/dist/patterns/flow.d.ts +0 -2
  94. package/dist/patterns/flow.js +0 -1
  95. package/dist/portable/memory-layers.d.ts +0 -8
  96. package/dist/portable/memory-layers.js +0 -8
@@ -146,15 +146,22 @@ function hydrateToolNode(node, ctx) {
146
146
  arguments: JSON.stringify(args),
147
147
  };
148
148
  execCtx.itemLog.append(callItem);
149
+ const layerState = {
150
+ get: (_layerId) => undefined,
151
+ set: (_layerId, _state) => { },
152
+ };
149
153
  const toolCtx = {
150
154
  ctx: execCtx,
151
155
  harness: execCtx.harness,
152
156
  fs: execCtx.fs,
153
157
  shell: execCtx.shell,
154
- memory: {
155
- get: (_layerId) => undefined,
156
- set: (_layerId, _state) => { },
157
- },
158
+ context: layerState,
159
+ // Deprecated alias — the same accessor object, as
160
+ // `buildToolExecutionContext` does. `Tool.execute` takes its second
161
+ // argument as `unknown`, so nothing here is structurally checked
162
+ // against `ToolExecutionContext`; the annotation above is what makes
163
+ // a missing field a compile error instead of a runtime `undefined`.
164
+ memory: layerState,
158
165
  assembledView: execCtx.itemLog.items,
159
166
  lastStepMeta: execCtx.lastStepMeta,
160
167
  };
@@ -285,7 +292,7 @@ function resolveNamedLayers({ names, nodeKind, nodeId, ctx, }) {
285
292
  if (!layer) {
286
293
  throw new NoeticConfigError({
287
294
  code: 'UNKNOWN_LAYER_REFERENCE',
288
- message: `Memory layer '${name}' referenced in ${nodeKind} node '${nodeId}' is not registered.`,
295
+ message: `Context layer '${name}' referenced in ${nodeKind} node '${nodeId}' is not registered.`,
289
296
  hint: `Available layers: ${[
290
297
  ...(ctx.layers?.keys() ?? []),
291
298
  ].join(', ') || '(none)'}. Pass named layers via HydrationContext.layers.`,
@@ -298,7 +305,7 @@ function hydrateSpawnNode(node, ctx) {
298
305
  if (node.kind !== 'spawn') {
299
306
  return frameworkCast(undefined);
300
307
  }
301
- // `memory` is left undefined when the node names no layers so the child
308
+ // `context` is left undefined when the node names no layers so the child
302
309
  // inherits the parent's layers (spec 04). An explicit list replaces them.
303
310
  const resolvedLayers = node.layers
304
311
  ? resolveNamedLayers({
@@ -312,7 +319,7 @@ function hydrateSpawnNode(node, ctx) {
312
319
  id: node.id,
313
320
  child: hydrateNode(node.child, ctx),
314
321
  timeout: node.timeout,
315
- memory: resolvedLayers,
322
+ context: resolvedLayers,
316
323
  });
317
324
  }
318
325
  function hydrateProvideNode(node, ctx) {
@@ -322,7 +329,7 @@ function hydrateProvideNode(node, ctx) {
322
329
  return provide({
323
330
  id: node.id,
324
331
  child: hydrateNode(node.child, ctx),
325
- memory: resolveNamedLayers({
332
+ context: resolveNamedLayers({
326
333
  names: node.layers,
327
334
  nodeKind: 'provide',
328
335
  nodeId: node.id,
@@ -401,6 +408,75 @@ function hydrateSubHarnessNode(node, ctx) {
401
408
  session: node.session,
402
409
  });
403
410
  }
411
+ /**
412
+ * Hydrates a `subflow` node lazily: the target document resolves and hydrates
413
+ * on first execution, memoized. Lazy because `HydrationContext.workflows` may
414
+ * be a live view that gains entries after hydration, and because it keeps
415
+ * cycle detection path-scoped — each ref chain threads its own ancestry set,
416
+ * so diamond reuse of a named workflow is legal while A→B→A throws.
417
+ */
418
+ function hydrateSubflowNode(node, ctx) {
419
+ if (node.kind !== 'subflow') {
420
+ return frameworkCast(undefined);
421
+ }
422
+ let cached;
423
+ const resolve = () => {
424
+ if (!cached) {
425
+ const { doc, childCtx } = resolveSubflowDocument(node, ctx);
426
+ cached = hydrateNode(suffixNodeIds(doc.root, `-${node.id}`), childCtx);
427
+ }
428
+ return cached;
429
+ };
430
+ return frameworkCast(step.run({
431
+ id: node.id,
432
+ execute: async (input, execCtx) => {
433
+ const child = resolve();
434
+ return stringifyResult(await ctx.executeStep(child, node.input ?? input, execCtx));
435
+ },
436
+ }));
437
+ }
438
+ function resolveSubflowDocument(node, ctx) {
439
+ if (node.document) {
440
+ // Inline documents are finite JSON trees — they cannot cycle, so they
441
+ // add nothing to the ancestry chain.
442
+ return {
443
+ doc: node.document,
444
+ childCtx: ctx,
445
+ };
446
+ }
447
+ const ref = node.ref ?? '';
448
+ const ancestry = ctx.subflowAncestry ?? new Set();
449
+ if (ancestry.has(ref)) {
450
+ throw new NoeticConfigError({
451
+ code: 'WORKFLOW_CYCLE',
452
+ message: `Sub-workflow '${ref}' referenced in subflow node '${node.id}' forms a reference cycle (${[
453
+ ...ancestry,
454
+ ref,
455
+ ].join(' -> ')}).`,
456
+ hint: 'A named sub-workflow may not reference itself, directly or transitively. Break the cycle or inline the document.',
457
+ });
458
+ }
459
+ const doc = ctx.workflows?.get(ref);
460
+ if (!doc) {
461
+ throw new NoeticConfigError({
462
+ code: 'UNKNOWN_WORKFLOW_REFERENCE',
463
+ message: `Sub-workflow '${ref}' referenced in subflow node '${node.id}' is not registered.`,
464
+ hint: `Pass named workflows via HydrationContext.workflows. Available: ${[
465
+ ...(ctx.workflows?.keys() ?? []),
466
+ ].join(', ') || '(none)'}.`,
467
+ });
468
+ }
469
+ return {
470
+ doc,
471
+ childCtx: {
472
+ ...ctx,
473
+ subflowAncestry: new Set([
474
+ ...ancestry,
475
+ ref,
476
+ ]),
477
+ },
478
+ };
479
+ }
404
480
  //#endregion
405
481
  //#region Handler Registry
406
482
  const NODE_HYDRATORS = {
@@ -414,6 +490,7 @@ const NODE_HYDRATORS = {
414
490
  loop: hydrateLoopNode,
415
491
  sequence: hydrateSequenceNode,
416
492
  every: hydrateEveryNode,
493
+ subflow: hydrateSubflowNode,
417
494
  'claude-code': hydrateSubHarnessNode,
418
495
  codex: hydrateSubHarnessNode,
419
496
  opencode: hydrateSubHarnessNode,
@@ -611,6 +688,8 @@ async function runCodeViaSubprocess(opts) {
611
688
  * @throws `NoeticConfigError` with code `UNKNOWN_NODE_KIND` if the node kind is unrecognised.
612
689
  * @throws `NoeticConfigError` with code `UNKNOWN_TOOL_REFERENCE` if a tool name cannot be resolved.
613
690
  * @throws `NoeticConfigError` with code `UNKNOWN_UNTIL_PREDICATE` if an until predicate kind is unrecognised.
691
+ * @throws `NoeticConfigError` with code `UNKNOWN_WORKFLOW_REFERENCE` (at execution time) if a subflow ref names no registered workflow.
692
+ * @throws `NoeticConfigError` with code `WORKFLOW_CYCLE` (at execution time) if named sub-workflow refs form a cycle.
614
693
  */
615
694
  export function hydrateNode(node, ctx) {
616
695
  const hydrator = NODE_HYDRATORS[node.kind];
@@ -0,0 +1,61 @@
1
+ /**
2
+ * `step.workflow` — runs a `WorkflowDocument` as a single composable step.
3
+ *
4
+ * Lives beside `step-builders.ts` (rather than inside it) because the hydrator
5
+ * imports the base `step` object; adding a hydrating builder there would create
6
+ * an import cycle. This module composes the public `step` namespace instead.
7
+ */
8
+ import type { ContextData, ContextLayer } from '@noetic-tools/context';
9
+ import type { OutputCodec, StepRun, SubHarness, SubHarnessKind, SubprocessAdapter, Tool, WorkflowDocument } from '@noetic-tools/types';
10
+ import * as stepBuilders from './step-builders.js';
11
+ /** @public Options for `step.workflow`. */
12
+ export interface StepWorkflowOpts {
13
+ id: string;
14
+ /** Inline workflow document. Mutually exclusive with `ref`. */
15
+ document?: WorkflowDocument;
16
+ /** Named workflow resolved from `workflows`. Mutually exclusive with `document`. */
17
+ ref?: string;
18
+ /** Client tools the document's `llm`/`tool` nodes may reference by name. Default: none. */
19
+ tools?: Tool[];
20
+ /** Named context layers for `provide`/`spawn` nodes. */
21
+ layers?: ReadonlyMap<string, ContextLayer>;
22
+ /** Named sub-workflows for `subflow` nodes — and for resolving `ref` itself. */
23
+ workflows?: ReadonlyMap<string, WorkflowDocument>;
24
+ /** SubHarness adapters for `claude-code`/`codex`/`opencode`/`pi` nodes. */
25
+ subHarnesses?: ReadonlyMap<SubHarnessKind, SubHarness>;
26
+ /** Output codecs for `llm` nodes' `output` codec references. */
27
+ uiLibraries?: ReadonlyMap<string, OutputCodec>;
28
+ /** Resolver for named subprocess adapters on `run` nodes. */
29
+ resolveSubprocess?: (ref: string) => SubprocessAdapter | undefined;
30
+ /** `'inherit'` (default) runs in the caller's session; `'spawn'` isolates via `spawn()`. */
31
+ isolation?: 'inherit' | 'spawn';
32
+ }
33
+ /**
34
+ * Creates a step that hydrates and executes a JSON workflow document.
35
+ *
36
+ * The document resolves lazily on first execution (so a `ref` may target a
37
+ * workflow registered after the step is built) and the hydrated tree is
38
+ * memoized across executions. When the step itself is built from a `ref`,
39
+ * that name seeds the subflow ancestry chain, so a self-referencing named
40
+ * workflow fails with `WORKFLOW_CYCLE` instead of recursing forever.
41
+ *
42
+ * @public
43
+ * @param opts - See `StepWorkflowOpts`.
44
+ * @returns A `StepRun` executing the workflow via the harness on the context.
45
+ * @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
46
+ * @throws `NoeticConfigError` with code `INVALID_WORKFLOW_SOURCE` unless exactly one of `document`/`ref` is set.
47
+ * @throws `NoeticConfigError` with code `MISSING_HARNESS_CONTEXT` (at execution) without `ctx.harness`.
48
+ * @throws `NoeticConfigError` with code `UNKNOWN_WORKFLOW_REFERENCE` (at execution) if `ref` names no registered workflow.
49
+ */
50
+ export declare function stepWorkflow(opts: StepWorkflowOpts): StepRun<ContextData, string, string>;
51
+ /** @public The step builder namespace: the base builders plus `workflow`. */
52
+ export declare const step: {
53
+ readonly run: <TContext = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: stepBuilders.StepRunOpts<TContext, I, O>) => StepRun<TContext, I, O>;
54
+ readonly llm: <TContext = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: stepBuilders.StepLLMOpts<TContext, O>) => import("@noetic-tools/types").StepLLM<TContext, I, O>;
55
+ readonly tool: <TContext = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: stepBuilders.StepToolOpts<I, O>) => import("@noetic-tools/types").StepTool<TContext, I, O>;
56
+ readonly claudeCode: <TContext = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: stepBuilders.StepSubHarnessOpts<TContext, O>) => import("@noetic-tools/types").StepSubHarness<TContext, I, O>;
57
+ readonly codex: <TContext = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: stepBuilders.StepSubHarnessOpts<TContext, O>) => import("@noetic-tools/types").StepSubHarness<TContext, I, O>;
58
+ readonly opencode: <TContext = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: stepBuilders.StepSubHarnessOpts<TContext, O>) => import("@noetic-tools/types").StepSubHarness<TContext, I, O>;
59
+ readonly pi: <TContext = Readonly<Record<string, Record<string, unknown>>>, I = unknown, O = unknown>(opts: stepBuilders.StepSubHarnessOpts<TContext, O>) => import("@noetic-tools/types").StepSubHarness<TContext, I, O>;
60
+ readonly workflow: typeof stepWorkflow;
61
+ };
@@ -0,0 +1,126 @@
1
+ /**
2
+ * `step.workflow` — runs a `WorkflowDocument` as a single composable step.
3
+ *
4
+ * Lives beside `step-builders.ts` (rather than inside it) because the hydrator
5
+ * imports the base `step` object; adding a hydrating builder there would create
6
+ * an import cycle. This module composes the public `step` namespace instead.
7
+ */
8
+ import { frameworkCast, NoeticConfigError } from '@noetic-tools/types';
9
+ import { spawn } from './spawn-builder.js';
10
+ import * as stepBuilders from './step-builders.js';
11
+ import { hydrateWorkflow } from './workflow-hydrator.js';
12
+ //#endregion
13
+ //#region Builder
14
+ /**
15
+ * Creates a step that hydrates and executes a JSON workflow document.
16
+ *
17
+ * The document resolves lazily on first execution (so a `ref` may target a
18
+ * workflow registered after the step is built) and the hydrated tree is
19
+ * memoized across executions. When the step itself is built from a `ref`,
20
+ * that name seeds the subflow ancestry chain, so a self-referencing named
21
+ * workflow fails with `WORKFLOW_CYCLE` instead of recursing forever.
22
+ *
23
+ * @public
24
+ * @param opts - See `StepWorkflowOpts`.
25
+ * @returns A `StepRun` executing the workflow via the harness on the context.
26
+ * @throws `NoeticConfigError` with code `EMPTY_STEP_ID` if `id` is empty.
27
+ * @throws `NoeticConfigError` with code `INVALID_WORKFLOW_SOURCE` unless exactly one of `document`/`ref` is set.
28
+ * @throws `NoeticConfigError` with code `MISSING_HARNESS_CONTEXT` (at execution) without `ctx.harness`.
29
+ * @throws `NoeticConfigError` with code `UNKNOWN_WORKFLOW_REFERENCE` (at execution) if `ref` names no registered workflow.
30
+ */
31
+ export function stepWorkflow(opts) {
32
+ if (!opts.id || opts.id.trim() === '') {
33
+ throw new NoeticConfigError({
34
+ code: 'EMPTY_STEP_ID',
35
+ message: 'step.workflow() requires a non-empty id.',
36
+ hint: 'Pass a unique string as the id field, e.g. step.workflow({ id: "verify", ... }).',
37
+ });
38
+ }
39
+ if ((opts.document === undefined) === (opts.ref === undefined)) {
40
+ throw new NoeticConfigError({
41
+ code: 'INVALID_WORKFLOW_SOURCE',
42
+ message: `step.workflow('${opts.id}') requires exactly one of 'document' (inline) or 'ref' (named).`,
43
+ hint: "Pass document: { version: 1, root: ... } or ref: '<name>' with a workflows registry.",
44
+ });
45
+ }
46
+ // The hydrated tree bakes the harness's executeStep into every nested
47
+ // node's closure, so the cache is keyed on the harness: a step shared
48
+ // across sessions re-hydrates when it runs under a different harness
49
+ // instead of routing nested steps through the first one.
50
+ let cached;
51
+ return stepBuilders.step.run({
52
+ id: opts.id,
53
+ execute: async (input, ctx) => {
54
+ const harness = ctx.harness;
55
+ if (!harness) {
56
+ throw new NoeticConfigError({
57
+ code: 'MISSING_HARNESS_CONTEXT',
58
+ message: 'step.workflow requires a harness on the execution context.',
59
+ hint: 'Execute this step via AgentHarness.run() or ensure ctx.harness is set.',
60
+ });
61
+ }
62
+ const executeStep = frameworkCast(harness.run.bind(harness));
63
+ if (!cached || cached.harness !== harness) {
64
+ cached = {
65
+ harness,
66
+ step: hydrate(opts, executeStep),
67
+ };
68
+ }
69
+ return stringify(await executeStep(cached.step, input, ctx));
70
+ },
71
+ });
72
+ }
73
+ /** @public The step builder namespace: the base builders plus `workflow`. */
74
+ export const step = {
75
+ ...stepBuilders.step,
76
+ workflow: stepWorkflow,
77
+ };
78
+ //#endregion
79
+ //#region Helpers
80
+ function hydrate(opts, executeStep) {
81
+ const doc = opts.document ?? (opts.ref ? opts.workflows?.get(opts.ref) : undefined);
82
+ if (!doc) {
83
+ throw new NoeticConfigError({
84
+ code: 'UNKNOWN_WORKFLOW_REFERENCE',
85
+ message: `Workflow '${opts.ref}' referenced by step.workflow('${opts.id}') is not registered.`,
86
+ hint: `Pass named workflows via the workflows option. Available: ${[
87
+ ...(opts.workflows?.keys() ?? []),
88
+ ].join(', ') || '(none)'}.`,
89
+ });
90
+ }
91
+ const hydrationCtx = {
92
+ tools: new Map((opts.tools ?? []).map((t) => [
93
+ t.name,
94
+ t,
95
+ ])),
96
+ executeStep,
97
+ layers: opts.layers,
98
+ workflows: opts.workflows,
99
+ subHarnesses: opts.subHarnesses,
100
+ uiLibraries: opts.uiLibraries,
101
+ resolveSubprocess: opts.resolveSubprocess,
102
+ subflowAncestry: opts.ref
103
+ ? new Set([
104
+ opts.ref,
105
+ ])
106
+ : undefined,
107
+ };
108
+ const hydrated = hydrateWorkflow(doc, hydrationCtx);
109
+ if (opts.isolation !== 'spawn') {
110
+ return hydrated;
111
+ }
112
+ return spawn({
113
+ id: `${opts.id}-spawn`,
114
+ child: hydrated,
115
+ });
116
+ }
117
+ function stringify(value) {
118
+ if (typeof value === 'string') {
119
+ return value;
120
+ }
121
+ if (value === null || value === undefined) {
122
+ return '';
123
+ }
124
+ return JSON.stringify(value);
125
+ }
126
+ //#endregion
@@ -1,17 +1,17 @@
1
- import type { ContextMemory, StorageAdapter } from '@noetic-tools/memory';
1
+ import type { ContextData, StorageAdapter } from '@noetic-tools/context';
2
2
  import type { Context, Step } from '@noetic-tools/types';
3
3
  import type { EmbedFn } from '../types/embed.js';
4
4
  export type Condition<I> = (input: I, ctx: Context) => Promise<boolean>;
5
- export interface WhenClause<TMemory = ContextMemory, I = unknown, O = unknown> {
5
+ export interface WhenClause<TContext = ContextData, I = unknown, O = unknown> {
6
6
  readonly kind: 'when';
7
7
  readonly condition: Condition<I>;
8
- readonly step: Step<TMemory, I, O>;
8
+ readonly step: Step<TContext, I, O>;
9
9
  }
10
- export interface OtherwiseClause<TMemory = ContextMemory, I = unknown, O = unknown> {
10
+ export interface OtherwiseClause<TContext = ContextData, I = unknown, O = unknown> {
11
11
  readonly kind: 'otherwise';
12
- readonly step: Step<TMemory, I, O>;
12
+ readonly step: Step<TContext, I, O>;
13
13
  }
14
- type Clause<TMemory, I, O> = WhenClause<TMemory, I, O> | OtherwiseClause<TMemory, I, O>;
14
+ type Clause<TContext, I, O> = WhenClause<TContext, I, O> | OtherwiseClause<TContext, I, O>;
15
15
  /**
16
16
  * Creates a conditional clause that routes to the given step when the condition is true.
17
17
  *
@@ -20,7 +20,7 @@ type Clause<TMemory, I, O> = WhenClause<TMemory, I, O> | OtherwiseClause<TMemory
20
20
  * @param step - Step to execute when the condition matches.
21
21
  * @returns A `WhenClause` for use in `semanticRoute`.
22
22
  */
23
- export declare function when<TMemory = ContextMemory, I = unknown, O = unknown>(condition: Condition<I>, step: Step<TMemory, I, O>): WhenClause<TMemory, I, O>;
23
+ export declare function when<TContext = ContextData, I = unknown, O = unknown>(condition: Condition<I>, step: Step<TContext, I, O>): WhenClause<TContext, I, O>;
24
24
  /**
25
25
  * Creates a fallback clause that always matches, used as the last clause in `semanticRoute`.
26
26
  *
@@ -28,7 +28,7 @@ export declare function when<TMemory = ContextMemory, I = unknown, O = unknown>(
28
28
  * @param step - Step to execute when no prior `when` clause matches.
29
29
  * @returns An `OtherwiseClause` for use in `semanticRoute`.
30
30
  */
31
- export declare function otherwise<TMemory = ContextMemory, I = unknown, O = unknown>(step: Step<TMemory, I, O>): OtherwiseClause<TMemory, I, O>;
31
+ export declare function otherwise<TContext = ContextData, I = unknown, O = unknown>(step: Step<TContext, I, O>): OtherwiseClause<TContext, I, O>;
32
32
  /**
33
33
  * Builds a route function from an ordered list of `when`/`otherwise` clauses.
34
34
  * Evaluates clauses sequentially, returning the first matching step or `null`.
@@ -37,21 +37,21 @@ export declare function otherwise<TMemory = ContextMemory, I = unknown, O = unkn
37
37
  * @param clauses - Ordered `WhenClause` and optional trailing `OtherwiseClause`.
38
38
  * @returns A route function suitable for `branch({ route })`.
39
39
  */
40
- export declare function semanticRoute<TMemory = ContextMemory, I = unknown, O = unknown>(...clauses: Clause<TMemory, I, O>[]): (input: I, ctx: Context) => Promise<Step<TMemory, I, O> | null>;
41
- interface SemanticSwitchSimple<TMemory, I, O> {
40
+ export declare function semanticRoute<TContext = ContextData, I = unknown, O = unknown>(...clauses: Clause<TContext, I, O>[]): (input: I, ctx: Context) => Promise<Step<TContext, I, O> | null>;
41
+ interface SemanticSwitchSimple<TContext, I, O> {
42
42
  embed: EmbedFn;
43
- cases: Record<string, Step<TMemory, I, O>>;
44
- default?: Step<TMemory, I, O>;
43
+ cases: Record<string, Step<TContext, I, O>>;
44
+ default?: Step<TContext, I, O>;
45
45
  threshold?: number;
46
46
  cache?: StorageAdapter;
47
47
  }
48
- interface SemanticSwitchAdvanced<TMemory, I, O> {
48
+ interface SemanticSwitchAdvanced<TContext, I, O> {
49
49
  embed: EmbedFn;
50
50
  cases: {
51
51
  labels: string | string[];
52
- step: Step<TMemory, I, O>;
52
+ step: Step<TContext, I, O>;
53
53
  }[];
54
- default?: Step<TMemory, I, O>;
54
+ default?: Step<TContext, I, O>;
55
55
  threshold?: number;
56
56
  cache?: StorageAdapter;
57
57
  }
@@ -62,9 +62,9 @@ interface SemanticSwitchAdvanced<TMemory, I, O> {
62
62
  * @param opts - Simple form with `Record<string, Step>` cases, or advanced form with multi-label cases.
63
63
  * @returns A route function suitable for `branch({ route })`.
64
64
  */
65
- export declare function semanticSwitch<TMemory = ContextMemory, I = unknown, O = unknown>(opts: SemanticSwitchSimple<TMemory, I, O>): (input: I, ctx: Context) => Promise<Step<TMemory, I, O> | null>;
65
+ export declare function semanticSwitch<TContext = ContextData, I = unknown, O = unknown>(opts: SemanticSwitchSimple<TContext, I, O>): (input: I, ctx: Context) => Promise<Step<TContext, I, O> | null>;
66
66
  /** @public */
67
- export declare function semanticSwitch<TMemory = ContextMemory, I = unknown, O = unknown>(opts: SemanticSwitchAdvanced<TMemory, I, O>): (input: I, ctx: Context) => Promise<Step<TMemory, I, O> | null>;
67
+ export declare function semanticSwitch<TContext = ContextData, I = unknown, O = unknown>(opts: SemanticSwitchAdvanced<TContext, I, O>): (input: I, ctx: Context) => Promise<Step<TContext, I, O> | null>;
68
68
  /**
69
69
  * Creates a condition that matches when the input embedding is within a cosine similarity threshold of a label.
70
70
  *
@@ -1,4 +1,4 @@
1
- import { storageGetMany } from '@noetic-tools/memory';
1
+ import { storageGetMany } from '@noetic-tools/context';
2
2
  import { createMessage, extractAssistantText, trackUsage } from '@noetic-tools/types';
3
3
  import { z } from 'zod';
4
4
  import { cosineSimilarity } from './cosine-similarity.js';
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Deprecated aliases from the "memory layer" era of the framework.
3
+ *
4
+ * The layer system assembles the model's *context window* — recall, budget
5
+ * allocation, history projection, the item-append pipeline — so it is named
6
+ * after context, not memory. Every name below still resolves to its
7
+ * replacement; nothing here changes behaviour.
8
+ *
9
+ * Most of these are plain pass-throughs: the alias and its replacement already
10
+ * live in `@noetic-tools/types` / `@noetic-tools/context`, and re-exporting
11
+ * carries each name's `@deprecated` pointer along with it. Only the renaming
12
+ * aliases — where core exports a symbol under a *different* name than its
13
+ * source package does — are declared here.
14
+ *
15
+ * The matching runtime aliases (the `memory:` config key on `provide`/`spawn`/
16
+ * `tool`/`react`/`AgentHarness`, and the `ctx.memory` accessor) are handled at
17
+ * their call sites — see `resolveContextOption`.
18
+ *
19
+ * Scheduled for removal in the next major of `@noetic-tools/core`.
20
+ */
21
+ export type { ObservationalMemoryConfig, PlanMemoryConfig, TemporalMemoryConfig, WorkingMemoryConfig, WorkingMemoryState, } from '@noetic-tools/context';
22
+ export { observationalMemory, planMemory, temporalMemory, toolMemoryLayer, workingMemory, } from '@noetic-tools/context';
23
+ export type { ContextMemory, InferMemory, InferMemoryShape, MemoryCallModelRequest, MemoryConfig, MemoryHooks, MemoryLayer, MemoryScope, MemoryTraceSpan, ToolMemory, ToolMemoryDeclaration, } from '@noetic-tools/types';
24
+ export {
25
+ /**
26
+ * @public
27
+ * @deprecated Renamed to `context`. Declared here rather than re-exported
28
+ * because the builder itself lives in core under its new name.
29
+ */
30
+ context as memory, } from './builders/context-builder.js';
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Deprecated aliases from the "memory layer" era of the framework.
3
+ *
4
+ * The layer system assembles the model's *context window* — recall, budget
5
+ * allocation, history projection, the item-append pipeline — so it is named
6
+ * after context, not memory. Every name below still resolves to its
7
+ * replacement; nothing here changes behaviour.
8
+ *
9
+ * Most of these are plain pass-throughs: the alias and its replacement already
10
+ * live in `@noetic-tools/types` / `@noetic-tools/context`, and re-exporting
11
+ * carries each name's `@deprecated` pointer along with it. Only the renaming
12
+ * aliases — where core exports a symbol under a *different* name than its
13
+ * source package does — are declared here.
14
+ *
15
+ * The matching runtime aliases (the `memory:` config key on `provide`/`spawn`/
16
+ * `tool`/`react`/`AgentHarness`, and the `ctx.memory` accessor) are handled at
17
+ * their call sites — see `resolveContextOption`.
18
+ *
19
+ * Scheduled for removal in the next major of `@noetic-tools/core`.
20
+ */
21
+ export { observationalMemory, planMemory, temporalMemory, toolMemoryLayer, workingMemory, } from '@noetic-tools/context';
22
+ export {
23
+ /**
24
+ * @public
25
+ * @deprecated Renamed to `context`. Declared here rather than re-exported
26
+ * because the builder itself lives in core under its new name.
27
+ */
28
+ context as memory, } from './builders/context-builder.js';