pi-fold 1.0.2 → 1.0.3
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/README.md +29 -40
- package/extensions/active-context.ts +2374 -600
- package/extensions/evidence.js +15 -2
- package/extensions/index.js +69 -21
- package/extensions/json.ts +33 -1
- package/extensions/lib/curation.ts +141 -139
- package/extensions/lib/folding.ts +418 -74
- package/extensions/lib/instrumentation.ts +24 -4
- package/extensions/lib/measurement.ts +92 -16
- package/extensions/lib/persistence.ts +212 -42
- package/extensions/lib/policy.ts +511 -155
- package/extensions/lib/rollback.ts +216 -0
- package/extensions/lib/scheduling.ts +414 -106
- package/extensions/lib/selection.ts +528 -144
- package/extensions/lib/surfacing.ts +479 -224
- package/extensions/lib/tool-surface.ts +25 -5
- package/extensions/lib/transcript.ts +146 -62
- package/extensions/summarizer.js +206 -10
- package/package.json +1 -1
- package/extensions/lib/advisory.ts +0 -309
|
@@ -137,24 +137,44 @@ export type ContextEventKind =
|
|
|
137
137
|
| "context.attempt"
|
|
138
138
|
/** One auto-snap applied to a requested span, referencing its attempt. */
|
|
139
139
|
| "context.correction"
|
|
140
|
+
/** One protect or unprotect: durable pin bookkeeping; no window bytes move. */
|
|
141
|
+
| "context.protect"
|
|
140
142
|
/** The resolved serving budget, stated once at startup so a live run can prove it. */
|
|
141
143
|
| "context.capacity"
|
|
142
|
-
/** One evaluation of the guided-curation last-call gate. */
|
|
143
|
-
| "context.gate"
|
|
144
|
-
/** One sparse occupancy reminder delivered into the window. */
|
|
145
|
-
| "context.reminder"
|
|
146
144
|
/** One receipt delivered into the window. */
|
|
147
145
|
| "context.receipt"
|
|
146
|
+
/** One post-commit rider composed and persisted: at most one per fold epoch. */
|
|
147
|
+
| "context.rider"
|
|
148
|
+
/** One pre-commit last-call exposure: the band-top prompt, with its telemetry. */
|
|
149
|
+
| "context.lastcall"
|
|
150
|
+
/** One gated round's outcome, attributed to the exposure it answers. */
|
|
151
|
+
| "context.response"
|
|
152
|
+
/** One surfacing suggestion issued: both channel scores, the divergence, the carrier. */
|
|
153
|
+
| "context.suggestion"
|
|
154
|
+
/** One surfacing suggestion graded: the acted/used/ignored join and its transition. */
|
|
155
|
+
| "context.outcome"
|
|
156
|
+
/** One append-once occupancy threshold notice delivered into the window. */
|
|
157
|
+
| "context.notice"
|
|
148
158
|
/** One commit epoch: the single mutation an epoch pays for. */
|
|
149
159
|
| "context.commit"
|
|
150
160
|
/** One fold created, by the ladder or by the agent. */
|
|
151
161
|
| "context.fold"
|
|
162
|
+
/**
|
|
163
|
+
* One generator call for a brief: what it read, what it wrote, and what it cost.
|
|
164
|
+
*
|
|
165
|
+
* The generator runs outside the session, so its spend appears in no provider ledger
|
|
166
|
+
* and its latency appears in no turn. Without this record a deployment cannot say what
|
|
167
|
+
* briefing costs it, which is the question the async lane exists to answer.
|
|
168
|
+
*/
|
|
169
|
+
| "context.brief"
|
|
152
170
|
/** One boundary sliver absorbed into its later neighbour. */
|
|
153
171
|
| "context.absorb"
|
|
154
172
|
/** One oversized span split into sequential bite-sized folds. */
|
|
155
173
|
| "context.split"
|
|
156
174
|
/** One overflow rollback and the recovery that followed it. */
|
|
157
175
|
| "context.recovery"
|
|
176
|
+
/** One tree rollback: what left the branch, and whether the request replayed. */
|
|
177
|
+
| "context.rollback"
|
|
158
178
|
/** One projection built, classified against the one before it. */
|
|
159
179
|
| "context.projection"
|
|
160
180
|
/** One provider response, which is where this stream joins provider usage. */
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
sha256Value,
|
|
8
8
|
} from "../json.ts";
|
|
9
9
|
import {
|
|
10
|
+
bytes,
|
|
10
11
|
clone,
|
|
11
12
|
exactRecord,
|
|
12
13
|
messageRole,
|
|
@@ -22,8 +23,7 @@ import {
|
|
|
22
23
|
import {
|
|
23
24
|
ACTIVE_CONTEXT_POLICY,
|
|
24
25
|
DEFAULT_CONTEXT_WINDOW,
|
|
25
|
-
|
|
26
|
-
TOOL_FOLD_CADENCE_WINDOW_FRACTION,
|
|
26
|
+
servingBudgetTokens,
|
|
27
27
|
} from "./policy.ts";
|
|
28
28
|
import type {
|
|
29
29
|
ActiveContextSnapshot,
|
|
@@ -35,7 +35,7 @@ import type {
|
|
|
35
35
|
export { protectionSha256, topologySha256 } from "./persistence.ts";
|
|
36
36
|
export { clone } from "./canonical.ts";
|
|
37
37
|
export { sha256Value } from "../json.ts";
|
|
38
|
-
export {
|
|
38
|
+
export { validAdvisoryState } from "./persistence.ts";
|
|
39
39
|
|
|
40
40
|
export const MAPPED_BY_KEY = new WeakMap<ActiveContextSnapshot, Map<string, MappedMessage>>();
|
|
41
41
|
|
|
@@ -89,6 +89,32 @@ export function contextUsageRatio(value: unknown): number | null {
|
|
|
89
89
|
return tokens / contextWindow;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* A measured WINDOW ratio, restated as occupancy of the serving budget.
|
|
94
|
+
*
|
|
95
|
+
* The provider reports tokens against its total window and the thermostat is declared
|
|
96
|
+
* against the serving budget, so exactly one conversion stands between them and it is
|
|
97
|
+
* written here rather than inferred at each reader. Before this build the trigger
|
|
98
|
+
* divided by the budget while the freeing target and the backstop divided by the
|
|
99
|
+
* window, which at a 383,616-token budget behind a 400,000-token window is a 4.5-point
|
|
100
|
+
* disagreement, and 10 points at a 100,000-token fixture.
|
|
101
|
+
*/
|
|
102
|
+
export function budgetOccupancy(snapshot: ActiveContextSnapshot, windowRatio: number | null): number | null {
|
|
103
|
+
if (typeof windowRatio !== "number" || !Number.isFinite(windowRatio)) return null;
|
|
104
|
+
if (!(snapshot.budgetTokens > 0) || !(snapshot.contextWindow > 0)) return null;
|
|
105
|
+
return windowRatio * snapshot.contextWindow / snapshot.budgetTokens;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The fence, as a ratio of the window the measured ratio is denominated against.
|
|
110
|
+
*
|
|
111
|
+
* A measured ratio is tokens over `contextWindow`, so "the request reached its serving
|
|
112
|
+
* budget" is exactly `ratio >= budgetTokens / contextWindow`. When the snapshot carries
|
|
113
|
+
* a budget the runtime uses it verbatim: a deployment that DECLARED its input budget has
|
|
114
|
+
* already netted out its output reservation, and re-subtracting one here would fence it
|
|
115
|
+
* roughly four points early. Only the ctx fallback, where nothing but a raw provider
|
|
116
|
+
* window is known, still estimates the reservation.
|
|
117
|
+
*/
|
|
92
118
|
export function hardFenceRatio(value?: unknown, ctx?: any): number {
|
|
93
119
|
const direct = ownValue(value, "contextWindow");
|
|
94
120
|
const reported = ownValue(ctx?.getContextUsage?.(), "contextWindow");
|
|
@@ -97,6 +123,10 @@ export function hardFenceRatio(value?: unknown, ctx?: any): number {
|
|
|
97
123
|
: typeof reported === "number" && Number.isFinite(reported) && reported > 0
|
|
98
124
|
? reported
|
|
99
125
|
: DEFAULT_CONTEXT_WINDOW;
|
|
126
|
+
const budgetTokens = ownValue(value, "budgetTokens");
|
|
127
|
+
if (typeof budgetTokens === "number" && Number.isFinite(budgetTokens) && budgetTokens > 0) {
|
|
128
|
+
return Math.min(1, budgetTokens / contextWindow);
|
|
129
|
+
}
|
|
100
130
|
const reserve = Math.min(
|
|
101
131
|
ACTIVE_CONTEXT_POLICY.responseReserve,
|
|
102
132
|
Math.floor(contextWindow * 0.1),
|
|
@@ -118,7 +148,7 @@ export function hardFenceRatio(value?: unknown, ctx?: any): number {
|
|
|
118
148
|
* is how a 25 percent error survived four instrumented runs.
|
|
119
149
|
*/
|
|
120
150
|
export interface CapacityAccounting {
|
|
121
|
-
/** "truthful" once the deployment declares its
|
|
151
|
+
/** "truthful" once the deployment declares its own serving budget. */
|
|
122
152
|
mode: "descriptor" | "truthful";
|
|
123
153
|
/** The denominator every pressure ratio and fence is computed against. */
|
|
124
154
|
window: number;
|
|
@@ -131,6 +161,18 @@ export interface CapacityAccounting {
|
|
|
131
161
|
descriptorWindow: number | null;
|
|
132
162
|
}
|
|
133
163
|
|
|
164
|
+
/**
|
|
165
|
+
* ONE denominator, and no guess in front of it.
|
|
166
|
+
*
|
|
167
|
+
* `truthful` means the deployment stated the budget it may actually fill, already net of
|
|
168
|
+
* whatever output reservation it holds back, so the value passes through untouched and
|
|
169
|
+
* the reservation this runtime reports is zero because it withheld nothing. Only the
|
|
170
|
+
* descriptor fallback still subtracts, because a per-request max-input descriptor is a
|
|
171
|
+
* total-window claim and the reservation inside it has to be estimated. That estimate was
|
|
172
|
+
* the defect the reshape removed: the runtime subtracted a fixed 16,384 tokens capped at
|
|
173
|
+
* a tenth of the window while the documentation claimed it subtracted the reservation
|
|
174
|
+
* actually in force.
|
|
175
|
+
*/
|
|
134
176
|
export function capacityAccounting(input: {
|
|
135
177
|
window: number;
|
|
136
178
|
truthful: boolean;
|
|
@@ -138,11 +180,8 @@ export function capacityAccounting(input: {
|
|
|
138
180
|
usedTokens: number | null;
|
|
139
181
|
}): CapacityAccounting {
|
|
140
182
|
const window = Number.isFinite(input.window) && input.window > 0 ? input.window : DEFAULT_CONTEXT_WINDOW;
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
Math.floor(window * 0.1),
|
|
144
|
-
);
|
|
145
|
-
const budgetTokens = window - outputReservation;
|
|
183
|
+
const budgetTokens = input.truthful ? window : servingBudgetTokens(window);
|
|
184
|
+
const outputReservation = window - budgetTokens;
|
|
146
185
|
const usedTokens = typeof input.usedTokens === "number" && Number.isFinite(input.usedTokens) &&
|
|
147
186
|
input.usedTokens >= 0 ? input.usedTokens : null;
|
|
148
187
|
return {
|
|
@@ -270,13 +309,6 @@ export function contextWindowFor(ctx: any): number | null {
|
|
|
270
309
|
return typeof modelWindow === "number" && Number.isFinite(modelWindow) && modelWindow > 0 ? modelWindow : null;
|
|
271
310
|
}
|
|
272
311
|
|
|
273
|
-
export function toolFoldCadence(contextWindow: number): number {
|
|
274
|
-
if (!Number.isFinite(contextWindow) || contextWindow <= 0) {
|
|
275
|
-
throw new Error("Tool-fold cadence requires a positive context window");
|
|
276
|
-
}
|
|
277
|
-
return Math.max(TOOL_FOLD_CADENCE_MIN_TOKENS, TOOL_FOLD_CADENCE_WINDOW_FRACTION * contextWindow);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
312
|
export function rootFolds(state: ActiveContextState): ActiveFold[] {
|
|
281
313
|
return state.folds.filter((fold) => fold.parentId === null);
|
|
282
314
|
}
|
|
@@ -370,6 +402,50 @@ export function toolRefsProtected(
|
|
|
370
402
|
});
|
|
371
403
|
}
|
|
372
404
|
|
|
405
|
+
/**
|
|
406
|
+
* Mass the agent's pins hold out of the ladder's reach: explicitly protected evidence
|
|
407
|
+
* outside the fresh tail. A pin's cost must be a number the agent sees on receipts,
|
|
408
|
+
* never a silent commit shortfall.
|
|
409
|
+
*/
|
|
410
|
+
export function protectedStaleMass(
|
|
411
|
+
snapshot: ActiveContextSnapshot,
|
|
412
|
+
state: ActiveContextState,
|
|
413
|
+
): { bytes: number; refs: number } {
|
|
414
|
+
const explicit = explicitProtectedKeys(state);
|
|
415
|
+
if (!explicit.size) return { bytes: 0, refs: 0 };
|
|
416
|
+
let total = 0;
|
|
417
|
+
let refs = 0;
|
|
418
|
+
for (const item of snapshot.mapped) {
|
|
419
|
+
if (!item.ref || !explicit.has(objectRefKey(item.ref))) continue;
|
|
420
|
+
if (snapshot.protectedIndices.has(item.index)) continue;
|
|
421
|
+
total += bytes(item.message);
|
|
422
|
+
refs += 1;
|
|
423
|
+
}
|
|
424
|
+
return { bytes: total, refs };
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Every byte protect currently holds raw, fresh or stale: the mass the pinned-share
|
|
429
|
+
* cap is measured against. protectedStaleMass narrows to what a commit could not
|
|
430
|
+
* reclaim TODAY; the cap has to see the whole promise, because a pin inside the
|
|
431
|
+
* fresh tail outlives the tail.
|
|
432
|
+
*/
|
|
433
|
+
export function explicitProtectedMass(
|
|
434
|
+
snapshot: ActiveContextSnapshot,
|
|
435
|
+
state: ActiveContextState,
|
|
436
|
+
): { bytes: number; refs: number } {
|
|
437
|
+
const explicit = explicitProtectedKeys(state);
|
|
438
|
+
if (!explicit.size) return { bytes: 0, refs: 0 };
|
|
439
|
+
let total = 0;
|
|
440
|
+
let refs = 0;
|
|
441
|
+
for (const item of snapshot.mapped) {
|
|
442
|
+
if (!item.ref || !explicit.has(objectRefKey(item.ref))) continue;
|
|
443
|
+
total += bytes(item.message);
|
|
444
|
+
refs += 1;
|
|
445
|
+
}
|
|
446
|
+
return { bytes: total, refs };
|
|
447
|
+
}
|
|
448
|
+
|
|
373
449
|
export interface AdmissionVerdict {
|
|
374
450
|
admitted: boolean;
|
|
375
451
|
reason: "admitted" | "unmeasured" | "would-cross-fence";
|