@noetic-tools/core 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -105,6 +105,13 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
105
105
  readonly layerStateStore: LayerStateStore;
106
106
  /** Per-harness memoization cache for `recallMode: 'eventual'` layers. */
107
107
  readonly recallCache: RecallCache;
108
+ /**
109
+ * Execution ids whose layer `init` hooks have already run, so repeated/nested
110
+ * `run()` calls and the session turn path never re-init (which would clobber
111
+ * accumulated in-memory state by re-hydrating from storage). Keyed by
112
+ * `ctx.id` (the layer-state store's executionId).
113
+ */
114
+ private readonly initializedExecutions;
108
115
  readonly traceExporter: TraceExporter;
109
116
  /**
110
117
  * Long-lived shared cwd state. The same reference is seeded into every
@@ -143,6 +150,14 @@ export declare class AgentHarness<TParams extends Record<string, unknown> = Reco
143
150
  /** Run all layer `init` hooks before the first step executes. Per spec 11,
144
151
  * init MUST complete before any recall fires so layer state is populated. */
145
152
  private initAndRun;
153
+ /**
154
+ * Idempotently run layer `init` hooks for `ctx` (keyed by `ctx.id`). Init
155
+ * MUST complete before any recall/store fires so init-bearing layers are not
156
+ * treated as disabled. Guarded so nested/repeated `run()` calls and the
157
+ * session turn path never re-init — re-init would re-hydrate from storage and
158
+ * clobber accumulated in-memory state.
159
+ */
160
+ private ensureLayersInit;
146
161
  detachedSpawn<I, O>(s: Step<ContextMemory, I, O>, input: I, parentCtx: Context, overrides?: DetachedSpawnOverrides): DetachedHandle<O>;
147
162
  createContext(opts?: {
148
163
  parent?: Context;
@@ -110,6 +110,13 @@ export class AgentHarness {
110
110
  layerStateStore;
111
111
  /** Per-harness memoization cache for `recallMode: 'eventual'` layers. */
112
112
  recallCache;
113
+ /**
114
+ * Execution ids whose layer `init` hooks have already run, so repeated/nested
115
+ * `run()` calls and the session turn path never re-init (which would clobber
116
+ * accumulated in-memory state by re-hydrating from storage). Keyed by
117
+ * `ctx.id` (the layer-state store's executionId).
118
+ */
119
+ initializedExecutions = new Set();
113
120
  traceExporter;
114
121
  /**
115
122
  * Long-lived shared cwd state. The same reference is seeded into every
@@ -356,17 +363,36 @@ export class AgentHarness {
356
363
  ...this.harnessTools,
357
364
  ]);
358
365
  }
366
+ // Hydrate/recall/persist memory on the bare `run()` path too (issue #48):
367
+ // configuring `memory` + `storage` must "just work" without going through
368
+ // `execute()`/`seedSessionHistory`. Idempotent — see `ensureLayersInit`.
369
+ await this.ensureLayersInit(ctx);
359
370
  return execute(s, input, ctx);
360
371
  }
361
372
  /** Run all layer `init` hooks before the first step executes. Per spec 11,
362
373
  * init MUST complete before any recall fires so layer state is populated. */
363
374
  async initAndRun(s, input, ctx) {
375
+ await this.ensureLayersInit(ctx);
376
+ return execute(s, input, ctx);
377
+ }
378
+ /**
379
+ * Idempotently run layer `init` hooks for `ctx` (keyed by `ctx.id`). Init
380
+ * MUST complete before any recall/store fires so init-bearing layers are not
381
+ * treated as disabled. Guarded so nested/repeated `run()` calls and the
382
+ * session turn path never re-init — re-init would re-hydrate from storage and
383
+ * clobber accumulated in-memory state.
384
+ */
385
+ async ensureLayersInit(ctx) {
364
386
  const layers = ctx.layers;
365
387
  const storage = this.config.storage;
366
- if (layers && layers.length > 0 && storage) {
367
- await this.initLayers(layers, ctx, storage);
388
+ if (!layers || layers.length === 0 || !storage) {
389
+ return;
368
390
  }
369
- return execute(s, input, ctx);
391
+ if (this.initializedExecutions.has(ctx.id)) {
392
+ return;
393
+ }
394
+ this.initializedExecutions.add(ctx.id);
395
+ await this.initLayers(layers, ctx, storage);
370
396
  }
371
397
  detachedSpawn(s, input, parentCtx, overrides) {
372
398
  return dispatchStepThroughAdapter(this, s, input, parentCtx, overrides);
@@ -538,6 +564,9 @@ export class AgentHarness {
538
564
  });
539
565
  }
540
566
  async disposeLayers(layers, ctx) {
567
+ // Drop the init guard so a deliberate dispose→run cycle re-hydrates from
568
+ // storage (disposeLayers also clears the layer-state store for this id).
569
+ this.initializedExecutions.delete(ctx.id);
541
570
  await disposeLayers({
542
571
  layers,
543
572
  ctx: this.toExecCtx(ctx),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noetic-tools/core",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "type": "module",
5
5
  "description": "Step primitives, interpreter, runtime, and memory layer contract for Noetic agents.",
6
6
  "license": "Apache-2.0",