pi-pier 0.3.0 → 0.4.1
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 +16 -12
- package/package.json +3 -3
- package/schemas/role-manifest.schema.json +7 -1
- package/skills/pi-herdr-workflow/SKILL.md +4 -5
- package/src/ansi-text.ts +62 -11
- package/src/ask-dialog.ts +308 -0
- package/src/ask-user.ts +113 -112
- package/src/bootstrap.ts +10 -13
- package/src/compact-coordinator.ts +279 -261
- package/src/compact-economics-core.ts +77 -145
- package/src/config-catalog-core.ts +77 -197
- package/src/config-command.ts +271 -64
- package/src/cordis-services.ts +64 -0
- package/src/dashboard-command.ts +77 -33
- package/src/delegation-core.ts +115 -0
- package/src/efficiency-config-core.ts +286 -486
- package/src/efficiency-store.ts +16 -29
- package/src/gc-core.ts +10 -36
- package/src/guards.ts +6 -0
- package/src/herdr-client.ts +202 -233
- package/src/history-store.ts +38 -23
- package/src/index-gates.ts +118 -0
- package/src/index-locks.ts +2 -7
- package/src/index-master.ts +31 -29
- package/src/index-notices.ts +28 -15
- package/src/index-pipe.ts +31 -12
- package/src/index-roles.ts +306 -0
- package/src/index-runtime.ts +16 -6
- package/src/index-worker.ts +8 -18
- package/src/index.ts +561 -570
- package/src/jev-client.ts +12 -17
- package/src/jev-core.ts +138 -90
- package/src/ledger.ts +13 -21
- package/src/lock-core.ts +28 -56
- package/src/manifest-compose.ts +35 -20
- package/src/observation-core.ts +52 -100
- package/src/pane-title.ts +19 -38
- package/src/panel-open.ts +47 -0
- package/src/pi-surface.ts +34 -22
- package/src/pier-options.ts +53 -50
- package/src/pipe-channel.ts +44 -59
- package/src/platform-paths.ts +19 -52
- package/src/{core → plugins}/grid-shape.ts +8 -10
- package/src/{core → plugins}/heat-plan.ts +20 -22
- package/src/plugins/observation.ts +475 -0
- package/src/plugins/subagent.ts +766 -0
- package/src/{core → plugins}/terminal.ts +198 -139
- package/src/{core → plugins}/todo.ts +73 -134
- package/src/progress-core.ts +16 -53
- package/src/reconcile-core.ts +24 -33
- package/src/reducer-core.ts +26 -64
- package/src/reducer-invoker.ts +266 -239
- package/src/renderers.ts +108 -84
- package/src/role-loader.ts +33 -28
- package/src/role-manifest.ts +25 -31
- package/src/role-state.ts +119 -0
- package/src/roles/worker-default.json +3 -3
- package/src/routing-telemetry.ts +136 -0
- package/src/runtime-policy.ts +25 -40
- package/src/session-tail.ts +65 -41
- package/src/settle-wake-core.ts +61 -22
- package/src/slim-frame.ts +25 -122
- package/src/stale-core.ts +17 -24
- package/src/storage-layout.ts +14 -43
- package/src/subagent-core.ts +423 -120
- package/src/subagent-gc.ts +109 -67
- package/src/subagent-poller.ts +383 -24
- package/src/subagent-session.ts +516 -0
- package/src/subagent-spawn.ts +577 -52
- package/src/swallow.ts +7 -17
- package/src/terminal-core.ts +187 -134
- package/src/todo-core.ts +57 -109
- package/src/todo-read-hook.ts +46 -39
- package/src/todo-reminder-core.ts +26 -51
- package/src/todo-window.ts +11 -12
- package/src/todos-service.ts +15 -35
- package/src/tool-error.ts +6 -13
- package/src/tool-gate.ts +38 -21
- package/src/tree-view.ts +162 -0
- package/src/vocab.ts +52 -25
- package/src/worker-marker.ts +76 -0
- package/src/ask-multi.ts +0 -260
- package/src/config-guide.ts +0 -361
- package/src/core/observation.ts +0 -555
- package/src/core/subagent.ts +0 -633
- package/src/efficiency-config-io.ts +0 -53
- package/src/focus-poller.ts +0 -244
- package/src/git-adapter.ts +0 -113
- package/src/notice-buffer.ts +0 -23
- package/src/subagent-execute.ts +0 -328
- package/src/subagent-git-io.ts +0 -80
- package/src/subagent-launch.ts +0 -114
- package/src/subagent-list-action.ts +0 -69
- package/src/subagent-output-action.ts +0 -104
- package/src/subagent-output-adapter.ts +0 -27
- package/src/subagent-output-core.ts +0 -263
- package/src/subagent-poll-loop.ts +0 -305
- package/src/subagent-port.ts +0 -27
- package/src/subagent-ready.ts +0 -89
- package/src/subagent-registry.ts +0 -70
- package/src/subagent-resolution.ts +0 -41
- package/src/subagent-scope.ts +0 -41
- package/src/subagent-session-io.ts +0 -230
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* D100 Online Context Compact
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* cache debt tracking, and native compaction feasibility preflights.
|
|
6
|
-
*
|
|
7
|
-
* Zero-dependency / pure algorithm core (except Pi's public cut point helper).
|
|
2
|
+
* D100 Online Context Compact economics & feasibility core: pure decision-making, request horizon
|
|
3
|
+
* estimation, cache debt tracking and native compaction feasibility preflights — no dependencies
|
|
4
|
+
* except pi's public cut-point helper.
|
|
8
5
|
*/
|
|
9
6
|
|
|
10
|
-
import {
|
|
11
|
-
findCutPoint,
|
|
12
|
-
sessionEntryToContextMessages,
|
|
13
|
-
type SessionEntry,
|
|
14
|
-
} from '@earendil-works/pi-coding-agent';
|
|
7
|
+
import { findCutPoint, sessionEntryToContextMessages, type SessionEntry } from '@earendil-works/pi-coding-agent';
|
|
15
8
|
|
|
16
|
-
|
|
9
|
+
interface CompactionEconomics {
|
|
17
10
|
readonly remainingRequestScale: number;
|
|
18
11
|
readonly remainingRequestStddevK: number;
|
|
19
12
|
readonly windowReserveTokens: number;
|
|
@@ -30,11 +23,10 @@ export const DEFAULT_COMPACTION_ECONOMICS: CompactionEconomics = Object.freeze({
|
|
|
30
23
|
});
|
|
31
24
|
|
|
32
25
|
/**
|
|
33
|
-
* Token-account cache ratio: a compaction request re-reads the whole
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* for all of them — 61/61 decisions `cache_ratio_unavailable`, zero compactions).
|
|
26
|
+
* Token-account cache ratio: a compaction request re-reads the whole context once (writeTokens), so
|
|
27
|
+
* breakeven = writeTokens / savingTokens ⇔ ratio 2. This is the `auto` fallback when no usable cache
|
|
28
|
+
* pricing exists, and a floor: ratio ≤ 1 would zero the incremental cost and compact even on the last
|
|
29
|
+
* boundary with nothing left to amortize.
|
|
38
30
|
*/
|
|
39
31
|
export const TOKEN_ACCOUNT_CACHE_RATIO = 2.0;
|
|
40
32
|
|
|
@@ -45,7 +37,7 @@ const PROVIDER_FAMILY_CACHE_RATIOS: Readonly<Record<string, number>> = Object.fr
|
|
|
45
37
|
deepseek: 10,
|
|
46
38
|
});
|
|
47
39
|
|
|
48
|
-
|
|
40
|
+
type CompactionReason =
|
|
49
41
|
| 'economic'
|
|
50
42
|
| 'window_protection'
|
|
51
43
|
| 'deferred_economic'
|
|
@@ -54,14 +46,13 @@ export type CompactionReason =
|
|
|
54
46
|
| 'horizon_unavailable'
|
|
55
47
|
| 'cache_ratio_unavailable'
|
|
56
48
|
| 'native_not_compactable'
|
|
49
|
+
| 'failure_backoff'
|
|
57
50
|
| 'non_positive_saving';
|
|
58
51
|
|
|
59
|
-
|
|
60
|
-
readonly completedBoundaryRequestCounts: readonly number[];
|
|
52
|
+
interface RequestHorizonEstimate {
|
|
61
53
|
readonly requestsPerBoundaryMean: number;
|
|
62
54
|
readonly requestsPerBoundaryLowerBound: number;
|
|
63
55
|
readonly unboundedExpectedRemainingRequests: number;
|
|
64
|
-
readonly averageContextTokenIncrement: number | null;
|
|
65
56
|
readonly windowRequestUpperBound: number | null;
|
|
66
57
|
readonly expectedRemainingRequests: number;
|
|
67
58
|
}
|
|
@@ -71,15 +62,8 @@ export interface CompactionDecision {
|
|
|
71
62
|
readonly archiveTokens: number;
|
|
72
63
|
readonly memoTokens: number;
|
|
73
64
|
readonly contextTokens: number;
|
|
74
|
-
readonly completedBoundaryRequestCounts: readonly number[] | null;
|
|
75
|
-
readonly requestsPerBoundaryMean: number | null;
|
|
76
|
-
readonly requestsPerBoundaryLowerBound: number | null;
|
|
77
|
-
readonly unboundedExpectedRemainingRequests: number | null;
|
|
78
|
-
readonly averageContextTokenIncrement: number | null;
|
|
79
|
-
readonly windowRequestUpperBound: number | null;
|
|
80
65
|
readonly expectedRemainingRequests: number | null;
|
|
81
66
|
readonly breakevenRequests: number | null;
|
|
82
|
-
readonly combinedBreakevenRequests: number | null;
|
|
83
67
|
readonly effectiveHorizonRequests: number | null;
|
|
84
68
|
readonly remainingBoundaries: number;
|
|
85
69
|
readonly cacheWriteReadRatio: number | null;
|
|
@@ -106,9 +90,7 @@ export function estimateRemainingRequests(input: {
|
|
|
106
90
|
readonly averageContextTokenIncrement: number | null;
|
|
107
91
|
}): RequestHorizonEstimate {
|
|
108
92
|
const counts = input.completedBoundaryRequestCounts;
|
|
109
|
-
const mean =
|
|
110
|
-
counts.reduce((total, count) => total + count, 0) /
|
|
111
|
-
Math.max(1, counts.length);
|
|
93
|
+
const mean = counts.reduce((total, count) => total + count, 0) / Math.max(1, counts.length);
|
|
112
94
|
let lowerBound = mean;
|
|
113
95
|
if (input.standardDeviationK !== 0) {
|
|
114
96
|
if (counts.length < MINIMUM_VARIANCE_SAMPLES) {
|
|
@@ -133,11 +115,9 @@ export function estimateRemainingRequests(input: {
|
|
|
133
115
|
);
|
|
134
116
|
|
|
135
117
|
return {
|
|
136
|
-
completedBoundaryRequestCounts: [...counts],
|
|
137
118
|
requestsPerBoundaryMean: mean,
|
|
138
119
|
requestsPerBoundaryLowerBound: lowerBound,
|
|
139
120
|
unboundedExpectedRemainingRequests,
|
|
140
|
-
averageContextTokenIncrement: input.averageContextTokenIncrement,
|
|
141
121
|
windowRequestUpperBound,
|
|
142
122
|
expectedRemainingRequests:
|
|
143
123
|
windowRequestUpperBound === null
|
|
@@ -162,97 +142,92 @@ export function decideCompaction(input: {
|
|
|
162
142
|
readonly economics?: CompactionEconomics;
|
|
163
143
|
}): CompactionDecision {
|
|
164
144
|
const economics = input.economics ?? DEFAULT_COMPACTION_ECONOMICS;
|
|
165
|
-
const horizon =
|
|
166
|
-
input.completedBoundaryRequestCounts
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
contextWindowTokens: input.contextWindowTokens,
|
|
175
|
-
averageContextTokenIncrement: input.averageContextTokenIncrement,
|
|
176
|
-
});
|
|
145
|
+
const horizon = input.completedBoundaryRequestCounts === null ? null : estimateRemainingRequests({
|
|
146
|
+
completedBoundaryRequestCounts: input.completedBoundaryRequestCounts,
|
|
147
|
+
remainingBoundaries: input.remainingBoundaries,
|
|
148
|
+
scale: economics.remainingRequestScale,
|
|
149
|
+
standardDeviationK: economics.remainingRequestStddevK,
|
|
150
|
+
contextTokens: input.contextTokens,
|
|
151
|
+
contextWindowTokens: input.contextWindowTokens,
|
|
152
|
+
averageContextTokenIncrement: input.averageContextTokenIncrement,
|
|
153
|
+
});
|
|
177
154
|
|
|
178
155
|
const savingTokens = input.archiveTokens - input.memoTokens;
|
|
156
|
+
const compressible = savingTokens > 0;
|
|
179
157
|
const incrementalCacheCostRatio =
|
|
180
158
|
input.cacheWriteReadRatio === null ? null : Math.max(0, input.cacheWriteReadRatio - 1);
|
|
159
|
+
const incrementalWriteCost = incrementalCacheCostRatio === null
|
|
160
|
+
? null
|
|
161
|
+
: input.writeTokens * incrementalCacheCostRatio;
|
|
181
162
|
|
|
182
|
-
const breakevenRequests =
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
163
|
+
const breakevenRequests = compressible && incrementalWriteCost !== null
|
|
164
|
+
? incrementalWriteCost / savingTokens
|
|
165
|
+
: null;
|
|
166
|
+
const combinedBreakevenRequests = compressible && incrementalWriteCost !== null
|
|
167
|
+
? (input.carriedDebtTokens + incrementalWriteCost) / savingTokens
|
|
168
|
+
: null;
|
|
186
169
|
|
|
187
|
-
const combinedBreakevenRequests =
|
|
188
|
-
savingTokens > 0 && incrementalCacheCostRatio !== null
|
|
189
|
-
? (input.carriedDebtTokens + input.writeTokens * incrementalCacheCostRatio) / savingTokens
|
|
190
|
-
: null;
|
|
191
170
|
const firstCompaction = input.priorCompactionCount === 0;
|
|
192
|
-
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
// and burn a full-context summarization for zero future benefit (2026-09-17 review).
|
|
171
|
+
const horizonRequests = horizon?.expectedRemainingRequests ?? null;
|
|
172
|
+
// The first-compaction relaxation absorbs cold-start sample noise, but only when work remains: with
|
|
173
|
+
// zero remaining boundaries the horizon is 1, and scaling it to 2 would burn a full-context summary.
|
|
196
174
|
const relaxFirstCompaction = firstCompaction && input.remainingBoundaries > 0;
|
|
197
|
-
const effectiveHorizonRequests =
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
: horizon.expectedRemainingRequests;
|
|
175
|
+
const effectiveHorizonRequests = horizon === null
|
|
176
|
+
? null
|
|
177
|
+
: relaxFirstCompaction
|
|
178
|
+
? Math.min(
|
|
179
|
+
horizon.expectedRemainingRequests * economics.firstCompactionRequestScale,
|
|
180
|
+
horizon.windowRequestUpperBound ?? Number.POSITIVE_INFINITY,
|
|
181
|
+
)
|
|
182
|
+
: horizon.expectedRemainingRequests;
|
|
206
183
|
|
|
207
184
|
const windowProtection =
|
|
208
185
|
input.contextWindowTokens !== null &&
|
|
209
186
|
input.contextTokens >= input.contextWindowTokens - economics.windowReserveTokens;
|
|
210
|
-
|
|
211
187
|
const baseEconomic =
|
|
212
|
-
|
|
213
|
-
|
|
188
|
+
horizonRequests !== null &&
|
|
189
|
+
horizonRequests > 0 &&
|
|
214
190
|
breakevenRequests !== null &&
|
|
215
|
-
breakevenRequests <=
|
|
216
|
-
|
|
191
|
+
breakevenRequests <= horizonRequests;
|
|
217
192
|
const firstEconomic =
|
|
218
193
|
firstCompaction &&
|
|
219
194
|
effectiveHorizonRequests !== null &&
|
|
220
195
|
effectiveHorizonRequests > 0 &&
|
|
221
196
|
breakevenRequests !== null &&
|
|
222
197
|
breakevenRequests <= effectiveHorizonRequests;
|
|
223
|
-
|
|
224
198
|
const subsequentMarginOpen =
|
|
225
199
|
!firstCompaction &&
|
|
226
|
-
|
|
200
|
+
horizonRequests !== null &&
|
|
227
201
|
breakevenRequests !== null &&
|
|
228
|
-
breakevenRequests * economics.subsequentCompactionMargin <=
|
|
229
|
-
|
|
202
|
+
breakevenRequests * economics.subsequentCompactionMargin <= horizonRequests;
|
|
230
203
|
const carriedDebtGateOpen =
|
|
231
204
|
!firstCompaction &&
|
|
232
|
-
|
|
205
|
+
horizonRequests !== null &&
|
|
233
206
|
combinedBreakevenRequests !== null &&
|
|
234
|
-
combinedBreakevenRequests <=
|
|
207
|
+
combinedBreakevenRequests <= horizonRequests;
|
|
235
208
|
|
|
236
209
|
const economic = firstCompaction ? firstEconomic : baseEconomic && subsequentMarginOpen && carriedDebtGateOpen;
|
|
237
|
-
const compressible = savingTokens > 0;
|
|
238
210
|
const compact = compressible && (windowProtection || economic);
|
|
239
211
|
|
|
212
|
+
// Ordered guards: first hit wins, so the tail entry is the fallback.
|
|
213
|
+
const reason = ([
|
|
214
|
+
['non_positive_saving', !compressible],
|
|
215
|
+
['window_protection', windowProtection],
|
|
216
|
+
['economic', economic],
|
|
217
|
+
['horizon_unavailable', horizon === null],
|
|
218
|
+
['cache_ratio_unavailable', breakevenRequests === null],
|
|
219
|
+
['deferred_subsequent_margin', !firstCompaction && baseEconomic && !subsequentMarginOpen],
|
|
220
|
+
['deferred_carried_debt', !firstCompaction && baseEconomic && !carriedDebtGateOpen],
|
|
221
|
+
['deferred_economic', true],
|
|
222
|
+
] as Array<[CompactionReason, boolean]>).find(([, hit]) => hit)![0];
|
|
223
|
+
|
|
240
224
|
return {
|
|
241
225
|
writeTokens: input.writeTokens,
|
|
242
226
|
archiveTokens: input.archiveTokens,
|
|
243
227
|
memoTokens: input.memoTokens,
|
|
244
228
|
contextTokens: input.contextTokens,
|
|
245
|
-
|
|
246
|
-
completedBoundaryRequestCounts: null,
|
|
247
|
-
requestsPerBoundaryMean: null,
|
|
248
|
-
requestsPerBoundaryLowerBound: null,
|
|
249
|
-
unboundedExpectedRemainingRequests: null,
|
|
250
|
-
averageContextTokenIncrement: input.averageContextTokenIncrement,
|
|
251
|
-
windowRequestUpperBound: null,
|
|
252
|
-
expectedRemainingRequests: null,
|
|
253
|
-
}),
|
|
229
|
+
expectedRemainingRequests: horizonRequests,
|
|
254
230
|
breakevenRequests,
|
|
255
|
-
combinedBreakevenRequests,
|
|
256
231
|
effectiveHorizonRequests,
|
|
257
232
|
remainingBoundaries: input.remainingBoundaries,
|
|
258
233
|
cacheWriteReadRatio: input.cacheWriteReadRatio,
|
|
@@ -261,56 +236,23 @@ export function decideCompaction(input: {
|
|
|
261
236
|
carriedDebtTokens: input.carriedDebtTokens,
|
|
262
237
|
cacheDebtRepaymentTokens: input.cacheDebtRepaymentTokens,
|
|
263
238
|
compact,
|
|
264
|
-
reason
|
|
265
|
-
? 'non_positive_saving'
|
|
266
|
-
: windowProtection
|
|
267
|
-
? 'window_protection'
|
|
268
|
-
: economic
|
|
269
|
-
? 'economic'
|
|
270
|
-
: horizon === null
|
|
271
|
-
? 'horizon_unavailable'
|
|
272
|
-
: breakevenRequests === null
|
|
273
|
-
? 'cache_ratio_unavailable'
|
|
274
|
-
: !firstCompaction && baseEconomic && !subsequentMarginOpen
|
|
275
|
-
? 'deferred_subsequent_margin'
|
|
276
|
-
: !firstCompaction && baseEconomic && !carriedDebtGateOpen
|
|
277
|
-
? 'deferred_carried_debt'
|
|
278
|
-
: 'deferred_economic',
|
|
239
|
+
reason,
|
|
279
240
|
};
|
|
280
241
|
}
|
|
281
242
|
|
|
282
243
|
/**
|
|
283
|
-
* Resolve the cache write/read cost ratio for
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
* b. cacheWrite == 0 && cacheRead > 0 && input > 0 → input/cacheRead
|
|
290
|
-
* (implicit cache: rewriting the prefix is billed at the input price)
|
|
291
|
-
* 3. Provider-family fallback (gemini≈4, grok/deepseek≈10 — implicit-cache
|
|
292
|
-
* families without a local cacheWrite SKU)
|
|
293
|
-
* 4. Token-account fallback 2.0: a compaction re-reads writeTokens once,
|
|
294
|
-
* so breakeven = writeTokens/savingTokens ⇔ ratio 2
|
|
295
|
-
*
|
|
296
|
-
* Returns null only for an explicitly invalid numeric config.
|
|
297
|
-
*
|
|
298
|
-
* History (P0-1): `auto` used to return null when cacheWrite==0, reading that
|
|
299
|
-
* as "no KV cache at all". The 2026-09-17 trial disproved it on this machine:
|
|
300
|
-
* grok/deepseek/gemini sessions all show non-zero cacheRead usage while
|
|
301
|
-
* cacheWrite stays 0 — there is no separate write SKU, not "no cache". null
|
|
302
|
-
* disabled OCC for every model actually used (61/61 decisions
|
|
303
|
-
* `cache_ratio_unavailable`, zero compactions). The floor matters as much as
|
|
304
|
-
* the fix: never implicitly fall back below 2.0, because ratio <= 1 zeroes the
|
|
305
|
-
* incremental cost and would compact even on the last boundary with nothing
|
|
306
|
-
* left to amortize (the original P0-1 failure mode).
|
|
244
|
+
* Resolve the cache write/read cost ratio for compaction decisions, in order: explicit numeric config
|
|
245
|
+
* (as-is, e.g. 12.5 for Anthropic-style pricing), model cost metadata (write/read, or input/cacheRead
|
|
246
|
+
* when cache writes are billed at the input price), provider-family fallback (gemini ≈ 4, grok/deepseek
|
|
247
|
+
* ≈ 10), then TOKEN_ACCOUNT_CACHE_RATIO. Returns null only for an explicitly invalid numeric config:
|
|
248
|
+
* `auto` must never resolve to null, since a zero-price table means "no local cacheWrite SKU", not
|
|
249
|
+
* "no cache", and null would disable OCC for every model in actual use.
|
|
307
250
|
*/
|
|
308
251
|
export function resolveCacheRatioFromCost(
|
|
309
252
|
ratioConfig: number | 'auto',
|
|
310
253
|
cost?: { input?: number; cacheRead?: number; cacheWrite?: number } | null,
|
|
311
254
|
identity?: { provider?: string; modelId?: string } | null,
|
|
312
255
|
): number | null {
|
|
313
|
-
// Explicit config takes absolute precedence
|
|
314
256
|
if (typeof ratioConfig === 'number') {
|
|
315
257
|
return Number.isFinite(ratioConfig) && ratioConfig >= 0 ? ratioConfig : null;
|
|
316
258
|
}
|
|
@@ -319,7 +261,6 @@ export function resolveCacheRatioFromCost(
|
|
|
319
261
|
const read = cost.cacheRead ?? 0;
|
|
320
262
|
const write = cost.cacheWrite ?? 0;
|
|
321
263
|
const input = cost.input ?? 0;
|
|
322
|
-
|
|
323
264
|
if (read > 0 && write > 0) return write / read;
|
|
324
265
|
if (read > 0 && write === 0 && input > 0) return input / read;
|
|
325
266
|
}
|
|
@@ -335,37 +276,27 @@ function compactionMessageCount(entries: readonly SessionEntry[], startIndex: nu
|
|
|
335
276
|
let count = 0;
|
|
336
277
|
for (let index = startIndex; index < endIndex; index++) {
|
|
337
278
|
const entry = entries[index];
|
|
338
|
-
if (entry && entry.type !== 'compaction' && sessionEntryToContextMessages(entry).length > 0)
|
|
339
|
-
count++;
|
|
340
|
-
}
|
|
279
|
+
if (entry && entry.type !== 'compaction' && sessionEntryToContextMessages(entry).length > 0) count++;
|
|
341
280
|
}
|
|
342
281
|
return count;
|
|
343
282
|
}
|
|
344
283
|
|
|
284
|
+
/** Appends the abort marker pi's cut-point search expects after our intentional abort. */
|
|
345
285
|
function branchAfterAbort(entries: readonly SessionEntry[]): SessionEntry[] {
|
|
346
|
-
const last = entries.at(-1);
|
|
347
|
-
const markerProvider = 'pi-herdr';
|
|
348
286
|
return [
|
|
349
287
|
...entries,
|
|
350
288
|
{
|
|
351
289
|
type: 'message',
|
|
352
290
|
id: 'pi-herdr-online-context-compact-abort-marker',
|
|
353
|
-
parentId:
|
|
291
|
+
parentId: entries.at(-1)?.id ?? null,
|
|
354
292
|
timestamp: new Date(0).toISOString(),
|
|
355
293
|
message: {
|
|
356
294
|
role: 'assistant',
|
|
357
295
|
content: [],
|
|
358
|
-
api:
|
|
359
|
-
provider:
|
|
296
|
+
api: 'pi-herdr',
|
|
297
|
+
provider: 'pi-herdr',
|
|
360
298
|
model: 'aborted',
|
|
361
|
-
usage: {
|
|
362
|
-
input: 0,
|
|
363
|
-
output: 0,
|
|
364
|
-
cacheRead: 0,
|
|
365
|
-
cacheWrite: 0,
|
|
366
|
-
totalTokens: 0,
|
|
367
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
368
|
-
},
|
|
299
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
|
|
369
300
|
stopReason: 'aborted',
|
|
370
301
|
timestamp: 0,
|
|
371
302
|
},
|
|
@@ -373,6 +304,7 @@ function branchAfterAbort(entries: readonly SessionEntry[]): SessionEntry[] {
|
|
|
373
304
|
];
|
|
374
305
|
}
|
|
375
306
|
|
|
307
|
+
/** Would pi's own compaction find history to summarize on this branch? OCC must not abort otherwise. */
|
|
376
308
|
export function nativeCompactionFeasible(entries: readonly SessionEntry[], keepRecentTokens: number): boolean {
|
|
377
309
|
if (!Array.isArray(entries) || entries.length === 0) return false;
|
|
378
310
|
const path = branchAfterAbort(entries);
|