@oh-my-pi/pi-agent-core 16.3.14 → 16.4.0
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 +11 -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 +4 -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 +61 -8
- package/src/compaction/compaction.ts +46 -10
- package/src/compaction/openai.ts +44 -3
- package/src/thinking.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [16.4.0] - 2026-07-10
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added the `ThinkingLevel.Max` ("max") configuration option, mapping to the `Effort.Max` tier for supported models.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- 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.
|
|
14
|
+
- Fixed an issue where aborted tool-result hooks could trigger subsequent provider calls before the abort signal fully settled.
|
|
15
|
+
|
|
5
16
|
## [16.3.12] - 2026-07-08
|
|
6
17
|
|
|
7
18
|
### 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
|
/**
|
|
@@ -70,6 +70,9 @@ export declare function buildOpenAiNativeHistory(messages: Message[], model: Mod
|
|
|
70
70
|
export declare function requestOpenAiRemoteCompaction(model: Model, apiKey: string, compactInput: Array<Record<string, unknown>>, instructions: string, signal?: AbortSignal, opts?: {
|
|
71
71
|
fetch?: FetchImpl;
|
|
72
72
|
timeoutMs?: number;
|
|
73
|
+
sessionId?: string;
|
|
74
|
+
providerSessionState?: Map<string, ProviderSessionState>;
|
|
75
|
+
codexCompaction?: CodexCompactionContext;
|
|
73
76
|
}): Promise<OpenAiRemoteCompactionResponse>;
|
|
74
77
|
/**
|
|
75
78
|
* 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.0",
|
|
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.0",
|
|
39
|
+
"@oh-my-pi/pi-catalog": "16.4.0",
|
|
40
|
+
"@oh-my-pi/pi-natives": "16.4.0",
|
|
41
|
+
"@oh-my-pi/pi-utils": "16.4.0",
|
|
42
|
+
"@oh-my-pi/pi-wire": "16.4.0",
|
|
43
|
+
"@oh-my-pi/snapcompact": "16.4.0",
|
|
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,10 +7,16 @@
|
|
|
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";
|
|
12
13
|
import {
|
|
13
|
-
|
|
14
|
+
createOpenAICodexCompactionRequestContext,
|
|
15
|
+
createOpenAICodexCompatibilityMetadata,
|
|
16
|
+
type OpenAICodexCompatibilityMetadata,
|
|
17
|
+
} from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
18
|
+
import {
|
|
19
|
+
getOpenAIPromptCacheKey,
|
|
14
20
|
getOpenAIResponsesRoutingSessionId,
|
|
15
21
|
parseAzureDeploymentNameMap,
|
|
16
22
|
resolveOpenAIRequestSetup,
|
|
@@ -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,25 +292,41 @@ 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`
|
|
270
299
|
// stays false — compaction must never persist a server-side response object.
|
|
271
300
|
const cacheOptions = { sessionId: request.sessionId, promptCacheKey: request.promptCacheKey };
|
|
272
|
-
const promptCacheKey =
|
|
301
|
+
const promptCacheKey = getOpenAIPromptCacheKey(cacheOptions);
|
|
273
302
|
const body: Record<string, unknown> = {
|
|
274
303
|
model: request.model,
|
|
275
304
|
input: [...request.input, COMPACTION_TRIGGER_ITEM],
|
|
276
305
|
instructions: request.instructions,
|
|
277
306
|
stream: true,
|
|
278
307
|
store: false,
|
|
279
|
-
...(request.reasoning
|
|
308
|
+
...(request.reasoning
|
|
309
|
+
? {
|
|
310
|
+
// Lite implies gpt-5.4+, where codex-rs sends `all_turns` replay.
|
|
311
|
+
reasoning: model.useResponsesLite ? { ...request.reasoning, context: "all_turns" } : request.reasoning,
|
|
312
|
+
include: ["reasoning.encrypted_content"],
|
|
313
|
+
}
|
|
314
|
+
: {}),
|
|
280
315
|
...(promptCacheKey ? { prompt_cache_key: promptCacheKey } : {}),
|
|
281
316
|
...(request.tools && request.tools.length > 0 ? { tools: request.tools, tool_choice: "auto" } : {}),
|
|
282
317
|
};
|
|
318
|
+
if (codexMetadata) {
|
|
319
|
+
body.client_metadata = codexMetadata.clientMetadata;
|
|
320
|
+
}
|
|
321
|
+
// Responses Lite models take the same rewrite on the compaction stream:
|
|
322
|
+
// instructions/tools ride as input items (codex-rs `compact_remote_v2`
|
|
323
|
+
// builds through `build_responses_request`).
|
|
324
|
+
if (model.useResponsesLite) {
|
|
325
|
+
applyCodexResponsesLiteShape(body);
|
|
326
|
+
}
|
|
283
327
|
const response = await fetchImpl(endpoint, {
|
|
284
328
|
method: "POST",
|
|
285
|
-
headers: buildCompactionV2Headers(model, apiKey, request),
|
|
329
|
+
headers: buildCompactionV2Headers(model, apiKey, request, codexMetadata),
|
|
286
330
|
body: JSON.stringify(body),
|
|
287
331
|
signal,
|
|
288
332
|
});
|
|
@@ -307,11 +351,16 @@ async function attemptCompactionV2Streaming(
|
|
|
307
351
|
return collectCompactionV2Output(response, request);
|
|
308
352
|
}
|
|
309
353
|
|
|
310
|
-
function buildCompactionV2Headers(
|
|
354
|
+
function buildCompactionV2Headers(
|
|
355
|
+
model: Model,
|
|
356
|
+
apiKey: string,
|
|
357
|
+
request: CompactionV2Request,
|
|
358
|
+
codexMetadata?: OpenAICodexCompatibilityMetadata,
|
|
359
|
+
): Record<string, string> {
|
|
311
360
|
const api = compactionV2Api(model);
|
|
312
361
|
const cacheOptions = { sessionId: request.sessionId, promptCacheKey: request.promptCacheKey };
|
|
313
362
|
const routingSessionId = getOpenAIResponsesRoutingSessionId(cacheOptions);
|
|
314
|
-
const promptCacheSessionId =
|
|
363
|
+
const promptCacheSessionId = getOpenAIPromptCacheKey(cacheOptions);
|
|
315
364
|
const headers: Record<string, string> =
|
|
316
365
|
api === "azure-openai-responses"
|
|
317
366
|
? {
|
|
@@ -338,7 +387,11 @@ function buildCompactionV2Headers(model: Model, apiKey: string, request: Compact
|
|
|
338
387
|
}
|
|
339
388
|
headers[OPENAI_HEADERS.BETA] = OPENAI_HEADER_VALUES.BETA_RESPONSES;
|
|
340
389
|
headers[OPENAI_HEADERS.ORIGINATOR] = OPENAI_HEADER_VALUES.ORIGINATOR_CODEX;
|
|
390
|
+
if (model.useResponsesLite) {
|
|
391
|
+
headers[OPENAI_HEADERS.RESPONSES_LITE] = "true";
|
|
392
|
+
}
|
|
341
393
|
}
|
|
394
|
+
if (codexMetadata) Object.assign(headers, codexMetadata.headers);
|
|
342
395
|
|
|
343
396
|
return headers;
|
|
344
397
|
}
|
|
@@ -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,
|
|
@@ -460,7 +473,13 @@ export async function requestOpenAiRemoteCompaction(
|
|
|
460
473
|
compactInput: Array<Record<string, unknown>>,
|
|
461
474
|
instructions: string,
|
|
462
475
|
signal?: AbortSignal,
|
|
463
|
-
opts?: {
|
|
476
|
+
opts?: {
|
|
477
|
+
fetch?: FetchImpl;
|
|
478
|
+
timeoutMs?: number;
|
|
479
|
+
sessionId?: string;
|
|
480
|
+
providerSessionState?: Map<string, ProviderSessionState>;
|
|
481
|
+
codexCompaction?: CodexCompactionContext;
|
|
482
|
+
},
|
|
464
483
|
): Promise<OpenAiRemoteCompactionResponse> {
|
|
465
484
|
const endpoint = resolveOpenAiCompactEndpoint(model);
|
|
466
485
|
const requestModel = resolveOpenAiCompactModel(model);
|
|
@@ -473,6 +492,8 @@ export async function requestOpenAiRemoteCompaction(
|
|
|
473
492
|
instructions,
|
|
474
493
|
};
|
|
475
494
|
const isAzureOpenAiResponses = (model.remoteCompaction?.api ?? model.api) === "azure-openai-responses";
|
|
495
|
+
const isCodexResponses =
|
|
496
|
+
model.provider === "openai-codex" || (model.remoteCompaction?.api ?? model.api) === "openai-codex-responses";
|
|
476
497
|
const headers: Record<string, string> = isAzureOpenAiResponses
|
|
477
498
|
? {
|
|
478
499
|
"content-type": "application/json",
|
|
@@ -486,13 +507,33 @@ export async function requestOpenAiRemoteCompaction(
|
|
|
486
507
|
};
|
|
487
508
|
|
|
488
509
|
// Codex endpoints require additional auth headers
|
|
489
|
-
if (
|
|
510
|
+
if (isCodexResponses) {
|
|
490
511
|
const accountId = getCodexAccountId(apiKey);
|
|
491
512
|
if (accountId) {
|
|
492
513
|
headers[OPENAI_HEADERS.ACCOUNT_ID] = accountId;
|
|
493
514
|
}
|
|
494
515
|
headers[OPENAI_HEADERS.BETA] = OPENAI_HEADER_VALUES.BETA_RESPONSES;
|
|
495
516
|
headers[OPENAI_HEADERS.ORIGINATOR] = OPENAI_HEADER_VALUES.ORIGINATOR_CODEX;
|
|
517
|
+
Object.assign(
|
|
518
|
+
headers,
|
|
519
|
+
createOpenAICodexCompatibilityMetadata({
|
|
520
|
+
sessionId: opts?.sessionId,
|
|
521
|
+
providerSessionState: opts?.providerSessionState,
|
|
522
|
+
requestKind: "compaction",
|
|
523
|
+
compaction: createOpenAICodexCompactionRequestContext({
|
|
524
|
+
context: opts?.codexCompaction,
|
|
525
|
+
implementation: "responses_compact",
|
|
526
|
+
}),
|
|
527
|
+
includeInstallationHeader: true,
|
|
528
|
+
}).headers,
|
|
529
|
+
);
|
|
530
|
+
// Responses Lite models take the same rewrite on `/responses/compact`:
|
|
531
|
+
// instructions ride as an input item and the lite marker header is set
|
|
532
|
+
// (codex-rs routes compaction through `build_responses_request`).
|
|
533
|
+
if (model.useResponsesLite) {
|
|
534
|
+
applyCodexResponsesLiteShape(request);
|
|
535
|
+
headers[OPENAI_HEADERS.RESPONSES_LITE] = "true";
|
|
536
|
+
}
|
|
496
537
|
}
|
|
497
538
|
|
|
498
539
|
const response = await (opts?.fetch ?? fetch)(endpoint, {
|