@oh-my-pi/pi-agent-core 16.2.3 → 16.2.5
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 +12 -0
- package/dist/types/compaction/branch-summarization.d.ts +8 -1
- package/dist/types/compaction/compaction.d.ts +12 -1
- package/package.json +7 -7
- package/src/agent-loop.ts +37 -2
- package/src/compaction/branch-summarization.ts +13 -2
- package/src/compaction/compaction.ts +26 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [16.2.4] - 2026-06-28
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Improved the reliability of remote compaction by introducing transient error retries, configurable timeouts, and immediate termination upon user-initiated aborts.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Fixed an issue where assistant responses and encrypted reasoning could be lost during local history trimming prior to remote compaction.
|
|
14
|
+
- Fixed type compatibility for hosts with title audit entries by adding support for `title_change` session metadata.
|
|
15
|
+
- Fixed an issue where transient stream read failures after a completed tool call were treated as terminal errors, allowing the agent to successfully execute the tool and continue the turn.
|
|
16
|
+
|
|
5
17
|
## [16.2.3] - 2026-06-28
|
|
6
18
|
|
|
7
19
|
### Changed
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* When navigating to a different point in the session tree, this generates
|
|
5
5
|
* a summary of the branch being left so context isn't lost.
|
|
6
6
|
*/
|
|
7
|
-
import type { ApiKey, Model } from "@oh-my-pi/pi-ai";
|
|
7
|
+
import type { Api, ApiKey, AssistantMessage, Context, Model, SimpleStreamOptions } from "@oh-my-pi/pi-ai";
|
|
8
8
|
import { type AgentTelemetry } from "../telemetry";
|
|
9
9
|
import type { AgentMessage } from "../types";
|
|
10
10
|
import type { ReadonlySessionManager, SessionEntry } from "./entries";
|
|
@@ -57,6 +57,13 @@ export interface GenerateBranchSummaryOptions {
|
|
|
57
57
|
* wrapped in an OTEL chat span tagged with `pi.gen_ai.oneshot.kind = "branch_summary"`.
|
|
58
58
|
*/
|
|
59
59
|
telemetry?: AgentTelemetry;
|
|
60
|
+
/**
|
|
61
|
+
* Optional completion transport override (same contract as
|
|
62
|
+
* {@link SummaryOptions.completeImpl}). Lets the host route the branch
|
|
63
|
+
* summary HTTP request through its provider-concurrency limiter instead
|
|
64
|
+
* of the default `completeSimple` transport.
|
|
65
|
+
*/
|
|
66
|
+
completeImpl?: <TApi extends Api>(model: Model<TApi>, ctx: Context, options: SimpleStreamOptions) => Promise<AssistantMessage>;
|
|
60
67
|
}
|
|
61
68
|
/**
|
|
62
69
|
* Collect entries that should be summarized when navigating from one position to another.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Pure functions for compaction logic. The session manager handles I/O,
|
|
5
5
|
* and after compaction the session is reloaded.
|
|
6
6
|
*/
|
|
7
|
-
import { type ApiKey, type Context, type FetchImpl, type MessageAttribution, type Model, type SimpleStreamOptions, type Tool, type Usage } from "@oh-my-pi/pi-ai";
|
|
7
|
+
import { type Api, type ApiKey, type AssistantMessage, type Context, type FetchImpl, type MessageAttribution, type Model, type SimpleStreamOptions, type Tool, type Usage } from "@oh-my-pi/pi-ai";
|
|
8
8
|
import { type AgentTelemetry } from "../telemetry";
|
|
9
9
|
import { ThinkingLevel } from "../thinking";
|
|
10
10
|
import type { AgentMessage } from "../types";
|
|
@@ -161,6 +161,15 @@ export interface SummaryOptions {
|
|
|
161
161
|
tools?: Tool[];
|
|
162
162
|
/** Optional fetch implementation threaded into remote compaction calls. */
|
|
163
163
|
fetch?: FetchImpl;
|
|
164
|
+
/**
|
|
165
|
+
* Optional completion transport override for host-level request wrappers
|
|
166
|
+
* (e.g. the coding-agent provider-concurrency limiter). When provided,
|
|
167
|
+
* every local summarization oneshot (`generateSummary`,
|
|
168
|
+
* `generateTurnPrefixSummary`, `generateShortSummary`) routes through it
|
|
169
|
+
* instead of the default `completeSimple`, so cap policies enforced on
|
|
170
|
+
* the live agent turn also bracket compaction HTTP requests.
|
|
171
|
+
*/
|
|
172
|
+
completeImpl?: <TApi extends Api>(model: Model<TApi>, ctx: Context, options: SimpleStreamOptions) => Promise<AssistantMessage>;
|
|
164
173
|
}
|
|
165
174
|
export declare function generateSummary(currentMessages: AgentMessage[], model: Model, reserveTokens: number, apiKey: ApiKey, signal?: AbortSignal, customInstructions?: string, previousSummary?: string, options?: SummaryOptions): Promise<string>;
|
|
166
175
|
export interface HandoffOptions {
|
|
@@ -197,6 +206,8 @@ export interface HandoffFromContextOptions {
|
|
|
197
206
|
* anything provided here.
|
|
198
207
|
*/
|
|
199
208
|
streamOptions: SimpleStreamOptions;
|
|
209
|
+
/** Optional completion transport override for host-level request wrappers. */
|
|
210
|
+
completeImpl?: <TApi extends Api>(model: Model<TApi>, ctx: Context, options: SimpleStreamOptions) => Promise<AssistantMessage>;
|
|
200
211
|
/** See {@link HandoffOptions.telemetry}. */
|
|
201
212
|
telemetry?: AgentTelemetry;
|
|
202
213
|
/** See {@link HandoffOptions.thinkingLevel}. */
|
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": "16.2.
|
|
4
|
+
"version": "16.2.5",
|
|
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": "16.2.
|
|
39
|
-
"@oh-my-pi/pi-catalog": "16.2.
|
|
40
|
-
"@oh-my-pi/pi-natives": "16.2.
|
|
41
|
-
"@oh-my-pi/pi-utils": "16.2.
|
|
42
|
-
"@oh-my-pi/pi-wire": "16.2.
|
|
43
|
-
"@oh-my-pi/snapcompact": "16.2.
|
|
38
|
+
"@oh-my-pi/pi-ai": "16.2.5",
|
|
39
|
+
"@oh-my-pi/pi-catalog": "16.2.5",
|
|
40
|
+
"@oh-my-pi/pi-natives": "16.2.5",
|
|
41
|
+
"@oh-my-pi/pi-utils": "16.2.5",
|
|
42
|
+
"@oh-my-pi/pi-wire": "16.2.5",
|
|
43
|
+
"@oh-my-pi/snapcompact": "16.2.5",
|
|
44
44
|
"@opentelemetry/api": "^1.9.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
package/src/agent-loop.ts
CHANGED
|
@@ -1355,7 +1355,10 @@ async function streamAssistantResponse(
|
|
|
1355
1355
|
|
|
1356
1356
|
const event = next.value;
|
|
1357
1357
|
if (event.type === "done" || event.type === "error") {
|
|
1358
|
-
let finalMessage =
|
|
1358
|
+
let finalMessage = recoverTransientErrorToolTurn(
|
|
1359
|
+
retainCompletedToolCalls(await response.result(), completedToolCallIds),
|
|
1360
|
+
context.tools ?? [],
|
|
1361
|
+
);
|
|
1359
1362
|
if (harmonyMitigationEnabled) {
|
|
1360
1363
|
const detection = detectHarmonyLeakInAssistantMessage(finalMessage);
|
|
1361
1364
|
if (detection) {
|
|
@@ -1515,8 +1518,40 @@ function retainCompletedToolCalls(
|
|
|
1515
1518
|
: {
|
|
1516
1519
|
type: STREAM_INTERRUPTED_AFTER_CONTENT_STOP_DETAIL,
|
|
1517
1520
|
category: message.stopDetails?.type ?? null,
|
|
1518
|
-
explanation: message.stopDetails?.explanation ?? null,
|
|
1521
|
+
explanation: message.stopDetails?.explanation ?? message.errorMessage ?? null,
|
|
1522
|
+
},
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
function recoverTransientErrorToolTurn(
|
|
1527
|
+
message: AssistantMessage,
|
|
1528
|
+
availableTools: ReadonlyArray<Pick<AgentTool, "name" | "customWireName">>,
|
|
1529
|
+
): AssistantMessage {
|
|
1530
|
+
if (message.stopReason !== "error") return message;
|
|
1531
|
+
const toolCalls = message.content.filter(block => block.type === "toolCall");
|
|
1532
|
+
if (toolCalls.length === 0) return message;
|
|
1533
|
+
const availableToolNames = new Set<string>();
|
|
1534
|
+
for (const tool of availableTools) {
|
|
1535
|
+
availableToolNames.add(tool.name);
|
|
1536
|
+
if (tool.customWireName !== undefined) availableToolNames.add(tool.customWireName);
|
|
1537
|
+
}
|
|
1538
|
+
if (!toolCalls.every(toolCall => availableToolNames.has(toolCall.name))) return message;
|
|
1539
|
+
if (!AIError.isStreamReadErrorText(`${message.errorMessage ?? ""}\n${message.stopDetails?.explanation ?? ""}`))
|
|
1540
|
+
return message;
|
|
1541
|
+
return {
|
|
1542
|
+
...message,
|
|
1543
|
+
stopReason: "toolUse",
|
|
1544
|
+
stopDetails:
|
|
1545
|
+
message.stopDetails?.type === STREAM_INTERRUPTED_AFTER_CONTENT_STOP_DETAIL
|
|
1546
|
+
? message.stopDetails
|
|
1547
|
+
: {
|
|
1548
|
+
type: STREAM_INTERRUPTED_AFTER_CONTENT_STOP_DETAIL,
|
|
1549
|
+
category: message.stopDetails?.type ?? null,
|
|
1550
|
+
explanation: message.stopDetails?.explanation ?? message.errorMessage ?? null,
|
|
1519
1551
|
},
|
|
1552
|
+
errorMessage: undefined,
|
|
1553
|
+
errorId: undefined,
|
|
1554
|
+
errorStatus: undefined,
|
|
1520
1555
|
};
|
|
1521
1556
|
}
|
|
1522
1557
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* a summary of the branch being left so context isn't lost.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { ApiKey, Model } from "@oh-my-pi/pi-ai";
|
|
8
|
+
import type { Api, ApiKey, AssistantMessage, Context, Model, SimpleStreamOptions } from "@oh-my-pi/pi-ai";
|
|
9
9
|
import { preferredDialect } from "@oh-my-pi/pi-catalog/identity";
|
|
10
10
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
11
11
|
import { type AgentTelemetry, instrumentedCompleteSimple } from "../telemetry";
|
|
@@ -88,6 +88,17 @@ export interface GenerateBranchSummaryOptions {
|
|
|
88
88
|
* wrapped in an OTEL chat span tagged with `pi.gen_ai.oneshot.kind = "branch_summary"`.
|
|
89
89
|
*/
|
|
90
90
|
telemetry?: AgentTelemetry;
|
|
91
|
+
/**
|
|
92
|
+
* Optional completion transport override (same contract as
|
|
93
|
+
* {@link SummaryOptions.completeImpl}). Lets the host route the branch
|
|
94
|
+
* summary HTTP request through its provider-concurrency limiter instead
|
|
95
|
+
* of the default `completeSimple` transport.
|
|
96
|
+
*/
|
|
97
|
+
completeImpl?: <TApi extends Api>(
|
|
98
|
+
model: Model<TApi>,
|
|
99
|
+
ctx: Context,
|
|
100
|
+
options: SimpleStreamOptions,
|
|
101
|
+
) => Promise<AssistantMessage>;
|
|
91
102
|
}
|
|
92
103
|
|
|
93
104
|
// ============================================================================
|
|
@@ -310,7 +321,7 @@ export async function generateBranchSummary(
|
|
|
310
321
|
model,
|
|
311
322
|
{ systemPrompt: [SUMMARIZATION_SYSTEM_PROMPT], messages: summarizationMessages },
|
|
312
323
|
{ apiKey, signal, maxTokens: 2048, metadata },
|
|
313
|
-
{ telemetry: options.telemetry, oneshotKind: "branch_summary" },
|
|
324
|
+
{ telemetry: options.telemetry, oneshotKind: "branch_summary", completeImpl: options.completeImpl },
|
|
314
325
|
);
|
|
315
326
|
|
|
316
327
|
// Check if aborted or errored
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
|
+
type Api,
|
|
9
10
|
type ApiKey,
|
|
10
11
|
type AssistantMessage,
|
|
11
12
|
type Context,
|
|
@@ -679,6 +680,19 @@ export interface SummaryOptions {
|
|
|
679
680
|
tools?: Tool[];
|
|
680
681
|
/** Optional fetch implementation threaded into remote compaction calls. */
|
|
681
682
|
fetch?: FetchImpl;
|
|
683
|
+
/**
|
|
684
|
+
* Optional completion transport override for host-level request wrappers
|
|
685
|
+
* (e.g. the coding-agent provider-concurrency limiter). When provided,
|
|
686
|
+
* every local summarization oneshot (`generateSummary`,
|
|
687
|
+
* `generateTurnPrefixSummary`, `generateShortSummary`) routes through it
|
|
688
|
+
* instead of the default `completeSimple`, so cap policies enforced on
|
|
689
|
+
* the live agent turn also bracket compaction HTTP requests.
|
|
690
|
+
*/
|
|
691
|
+
completeImpl?: <TApi extends Api>(
|
|
692
|
+
model: Model<TApi>,
|
|
693
|
+
ctx: Context,
|
|
694
|
+
options: SimpleStreamOptions,
|
|
695
|
+
) => Promise<AssistantMessage>;
|
|
682
696
|
}
|
|
683
697
|
|
|
684
698
|
function formatPreviousSnapcompactArchive(archiveText: string): string {
|
|
@@ -768,7 +782,7 @@ export async function generateSummary(
|
|
|
768
782
|
initiatorOverride: options?.initiatorOverride,
|
|
769
783
|
metadata: options?.metadata,
|
|
770
784
|
},
|
|
771
|
-
{ telemetry: options?.telemetry, oneshotKind: "compaction_summary" },
|
|
785
|
+
{ telemetry: options?.telemetry, oneshotKind: "compaction_summary", completeImpl: options?.completeImpl },
|
|
772
786
|
);
|
|
773
787
|
|
|
774
788
|
if (response.stopReason === "error") {
|
|
@@ -828,6 +842,12 @@ export interface HandoffFromContextOptions {
|
|
|
828
842
|
* anything provided here.
|
|
829
843
|
*/
|
|
830
844
|
streamOptions: SimpleStreamOptions;
|
|
845
|
+
/** Optional completion transport override for host-level request wrappers. */
|
|
846
|
+
completeImpl?: <TApi extends Api>(
|
|
847
|
+
model: Model<TApi>,
|
|
848
|
+
ctx: Context,
|
|
849
|
+
options: SimpleStreamOptions,
|
|
850
|
+
) => Promise<AssistantMessage>;
|
|
831
851
|
/** See {@link HandoffOptions.telemetry}. */
|
|
832
852
|
telemetry?: AgentTelemetry;
|
|
833
853
|
/** See {@link HandoffOptions.thinkingLevel}. */
|
|
@@ -859,7 +879,7 @@ export async function generateHandoffFromContext(
|
|
|
859
879
|
reasoning: resolveCompactionEffort(model, options.thinkingLevel),
|
|
860
880
|
toolChoice: "none",
|
|
861
881
|
},
|
|
862
|
-
{ telemetry: options.telemetry, oneshotKind: "handoff" },
|
|
882
|
+
{ telemetry: options.telemetry, oneshotKind: "handoff", completeImpl: options.completeImpl },
|
|
863
883
|
);
|
|
864
884
|
|
|
865
885
|
if (response.stopReason === "error") {
|
|
@@ -953,7 +973,7 @@ async function generateShortSummary(
|
|
|
953
973
|
initiatorOverride: options?.initiatorOverride,
|
|
954
974
|
metadata: options?.metadata,
|
|
955
975
|
},
|
|
956
|
-
{ telemetry: options?.telemetry, oneshotKind: "compaction_short_summary" },
|
|
976
|
+
{ telemetry: options?.telemetry, oneshotKind: "compaction_short_summary", completeImpl: options?.completeImpl },
|
|
957
977
|
);
|
|
958
978
|
|
|
959
979
|
if (response.stopReason === "error") {
|
|
@@ -1222,6 +1242,7 @@ export async function compact(
|
|
|
1222
1242
|
promptCacheKey: options?.promptCacheKey,
|
|
1223
1243
|
tools: options?.tools,
|
|
1224
1244
|
fetch: options?.fetch,
|
|
1245
|
+
completeImpl: options?.completeImpl,
|
|
1225
1246
|
};
|
|
1226
1247
|
|
|
1227
1248
|
const previousSnapcompactArchive = snapcompact.getPreservedArchive(previousPreserveData);
|
|
@@ -1406,6 +1427,7 @@ export async function compact(
|
|
|
1406
1427
|
// resolves its own reasoning via resolveCompactionEffort.
|
|
1407
1428
|
thinkingLevel: options?.thinkingLevel,
|
|
1408
1429
|
fetch: summaryOptions.fetch,
|
|
1430
|
+
completeImpl: summaryOptions.completeImpl,
|
|
1409
1431
|
});
|
|
1410
1432
|
|
|
1411
1433
|
// Compute file lists and append to summary
|
|
@@ -1469,7 +1491,7 @@ async function generateTurnPrefixSummary(
|
|
|
1469
1491
|
initiatorOverride: options?.initiatorOverride,
|
|
1470
1492
|
metadata: options?.metadata,
|
|
1471
1493
|
},
|
|
1472
|
-
{ telemetry: options?.telemetry, oneshotKind: "compaction_turn_prefix" },
|
|
1494
|
+
{ telemetry: options?.telemetry, oneshotKind: "compaction_turn_prefix", completeImpl: options?.completeImpl },
|
|
1473
1495
|
);
|
|
1474
1496
|
|
|
1475
1497
|
if (response.stopReason === "error") {
|