@noetic-tools/context 1.0.0 → 1.2.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.
- package/dist/context/cache-anchoring.d.ts +103 -0
- package/dist/context/cache-anchoring.js +273 -0
- package/dist/context/layer-lifecycle.d.ts +3 -5
- package/dist/context/layer-lifecycle.js +12 -2
- package/dist/context/layer-usage.d.ts +18 -3
- package/dist/context/layer-usage.js +10 -1
- package/dist/context/layers/file-reference.js +57 -0
- package/dist/context/layers/plan-context.d.ts +16 -0
- package/dist/context/layers/plan-context.js +38 -104
- package/dist/context/layers/plan-prompts.d.ts +59 -0
- package/dist/context/layers/plan-prompts.js +420 -0
- package/dist/context/layers/static-content.d.ts +1 -0
- package/dist/context/layers/static-content.js +3 -0
- package/dist/context/layers/steering.d.ts +1 -0
- package/dist/context/layers/steering.js +5 -0
- package/dist/context/layers/temporal-context.js +6 -0
- package/dist/context/projector.d.ts +27 -8
- package/dist/context/projector.js +42 -13
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +2 -2
|
@@ -12,6 +12,9 @@ export function staticContent(opts) {
|
|
|
12
12
|
id: opts.id ?? 'static-content',
|
|
13
13
|
slot: opts.slot ?? Slot.WORKING_MEMORY + 5,
|
|
14
14
|
scope: opts.scope ?? 'resource',
|
|
15
|
+
// Loaded once in `init` and never rewritten, so it can be pinned outright
|
|
16
|
+
// rather than waiting for churn telemetry to work that out.
|
|
17
|
+
placement: 'anchor',
|
|
15
18
|
hooks: {
|
|
16
19
|
async init() {
|
|
17
20
|
const raw = await opts.load();
|
|
@@ -162,6 +162,11 @@ export function steering(config) {
|
|
|
162
162
|
name: 'Steering',
|
|
163
163
|
slot: Slot.STEERING,
|
|
164
164
|
scope,
|
|
165
|
+
// `recall` drains the pending queue as it renders, so its output can never
|
|
166
|
+
// be replayed from a pin — the drain is already committed, and serving an
|
|
167
|
+
// older render would lose the feedback for good. Rendering after history
|
|
168
|
+
// also puts guidance where the model weighs it most.
|
|
169
|
+
placement: 'live',
|
|
165
170
|
budget: {
|
|
166
171
|
min: 0,
|
|
167
172
|
max: 500,
|
|
@@ -211,6 +211,12 @@ export function temporalContext(config) {
|
|
|
211
211
|
// Grounding sits near the top of the window, before reasoning content.
|
|
212
212
|
slot: Slot.REMINDER,
|
|
213
213
|
scope: config?.scope ?? 'resource',
|
|
214
|
+
// The `<current_datetime>` block changes every turn by construction, so
|
|
215
|
+
// anchoring it would re-bill the whole window each time. Churn telemetry
|
|
216
|
+
// would reach the same verdict — this just skips the learning cost. With
|
|
217
|
+
// grounding off, only the slow-moving fact ledger remains, which is worth
|
|
218
|
+
// anchoring, so leave that to `'auto'`.
|
|
219
|
+
placement: groundDateTime ? 'live' : 'auto',
|
|
214
220
|
budget: {
|
|
215
221
|
min: 0,
|
|
216
222
|
max: injectLedger ? 800 : 200,
|
|
@@ -1,19 +1,38 @@
|
|
|
1
1
|
import type { Item, ProjectionPolicy } from '@noetic-tools/types';
|
|
2
2
|
interface AssembleViewParams {
|
|
3
3
|
systemPromptItems: Item[];
|
|
4
|
+
/** Anchor band — layer output rendered before history, where a prompt cache can hold it. */
|
|
4
5
|
layerOutputItems: Item[];
|
|
5
6
|
historyItems: Item[];
|
|
7
|
+
/** Live band — layer output rendered after history, slot-ascending. */
|
|
8
|
+
liveLayerItems?: Item[];
|
|
9
|
+
/** Supersedes for anchored layers whose pinned output went stale. */
|
|
10
|
+
deltaItems?: Item[];
|
|
11
|
+
/** Items that must land last, after everything else. Never dropped. */
|
|
12
|
+
tailItems?: Item[];
|
|
6
13
|
policy?: ProjectionPolicy;
|
|
7
14
|
}
|
|
8
15
|
/**
|
|
9
|
-
* Assemble the model's context window
|
|
10
|
-
* recall output (slot-ascending), and conversation history.
|
|
16
|
+
* Assemble the model's context window in bands:
|
|
11
17
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
18
|
+
* ```
|
|
19
|
+
* system | anchor layers | history | live layers | supersedes | tail
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* The split exists for the prompt cache, which matches on a prefix. Stable
|
|
23
|
+
* layer output sits ahead of history where it can be cached; volatile output
|
|
24
|
+
* sits after it, where re-rendering costs almost nothing. Both bands arrive
|
|
25
|
+
* slot-ascending.
|
|
26
|
+
*
|
|
27
|
+
* Without a `policy` the bands are concatenated as-is (optionally sliding the
|
|
28
|
+
* history window by `windowSize`). With a `policy` the view is held to a hard
|
|
29
|
+
* token budget, claimed in this order: system items, then anchor output, then
|
|
30
|
+
* live output, then supersedes, then the tail — with history taking whatever
|
|
31
|
+
* remains and keeping the most recent turns.
|
|
32
|
+
*
|
|
33
|
+
* Supersedes are claimed ahead of history, and all together or not at all: a
|
|
34
|
+
* dropped supersede would leave the model reading a pinned block the runtime
|
|
35
|
+
* knows is stale. The caller re-anchors instead — see `prepareBandedView`.
|
|
17
36
|
*/
|
|
18
|
-
export declare function assembleView({ systemPromptItems, layerOutputItems, historyItems, policy, }: AssembleViewParams): Item[];
|
|
37
|
+
export declare function assembleView({ systemPromptItems, layerOutputItems, historyItems, liveLayerItems, deltaItems, tailItems, policy, }: AssembleViewParams): Item[];
|
|
19
38
|
export {};
|
|
@@ -57,33 +57,62 @@ function keepRecentWithinBudget(items, budget, windowSize) {
|
|
|
57
57
|
//#endregion
|
|
58
58
|
//#region Public API
|
|
59
59
|
/**
|
|
60
|
-
* Assemble the model's context window
|
|
61
|
-
* recall output (slot-ascending), and conversation history.
|
|
60
|
+
* Assemble the model's context window in bands:
|
|
62
61
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
62
|
+
* ```
|
|
63
|
+
* system | anchor layers | history | live layers | supersedes | tail
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* The split exists for the prompt cache, which matches on a prefix. Stable
|
|
67
|
+
* layer output sits ahead of history where it can be cached; volatile output
|
|
68
|
+
* sits after it, where re-rendering costs almost nothing. Both bands arrive
|
|
69
|
+
* slot-ascending.
|
|
70
|
+
*
|
|
71
|
+
* Without a `policy` the bands are concatenated as-is (optionally sliding the
|
|
72
|
+
* history window by `windowSize`). With a `policy` the view is held to a hard
|
|
73
|
+
* token budget, claimed in this order: system items, then anchor output, then
|
|
74
|
+
* live output, then supersedes, then the tail — with history taking whatever
|
|
75
|
+
* remains and keeping the most recent turns.
|
|
76
|
+
*
|
|
77
|
+
* Supersedes are claimed ahead of history, and all together or not at all: a
|
|
78
|
+
* dropped supersede would leave the model reading a pinned block the runtime
|
|
79
|
+
* knows is stale. The caller re-anchors instead — see `prepareBandedView`.
|
|
68
80
|
*/
|
|
69
|
-
export function assembleView({ systemPromptItems, layerOutputItems, historyItems, policy, }) {
|
|
81
|
+
export function assembleView({ systemPromptItems, layerOutputItems, historyItems, liveLayerItems = [], deltaItems = [], tailItems = [], policy, }) {
|
|
70
82
|
if (!policy) {
|
|
71
83
|
return [
|
|
72
84
|
...systemPromptItems,
|
|
73
85
|
...layerOutputItems,
|
|
74
86
|
...historyItems,
|
|
87
|
+
...liveLayerItems,
|
|
88
|
+
...deltaItems,
|
|
89
|
+
...tailItems,
|
|
75
90
|
];
|
|
76
91
|
}
|
|
77
92
|
const budget = Math.max(0, policy.tokenBudget - policy.responseReserve);
|
|
78
93
|
// System items are never dropped — they anchor the conversation.
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
const
|
|
94
|
+
let left = Math.max(0, budget - totalTokens(systemPromptItems));
|
|
95
|
+
const keptAnchor = keepFrontWithinBudget(layerOutputItems, left);
|
|
96
|
+
left = Math.max(0, left - totalTokens(keptAnchor));
|
|
97
|
+
const keptLive = keepFrontWithinBudget(liveLayerItems, left);
|
|
98
|
+
left = Math.max(0, left - totalTokens(keptLive));
|
|
99
|
+
// The tail carries steering guidance, which must reach the model whatever the
|
|
100
|
+
// budget says — it is the correction the retry exists to deliver.
|
|
101
|
+
left = Math.max(0, left - totalTokens(tailItems));
|
|
102
|
+
// Supersedes are never dropped either. Each one corrects a pinned block that
|
|
103
|
+
// is already in the view, so dropping one leaves the model reading content
|
|
104
|
+
// the runtime knows is stale — silent corruption, and far worse than losing
|
|
105
|
+
// a turn of history. History absorbs the cost; `deltaBudgetFraction` keeps
|
|
106
|
+
// the supersedes from growing large enough for that to hurt.
|
|
107
|
+
left = Math.max(0, left - totalTokens(deltaItems));
|
|
108
|
+
const keptHistory = keepRecentWithinBudget(historyItems, left, policy.windowSize);
|
|
83
109
|
return [
|
|
84
110
|
...systemPromptItems,
|
|
85
|
-
...
|
|
111
|
+
...keptAnchor,
|
|
86
112
|
...keptHistory,
|
|
113
|
+
...keptLive,
|
|
114
|
+
...deltaItems,
|
|
115
|
+
...tailItems,
|
|
87
116
|
];
|
|
88
117
|
}
|
|
89
118
|
//#endregion
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
export type { ContextScope, ExecutionContext, ExecutionOutcome, LayerCallModelRequest, } from '@noetic-tools/types';
|
|
7
7
|
export * from '@noetic-tools/types/contract';
|
|
8
8
|
export * from './context/budget.js';
|
|
9
|
+
export * from './context/cache-anchoring.js';
|
|
9
10
|
export * from './context/exec-context-factory.js';
|
|
10
11
|
export * from './context/function-call-utils.js';
|
|
11
12
|
export * from './context/layer-api.js';
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// @noetic-tools/context remains the one-stop import for context-layer authoring.
|
|
9
9
|
export * from '@noetic-tools/types/contract';
|
|
10
10
|
export * from './context/budget.js';
|
|
11
|
+
export * from './context/cache-anchoring.js';
|
|
11
12
|
export * from './context/exec-context-factory.js';
|
|
12
13
|
export * from './context/function-call-utils.js';
|
|
13
14
|
export * from './context/layer-api.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noetic-tools/context",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.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": "^
|
|
47
|
+
"@noetic-tools/types": "^3.1.0",
|
|
48
48
|
"zod": "^4.0.0"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|