@oh-my-pi/pi-agent-core 17.2.1 → 17.2.2
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
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [17.2.2] - 2026-07-31
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed an issue where response-only usage records were incorrectly treated as authoritative context anchors, while ensuring prompt and total-only provider telemetry remains preserved.
|
|
10
|
+
- Fixed context compaction summaries growing excessively with large context windows by capping the summary output budget to 16,384 tokens, ensuring conversations are properly compressed rather than duplicated.
|
|
11
|
+
|
|
5
12
|
## [17.2.0] - 2026-07-30
|
|
6
13
|
|
|
7
14
|
### Fixed
|
|
@@ -52,18 +52,30 @@ export interface CompactionSettings {
|
|
|
52
52
|
}
|
|
53
53
|
/** Reserve applied when {@link CompactionSettings.reserveTokens} is unset. */
|
|
54
54
|
export declare const DEFAULT_RESERVE_TOKENS = 16384;
|
|
55
|
+
/**
|
|
56
|
+
* Hard ceiling on a generated compaction summary.
|
|
57
|
+
*
|
|
58
|
+
* The summary budget is `floor(0.8 * reserveTokens)`, and the effective reserve is
|
|
59
|
+
* at least 15% of the declared context window, so a 1M-token window authorizes a
|
|
60
|
+
* ~120k-token summary. At that size the model copies rather than compresses, and
|
|
61
|
+
* output is the slowest and most expensive token class. Capping absolutely keeps
|
|
62
|
+
* the compression ratio improving with window size instead of degrading. The value
|
|
63
|
+
* mirrors {@link DEFAULT_RESERVE_TOKENS} so this adds no new tuning constant.
|
|
64
|
+
*/
|
|
65
|
+
export declare const MAX_SUMMARY_TOKENS = 16384;
|
|
55
66
|
export declare const DEFAULT_COMPACTION_SETTINGS: CompactionSettings;
|
|
56
67
|
/** Whether a compaction candidate preserves provider-native transport under the effective settings. */
|
|
57
68
|
export declare function shouldUseProviderNativeCompaction(model: Model, settings: Pick<CompactionSettings, "remoteEnabled" | "remoteStreamingV2Enabled">): boolean;
|
|
58
69
|
/**
|
|
59
70
|
* Calculate total context tokens from usage.
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
71
|
+
* Prefers an explicit provider-reported context occupancy when available.
|
|
72
|
+
* Otherwise uses totalTokens and falls back to computing from billable
|
|
73
|
+
* components. Provider-side orchestration tokens are billable but never replay
|
|
74
|
+
* into the conversation prefix, so they are excluded from context sizing.
|
|
64
75
|
*/
|
|
65
76
|
export declare function calculateContextTokens(usage: Usage): number;
|
|
66
77
|
export declare function calculatePromptTokens(usage: Usage): number;
|
|
78
|
+
export declare function hasContextTokenUsage(usage: Usage): boolean;
|
|
67
79
|
/**
|
|
68
80
|
* Find the last non-aborted assistant message usage from session entries.
|
|
69
81
|
*/
|
|
@@ -65,6 +65,7 @@ export interface OpenAiRemoteCompactionResponse extends OpenAiRemoteCompactionPr
|
|
|
65
65
|
export interface RemoteCompactionRequest {
|
|
66
66
|
systemPrompt: string;
|
|
67
67
|
prompt: string;
|
|
68
|
+
maxTokens?: number;
|
|
68
69
|
}
|
|
69
70
|
export interface RemoteCompactionResponse {
|
|
70
71
|
summary: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-agent-core",
|
|
4
|
-
"version": "17.2.
|
|
4
|
+
"version": "17.2.2",
|
|
5
5
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"fmt": "biome format --write ."
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@oh-my-pi/pi-ai": "17.2.
|
|
39
|
-
"@oh-my-pi/pi-catalog": "17.2.
|
|
40
|
-
"@oh-my-pi/pi-natives": "17.2.
|
|
41
|
-
"@oh-my-pi/pi-utils": "17.2.
|
|
42
|
-
"@oh-my-pi/pi-wire": "17.2.
|
|
43
|
-
"@oh-my-pi/snapcompact": "17.2.
|
|
38
|
+
"@oh-my-pi/pi-ai": "17.2.2",
|
|
39
|
+
"@oh-my-pi/pi-catalog": "17.2.2",
|
|
40
|
+
"@oh-my-pi/pi-natives": "17.2.2",
|
|
41
|
+
"@oh-my-pi/pi-utils": "17.2.2",
|
|
42
|
+
"@oh-my-pi/pi-wire": "17.2.2",
|
|
43
|
+
"@oh-my-pi/snapcompact": "17.2.2",
|
|
44
44
|
"@opentelemetry/api": "^1.9.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
@@ -187,6 +187,18 @@ export interface CompactionSettings {
|
|
|
187
187
|
/** Reserve applied when {@link CompactionSettings.reserveTokens} is unset. */
|
|
188
188
|
export const DEFAULT_RESERVE_TOKENS = 16384;
|
|
189
189
|
|
|
190
|
+
/**
|
|
191
|
+
* Hard ceiling on a generated compaction summary.
|
|
192
|
+
*
|
|
193
|
+
* The summary budget is `floor(0.8 * reserveTokens)`, and the effective reserve is
|
|
194
|
+
* at least 15% of the declared context window, so a 1M-token window authorizes a
|
|
195
|
+
* ~120k-token summary. At that size the model copies rather than compresses, and
|
|
196
|
+
* output is the slowest and most expensive token class. Capping absolutely keeps
|
|
197
|
+
* the compression ratio improving with window size instead of degrading. The value
|
|
198
|
+
* mirrors {@link DEFAULT_RESERVE_TOKENS} so this adds no new tuning constant.
|
|
199
|
+
*/
|
|
200
|
+
export const MAX_SUMMARY_TOKENS = DEFAULT_RESERVE_TOKENS;
|
|
201
|
+
|
|
190
202
|
// reserveTokens is deliberately absent: an unset reserve is what marks it as
|
|
191
203
|
// defaulted, which resolveBudgetReserveTokens needs to distinguish "user never
|
|
192
204
|
// chose a reserve" from "user explicitly configured the default value".
|
|
@@ -221,12 +233,15 @@ export function shouldUseProviderNativeCompaction(
|
|
|
221
233
|
|
|
222
234
|
/**
|
|
223
235
|
* Calculate total context tokens from usage.
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
236
|
+
* Prefers an explicit provider-reported context occupancy when available.
|
|
237
|
+
* Otherwise uses totalTokens and falls back to computing from billable
|
|
238
|
+
* components. Provider-side orchestration tokens are billable but never replay
|
|
239
|
+
* into the conversation prefix, so they are excluded from context sizing.
|
|
228
240
|
*/
|
|
229
241
|
export function calculateContextTokens(usage: Usage): number {
|
|
242
|
+
if (usage.contextTokens !== undefined) {
|
|
243
|
+
return Math.max(0, usage.contextTokens);
|
|
244
|
+
}
|
|
230
245
|
const orchestration = usage.orchestration;
|
|
231
246
|
const orchestrationTotal = orchestration
|
|
232
247
|
? (orchestration.input ?? 0) + (orchestration.output ?? 0) + (orchestration.cacheRead ?? 0)
|
|
@@ -236,6 +251,9 @@ export function calculateContextTokens(usage: Usage): number {
|
|
|
236
251
|
}
|
|
237
252
|
|
|
238
253
|
export function calculatePromptTokens(usage: Usage): number {
|
|
254
|
+
if (usage.contextTokens !== undefined) {
|
|
255
|
+
return Math.max(0, usage.contextTokens);
|
|
256
|
+
}
|
|
239
257
|
const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
240
258
|
if (promptTokens > 0) {
|
|
241
259
|
return promptTokens;
|
|
@@ -243,6 +261,14 @@ export function calculatePromptTokens(usage: Usage): number {
|
|
|
243
261
|
return calculateContextTokens(usage);
|
|
244
262
|
}
|
|
245
263
|
|
|
264
|
+
export function hasContextTokenUsage(usage: Usage): boolean {
|
|
265
|
+
return (
|
|
266
|
+
(usage.contextTokens ?? 0) > 0 ||
|
|
267
|
+
usage.input + usage.cacheRead + usage.cacheWrite > 0 ||
|
|
268
|
+
calculateContextTokens(usage) > usage.output
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
246
272
|
/**
|
|
247
273
|
* Get usage from an assistant message if available.
|
|
248
274
|
* Skips aborted and error messages as they don't have valid usage data.
|
|
@@ -842,7 +868,7 @@ export async function generateSummary(
|
|
|
842
868
|
previousSummary?: string,
|
|
843
869
|
options?: SummaryOptions,
|
|
844
870
|
): Promise<string> {
|
|
845
|
-
const maxTokens = Math.floor(0.8 * reserveTokens);
|
|
871
|
+
const maxTokens = Math.min(Math.floor(0.8 * reserveTokens), MAX_SUMMARY_TOKENS);
|
|
846
872
|
|
|
847
873
|
// Use update prompt if we have a previous summary, otherwise initial prompt
|
|
848
874
|
let basePrompt = previousSummary ? UPDATE_SUMMARIZATION_PROMPT : SUMMARIZATION_PROMPT;
|
|
@@ -881,7 +907,7 @@ export async function generateSummary(
|
|
|
881
907
|
key =>
|
|
882
908
|
requestRemoteCompaction(
|
|
883
909
|
endpoint,
|
|
884
|
-
{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, prompt: promptText },
|
|
910
|
+
{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, prompt: promptText, maxTokens },
|
|
885
911
|
signal,
|
|
886
912
|
{ fetch: options.fetch, model, apiKey: key },
|
|
887
913
|
),
|
|
@@ -1086,7 +1112,7 @@ async function generateShortSummary(
|
|
|
1086
1112
|
key =>
|
|
1087
1113
|
requestRemoteCompaction(
|
|
1088
1114
|
endpoint,
|
|
1089
|
-
{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, prompt: promptText },
|
|
1115
|
+
{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, prompt: promptText, maxTokens },
|
|
1090
1116
|
signal,
|
|
1091
1117
|
{ fetch: options?.fetch, model, apiKey: key },
|
|
1092
1118
|
),
|
|
@@ -1657,7 +1683,7 @@ async function generateTurnPrefixSummary(
|
|
|
1657
1683
|
signal?: AbortSignal,
|
|
1658
1684
|
options?: SummaryOptions,
|
|
1659
1685
|
): Promise<string> {
|
|
1660
|
-
const maxTokens = Math.floor(0.5 * reserveTokens); // Smaller budget for turn prefix
|
|
1686
|
+
const maxTokens = Math.min(Math.floor(0.5 * reserveTokens), MAX_SUMMARY_TOKENS); // Smaller budget for turn prefix
|
|
1661
1687
|
|
|
1662
1688
|
const llmMessages = (options?.convertToLlm ?? defaultConvertToLlm)(messages);
|
|
1663
1689
|
const conversationText = serializeConversationForSummary(llmMessages, preferredDialect(model.id));
|
package/src/compaction/openai.ts
CHANGED
|
@@ -239,6 +239,7 @@ export interface OpenAiRemoteCompactionResponse extends OpenAiRemoteCompactionPr
|
|
|
239
239
|
export interface RemoteCompactionRequest {
|
|
240
240
|
systemPrompt: string;
|
|
241
241
|
prompt: string;
|
|
242
|
+
maxTokens?: number;
|
|
242
243
|
}
|
|
243
244
|
|
|
244
245
|
export interface RemoteCompactionResponse {
|
|
@@ -928,8 +929,9 @@ export async function requestRemoteCompaction(
|
|
|
928
929
|
{ role: "user", content: request.prompt },
|
|
929
930
|
],
|
|
930
931
|
stream: false,
|
|
932
|
+
max_tokens: request.maxTokens,
|
|
931
933
|
}
|
|
932
|
-
: { systemPrompt: request.systemPrompt, prompt: request.prompt };
|
|
934
|
+
: { systemPrompt: request.systemPrompt, prompt: request.prompt, maxTokens: request.maxTokens };
|
|
933
935
|
|
|
934
936
|
const response = await (opts?.fetch ?? fetch)(endpoint, {
|
|
935
937
|
method: "POST",
|