@noetic-tools/context 1.9.0 → 1.10.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.
@@ -1,4 +1,4 @@
1
- import type { ContextLayer, DecisionRecord, ExecutionContext, Item, ItemLog, ItemSchemaRegistry, LLMResponse, ScopedStorage, SteeringDecision, StorageAdapter } from '@noetic-tools/types';
1
+ import type { ContextLayer, DecisionRecord, ExecutionContext, Item, ItemLog, ItemSchemaRegistry, LLMResponse, OnSteerParams, ScopedStorage, SteeringDecision, SteerVerdict, StorageAdapter } from '@noetic-tools/types';
2
2
  import type { LiveChild } from './parent-updates.js';
3
3
  export interface LayerStateStore {
4
4
  get<T>(executionId: string, layerId: string): T | undefined;
@@ -154,6 +154,11 @@ interface AfterModelCallLayersParams {
154
154
  ctx: ExecutionContext;
155
155
  store: LayerStateStore;
156
156
  }
157
+ interface OnSteerLayersParams extends Pick<OnSteerParams, 'steer' | 'point' | 'action' | 'pendingCalls'> {
158
+ layers: ContextLayer[];
159
+ ctx: ExecutionContext;
160
+ store: LayerStateStore;
161
+ }
157
162
  interface ProjectHistoryLayersParams {
158
163
  layers: ContextLayer[];
159
164
  items: ReadonlyArray<Item>;
@@ -274,6 +279,12 @@ export declare function returnLayers<T>({ layers, stepId, parentCtx, childCtx, c
274
279
  export declare function completeLayers({ layers, ctx, log, outcome, store, }: CompleteLayersParams): Promise<void>;
275
280
  export declare function beforeToolCallLayers({ layers, toolName, toolArgs, callId, ctx, store, }: BeforeToolCallLayersParams): Promise<SteeringDecision>;
276
281
  export declare function afterModelCallLayers({ layers, response, ctx, store, }: AfterModelCallLayersParams): Promise<SteeringDecision>;
282
+ /**
283
+ * Run a steer through every layer's `onSteer` hook in slot order. Each layer
284
+ * sees the action and items the previous layer left, so the last layer to
285
+ * speak wins. A hook that throws or times out leaves both unchanged.
286
+ */
287
+ export declare function onSteerLayers({ layers, steer, point, action, pendingCalls, ctx, store, }: OnSteerLayersParams): Promise<SteerVerdict>;
277
288
  /**
278
289
  * Run history items through every layer's `projectHistory` hook in slot order.
279
290
  * Each layer receives the previous layer's output. Storage (`itemLog`) is
@@ -889,6 +889,70 @@ export async function afterModelCallLayers({ layers, response, ctx, store, }) {
889
889
  }
890
890
  return mostRestrictive(decisions);
891
891
  }
892
+ /**
893
+ * Run a steer through every layer's `onSteer` hook in slot order. Each layer
894
+ * sees the action and items the previous layer left, so the last layer to
895
+ * speak wins. A hook that throws or times out leaves both unchanged.
896
+ */
897
+ export async function onSteerLayers({ layers, steer, point, action, pendingCalls, ctx, store, }) {
898
+ const sorted = [
899
+ ...layers,
900
+ ].sort((a, b) => a.slot - b.slot);
901
+ let verdict = {
902
+ action,
903
+ items: steer.items,
904
+ };
905
+ for (const layer of sorted) {
906
+ if (!layer.hooks.onSteer) {
907
+ continue;
908
+ }
909
+ const state = store.get(ctx.executionId, layer.id);
910
+ if (isLayerDisabled({
911
+ store,
912
+ executionId: ctx.executionId,
913
+ layer,
914
+ state,
915
+ })) {
916
+ await traceSkipped(ctx, layer.id, 'onSteer');
917
+ continue;
918
+ }
919
+ const onSteer = layer.hooks.onSteer;
920
+ const current = verdict;
921
+ try {
922
+ const result = await callHook({
923
+ ctx,
924
+ layerId: layer.id,
925
+ hook: 'onSteer',
926
+ timeout: layer.timeouts?.onSteer ?? 5e3,
927
+ run: () => onSteer({
928
+ steer: {
929
+ id: steer.id,
930
+ items: current.items,
931
+ },
932
+ point,
933
+ action: current.action,
934
+ pendingCalls,
935
+ ctx,
936
+ state,
937
+ }),
938
+ });
939
+ if (result.state !== undefined) {
940
+ store.set(ctx.executionId, layer.id, result.state);
941
+ }
942
+ verdict = {
943
+ action: result.action ?? current.action,
944
+ items: result.items ?? current.items,
945
+ };
946
+ }
947
+ catch (e) {
948
+ if (e instanceof NoeticConfigError) {
949
+ throw e;
950
+ }
951
+ store.diagnostic(layer.id, 'onSteer', e);
952
+ }
953
+ }
954
+ return verdict;
955
+ }
892
956
  /**
893
957
  * Run history items through every layer's `projectHistory` hook in slot order.
894
958
  * Each layer receives the previous layer's output. Storage (`itemLog`) is
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noetic-tools/context",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "type": "module",
5
5
  "description": "Context layer system for Noetic agents: the ContextLayer contract, lifecycle, budget/projection machinery, and built-in layer implementations.",
6
6
  "license": "Apache-2.0",
@@ -44,7 +44,7 @@
44
44
  "zod": "^4.0.0"
45
45
  },
46
46
  "dependencies": {
47
- "@noetic-tools/types": "^3.10.0",
47
+ "@noetic-tools/types": "^3.13.0",
48
48
  "zod": "^4.0.0"
49
49
  },
50
50
  "scripts": {