pi-tuck 1.0.23 → 1.0.25
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/CHANGELOG.md +53 -0
- package/README.md +6 -3
- package/dist/src/build-id.d.ts +1 -1
- package/dist/src/build-id.js +1 -1
- package/dist/src/compaction.d.ts +2 -1
- package/dist/src/compaction.js +223 -43
- package/dist/src/diagnostics.d.ts +1 -1
- package/dist/src/request-capacity.d.ts +5 -1
- package/dist/src/request-capacity.js +12 -3
- package/dist/src/status.d.ts +2 -0
- package/dist/src/status.js +3 -0
- package/dist/src/tuck.d.ts +1 -0
- package/dist/src/tuck.js +8 -0
- package/package.json +1 -1
- package/src/build-id.ts +1 -1
- package/src/compaction.ts +213 -51
- package/src/request-capacity.ts +15 -4
- package/src/status.ts +4 -1
- package/src/tuck.ts +9 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type RecallPolicy } from './recall.js';
|
|
2
2
|
import type { SessionEntry } from '@earendil-works/pi-coding-agent';
|
|
3
|
-
export declare const DIAGNOSTIC_BUILD = "
|
|
3
|
+
export declare const DIAGNOSTIC_BUILD = "48d3f777f203edb56b29154215540eb8245182237d18cdc50c6cbe704ea28e7e";
|
|
4
4
|
export interface Receipt {
|
|
5
5
|
id: string;
|
|
6
6
|
build: string;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { SessionEntry } from '@earendil-works/pi-coding-agent';
|
|
2
|
-
import type { Messages } from './budget.js';
|
|
2
|
+
import type { AgentMessage, Messages } from './budget.js';
|
|
3
3
|
/** Read Pi's private safety allowance through its public clamp, rather than copying it.
|
|
4
4
|
* Older/unavailable subpaths fall back to Pi 1.2–1.5's documented 4,096-token allowance.
|
|
5
5
|
*/
|
|
6
6
|
export declare function piContextSafetyMargin(): Promise<number>;
|
|
7
7
|
/** The smallest reply room a request above the room must leave after Pi's own clamp: above the user's p99 reply (3,270 tokens). */
|
|
8
8
|
export declare const REPLY_FLOOR_MIN = 3584;
|
|
9
|
+
/** A spent thinking budget that produced neither a visible answer nor work. Empty/text/tool replies keep the existing length recovery. */
|
|
10
|
+
export declare const thinkingOnlyLength: (message: AgentMessage) => boolean;
|
|
11
|
+
/** Thinking-only exhaustion uses the observed largest reply, not the full reserve. Every other failed length/overflow keeps its override. */
|
|
12
|
+
export declare const needsFullReplyReserve: (message: AgentMessage) => boolean;
|
|
9
13
|
/** Read the whole current branch, including replies before cuts. No session-local fallback flag. */
|
|
10
14
|
export declare function branchReplyFloor(branch: readonly SessionEntry[], reserve: number): number;
|
|
11
15
|
/** Admission never promises more output than a model with a positive reply cap can produce. */
|
|
@@ -20,20 +20,29 @@ export async function piContextSafetyMargin() {
|
|
|
20
20
|
}
|
|
21
21
|
/** The smallest reply room a request above the room must leave after Pi's own clamp: above the user's p99 reply (3,270 tokens). */
|
|
22
22
|
export const REPLY_FLOOR_MIN = 3_584;
|
|
23
|
+
/** A spent thinking budget that produced neither a visible answer nor work. Empty/text/tool replies keep the existing length recovery. */
|
|
24
|
+
export const thinkingOnlyLength = (message) => message.role === 'assistant' && message.stopReason === 'length' &&
|
|
25
|
+
message.content.length > 0 && message.content.every(block => block.type === 'thinking');
|
|
26
|
+
/** Thinking-only exhaustion uses the observed largest reply, not the full reserve. Every other failed length/overflow keeps its override. */
|
|
27
|
+
export const needsFullReplyReserve = (message) => message.role === 'assistant' &&
|
|
28
|
+
(message.stopReason === 'length' && !thinkingOnlyLength(message) || message.stopReason === 'error' && isContextOverflow(message));
|
|
23
29
|
/** Read the whole current branch, including replies before cuts. No session-local fallback flag. */
|
|
24
30
|
export function branchReplyFloor(branch, reserve) {
|
|
25
|
-
let largest = REPLY_FLOOR_MIN;
|
|
31
|
+
let largest = REPLY_FLOOR_MIN, thinkingStop = false;
|
|
26
32
|
for (const entry of branch) {
|
|
27
33
|
if (entry.type !== 'message' || entry.message.role !== 'assistant')
|
|
28
34
|
continue;
|
|
29
35
|
const message = entry.message;
|
|
30
|
-
if (
|
|
36
|
+
if (needsFullReplyReserve(message))
|
|
31
37
|
return reserve;
|
|
38
|
+
thinkingStop ||= thinkingOnlyLength(message);
|
|
32
39
|
const output = message.usage?.output;
|
|
33
40
|
if (typeof output === 'number' && Number.isFinite(output) && output > largest)
|
|
34
41
|
largest = output;
|
|
35
42
|
}
|
|
36
|
-
|
|
43
|
+
// Include the exhausted thinking reply itself, even across later cuts/restarts. Its observed output must fit again;
|
|
44
|
+
// requestReplyFloor applies the model cap. Ordinary branches retain their existing reserve cap.
|
|
45
|
+
return thinkingStop ? Math.ceil(largest) : Math.min(reserve, Math.ceil(largest));
|
|
37
46
|
}
|
|
38
47
|
/** Admission never promises more output than a model with a positive reply cap can produce. */
|
|
39
48
|
export function requestReplyFloor(branch, reserve, maxTokens) {
|
package/dist/src/status.d.ts
CHANGED
package/dist/src/status.js
CHANGED
|
@@ -21,6 +21,8 @@ export function statusText(input) {
|
|
|
21
21
|
const cutLine = ours.length === 0 ? "Cuts: none yet in this session. The recall tools appear after the first cut."
|
|
22
22
|
: `Cuts: ${ours.length} by pi-tuck in this session` + (typeof before === "number" && typeof after === "number" ? `, the last from ${count(before)} to ${count(after)} tokens.` : ".");
|
|
23
23
|
const native = cuts.length - ours.length;
|
|
24
|
+
const retries = input.branch.filter(entry => entry.type === "custom" && entry.customType === "pi-tuck-capacity" &&
|
|
25
|
+
entry.data?.kind === "retry").length;
|
|
24
26
|
const searchLine = !input.search ? "Search: by keyword (search by meaning needs macOS on Apple silicon)."
|
|
25
27
|
: input.semantic.state === "ready" || input.semantic.state === "waiting" ? "Search: by meaning and keyword."
|
|
26
28
|
: input.semantic.state === "preparing" ? "Search: by meaning and keyword; indexing history in the background."
|
|
@@ -28,6 +30,7 @@ export function statusText(input) {
|
|
|
28
30
|
return [
|
|
29
31
|
`pi-tuck ${input.version} (the version this session loaded; restart Pi after an update).`,
|
|
30
32
|
cutLine,
|
|
33
|
+
...(retries ? [`Retries: ${retries} after thinking-only length stops in this session.`] : []),
|
|
31
34
|
...(native > 0 ? [`Pi's own compaction cut ${native} time${native === 1 ? "" : "s"} in this session.`] : []),
|
|
32
35
|
input.cutAt === undefined ? "Cut point: adapts by itself." : `Cut point: fixed at cutAt ${input.cutAt} of the input room. Remove cutAt from pi-tuck.json to let it adapt.`,
|
|
33
36
|
searchLine,
|
package/dist/src/tuck.d.ts
CHANGED
|
@@ -87,6 +87,7 @@ export declare function tuckObservedDraft(tuck: Tuck, input: {
|
|
|
87
87
|
newPrompt?: boolean;
|
|
88
88
|
reRenderSummary?: boolean;
|
|
89
89
|
protectedPromptEntryId?: string;
|
|
90
|
+
deepest?: boolean;
|
|
90
91
|
}, ctx: ExtensionContext, reserveTokens: number, measure: Measure, policy?: RecallPolicy, retainCurrentInput?: boolean): Draft;
|
|
91
92
|
/** Numeric references use the original session index, then intersect with readable current-branch entries. */
|
|
92
93
|
export declare function tuckRecall(tuck: Tuck, entries: readonly SessionEntry[], branch: readonly SessionEntry[], input: RecallOptions & {
|
package/dist/src/tuck.js
CHANGED
|
@@ -311,6 +311,14 @@ export function tuckObservedDraft(tuck, input, ctx, reserveTokens, measure, poli
|
|
|
311
311
|
};
|
|
312
312
|
const calibrationHigh = highAt(floorBoundary, minimumOpeningLength);
|
|
313
313
|
const floorSummary = render(calibrationHigh.rows), floorProjection = preview(floorSummary, floorBoundary);
|
|
314
|
+
// The last admission attempt and thinking-only retry share this exact floor: whole protected prompts, the smallest
|
|
315
|
+
// existing summary representation, and the required fresh/native suffix. No historical fill or room target spends reply space.
|
|
316
|
+
if (input.deepest) {
|
|
317
|
+
assertNativeToolRounds(floorProjection);
|
|
318
|
+
const after = measure(floorProjection);
|
|
319
|
+
return { compaction: { summary: floorSummary, firstKeptEntryId: entries[floorBoundary]?.id ?? "", tokensBefore: input.tokensBefore,
|
|
320
|
+
details: { ...detailsAt(floorBoundary), tokensAfter: after, carriedTarget: after, view: "shrunk-dialogue", mode: "shrunk", deepest: true } }, after, mode: "shrunk" };
|
|
321
|
+
}
|
|
314
322
|
const offset = measure(floorProjection) - nativeAt(floorBoundary) - summaryTokens(floorSummary.length);
|
|
315
323
|
const price = (characters, boundary) => offset + nativeAt(boundary) + summaryTokens(characters);
|
|
316
324
|
const listCache = new Map();
|
package/package.json
CHANGED
package/src/build-id.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const BUILD_ID = "
|
|
1
|
+
export const BUILD_ID = "48d3f777f203edb56b29154215540eb8245182237d18cdc50c6cbe704ea28e7e";
|