@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
@@ -2,32 +2,19 @@ import { ItemSchemaRegistry } from '@noetic-tools/types';
2
2
  import type { LayerStateStore, RecallCache } from './deps/context.js';
3
3
  import type { DetachedSpawnOverrides } from './deps/interpreter.js';
4
4
  import type { CheckpointStore, EventBroadcaster, RestoreCheckpointOptions, StepLedgerRetention, StepLedgerStore } from './deps/runtime.js';
5
- import type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, Channel, ChannelHandle, Context, ContextCacheConfig, ContextCacheStore, ContextData, ContextLayer, CwdState, DeliveryMode, DetachedHandle, ExecuteInput, ExecuteOptions, ExternalChannel, FsAdapter, HarnessResponse, HarnessStatus, Item, ItemSchemaExtensions, LLMResponse, LlmProviderConfig, ProjectionPolicy, RecallLayerOutput, SessionScope, ShellAdapter, Span, SteeringDecision, Step, StorageAdapter, StreamEvent, StreamingItem, SubHarnessSession, SubprocessAdapter, Tool, TraceExporter, ZodType } from './deps/types.js';
5
+ import type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, Channel, ChannelHandle, Context, ContextCacheConfig, ContextCacheStore, ContextData, ContextLayer, CwdState, DeliveryMode, DetachedHandle, ExecuteInput, ExecuteOptions, ExternalChannel, FsAdapter, HarnessResponse, HarnessStatus, Item, ItemSchemaConfig, LLMResponse, LlmProviderConfig, ProjectionPolicy, RecallLayerOutput, SessionScope, SessionUsage, ShellAdapter, Span, SteeringDecision, Step, StorageAdapter, StreamEvent, StreamingItem, SubHarnessSession, SubprocessAdapter, Tool, TraceExporter, ZodType } from './deps/types.js';
6
6
  export { createStreamIdleWatchdog } from './model-call.js';
7
- interface AgentHarnessOpts<TParams extends Record<string, unknown> = Record<string, unknown>> {
8
- name: string;
9
- initialStep?: Step<ContextData, string, string>;
10
- /** Default context layers applied to every context created via `createContext()` / `execute()`. */
11
- context?: ContextLayer[];
12
- /** @deprecated Renamed to `context`. */
13
- memory?: ContextLayer[];
14
- storage?: StorageAdapter;
15
- hooks?: AgentHooks;
7
+ /**
8
+ * Storage-scoped environment configuration for `AgentHarness`.
9
+ *
10
+ * @public
11
+ */
12
+ export interface StorageEnvironmentConfig {
16
13
  /**
17
- * Harness-wide tool pool. Merged (identity-deduplicated) with tools
18
- * collected from `initialStep` to form every context's `unifiedTools`.
19
- * Use this when the workflow step tree is static and tools are supplied
20
- * per harness instance rather than baked into individual `step.llm` calls.
14
+ * Key-value storage adapter backing context-layer persistence and the
15
+ * step-completion ledger. Defaults to an in-memory adapter.
21
16
  */
22
- tools?: Tool[];
23
- params: TParams;
24
- paramsSchema?: ZodType<TParams>;
25
- /** Filesystem adapter. Defaults to local node:fs when not provided. */
26
- fs?: FsAdapter;
27
- /** Shell adapter. Defaults to local sh when not provided. */
28
- shell?: ShellAdapter;
29
- /** Subprocess adapter. Defaults to an in-memory, same-process adapter. */
30
- subprocess?: SubprocessAdapter;
17
+ adapter?: StorageAdapter;
31
18
  /**
32
19
  * Checkpoint store used by `harness.checkpoint(ctx)` / `harness.restore()`.
33
20
  * When absent, checkpoint/restore are no-ops — a zero-config harness keeps
@@ -35,6 +22,8 @@ interface AgentHarnessOpts<TParams extends Record<string, unknown> = Record<stri
35
22
  * to enable durable execution.
36
23
  */
37
24
  checkpointStore?: CheckpointStore;
25
+ /** Layer-state store override. Defaults to an in-memory store. */
26
+ layerStateStore?: LayerStateStore;
38
27
  /**
39
28
  * Bounds on the step-completion ledger that backs step-level resume. Only meaningful
40
29
  * alongside a `checkpointStore`. Defaults to `DEFAULT_STEP_LEDGER_RETENTION` — 128 KiB
@@ -43,11 +32,45 @@ interface AgentHarnessOpts<TParams extends Record<string, unknown> = Record<stri
43
32
  * never correctness.
44
33
  */
45
34
  stepLedgerRetention?: StepLedgerRetention;
46
- llm?: LlmProviderConfig;
47
- /** Harness-wide item schema extensions. */
48
- itemSchemas?: ItemSchemaExtensions;
49
- /** Whether unknown extension item types must match a registered schema. Defaults to true. */
50
- strictItemSchemas?: boolean;
35
+ }
36
+ /**
37
+ * Execution-environment configuration for `AgentHarness`: the storage,
38
+ * filesystem, shell, and subprocess surfaces the agent runs against.
39
+ *
40
+ * @public
41
+ */
42
+ export interface AgentEnvironmentConfig {
43
+ /** Storage configuration: adapter, durability stores, ledger retention. */
44
+ storage?: StorageEnvironmentConfig;
45
+ /** Filesystem adapter. Defaults to an in-memory adapter. */
46
+ fs?: FsAdapter;
47
+ /** Shell adapter. Defaults to an in-memory adapter. */
48
+ shell?: ShellAdapter;
49
+ /** Subprocess adapter. Defaults to an in-memory, same-process adapter. */
50
+ subprocess?: SubprocessAdapter;
51
+ }
52
+ interface AgentHarnessOpts<TParams extends Record<string, unknown> = Record<string, unknown>> {
53
+ name: string;
54
+ /** Root step tree executed for every turn submitted via `execute()`. */
55
+ agentGraph?: Step<ContextData, string, string>;
56
+ /** Default context layers applied to every context created via `createContext()` / `execute()`. */
57
+ contextLayers?: ContextLayer[];
58
+ hooks?: AgentHooks;
59
+ /**
60
+ * Harness-wide tool pool. Merged (identity-deduplicated) with tools
61
+ * collected from `agentGraph` to form every context's `unifiedTools`.
62
+ * Use this when the workflow step tree is static and tools are supplied
63
+ * per harness instance rather than baked into individual `step.callModel` calls.
64
+ */
65
+ tools?: Tool[];
66
+ params: TParams;
67
+ paramsSchema?: ZodType<TParams>;
68
+ /** Execution environment: storage, filesystem, shell, subprocess. */
69
+ environment?: AgentEnvironmentConfig;
70
+ /** Default provider configuration for model calls made through this harness. */
71
+ callModelDefaults?: LlmProviderConfig;
72
+ /** Harness-wide item schema extensions and validation strictness. */
73
+ itemSchemas?: ItemSchemaConfig;
51
74
  /** Default projection policy for all LLM steps. Individual steps override via `step.projection`. */
52
75
  projection?: ProjectionPolicy;
53
76
  /** When true, every layer is recalled atomically regardless of its `recallMode`. */
@@ -55,15 +78,8 @@ interface AgentHarnessOpts<TParams extends Record<string, unknown> = Record<stri
55
78
  /** Tuning for prompt-cache anchoring. See `ContextCacheConfig` for the defaults. */
56
79
  contextCache?: ContextCacheConfig;
57
80
  traceExporter?: TraceExporter;
58
- layerStateStore?: LayerStateStore;
59
81
  /** Default delivery mode for messages that don't specify one. Defaults to `next-turn`. */
60
82
  defaultDeliveryMode?: DeliveryMode;
61
- /**
62
- * Abort the in-flight model call if the provider stream emits no events for this
63
- * many milliseconds. Defaults to `DEFAULT_STREAM_IDLE_TIMEOUT_MS` (120s).
64
- * Pass `0` or a negative number to disable the watchdog.
65
- */
66
- streamIdleTimeoutMs?: number;
67
83
  /**
68
84
  * Initial working directory for the harness. Used as the seed value for the
69
85
  * shared `cwdState.cwd` on every Context this harness creates, including
@@ -129,7 +145,7 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
129
145
  * @internal
130
146
  */
131
147
  readonly stepLedgerRetention: Required<StepLedgerRetention>;
132
- private readonly initialStep?;
148
+ private readonly agentGraph?;
133
149
  /** Harness-wide tool pool merged into every context's `unifiedTools`. */
134
150
  private readonly harnessTools;
135
151
  /** @internal Context layers configured for this harness. Exposed non-private
@@ -142,7 +158,6 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
142
158
  private readonly rootRunDepth;
143
159
  private readonly callModelOverride?;
144
160
  private readonly defaultDeliveryMode;
145
- private readonly streamIdleTimeoutMs;
146
161
  private readonly sessions;
147
162
  /**
148
163
  * @internal Cross-step harness sessions keyed by `step.session.reuse`, kept
@@ -193,6 +208,7 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
193
208
  }): Promise<void>;
194
209
  getStatus(scope?: SessionScope): HarnessStatus;
195
210
  getQueueSize(scope?: SessionScope): number;
211
+ getUsage(scope?: SessionScope): SessionUsage;
196
212
  seedSessionHistory(threadId: string, items: ReadonlyArray<Item>): void;
197
213
  private getOrCreateSession;
198
214
  private requireSession;
@@ -225,9 +241,7 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
225
241
  state?: unknown;
226
242
  threadId?: string;
227
243
  resourceId?: string;
228
- context?: ContextLayer[];
229
- /** @deprecated Renamed to `context`. */
230
- memory?: ContextLayer[];
244
+ contextLayers?: ContextLayer[];
231
245
  /**
232
246
  * Initial cwd for the new context. When set, takes precedence over both
233
247
  * the parent snapshot and the harness root cwd — used by worktree
@@ -8,7 +8,6 @@ import { buildItemStream, ChannelStore, ContextImpl, captureCheckpoint, clearChe
8
8
  import { SteeringAction } from './deps/types.js';
9
9
  import { AgentHarnessModelCaller } from './model-call.js';
10
10
  export { createStreamIdleWatchdog } from './model-call.js';
11
- import { resolveContextOption } from '../builders/context-option.js';
12
11
  import { buildItemSchemaRegistry } from './model-schema.js';
13
12
  //#endregion
14
13
  const DEFAULT_THREAD_ID = '__default__';
@@ -178,7 +177,7 @@ export class AgentHarness {
178
177
  * @internal
179
178
  */
180
179
  stepLedgerRetention;
181
- initialStep;
180
+ agentGraph;
182
181
  /** Harness-wide tool pool merged into every context's `unifiedTools`. */
183
182
  harnessTools;
184
183
  /** @internal Context layers configured for this harness. Exposed non-private
@@ -191,7 +190,6 @@ export class AgentHarness {
191
190
  rootRunDepth = new Map();
192
191
  callModelOverride;
193
192
  defaultDeliveryMode;
194
- streamIdleTimeoutMs;
195
193
  sessions = new Map();
196
194
  /**
197
195
  * @internal Cross-step harness sessions keyed by `step.session.reuse`, kept
@@ -225,45 +223,47 @@ export class AgentHarness {
225
223
  itemSchemas;
226
224
  constructor(opts) {
227
225
  const validatedParams = opts.paramsSchema ? opts.paramsSchema.parse(opts.params) : opts.params;
226
+ const environment = opts.environment;
227
+ const storageEnv = environment?.storage;
228
228
  this.config = {
229
229
  name: opts.name,
230
- storage: opts.storage ?? createInMemoryStorage(),
230
+ storage: storageEnv?.adapter ?? createInMemoryStorage(),
231
231
  hooks: opts.hooks,
232
232
  params: validatedParams,
233
233
  itemSchemas: opts.itemSchemas,
234
- strictItemSchemas: opts.strictItemSchemas ?? true,
235
234
  projection: opts.projection,
236
235
  forceAtomicRecall: opts.forceAtomicRecall,
237
236
  contextCache: opts.contextCache,
238
237
  };
239
- this.fs = opts.fs ?? createInMemoryFsAdapter();
240
- this.shell = opts.shell ?? createInMemoryShellAdapter();
241
- this.subprocess = opts.subprocess ?? createInMemorySubprocessAdapter();
242
- this.checkpointStore = opts.checkpointStore;
243
- this.stepLedgerStore = opts.checkpointStore
238
+ this.fs = environment?.fs ?? createInMemoryFsAdapter();
239
+ this.shell = environment?.shell ?? createInMemoryShellAdapter();
240
+ this.subprocess = environment?.subprocess ?? createInMemorySubprocessAdapter();
241
+ this.checkpointStore = storageEnv?.checkpointStore;
242
+ this.stepLedgerStore = storageEnv?.checkpointStore
244
243
  ? createStepLedgerStore({
245
244
  storage: this.config.storage ?? createInMemoryStorage(),
246
245
  })
247
246
  : undefined;
248
- this.stepLedgerRetention = resolveStepLedgerRetention(opts.stepLedgerRetention);
249
- this.initialStep = opts.initialStep;
247
+ this.stepLedgerRetention = resolveStepLedgerRetention(storageEnv?.stepLedgerRetention);
248
+ this.agentGraph = opts.agentGraph;
250
249
  this.harnessTools = opts.tools ?? [];
251
- this._contextLayers = resolveContextOption(opts);
250
+ this._contextLayers = opts.contextLayers;
252
251
  this.callModelOverride = opts._testCallModel;
253
- this.client = opts._testCallModel ? undefined : createClient(opts.llm, opts.contextCache);
252
+ this.client = opts._testCallModel
253
+ ? undefined
254
+ : createClient(opts.callModelDefaults, opts.contextCache);
254
255
  this.channelStore = new ChannelStore();
255
256
  this.traceExporter = opts.traceExporter ?? new NoopExporter();
256
257
  this.layerStateStore =
257
- opts.layerStateStore ??
258
+ storageEnv?.layerStateStore ??
258
259
  createLayerStateStore((layerId, hook, error) => {
259
260
  console.warn(`[noetic] context layer '${layerId}' ${hook} error:`, error);
260
261
  });
261
262
  this.recallCache = createRecallCache();
262
263
  this.contextCache = createContextCacheStore();
263
264
  this.defaultDeliveryMode = opts.defaultDeliveryMode ?? 'next-turn';
264
- this.streamIdleTimeoutMs = opts.streamIdleTimeoutMs ?? DEFAULT_STREAM_IDLE_TIMEOUT_MS;
265
- this.itemSchemas = new ItemSchemaRegistry(opts.itemSchemas, {
266
- strictUnknownExtensions: opts.strictItemSchemas ?? true,
265
+ this.itemSchemas = new ItemSchemaRegistry(opts.itemSchemas?.schemas, {
266
+ strictUnknownExtensions: opts.itemSchemas?.strict ?? true,
267
267
  });
268
268
  this.rootCwdState = {
269
269
  cwd: opts.initialCwd ?? '/',
@@ -284,11 +284,11 @@ export class AgentHarness {
284
284
  }
285
285
  //#region Session Accessors
286
286
  execute(input, options) {
287
- if (!this.initialStep) {
287
+ if (!this.agentGraph) {
288
288
  return Promise.reject(new NoeticConfigError({
289
289
  code: 'NO_STEP_CONFIGURED',
290
- message: 'No initialStep configured on this harness.',
291
- hint: 'Pass `initialStep` in constructor options, or use run() directly.',
290
+ message: 'No agentGraph configured on this harness.',
291
+ hint: 'Pass `agentGraph` in constructor options, or use run() directly.',
292
292
  }));
293
293
  }
294
294
  const threadId = options?.threadId ?? DEFAULT_THREAD_ID;
@@ -353,6 +353,17 @@ export class AgentHarness {
353
353
  const session = this.sessions.get(threadId);
354
354
  return session ? session.runner.queue.size : 0;
355
355
  }
356
+ getUsage(scope) {
357
+ const threadId = scope?.threadId ?? DEFAULT_THREAD_ID;
358
+ const session = this.sessions.get(threadId);
359
+ if (!session) {
360
+ return {
361
+ inputTokens: 0,
362
+ outputTokens: 0,
363
+ };
364
+ }
365
+ return session.runner.getUsage();
366
+ }
356
367
  seedSessionHistory(threadId, items) {
357
368
  const session = this.getOrCreateSession(threadId);
358
369
  session.accumulatedItems = [
@@ -385,15 +396,15 @@ export class AgentHarness {
385
396
  threadId,
386
397
  resourceId: perTurnOptions.resourceId,
387
398
  state: perTurnOptions.state,
388
- context: resolveContextOption(perTurnOptions),
399
+ contextLayers: perTurnOptions.contextLayers,
389
400
  _broadcaster: session.runner.broadcaster,
390
401
  });
391
402
  const ext = frameworkCast(ctx);
392
403
  ext._sessionQueue = session.runner.queue;
393
404
  ext._sessionBetweenRounds = true;
394
405
  ext._sessionRunnerAgentName = this.config.name;
395
- if (this.initialStep || this.harnessTools.length > 0) {
396
- const stepTools = this.initialStep ? collectAllTools(this.initialStep) : [];
406
+ if (this.agentGraph || this.harnessTools.length > 0) {
407
+ const stepTools = this.agentGraph ? collectAllTools(this.agentGraph) : [];
397
408
  this.setUnifiedTools(ctx, [
398
409
  ...stepTools,
399
410
  ...this.harnessTools,
@@ -402,11 +413,11 @@ export class AgentHarness {
402
413
  return ctx;
403
414
  },
404
415
  runTurn: async (ctx, _turn, signal) => {
405
- if (!this.initialStep) {
416
+ if (!this.agentGraph) {
406
417
  throw new NoeticConfigError({
407
418
  code: 'NO_STEP_CONFIGURED',
408
- message: 'No initialStep configured on this harness.',
409
- hint: 'Pass `initialStep` in constructor options.',
419
+ message: 'No agentGraph configured on this harness.',
420
+ hint: 'Pass `agentGraph` in constructor options.',
410
421
  });
411
422
  }
412
423
  // Wire signal-abort to context-abort so the interpreter bails cleanly.
@@ -420,7 +431,7 @@ export class AgentHarness {
420
431
  once: true,
421
432
  });
422
433
  }
423
- const result = await this.initAndRun(this.initialStep, '', ctx);
434
+ const result = await this.initAndRun(this.agentGraph, '', ctx);
424
435
  // Snapshot final items into session history for the next turn.
425
436
  session.accumulatedItems = [
426
437
  ...ctx.itemLog.items,
@@ -450,7 +461,7 @@ export class AgentHarness {
450
461
  itemSchemas: this.itemSchemas,
451
462
  client: this.client,
452
463
  callModelOverride: this.callModelOverride,
453
- streamIdleTimeoutMs: this.streamIdleTimeoutMs,
464
+ streamIdleTimeoutMs: DEFAULT_STREAM_IDLE_TIMEOUT_MS,
454
465
  harness: this,
455
466
  traceExporter: this.traceExporter,
456
467
  }).callModel(request);
@@ -540,10 +551,10 @@ export class AgentHarness {
540
551
  }
541
552
  createContext(opts) {
542
553
  const resolved = opts ?? {};
543
- // `ContextImpl` takes the layers as `layers`, so both option spellings are
554
+ // `ContextImpl` takes the layers as `layers`, so the option spelling is
544
555
  // dropped from `rest` rather than spread through under the wrong name.
545
- const { context: _context, memory: _memory, cwdInit, ...rest } = resolved;
546
- const effectiveLayers = resolveContextOption(resolved) ?? this._contextLayers;
556
+ const { contextLayers, cwdInit, ...rest } = resolved;
557
+ const effectiveLayers = contextLayers ?? this._contextLayers;
547
558
  const itemSchemas = buildItemSchemaRegistry({
548
559
  base: this.itemSchemas,
549
560
  layers: effectiveLayers,
@@ -696,7 +707,7 @@ export class AgentHarness {
696
707
  const ctx = this.createContext({
697
708
  items: historyItems,
698
709
  threadId,
699
- context: this._contextLayers,
710
+ contextLayers: this._contextLayers,
700
711
  });
701
712
  const layers = ctx.layers ?? [];
702
713
  if (layers.length === 0) {
@@ -1,4 +1,4 @@
1
1
  export type { ContextCacheConfig, ContextCacheStore, ContextData, ContextLayer, ExecutionContext, ProjectionPolicy, StorageAdapter, } from '@noetic-tools/context';
2
- export type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, Channel, ChannelHandle, Context, CwdState, DeliveryMode, DetachedHandle, ExecuteInput, ExecuteOptions, ExternalChannel, FsAdapter, HarnessResponse, HarnessStatus, Item, ItemSchemaExtensions, LLMResponse, LlmProviderConfig, RecallLayerOutput, SessionScope, ShellAdapter, Span, SteeringDecision, Step, StreamEvent, StreamingItem, SubHarnessSession, SubprocessAdapter, Tool, TraceExporter, } from '@noetic-tools/types';
2
+ export type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, Channel, ChannelHandle, Context, CwdState, DeliveryMode, DetachedHandle, ExecuteInput, ExecuteOptions, ExternalChannel, FsAdapter, HarnessResponse, HarnessStatus, Item, ItemSchemaConfig, ItemSchemaExtensions, LLMResponse, LlmProviderConfig, RecallLayerOutput, SessionScope, SessionUsage, ShellAdapter, Span, SteeringDecision, Step, StreamEvent, StreamingItem, SubHarnessSession, SubprocessAdapter, Tool, TraceExporter, } from '@noetic-tools/types';
3
3
  export { SteeringAction } from '@noetic-tools/types';
4
4
  export type { ZodType } from 'zod';
@@ -10,7 +10,7 @@ interface StreamIdleWatchdog {
10
10
  /** @internal Create a watchdog that aborts `controller` when no
11
11
  * {@link StreamIdleWatchdog.reset reset} is called within `timeoutMs`. When
12
12
  * `timeoutMs <= 0`, returns an inert no-op so callers can always call `.reset()`
13
- * / `.stop()` without a branch. Starts armed: the caller is responsible for
13
+ * / `.stop()` without branching. Starts armed: the caller is responsible for
14
14
  * `.stop()` in a `finally`. `onTimeout` runs before the abort so observers can
15
15
  * emit a framework event with the original cause. Exported only for unit tests. */
16
16
  export declare function createStreamIdleWatchdog(timeoutMs: number, controller: AbortController, onTimeout?: () => void): StreamIdleWatchdog;
@@ -1,7 +1,6 @@
1
1
  import { frameworkCast, NoeticConfigError } from '@noetic-tools/types';
2
2
  import { serverTool } from '@openrouter/agent';
3
- import { z } from 'zod';
4
- import { convertTools, executeToolCall, extractOutputItems, extractSystemInstruction, extractUsage, itemsToInput, sanitizeToolNameForWire, } from '../adapters/openrouter.js';
3
+ import { convertTools, executeToolCall, extractOutputItems, extractSystemInstruction, extractUsage, itemsToInput, resolveWireJsonSchema, sanitizeToolNameForWire, } from '../adapters/openrouter.js';
5
4
  import { isFunctionCall } from '../interpreter/typeguards.js';
6
5
  import { GenAI, NoeticAttr, ToolAttr } from '../observability/genai-attributes.js';
7
6
  import { emitFrameworkEvent, getBroadcaster, shouldEmit } from '../runtime/broadcaster-utils.js';
@@ -9,8 +8,12 @@ import { buildItemSchemaRegistry, createToolResultItem } from './model-schema.js
9
8
  const MAX_TOOL_ROUNDS = 32;
10
9
  const MAX_RECOVERY_CONTINUATIONS = 3;
11
10
  const EPHEMERAL_CONTINUE_INPUT = 'continue';
12
- function buildTextFormat(schema) {
13
- const jsonSchema = z.toJSONSchema(schema);
11
+ function buildTextFormat(schema, explicitJsonSchema) {
12
+ const jsonSchema = resolveWireJsonSchema({
13
+ schema,
14
+ explicitJsonSchema,
15
+ what: 'structured output schema',
16
+ });
14
17
  return {
15
18
  format: {
16
19
  type: 'json_schema',
@@ -133,7 +136,7 @@ async function pipeStreamEventsToBroadcaster(opts) {
133
136
  /** @internal Create a watchdog that aborts `controller` when no
134
137
  * {@link StreamIdleWatchdog.reset reset} is called within `timeoutMs`. When
135
138
  * `timeoutMs <= 0`, returns an inert no-op so callers can always call `.reset()`
136
- * / `.stop()` without a branch. Starts armed: the caller is responsible for
139
+ * / `.stop()` without branching. Starts armed: the caller is responsible for
137
140
  * `.stop()` in a `finally`. `onTimeout` runs before the abort so observers can
138
141
  * emit a framework event with the original cause. Exported only for unit tests. */
139
142
  export function createStreamIdleWatchdog(timeoutMs, controller, onTimeout) {
@@ -150,7 +153,7 @@ export function createStreamIdleWatchdog(timeoutMs, controller, onTimeout) {
150
153
  if (stopped) {
151
154
  return;
152
155
  }
153
- const reason = new Error(`llm stream idle timeout after ${timeoutMs}ms`);
156
+ const reason = new Error(`model stream idle timeout after ${timeoutMs}ms`);
154
157
  onTimeout?.();
155
158
  controller.abort(reason);
156
159
  }, timeoutMs);
@@ -354,7 +357,7 @@ export class AgentHarnessModelCaller {
354
357
  throw new NoeticConfigError({
355
358
  code: 'NO_LLM_PROVIDER',
356
359
  message: 'No LLM provider configured on this harness.',
357
- hint: 'Pass `llm: { apiKey: "..." }` (defaults to the Noetic platform) or set NOETIC_API_KEY. For direct OpenRouter, use `llm: { provider: "openrouter", apiKey: "..." }` or set OPENROUTER_API_KEY.',
360
+ hint: 'Pass `callModelDefaults: { apiKey: "..." }` (defaults to the Noetic platform) or set NOETIC_API_KEY. For direct OpenRouter, use `callModelDefaults: { provider: "openrouter", apiKey: "..." }` or set OPENROUTER_API_KEY.',
358
361
  });
359
362
  }
360
363
  async callModel(request) {
@@ -384,7 +387,9 @@ export class AgentHarnessModelCaller {
384
387
  const rounds = [];
385
388
  let totalCost = 0;
386
389
  const conversationInput = itemsToInput(prepared.remaining);
387
- const textFormat = request.outputSchema ? buildTextFormat(request.outputSchema) : undefined;
390
+ const textFormat = request.outputSchema
391
+ ? buildTextFormat(request.outputSchema, request.outputJsonSchema)
392
+ : undefined;
388
393
  let round = 0;
389
394
  let invalidRecoveryContinuations = 0;
390
395
  let toolLimitRecoveryContinuations = 0;
@@ -406,7 +411,7 @@ export class AgentHarnessModelCaller {
406
411
  let idleStalled = false;
407
412
  const watchdog = createStreamIdleWatchdog(this.opts.streamIdleTimeoutMs, roundController, () => {
408
413
  idleStalled = true;
409
- prepared.emitIfAllowed('llm_call_stalled', {
414
+ prepared.emitIfAllowed('model_call_stalled', {
410
415
  round,
411
416
  idleTimeoutMs: this.opts.streamIdleTimeoutMs,
412
417
  });
@@ -414,7 +419,7 @@ export class AgentHarnessModelCaller {
414
419
  const modelInput = recoveryContinuation
415
420
  ? withEphemeralContinueInput(conversationInput)
416
421
  : frameworkCast(conversationInput);
417
- prepared.emitIfAllowed('llm_call_started', {
422
+ prepared.emitIfAllowed('model_call_started', {
418
423
  round,
419
424
  messageCount: modelInput.length,
420
425
  toolCount: prepared.sdkTools?.length ?? 0,
@@ -446,7 +451,7 @@ export class AgentHarnessModelCaller {
446
451
  watchdog.reset();
447
452
  if (!firstEventSeen) {
448
453
  firstEventSeen = true;
449
- prepared.emitIfAllowed('llm_call_first_event', {
454
+ prepared.emitIfAllowed('model_call_first_event', {
450
455
  round,
451
456
  });
452
457
  }
@@ -462,7 +467,7 @@ export class AgentHarnessModelCaller {
462
467
  if (idleStalled) {
463
468
  throw roundSignal.reason instanceof Error
464
469
  ? roundSignal.reason
465
- : new Error(`llm stream idle timeout after ${this.opts.streamIdleTimeoutMs}ms`);
470
+ : new Error(`model stream idle timeout after ${this.opts.streamIdleTimeoutMs}ms`);
466
471
  }
467
472
  if (request.signal?.aborted) {
468
473
  break;
@@ -507,7 +512,7 @@ export class AgentHarnessModelCaller {
507
512
  continue;
508
513
  }
509
514
  invalidRecoveryContinuations = 0;
510
- prepared.emitIfAllowed('llm_call_completed', {
515
+ prepared.emitIfAllowed('model_call_completed', {
511
516
  round,
512
517
  itemCount: sdkResponse.output?.length ?? 0,
513
518
  });
@@ -605,7 +610,7 @@ export class AgentHarnessModelCaller {
605
610
  kind: 'ok',
606
611
  };
607
612
  }
608
- params.emitIfAllowed('llm_call_failed', {
613
+ params.emitIfAllowed('model_call_failed', {
609
614
  round: params.round,
610
615
  status: terminalError.status,
611
616
  error: terminalError.message,
@@ -615,7 +620,7 @@ export class AgentHarnessModelCaller {
615
620
  throw new Error(terminalError.message);
616
621
  }
617
622
  const next = params.invalidRecoveryContinuations + 1;
618
- params.emitIfAllowed('llm_call_recovery_continue', {
623
+ params.emitIfAllowed('model_call_recovery_continue', {
619
624
  round: params.round,
620
625
  status: terminalError.status,
621
626
  attempt: next,
@@ -633,7 +638,7 @@ export class AgentHarnessModelCaller {
633
638
  };
634
639
  }
635
640
  const message = 'LLM response completed with no output items';
636
- params.emitIfAllowed('llm_call_failed', {
641
+ params.emitIfAllowed('model_call_failed', {
637
642
  round: params.round,
638
643
  status: 'completed',
639
644
  error: message,
@@ -643,7 +648,7 @@ export class AgentHarnessModelCaller {
643
648
  throw new Error(message);
644
649
  }
645
650
  const next = params.invalidRecoveryContinuations + 1;
646
- params.emitIfAllowed('llm_call_recovery_continue', {
651
+ params.emitIfAllowed('model_call_recovery_continue', {
647
652
  round: params.round,
648
653
  status: 'completed',
649
654
  attempt: next,
@@ -750,7 +755,7 @@ export class AgentHarnessModelCaller {
750
755
  recordMalformedToolCall(params) {
751
756
  const { fc, request, allItems, conversationInput } = params;
752
757
  const errorOutput = `Error: malformed JSON in tool arguments: ${fc.arguments}`;
753
- const toolForCall = request.tools?.find((tool) => tool.name === fc.name);
758
+ const toolForCall = request.tools?.find((tool) => tool.name === fc.name || sanitizeToolNameForWire(tool.name) === fc.name);
754
759
  // Owner-scoped result validation (see executeFunctionCall).
755
760
  const outputItem = createToolResultItem({
756
761
  output: errorOutput,
package/dist/index.d.ts CHANGED
@@ -11,31 +11,35 @@ export { channel } from './builders/channel-builder.js';
11
11
  /** @public */
12
12
  export { context } from './builders/context-builder.js';
13
13
  /** @public */
14
- export { branch, fork } from './builders/control-flow-builders.js';
14
+ export { conditional, inParallel } from './builders/control-flow-builders.js';
15
15
  /** @public */
16
- export type { EveryOptions } from './builders/every.js';
16
+ export type { ScheduleOptions } from './builders/every.js';
17
17
  /** @public */
18
- export { every } from './builders/every.js';
18
+ export { schedule } from './builders/every.js';
19
19
  /** @public */
20
- export { layerData, layerFn } from './builders/layer-provides-builders.js';
20
+ export { layerData, layerFunction } from './builders/layer-provides-builders.js';
21
21
  /** @public */
22
22
  export type { LoopConfig } from './builders/loop-builder.js';
23
23
  /** @public */
24
24
  export { loop } from './builders/loop-builder.js';
25
25
  /** @public */
26
- export { provide } from './builders/provide-builder.js';
26
+ export { withContext } from './builders/provide-builder.js';
27
27
  /** @public */
28
28
  export { spawn } from './builders/spawn-builder.js';
29
29
  /** @public */
30
+ export type { CallModelOpts, InvokeToolOpts, RunCodeOpts } from './builders/step-builders.js';
31
+ /** @public */
32
+ export { callModel, invokeTool, runCode, step } from './builders/step-builders.js';
33
+ /** @public */
30
34
  export { tool, toolWithGenerator } from './builders/tool-builder.js';
31
35
  /** @public */
32
36
  export type { HydrationContext } from './builders/workflow-hydrator.js';
33
37
  /** @public */
34
38
  export { hydrateNode, hydrateWorkflow } from './builders/workflow-hydrator.js';
35
39
  /** @public */
36
- export type { StepWorkflowOpts } from './builders/workflow-step.js';
40
+ export type { WorkflowOpts } from './builders/workflow-step.js';
37
41
  /** @public */
38
- export { step } from './builders/workflow-step.js';
42
+ export { workflow } from './builders/workflow-step.js';
39
43
  /** @public */
40
44
  export type { Condition, OtherwiseClause, WhenClause } from './conditions/conditions.js';
41
45
  /** @public */
@@ -57,7 +61,7 @@ export { execute } from './interpreter/execute.js';
57
61
  /** @public */
58
62
  /** @public */
59
63
  /** @public */
60
- export type { DurableTaskState, FactExtractor, FactSearcher, HistoryWindowConfig, ObservationalContextConfig, ObservationalState, PlanContextConfig, PlanEnterSessionCallback, PlanExecutionEntry, PlanExitCallback, PlanState, TemporalContextConfig, TemporalFact, TemporalSearchResult, WorkingMemoryContextConfig, WorkingMemoryContextState, } from '@noetic-tools/context';
64
+ export type { FactExtractor, FactSearcher, HistoryConfig, ObservationsConfig, ObservationsState, PlanConfig, PlanEnterSessionCallback, PlanExecutionEntry, PlanExitCallback, PlanState, ScratchpadConfig, ScratchpadState, TaskState, TemporalConfig, TemporalFact, TemporalSearchResult, } from '@noetic-tools/context';
61
65
  /** @public */
62
66
  /** @public */
63
67
  /** @public */
@@ -70,7 +74,7 @@ export type { DurableTaskState, FactExtractor, FactSearcher, HistoryWindowConfig
70
74
  /** @public */
71
75
  /** @public */
72
76
  /** @public */
73
- export { durableTaskState, fileReference, findFunctionCall, historyWindow, observationalContext, PlanPhase, PlanStyle, planContext, staticContent, steering, storageGetMany, stripUnresolvedToolCalls, temporalContext, toolContextLayer, workingMemoryContext, } from '@noetic-tools/context';
77
+ export { filesystem, findFunctionCall, history, instructions, observations, PlanPhase, PlanStyle, plan, scratchpad, steering, storageGetMany, stripUnresolvedToolCalls, taskState, temporal, toolCalls, } from '@noetic-tools/context';
74
78
  /** @public */
75
79
  export { createMessage, estimateTokens } from '@noetic-tools/types';
76
80
  /** @public */
@@ -80,21 +84,11 @@ export { InMemoryExporter, NoopExporter } from './observability/trace-exporter.j
80
84
  /** @public */
81
85
  export { createInMemoryStorage } from './runtime/in-memory-storage.js';
82
86
  /** @public */
83
- export type { DynamicWorkflowOpts, ParseAndRunWorkflowOpts } from './patterns/dynamic-workflow.js';
84
- /** @public */
85
- export { dynamicWorkflow, parseAndRunWorkflow } from './patterns/dynamic-workflow.js';
86
- /** @public */
87
- export type { InterviewOpts, InterviewQuestionAnswer, InterviewResult } from './patterns/interview.js';
88
- /** @public */
89
- export { interview } from './patterns/interview.js';
90
- /** @public */
91
- export type { PlanConstraints, PlanNode } from './patterns/plans.js';
92
- /** @public */
93
- export { adaptivePlan, compilePlan, PlanNodeSchema } from './patterns/plans.js';
87
+ export type { DynamicWorkflowOpts, ParseAndRunWorkflowOpts } from './builders/dynamic-workflow.js';
94
88
  /** @public */
95
- export { ralphWiggum } from './patterns/ralph-wiggum.js';
89
+ export { dynamicWorkflow, parseAndRunWorkflow } from './builders/dynamic-workflow.js';
96
90
  /** @public */
97
- export { react } from './patterns/react.js';
91
+ export type { AgentEnvironmentConfig, StorageEnvironmentConfig, } from './harness/agent-harness.js';
98
92
  /** @public */
99
93
  export { AgentHarness } from './harness/agent-harness.js';
100
94
  /** @public */
@@ -106,16 +100,16 @@ export { getRegistry, lookupStep, registerStep } from './runtime/step-registry.j
106
100
  /** @public */
107
101
  export { defaultItemSchemaRegistry, ItemSchema, ItemSchemaRegistry } from '@noetic-tools/types';
108
102
  /** @public */
109
- export type { BranchRoute, BranchWorkflowNode, EveryWorkflowNode, ForkWorkflowNode, LlmWorkflowNode, LoopWorkflowNode, MergeStrategy, ProvideWorkflowNode, SequenceWorkflowNode, SpawnWorkflowNode, SubflowWorkflowNode, SubHarnessWorkflowNode, ToolWorkflowNode, UntilPredicate, WorkflowDocument, WorkflowNode, } from './schemas/workflow.js';
103
+ export type { CallModelWorkflowNode, ConditionalRoute, ConditionalWorkflowNode, InParallelWorkflowNode, InvokeToolWorkflowNode, LoopWorkflowNode, MergeStrategy, ScheduleWorkflowNode, SequenceWorkflowNode, SpawnWorkflowNode, SubflowWorkflowNode, SubHarnessWorkflowNode, UntilPredicate, WithContextWorkflowNode, WorkflowDocument, WorkflowNode, } from './schemas/workflow.js';
110
104
  /** @public */
111
105
  export { MergeStrategySchema, UntilPredicateSchema, validateWorkflow, WorkflowDocumentSchema, WorkflowNodeSchema, walkWorkflow, workflowDepth, } from './schemas/workflow.js';
112
106
  /** @public */
113
107
  export type { Channel, ChannelHandle, ExternalChannel } from '@noetic-tools/types';
114
108
  /** @public */
115
109
  /** @public */
116
- export type { LLMResponse, LlmProviderConfig, ModelParams, RetryPolicy, RoundUsage, ServerToolSpec, StepMeta, TokenUsage, Tool, ToolContextDeclaration, } from '@noetic-tools/types';
110
+ export type { InferSchemaInput, InferSchemaOutput, InputSchemaConfig, LLMResponse, LlmProviderConfig, ModelParams, RetryPolicy, RoundUsage, SchemaValidationFailure, SchemaValidationResult, SchemaValidationSuccess, ServerToolSpec, StandardJSONSchemaV1, StandardSchemaV1, StepMeta, TokenUsage, Tool, ToolContextDeclaration, } from '@noetic-tools/types';
117
111
  /** @public */
118
- export { isServerToolSpec } from '@noetic-tools/types';
112
+ export { isServerToolSpec, isStandardJsonSchema, isZodSchema, standardIssuesToZodError, validateSchema, } from '@noetic-tools/types';
119
113
  /** @public */
120
114
  /** @public */
121
115
  /** @public */
@@ -147,13 +141,13 @@ export type { LayerTraceSpan, Span, TraceExporter } from '@noetic-tools/types';
147
141
  /** @public */
148
142
  export type { FrameworkStreamEvent, HarnessResponse, SdkStreamEvent, StreamEvent, StreamingItem, } from '@noetic-tools/types';
149
143
  /** @public */
150
- export type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, ContextCacheConfig, ContextCacheStore, ContextEpoch, DeliveryMode, ExecuteOptions, HarnessStatus, ReanchorReason, RecallLayerOutput, SessionScope, } from '@noetic-tools/types';
144
+ export type { AgentConfig, AgentHarnessContract, AgentHooks, CallModelRequest, ContextCacheConfig, ContextCacheStore, ContextEpoch, DeliveryMode, ExecuteOptions, HarnessStatus, ItemSchemaConfig, ReanchorReason, RecallLayerOutput, SessionScope, SessionUsage, } from '@noetic-tools/types';
151
145
  /** @public */
152
146
  export type { AfterModelCallParams, AfterModelCallResult, BeforeToolCallParams, BeforeToolCallResult, LedgerEntry, SteeringConfig, SteeringDecision, SteeringRule, SteeringState, } from '@noetic-tools/types';
153
147
  /** @public */
154
148
  export { LedgerEntryKind, SteeringAction } from '@noetic-tools/types';
155
149
  /** @public */
156
- export type { ExecuteStepFn, SettleResult, Snapshot, Step, StepBranch, StepFork, StepForkAll, StepForkRace, StepForkSettle, StepLLM, StepLoop, StepProvide, StepRun, StepSpawn, StepSubHarness, StepTool, Until, Verdict, } from '@noetic-tools/types';
150
+ export type { ExecuteStepFn, SettleResult, Snapshot, Step, StepCallModel, StepConditional, StepInParallel, StepInParallelAll, StepInParallelRace, StepInParallelSettle, StepInvokeTool, StepLoop, StepRunCode, StepSpawn, StepSubHarness, StepWithContext, Until, Verdict, } from '@noetic-tools/types';
157
151
  /** @public */
158
152
  export type { SubHarness, SubHarnessBuiltinTool, SubHarnessContinueState, SubHarnessContinueTurnOptions, SubHarnessFinishReason, SubHarnessPromptTurnOptions, SubHarnessResumeState, SubHarnessRunContext, SubHarnessSession, SubHarnessSessionPolicy, SubHarnessSettings, SubHarnessStartOptions, SubHarnessStreamPart, SubHarnessTurnResult, } from '@noetic-tools/types';
159
153
  /** @public */
@@ -175,9 +169,3 @@ export { all, any } from './until/combinators.js';
175
169
  export type { ConvergeConfig, VerifyFn } from './until/predicates.js';
176
170
  /** @public */
177
171
  export { until } from './until/predicates.js';
178
- /**
179
- * Pre-rename names for the context layer system — `MemoryLayer`, `memory()`,
180
- * `workingMemory`, and friends. Each carries its own `@deprecated` pointer to
181
- * its replacement in `./deprecated`. Removed in the next major.
182
- */
183
- export * from './deprecated.js';