@oh-my-pi/pi-agent-core 16.3.15 → 16.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/CHANGELOG.md +17 -0
- package/README.md +1 -1
- package/dist/types/agent-loop.d.ts +6 -0
- package/dist/types/compaction/compaction-v2-streaming.d.ts +3 -1
- package/dist/types/compaction/compaction.d.ts +5 -1
- package/dist/types/compaction/openai.d.ts +9 -1
- package/dist/types/thinking.d.ts +1 -0
- package/package.json +7 -7
- package/src/agent-loop.ts +13 -0
- package/src/compaction/compaction-v2-streaming.ts +60 -5
- package/src/compaction/compaction.ts +46 -10
- package/src/compaction/openai.ts +54 -3
- package/src/thinking.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [16.4.1] - 2026-07-10
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Enabled reasoning encryption content for all Responses Lite compaction requests
|
|
10
|
+
|
|
11
|
+
## [16.4.0] - 2026-07-10
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Added the `ThinkingLevel.Max` ("max") configuration option, mapping to the `Effort.Max` tier for supported models.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Fixed remote compaction behavior for Codex Responses Lite (GPT-5.6 family) models across both V1 and V2 endpoints to ensure correct formatting and routing.
|
|
20
|
+
- Fixed an issue where aborted tool-result hooks could trigger subsequent provider calls before the abort signal fully settled.
|
|
21
|
+
|
|
5
22
|
## [16.3.12] - 2026-07-08
|
|
6
23
|
|
|
7
24
|
### Added
|
package/README.md
CHANGED
|
@@ -134,7 +134,7 @@ const agent = new Agent({
|
|
|
134
134
|
initialState: {
|
|
135
135
|
systemPrompt: string[],
|
|
136
136
|
model: Model,
|
|
137
|
-
thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh",
|
|
137
|
+
thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max",
|
|
138
138
|
tools: AgentTool<any>[],
|
|
139
139
|
messages: AgentMessage[],
|
|
140
140
|
},
|
|
@@ -26,6 +26,12 @@ export interface ToolScopedAbortReason {
|
|
|
26
26
|
}
|
|
27
27
|
/** Creates an abort reason that labels matching tool calls separately from siblings. */
|
|
28
28
|
export declare function createToolScopedAbortReason(message: string, toolCallMessages: Record<string, string>, defaultToolCallMessage: string): ToolScopedAbortReason;
|
|
29
|
+
/**
|
|
30
|
+
* Marks an abort raised by a completed post-tool hook as terminal for the
|
|
31
|
+
* current run. External/user aborts still synthesize an aborted assistant
|
|
32
|
+
* boundary; this reason stops after persisting the completed tool batch.
|
|
33
|
+
*/
|
|
34
|
+
export declare const TERMINAL_TOOL_RESULT_ABORT_REASON: unique symbol;
|
|
29
35
|
export declare function resolveOwnedDialectFromEnv(value: string | undefined): Dialect | undefined;
|
|
30
36
|
/**
|
|
31
37
|
* Start an agent loop with a new prompt message.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* compaction output item, then install retained real user messages plus that
|
|
7
7
|
* compaction item as replacement history.
|
|
8
8
|
*/
|
|
9
|
-
import type { FetchImpl, Model } from "@oh-my-pi/pi-ai";
|
|
9
|
+
import type { CodexCompactionContext, FetchImpl, Model, ProviderSessionState } from "@oh-my-pi/pi-ai";
|
|
10
10
|
/** Retained-message budget Codex uses after streamed V2 compaction. */
|
|
11
11
|
export declare const V2_RETAINED_MESSAGE_TOKEN_BUDGET = 64000;
|
|
12
12
|
/** Max retries for V2 streaming compaction on transient stream errors. */
|
|
@@ -66,6 +66,8 @@ export declare function requestCompactionV2Streaming(model: Model, apiKey: strin
|
|
|
66
66
|
fetch?: FetchImpl;
|
|
67
67
|
timeoutMs?: number;
|
|
68
68
|
retryWait?: (delayMs: number, signal?: AbortSignal) => Promise<void>;
|
|
69
|
+
providerSessionState?: Map<string, ProviderSessionState>;
|
|
70
|
+
codexCompaction?: CodexCompactionContext;
|
|
69
71
|
}): Promise<CompactionV2Response>;
|
|
70
72
|
/** Build Codex-style V2 replacement history from prompt input plus compaction output. */
|
|
71
73
|
export declare function buildCompactionV2ReplacementHistory(input: unknown[], compactionItem: Record<string, unknown>, retainedMessageBudget?: number): {
|
|
@@ -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 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";
|
|
7
|
+
import { type Api, type ApiKey, type AssistantMessage, type CodexCompactionContext, type Context, type FetchImpl, type MessageAttribution, type Model, type ProviderSessionState, type SimpleStreamOptions, type Tool, type Usage } from "@oh-my-pi/pi-ai";
|
|
8
8
|
import { type AgentTelemetry } from "../telemetry.js";
|
|
9
9
|
import { ThinkingLevel } from "../thinking.js";
|
|
10
10
|
import type { AgentMessage } from "../types.js";
|
|
@@ -184,6 +184,10 @@ export interface SummaryOptions {
|
|
|
184
184
|
sessionId?: string;
|
|
185
185
|
/** Prompt-cache key for remote compaction transports that support provider prefix caching. */
|
|
186
186
|
promptCacheKey?: string;
|
|
187
|
+
/** Mutable provider state used to keep Codex compaction on the live session identity. */
|
|
188
|
+
providerSessionState?: Map<string, ProviderSessionState>;
|
|
189
|
+
/** Classification shared by every provider request in this logical compaction. */
|
|
190
|
+
codexCompaction?: CodexCompactionContext;
|
|
187
191
|
/** Provider-visible tools for remote compaction transports that replay native tool history. */
|
|
188
192
|
tools?: Tool[];
|
|
189
193
|
/** Optional fetch implementation threaded into remote compaction calls. */
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* summarization endpoints that accept `{ systemPrompt, prompt }` and reply
|
|
15
15
|
* with `{ summary, shortSummary? }`.
|
|
16
16
|
*/
|
|
17
|
-
import type { FetchImpl, Message, Model } from "@oh-my-pi/pi-ai/types";
|
|
17
|
+
import type { CodexCompactionContext, FetchImpl, Message, Model, ProviderSessionState } from "@oh-my-pi/pi-ai/types";
|
|
18
18
|
export * from "./compaction-v2-streaming.js";
|
|
19
19
|
export declare const OPENAI_REMOTE_COMPACTION_PRESERVE_KEY = "openaiRemoteCompaction";
|
|
20
20
|
/**
|
|
@@ -40,6 +40,11 @@ export interface OpenAiRemoteCompactionRequest {
|
|
|
40
40
|
model: string;
|
|
41
41
|
input: Array<Record<string, unknown>>;
|
|
42
42
|
instructions: string;
|
|
43
|
+
reasoning?: {
|
|
44
|
+
context?: string;
|
|
45
|
+
[key: string]: unknown;
|
|
46
|
+
};
|
|
47
|
+
include?: string[];
|
|
43
48
|
}
|
|
44
49
|
export interface OpenAiRemoteCompactionResponse extends OpenAiRemoteCompactionPreserveData {
|
|
45
50
|
}
|
|
@@ -70,6 +75,9 @@ export declare function buildOpenAiNativeHistory(messages: Message[], model: Mod
|
|
|
70
75
|
export declare function requestOpenAiRemoteCompaction(model: Model, apiKey: string, compactInput: Array<Record<string, unknown>>, instructions: string, signal?: AbortSignal, opts?: {
|
|
71
76
|
fetch?: FetchImpl;
|
|
72
77
|
timeoutMs?: number;
|
|
78
|
+
sessionId?: string;
|
|
79
|
+
providerSessionState?: Map<string, ProviderSessionState>;
|
|
80
|
+
codexCompaction?: CodexCompactionContext;
|
|
73
81
|
}): Promise<OpenAiRemoteCompactionResponse>;
|
|
74
82
|
/**
|
|
75
83
|
* Generic remote-compaction POST. Two wire shapes are auto-selected by
|
package/dist/types/thinking.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare const ThinkingLevel: {
|
|
|
12
12
|
readonly Medium: Effort.Medium;
|
|
13
13
|
readonly High: Effort.High;
|
|
14
14
|
readonly XHigh: Effort.XHigh;
|
|
15
|
+
readonly Max: Effort.Max;
|
|
15
16
|
};
|
|
16
17
|
export type ThinkingLevel = (typeof ThinkingLevel)[keyof typeof ThinkingLevel];
|
|
17
18
|
export type ResolvedThinkingLevel = Exclude<ThinkingLevel, "inherit">;
|
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.
|
|
4
|
+
"version": "16.4.1",
|
|
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.
|
|
39
|
-
"@oh-my-pi/pi-catalog": "16.
|
|
40
|
-
"@oh-my-pi/pi-natives": "16.
|
|
41
|
-
"@oh-my-pi/pi-utils": "16.
|
|
42
|
-
"@oh-my-pi/pi-wire": "16.
|
|
43
|
-
"@oh-my-pi/snapcompact": "16.
|
|
38
|
+
"@oh-my-pi/pi-ai": "16.4.1",
|
|
39
|
+
"@oh-my-pi/pi-catalog": "16.4.1",
|
|
40
|
+
"@oh-my-pi/pi-natives": "16.4.1",
|
|
41
|
+
"@oh-my-pi/pi-utils": "16.4.1",
|
|
42
|
+
"@oh-my-pi/pi-wire": "16.4.1",
|
|
43
|
+
"@oh-my-pi/snapcompact": "16.4.1",
|
|
44
44
|
"@opentelemetry/api": "^1.9.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
package/src/agent-loop.ts
CHANGED
|
@@ -132,6 +132,13 @@ export function createToolScopedAbortReason(
|
|
|
132
132
|
return { kind: "tool-scoped-abort", message, toolCallMessages, defaultToolCallMessage };
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Marks an abort raised by a completed post-tool hook as terminal for the
|
|
137
|
+
* current run. External/user aborts still synthesize an aborted assistant
|
|
138
|
+
* boundary; this reason stops after persisting the completed tool batch.
|
|
139
|
+
*/
|
|
140
|
+
export const TERMINAL_TOOL_RESULT_ABORT_REASON = Symbol.for("pi-agent-core.terminal-tool-result");
|
|
141
|
+
|
|
135
142
|
const STEERING_INTERRUPT_POLL_MS = 250;
|
|
136
143
|
|
|
137
144
|
class HarmonyLeakInterruption extends Error {
|
|
@@ -1084,6 +1091,12 @@ async function runLoopBody(
|
|
|
1084
1091
|
}
|
|
1085
1092
|
}
|
|
1086
1093
|
|
|
1094
|
+
// A tool hook may mark its completed result as terminal (e.g. subagent yield).
|
|
1095
|
+
// Stop before the next provider call without changing external/user abort semantics.
|
|
1096
|
+
if (signal?.reason === TERMINAL_TOOL_RESULT_ABORT_REASON) {
|
|
1097
|
+
hasMoreToolCalls = false;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1087
1100
|
if (toolCalls.length > 0) {
|
|
1088
1101
|
pausedTurnContinuations = 0;
|
|
1089
1102
|
} else if (
|
|
@@ -7,8 +7,14 @@
|
|
|
7
7
|
* compaction item as replacement history.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { Api, FetchImpl, Model } from "@oh-my-pi/pi-ai";
|
|
10
|
+
import type { Api, CodexCompactionContext, FetchImpl, Model, ProviderSessionState } from "@oh-my-pi/pi-ai";
|
|
11
11
|
import { isTransientStatus, ProviderHttpError } from "@oh-my-pi/pi-ai/error";
|
|
12
|
+
import { applyCodexResponsesLiteShape } from "@oh-my-pi/pi-ai/providers/openai-codex/request-transformer";
|
|
13
|
+
import {
|
|
14
|
+
createOpenAICodexCompactionRequestContext,
|
|
15
|
+
createOpenAICodexCompatibilityMetadata,
|
|
16
|
+
type OpenAICodexCompatibilityMetadata,
|
|
17
|
+
} from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
12
18
|
import {
|
|
13
19
|
getOpenAIPromptCacheKey,
|
|
14
20
|
getOpenAIResponsesRoutingSessionId,
|
|
@@ -219,6 +225,8 @@ export async function requestCompactionV2Streaming(
|
|
|
219
225
|
fetch?: FetchImpl;
|
|
220
226
|
timeoutMs?: number;
|
|
221
227
|
retryWait?: (delayMs: number, signal?: AbortSignal) => Promise<void>;
|
|
228
|
+
providerSessionState?: Map<string, ProviderSessionState>;
|
|
229
|
+
codexCompaction?: CodexCompactionContext;
|
|
222
230
|
},
|
|
223
231
|
): Promise<CompactionV2Response> {
|
|
224
232
|
const endpoint = getCompactionV2Endpoint(model);
|
|
@@ -228,12 +236,32 @@ export async function requestCompactionV2Streaming(
|
|
|
228
236
|
|
|
229
237
|
const fetchImpl = options?.fetch ?? globalThis.fetch;
|
|
230
238
|
const retryWait = options?.retryWait ?? ((delayMs: number) => Bun.sleep(delayMs));
|
|
239
|
+
const isCodexResponses = compactionV2Api(model) === "openai-codex-responses" || model.provider === "openai-codex";
|
|
240
|
+
const codexMetadata = isCodexResponses
|
|
241
|
+
? createOpenAICodexCompatibilityMetadata({
|
|
242
|
+
sessionId: request.sessionId,
|
|
243
|
+
providerSessionState: options?.providerSessionState,
|
|
244
|
+
requestKind: "compaction",
|
|
245
|
+
compaction: createOpenAICodexCompactionRequestContext({
|
|
246
|
+
context: options?.codexCompaction,
|
|
247
|
+
implementation: "responses_compaction_v2",
|
|
248
|
+
}),
|
|
249
|
+
})
|
|
250
|
+
: undefined;
|
|
231
251
|
let lastError: Error | undefined;
|
|
232
252
|
|
|
233
253
|
for (let attempt = 0; attempt <= V2_COMPACTION_MAX_RETRIES; attempt++) {
|
|
234
254
|
const timeoutSignal = withRequestTimeout(signal, options?.timeoutMs ?? V2_COMPACTION_TIMEOUT_MS);
|
|
235
255
|
try {
|
|
236
|
-
return await attemptCompactionV2Streaming(
|
|
256
|
+
return await attemptCompactionV2Streaming(
|
|
257
|
+
endpoint,
|
|
258
|
+
apiKey,
|
|
259
|
+
model,
|
|
260
|
+
request,
|
|
261
|
+
fetchImpl,
|
|
262
|
+
timeoutSignal,
|
|
263
|
+
codexMetadata,
|
|
264
|
+
);
|
|
237
265
|
} catch (err) {
|
|
238
266
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
239
267
|
if (signal?.aborted) throw error;
|
|
@@ -264,6 +292,7 @@ async function attemptCompactionV2Streaming(
|
|
|
264
292
|
request: CompactionV2Request,
|
|
265
293
|
fetchImpl: FetchImpl,
|
|
266
294
|
signal?: AbortSignal,
|
|
295
|
+
codexMetadata?: OpenAICodexCompatibilityMetadata,
|
|
267
296
|
): Promise<CompactionV2Response> {
|
|
268
297
|
// Faithful to Codex: append the compaction trigger as the final input item
|
|
269
298
|
// of an otherwise-normal Responses request, then stream the result. `store`
|
|
@@ -276,13 +305,30 @@ async function attemptCompactionV2Streaming(
|
|
|
276
305
|
instructions: request.instructions,
|
|
277
306
|
stream: true,
|
|
278
307
|
store: false,
|
|
279
|
-
...(request.reasoning
|
|
308
|
+
...(request.reasoning || model.useResponsesLite
|
|
309
|
+
? {
|
|
310
|
+
// Lite implies gpt-5.4+, where codex-rs sends `all_turns` replay.
|
|
311
|
+
reasoning: model.useResponsesLite
|
|
312
|
+
? { ...(request.reasoning ?? {}), context: "all_turns" }
|
|
313
|
+
: request.reasoning,
|
|
314
|
+
include: ["reasoning.encrypted_content"],
|
|
315
|
+
}
|
|
316
|
+
: {}),
|
|
280
317
|
...(promptCacheKey ? { prompt_cache_key: promptCacheKey } : {}),
|
|
281
318
|
...(request.tools && request.tools.length > 0 ? { tools: request.tools, tool_choice: "auto" } : {}),
|
|
282
319
|
};
|
|
320
|
+
if (codexMetadata) {
|
|
321
|
+
body.client_metadata = codexMetadata.clientMetadata;
|
|
322
|
+
}
|
|
323
|
+
// Responses Lite models take the same rewrite on the compaction stream:
|
|
324
|
+
// instructions/tools ride as input items (codex-rs `compact_remote_v2`
|
|
325
|
+
// builds through `build_responses_request`).
|
|
326
|
+
if (model.useResponsesLite) {
|
|
327
|
+
applyCodexResponsesLiteShape(body);
|
|
328
|
+
}
|
|
283
329
|
const response = await fetchImpl(endpoint, {
|
|
284
330
|
method: "POST",
|
|
285
|
-
headers: buildCompactionV2Headers(model, apiKey, request),
|
|
331
|
+
headers: buildCompactionV2Headers(model, apiKey, request, codexMetadata),
|
|
286
332
|
body: JSON.stringify(body),
|
|
287
333
|
signal,
|
|
288
334
|
});
|
|
@@ -307,7 +353,12 @@ async function attemptCompactionV2Streaming(
|
|
|
307
353
|
return collectCompactionV2Output(response, request);
|
|
308
354
|
}
|
|
309
355
|
|
|
310
|
-
function buildCompactionV2Headers(
|
|
356
|
+
function buildCompactionV2Headers(
|
|
357
|
+
model: Model,
|
|
358
|
+
apiKey: string,
|
|
359
|
+
request: CompactionV2Request,
|
|
360
|
+
codexMetadata?: OpenAICodexCompatibilityMetadata,
|
|
361
|
+
): Record<string, string> {
|
|
311
362
|
const api = compactionV2Api(model);
|
|
312
363
|
const cacheOptions = { sessionId: request.sessionId, promptCacheKey: request.promptCacheKey };
|
|
313
364
|
const routingSessionId = getOpenAIResponsesRoutingSessionId(cacheOptions);
|
|
@@ -338,7 +389,11 @@ function buildCompactionV2Headers(model: Model, apiKey: string, request: Compact
|
|
|
338
389
|
}
|
|
339
390
|
headers[OPENAI_HEADERS.BETA] = OPENAI_HEADER_VALUES.BETA_RESPONSES;
|
|
340
391
|
headers[OPENAI_HEADERS.ORIGINATOR] = OPENAI_HEADER_VALUES.ORIGINATOR_CODEX;
|
|
392
|
+
if (model.useResponsesLite) {
|
|
393
|
+
headers[OPENAI_HEADERS.RESPONSES_LITE] = "true";
|
|
394
|
+
}
|
|
341
395
|
}
|
|
396
|
+
if (codexMetadata) Object.assign(headers, codexMetadata.headers);
|
|
342
397
|
|
|
343
398
|
return headers;
|
|
344
399
|
}
|
|
@@ -9,18 +9,21 @@ import {
|
|
|
9
9
|
type Api,
|
|
10
10
|
type ApiKey,
|
|
11
11
|
type AssistantMessage,
|
|
12
|
+
type CodexCompactionContext,
|
|
12
13
|
type Context,
|
|
13
14
|
Effort,
|
|
14
15
|
type FetchImpl,
|
|
15
16
|
type Message,
|
|
16
17
|
type MessageAttribution,
|
|
17
18
|
type Model,
|
|
19
|
+
type ProviderSessionState,
|
|
18
20
|
type SimpleStreamOptions,
|
|
19
21
|
type Tool,
|
|
20
22
|
type Usage,
|
|
21
23
|
withAuth,
|
|
22
24
|
} from "@oh-my-pi/pi-ai";
|
|
23
25
|
import { ProviderHttpError } from "@oh-my-pi/pi-ai/error";
|
|
26
|
+
import { createOpenAICodexCompactionRequestContext } from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
24
27
|
import { convertTools } from "@oh-my-pi/pi-ai/providers/openai-responses";
|
|
25
28
|
import { buildResponsesInput, resolveOpenAICompatPolicy } from "@oh-my-pi/pi-ai/providers/openai-shared";
|
|
26
29
|
import { preferredDialect } from "@oh-my-pi/pi-catalog/identity";
|
|
@@ -656,6 +659,8 @@ function effortFromThinkingLevel(level: ThinkingLevel): Effort {
|
|
|
656
659
|
return Effort.High;
|
|
657
660
|
case ThinkingLevel.XHigh:
|
|
658
661
|
return Effort.XHigh;
|
|
662
|
+
case ThinkingLevel.Max:
|
|
663
|
+
return Effort.Max;
|
|
659
664
|
case ThinkingLevel.Off:
|
|
660
665
|
case ThinkingLevel.Inherit:
|
|
661
666
|
throw new Error(`effortFromThinkingLevel: ${level} must be handled by caller`);
|
|
@@ -736,6 +741,10 @@ export interface SummaryOptions {
|
|
|
736
741
|
sessionId?: string;
|
|
737
742
|
/** Prompt-cache key for remote compaction transports that support provider prefix caching. */
|
|
738
743
|
promptCacheKey?: string;
|
|
744
|
+
/** Mutable provider state used to keep Codex compaction on the live session identity. */
|
|
745
|
+
providerSessionState?: Map<string, ProviderSessionState>;
|
|
746
|
+
/** Classification shared by every provider request in this logical compaction. */
|
|
747
|
+
codexCompaction?: CodexCompactionContext;
|
|
739
748
|
/** Provider-visible tools for remote compaction transports that replay native tool history. */
|
|
740
749
|
tools?: Tool[];
|
|
741
750
|
/** Optional fetch implementation threaded into remote compaction calls. */
|
|
@@ -755,6 +764,13 @@ export interface SummaryOptions {
|
|
|
755
764
|
) => Promise<AssistantMessage>;
|
|
756
765
|
}
|
|
757
766
|
|
|
767
|
+
function localCodexCompaction(options: SummaryOptions | undefined) {
|
|
768
|
+
return createOpenAICodexCompactionRequestContext({
|
|
769
|
+
context: options?.codexCompaction,
|
|
770
|
+
implementation: "responses",
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
|
|
758
774
|
function formatPreviousSnapcompactArchive(archiveText: string): string {
|
|
759
775
|
return prompt.render(snapcompactArchiveContextPrompt, { archiveText });
|
|
760
776
|
}
|
|
@@ -844,6 +860,11 @@ export async function generateSummary(
|
|
|
844
860
|
reasoning: resolveCompactionEffort(model, options?.thinkingLevel),
|
|
845
861
|
initiatorOverride: options?.initiatorOverride,
|
|
846
862
|
metadata: options?.metadata,
|
|
863
|
+
fetch: options?.fetch,
|
|
864
|
+
sessionId: options?.sessionId,
|
|
865
|
+
promptCacheKey: options?.promptCacheKey,
|
|
866
|
+
providerSessionState: options?.providerSessionState,
|
|
867
|
+
codexCompaction: localCodexCompaction(options),
|
|
847
868
|
},
|
|
848
869
|
{ telemetry: options?.telemetry, oneshotKind: "compaction_summary", completeImpl: options?.completeImpl },
|
|
849
870
|
);
|
|
@@ -1047,6 +1068,11 @@ async function generateShortSummary(
|
|
|
1047
1068
|
reasoning: resolveCompactionEffort(model, options?.thinkingLevel),
|
|
1048
1069
|
initiatorOverride: options?.initiatorOverride,
|
|
1049
1070
|
metadata: options?.metadata,
|
|
1071
|
+
fetch: options?.fetch,
|
|
1072
|
+
sessionId: options?.sessionId,
|
|
1073
|
+
promptCacheKey: options?.promptCacheKey,
|
|
1074
|
+
providerSessionState: options?.providerSessionState,
|
|
1075
|
+
codexCompaction: localCodexCompaction(options),
|
|
1050
1076
|
},
|
|
1051
1077
|
{ telemetry: options?.telemetry, oneshotKind: "compaction_short_summary", completeImpl: options?.completeImpl },
|
|
1052
1078
|
);
|
|
@@ -1317,6 +1343,8 @@ export async function compact(
|
|
|
1317
1343
|
thinkingLevel: options?.thinkingLevel,
|
|
1318
1344
|
sessionId: options?.sessionId,
|
|
1319
1345
|
promptCacheKey: options?.promptCacheKey,
|
|
1346
|
+
providerSessionState: options?.providerSessionState,
|
|
1347
|
+
codexCompaction: options?.codexCompaction,
|
|
1320
1348
|
tools: options?.tools,
|
|
1321
1349
|
fetch: options?.fetch,
|
|
1322
1350
|
completeImpl: options?.completeImpl,
|
|
@@ -1375,7 +1403,12 @@ export async function compact(
|
|
|
1375
1403
|
);
|
|
1376
1404
|
const remote = await withAuth(
|
|
1377
1405
|
apiKey,
|
|
1378
|
-
key =>
|
|
1406
|
+
key =>
|
|
1407
|
+
requestCompactionV2Streaming(model, key, request, signal, {
|
|
1408
|
+
fetch: summaryOptions.fetch,
|
|
1409
|
+
providerSessionState: summaryOptions.providerSessionState,
|
|
1410
|
+
codexCompaction: summaryOptions.codexCompaction,
|
|
1411
|
+
}),
|
|
1379
1412
|
{ signal },
|
|
1380
1413
|
);
|
|
1381
1414
|
preserveData = { ...(preserveData ?? {}), ...storeCompactionV2PreserveData(remote, model) };
|
|
@@ -1419,7 +1452,12 @@ export async function compact(
|
|
|
1419
1452
|
remoteHistory,
|
|
1420
1453
|
summaryOptions.remoteInstructions ?? SUMMARIZATION_SYSTEM_PROMPT,
|
|
1421
1454
|
signal,
|
|
1422
|
-
{
|
|
1455
|
+
{
|
|
1456
|
+
fetch: summaryOptions.fetch,
|
|
1457
|
+
sessionId: summaryOptions.sessionId,
|
|
1458
|
+
providerSessionState: summaryOptions.providerSessionState,
|
|
1459
|
+
codexCompaction: summaryOptions.codexCompaction,
|
|
1460
|
+
},
|
|
1423
1461
|
),
|
|
1424
1462
|
{ signal },
|
|
1425
1463
|
);
|
|
@@ -1495,16 +1533,9 @@ export async function compact(
|
|
|
1495
1533
|
const shortSummary = usedRemoteCompaction
|
|
1496
1534
|
? "Remote compaction"
|
|
1497
1535
|
: await generateShortSummary(recentMessages, summary, model, reserveTokens, apiKey, signal, {
|
|
1536
|
+
...summaryOptions,
|
|
1498
1537
|
extraContext: options?.extraContext,
|
|
1499
|
-
remoteEndpoint: summaryOptions.remoteEndpoint,
|
|
1500
|
-
initiatorOverride: summaryOptions.initiatorOverride,
|
|
1501
|
-
metadata: summaryOptions.metadata,
|
|
1502
|
-
telemetry: summaryOptions.telemetry,
|
|
1503
|
-
// Same propagation as summaryOptions above — generateShortSummary
|
|
1504
|
-
// resolves its own reasoning via resolveCompactionEffort.
|
|
1505
1538
|
thinkingLevel: options?.thinkingLevel,
|
|
1506
|
-
fetch: summaryOptions.fetch,
|
|
1507
|
-
completeImpl: summaryOptions.completeImpl,
|
|
1508
1539
|
});
|
|
1509
1540
|
|
|
1510
1541
|
// Compute file lists and append to summary
|
|
@@ -1567,6 +1598,11 @@ async function generateTurnPrefixSummary(
|
|
|
1567
1598
|
reasoning: resolveCompactionEffort(model, options?.thinkingLevel),
|
|
1568
1599
|
initiatorOverride: options?.initiatorOverride,
|
|
1569
1600
|
metadata: options?.metadata,
|
|
1601
|
+
fetch: options?.fetch,
|
|
1602
|
+
sessionId: options?.sessionId,
|
|
1603
|
+
promptCacheKey: options?.promptCacheKey,
|
|
1604
|
+
providerSessionState: options?.providerSessionState,
|
|
1605
|
+
codexCompaction: localCodexCompaction(options),
|
|
1570
1606
|
},
|
|
1571
1607
|
{ telemetry: options?.telemetry, oneshotKind: "compaction_turn_prefix", completeImpl: options?.completeImpl },
|
|
1572
1608
|
);
|
package/src/compaction/openai.ts
CHANGED
|
@@ -16,9 +16,22 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { ProviderHttpError } from "@oh-my-pi/pi-ai/error";
|
|
19
|
+
import { applyCodexResponsesLiteShape } from "@oh-my-pi/pi-ai/providers/openai-codex/request-transformer";
|
|
20
|
+
import {
|
|
21
|
+
createOpenAICodexCompactionRequestContext,
|
|
22
|
+
createOpenAICodexCompatibilityMetadata,
|
|
23
|
+
} from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
19
24
|
import { parseAzureDeploymentNameMap, parseTextSignature } from "@oh-my-pi/pi-ai/providers/openai-shared";
|
|
20
25
|
import { transformMessages } from "@oh-my-pi/pi-ai/providers/transform-messages";
|
|
21
|
-
import type {
|
|
26
|
+
import type {
|
|
27
|
+
Api,
|
|
28
|
+
AssistantMessage,
|
|
29
|
+
CodexCompactionContext,
|
|
30
|
+
FetchImpl,
|
|
31
|
+
Message,
|
|
32
|
+
Model,
|
|
33
|
+
ProviderSessionState,
|
|
34
|
+
} from "@oh-my-pi/pi-ai/types";
|
|
22
35
|
import {
|
|
23
36
|
getOpenAIResponsesHistoryItems,
|
|
24
37
|
getOpenAIResponsesHistoryPayload,
|
|
@@ -75,6 +88,11 @@ export interface OpenAiRemoteCompactionRequest {
|
|
|
75
88
|
model: string;
|
|
76
89
|
input: Array<Record<string, unknown>>;
|
|
77
90
|
instructions: string;
|
|
91
|
+
reasoning?: {
|
|
92
|
+
context?: string;
|
|
93
|
+
[key: string]: unknown;
|
|
94
|
+
};
|
|
95
|
+
include?: string[];
|
|
78
96
|
}
|
|
79
97
|
|
|
80
98
|
export interface OpenAiRemoteCompactionResponse extends OpenAiRemoteCompactionPreserveData {}
|
|
@@ -460,7 +478,13 @@ export async function requestOpenAiRemoteCompaction(
|
|
|
460
478
|
compactInput: Array<Record<string, unknown>>,
|
|
461
479
|
instructions: string,
|
|
462
480
|
signal?: AbortSignal,
|
|
463
|
-
opts?: {
|
|
481
|
+
opts?: {
|
|
482
|
+
fetch?: FetchImpl;
|
|
483
|
+
timeoutMs?: number;
|
|
484
|
+
sessionId?: string;
|
|
485
|
+
providerSessionState?: Map<string, ProviderSessionState>;
|
|
486
|
+
codexCompaction?: CodexCompactionContext;
|
|
487
|
+
},
|
|
464
488
|
): Promise<OpenAiRemoteCompactionResponse> {
|
|
465
489
|
const endpoint = resolveOpenAiCompactEndpoint(model);
|
|
466
490
|
const requestModel = resolveOpenAiCompactModel(model);
|
|
@@ -473,6 +497,8 @@ export async function requestOpenAiRemoteCompaction(
|
|
|
473
497
|
instructions,
|
|
474
498
|
};
|
|
475
499
|
const isAzureOpenAiResponses = (model.remoteCompaction?.api ?? model.api) === "azure-openai-responses";
|
|
500
|
+
const isCodexResponses =
|
|
501
|
+
model.provider === "openai-codex" || (model.remoteCompaction?.api ?? model.api) === "openai-codex-responses";
|
|
476
502
|
const headers: Record<string, string> = isAzureOpenAiResponses
|
|
477
503
|
? {
|
|
478
504
|
"content-type": "application/json",
|
|
@@ -486,13 +512,38 @@ export async function requestOpenAiRemoteCompaction(
|
|
|
486
512
|
};
|
|
487
513
|
|
|
488
514
|
// Codex endpoints require additional auth headers
|
|
489
|
-
if (
|
|
515
|
+
if (isCodexResponses) {
|
|
490
516
|
const accountId = getCodexAccountId(apiKey);
|
|
491
517
|
if (accountId) {
|
|
492
518
|
headers[OPENAI_HEADERS.ACCOUNT_ID] = accountId;
|
|
493
519
|
}
|
|
494
520
|
headers[OPENAI_HEADERS.BETA] = OPENAI_HEADER_VALUES.BETA_RESPONSES;
|
|
495
521
|
headers[OPENAI_HEADERS.ORIGINATOR] = OPENAI_HEADER_VALUES.ORIGINATOR_CODEX;
|
|
522
|
+
Object.assign(
|
|
523
|
+
headers,
|
|
524
|
+
createOpenAICodexCompatibilityMetadata({
|
|
525
|
+
sessionId: opts?.sessionId,
|
|
526
|
+
providerSessionState: opts?.providerSessionState,
|
|
527
|
+
requestKind: "compaction",
|
|
528
|
+
compaction: createOpenAICodexCompactionRequestContext({
|
|
529
|
+
context: opts?.codexCompaction,
|
|
530
|
+
implementation: "responses_compact",
|
|
531
|
+
}),
|
|
532
|
+
includeInstallationHeader: true,
|
|
533
|
+
}).headers,
|
|
534
|
+
);
|
|
535
|
+
// Responses Lite models take the same rewrite on `/responses/compact`:
|
|
536
|
+
// instructions ride as an input item and the lite marker header is set
|
|
537
|
+
// (codex-rs routes compaction through `build_responses_request`).
|
|
538
|
+
if (model.useResponsesLite) {
|
|
539
|
+
applyCodexResponsesLiteShape(request);
|
|
540
|
+
headers[OPENAI_HEADERS.RESPONSES_LITE] = "true";
|
|
541
|
+
request.reasoning = {
|
|
542
|
+
...request.reasoning,
|
|
543
|
+
context: "all_turns",
|
|
544
|
+
};
|
|
545
|
+
request.include = Array.from(new Set([...(request.include ?? []), "reasoning.encrypted_content"]));
|
|
546
|
+
}
|
|
496
547
|
}
|
|
497
548
|
|
|
498
549
|
const response = await (opts?.fetch ?? fetch)(endpoint, {
|