@noetic-tools/context 1.9.0 → 1.11.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,13 @@ 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. Any layer asking to recall is enough. A hook that throws or
286
+ * times out leaves the verdict unchanged.
287
+ */
288
+ export declare function onSteerLayers({ layers, steer, point, action, pendingCalls, ctx, store, }: OnSteerLayersParams): Promise<SteerVerdict>;
277
289
  /**
278
290
  * Run history items through every layer's `projectHistory` hook in slot order.
279
291
  * Each layer receives the previous layer's output. Storage (`itemLog`) is
@@ -889,6 +889,72 @@ 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. Any layer asking to recall is enough. A hook that throws or
896
+ * times out leaves the verdict unchanged.
897
+ */
898
+ export async function onSteerLayers({ layers, steer, point, action, pendingCalls, ctx, store, }) {
899
+ const sorted = [
900
+ ...layers,
901
+ ].sort((a, b) => a.slot - b.slot);
902
+ let verdict = {
903
+ action,
904
+ items: steer.items,
905
+ };
906
+ for (const layer of sorted) {
907
+ if (!layer.hooks.onSteer) {
908
+ continue;
909
+ }
910
+ const state = store.get(ctx.executionId, layer.id);
911
+ if (isLayerDisabled({
912
+ store,
913
+ executionId: ctx.executionId,
914
+ layer,
915
+ state,
916
+ })) {
917
+ await traceSkipped(ctx, layer.id, 'onSteer');
918
+ continue;
919
+ }
920
+ const onSteer = layer.hooks.onSteer;
921
+ const current = verdict;
922
+ try {
923
+ const result = await callHook({
924
+ ctx,
925
+ layerId: layer.id,
926
+ hook: 'onSteer',
927
+ timeout: layer.timeouts?.onSteer ?? 5e3,
928
+ run: () => onSteer({
929
+ steer: {
930
+ id: steer.id,
931
+ items: current.items,
932
+ },
933
+ point,
934
+ action: current.action,
935
+ pendingCalls,
936
+ ctx,
937
+ state,
938
+ }),
939
+ });
940
+ if (result.state !== undefined) {
941
+ store.set(ctx.executionId, layer.id, result.state);
942
+ }
943
+ verdict = {
944
+ action: result.action ?? current.action,
945
+ items: result.items ?? current.items,
946
+ recall: current.recall || result.recall,
947
+ };
948
+ }
949
+ catch (e) {
950
+ if (e instanceof NoeticConfigError) {
951
+ throw e;
952
+ }
953
+ store.diagnostic(layer.id, 'onSteer', e);
954
+ }
955
+ }
956
+ return verdict;
957
+ }
892
958
  /**
893
959
  * Run history items through every layer's `projectHistory` hook in slot order.
894
960
  * 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.11.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.15.0",
48
48
  "zod": "^4.0.0"
49
49
  },
50
50
  "scripts": {