@oh-my-pi/pi-ai 16.3.13 → 16.3.14
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,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [16.3.14] - 2026-07-09
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Updated Codex reasoning effort mapping to support shifted wire tiers for newer models
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Fixed the Codex Responses request transformer bypassing catalog/compat reasoning effort maps: the clamped user effort is now remapped to the provider wire tier (GPT-5.6's shifted five-tier scale sends `max` for user `xhigh` and `xhigh` for `high`), failing loudly if a map produces a value outside the Codex wire vocabulary.
|
|
14
|
+
|
|
5
15
|
## [16.3.13] - 2026-07-09
|
|
6
16
|
|
|
7
17
|
### Changed
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Model } from "../../types.js";
|
|
2
2
|
/** Reasoning replay scope for the Codex Responses API (`reasoning.context`). */
|
|
3
3
|
export type CodexReasoningContext = "auto" | "current_turn" | "all_turns";
|
|
4
|
+
/** User-facing effort levels accepted by Codex request options. */
|
|
5
|
+
type CodexCallerEffort = "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
4
6
|
export interface ReasoningConfig {
|
|
5
|
-
effort: "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
7
|
+
effort: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
6
8
|
summary?: "auto" | "concise" | "detailed";
|
|
7
9
|
context?: CodexReasoningContext;
|
|
8
10
|
}
|
|
9
11
|
export interface CodexRequestOptions {
|
|
10
|
-
|
|
12
|
+
/** User-facing effort; the wire-only `max` tier is reached via the model's effort map. */
|
|
13
|
+
reasoningEffort?: CodexCallerEffort | "none";
|
|
11
14
|
reasoningSummary?: ReasoningConfig["summary"] | null;
|
|
12
15
|
/** Explicit `reasoning.context` override; defaults to `all_turns` when unset. The `all_turns` value is gated to gpt-5.4+ Codex models — older ids reject it, so it is suppressed and `context` omitted. */
|
|
13
16
|
reasoningContext?: CodexReasoningContext;
|
|
@@ -49,6 +52,7 @@ export interface RequestBody {
|
|
|
49
52
|
}
|
|
50
53
|
/** Returns whether a Codex request can use the text-only Responses Lite transport. */
|
|
51
54
|
export declare function shouldUseCodexResponsesLite(body: RequestBody, requested: boolean | undefined): boolean;
|
|
52
|
-
export declare function transformRequestBody(body: RequestBody, model: Model<
|
|
55
|
+
export declare function transformRequestBody(body: RequestBody, model: Model<"openai-codex-responses">, options?: CodexRequestOptions, prompt?: {
|
|
53
56
|
developerMessages: string[];
|
|
54
57
|
}): Promise<RequestBody>;
|
|
58
|
+
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Effort } from "@oh-my-pi/pi-catalog/effort";
|
|
1
2
|
import type { OpenAICompat, OpenAIReasoningDisableMode, OpenAIStreamMarkupHealingPattern, OpenRouterRouting, ResolvedOpenAICompat, ResolvedOpenAIResponsesCompat, ResolvedOpenAISharedCompat, VercelGatewayRouting } from "@oh-my-pi/pi-catalog/types";
|
|
2
3
|
import { type Api, type AssistantMessage, type CacheRetention, type Context, type ImageContent, type Message, type MessageAttribution, type Model, type ServiceTier, type StopReason, type StreamOptions, type TextContent, type TextSignatureV1, type ThinkingContent, type Tool, type ToolCall, type ToolResultMessage, type Usage } from "../types.js";
|
|
3
4
|
import { kStreamingLastParseLen, kStreamingPartialJson } from "../utils/block-symbols.js";
|
|
@@ -275,6 +276,15 @@ export interface OpenAICompatPolicy {
|
|
|
275
276
|
emptyLengthFinishIsContextError: boolean;
|
|
276
277
|
};
|
|
277
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* Map a user-facing effort to the provider wire value: explicit compat
|
|
281
|
+
* override first, then the model's baked `thinking.effortMap`, else identity.
|
|
282
|
+
* Shared by the chat-completions/Responses policy resolver and the Codex
|
|
283
|
+
* request transformer.
|
|
284
|
+
*/
|
|
285
|
+
export declare function mapOpenAIReasoningEffort(model: Pick<Model, "thinking">, compat: {
|
|
286
|
+
reasoningEffortMap?: Partial<Record<Effort, string>>;
|
|
287
|
+
} | undefined, effort: string): string;
|
|
278
288
|
export declare function resolveOpenAICompatPolicy<TApi extends Api>(model: Model<TApi>, options: ResolveOpenAICompatPolicyOptions): OpenAICompatPolicy;
|
|
279
289
|
export declare function applyChatCompletionsCompatPolicy(params: OpenAICompletionsParams, policy: OpenAICompatPolicy): void;
|
|
280
290
|
export declare function applyChatCompletionsReasoningParams(params: OpenAICompletionsParams, model: Model<"openai-completions">, compat: ResolvedOpenAICompat, options: (ChatCompletionsReasoningOptions & {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-ai",
|
|
4
|
-
"version": "16.3.
|
|
4
|
+
"version": "16.3.14",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@bufbuild/protobuf": "^2.12.0",
|
|
41
|
-
"@oh-my-pi/pi-catalog": "16.3.
|
|
42
|
-
"@oh-my-pi/pi-utils": "16.3.
|
|
43
|
-
"@oh-my-pi/pi-wire": "16.3.
|
|
41
|
+
"@oh-my-pi/pi-catalog": "16.3.14",
|
|
42
|
+
"@oh-my-pi/pi-utils": "16.3.14",
|
|
43
|
+
"@oh-my-pi/pi-wire": "16.3.14",
|
|
44
44
|
"arktype": "^2.2.0",
|
|
45
45
|
"zod": "^4"
|
|
46
46
|
},
|
|
@@ -1,19 +1,33 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Effort } from "@oh-my-pi/pi-catalog/effort";
|
|
2
2
|
import { supportsAllTurnsReasoningContext, supportsCodexReasoningSummary } from "@oh-my-pi/pi-catalog/identity";
|
|
3
3
|
import { requireSupportedEffort } from "@oh-my-pi/pi-catalog/model-thinking";
|
|
4
|
-
import type {
|
|
4
|
+
import type { Model } from "../../types";
|
|
5
|
+
import { mapOpenAIReasoningEffort } from "../openai-shared";
|
|
5
6
|
|
|
6
7
|
/** Reasoning replay scope for the Codex Responses API (`reasoning.context`). */
|
|
7
8
|
export type CodexReasoningContext = "auto" | "current_turn" | "all_turns";
|
|
8
9
|
|
|
10
|
+
/** User-facing effort levels accepted by Codex request options. */
|
|
11
|
+
type CodexCallerEffort = "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
12
|
+
|
|
13
|
+
/** Caller literal → catalog `Effort` bridge (the enum is nominal). */
|
|
14
|
+
const EFFORT_BY_NAME: Record<CodexCallerEffort, Effort> = {
|
|
15
|
+
minimal: Effort.Minimal,
|
|
16
|
+
low: Effort.Low,
|
|
17
|
+
medium: Effort.Medium,
|
|
18
|
+
high: Effort.High,
|
|
19
|
+
xhigh: Effort.XHigh,
|
|
20
|
+
};
|
|
21
|
+
|
|
9
22
|
export interface ReasoningConfig {
|
|
10
|
-
effort: "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
23
|
+
effort: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
11
24
|
summary?: "auto" | "concise" | "detailed";
|
|
12
25
|
context?: CodexReasoningContext;
|
|
13
26
|
}
|
|
14
27
|
|
|
15
28
|
export interface CodexRequestOptions {
|
|
16
|
-
|
|
29
|
+
/** User-facing effort; the wire-only `max` tier is reached via the model's effort map. */
|
|
30
|
+
reasoningEffort?: CodexCallerEffort | "none";
|
|
17
31
|
reasoningSummary?: ReasoningConfig["summary"] | null;
|
|
18
32
|
/** Explicit `reasoning.context` override; defaults to `all_turns` when unset. The `all_turns` value is gated to gpt-5.4+ Codex models — older ids reject it, so it is suppressed and `context` omitted. */
|
|
19
33
|
reasoningContext?: CodexReasoningContext;
|
|
@@ -80,10 +94,40 @@ export function shouldUseCodexResponsesLite(body: RequestBody, requested: boolea
|
|
|
80
94
|
return requested === true && !containsInputImage(body.input);
|
|
81
95
|
}
|
|
82
96
|
|
|
83
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Clamp a user-facing effort to the model's ladder, then remap to the wire
|
|
99
|
+
* tier (e.g. GPT-5.6's shifted five-tier scale sends `max` for user `xhigh`).
|
|
100
|
+
* A mapped value outside the Codex wire vocabulary is a broken compat/model
|
|
101
|
+
* effort map — fail loudly rather than silently sending a different tier.
|
|
102
|
+
*/
|
|
103
|
+
function mapCodexWireEffort(
|
|
104
|
+
model: Model<"openai-codex-responses">,
|
|
105
|
+
effort: CodexCallerEffort,
|
|
106
|
+
): ReasoningConfig["effort"] {
|
|
107
|
+
const mapped = mapOpenAIReasoningEffort(model, model.compat, requireSupportedEffort(model, EFFORT_BY_NAME[effort]));
|
|
108
|
+
switch (mapped) {
|
|
109
|
+
case "none":
|
|
110
|
+
case "minimal":
|
|
111
|
+
case "low":
|
|
112
|
+
case "medium":
|
|
113
|
+
case "high":
|
|
114
|
+
case "xhigh":
|
|
115
|
+
case "max":
|
|
116
|
+
return mapped;
|
|
117
|
+
default:
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Effort map for ${model.provider}/${model.id} produced invalid Codex reasoning effort "${mapped}"`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function getReasoningConfig(
|
|
125
|
+
model: Model<"openai-codex-responses">,
|
|
126
|
+
effort: NonNullable<CodexRequestOptions["reasoningEffort"]>,
|
|
127
|
+
options: CodexRequestOptions,
|
|
128
|
+
): ReasoningConfig {
|
|
84
129
|
const config: ReasoningConfig = {
|
|
85
|
-
effort:
|
|
86
|
-
options.reasoningEffort === "none" ? "none" : requireSupportedEffort(model, options.reasoningEffort as Effort),
|
|
130
|
+
effort: effort === "none" ? "none" : mapCodexWireEffort(model, effort),
|
|
87
131
|
};
|
|
88
132
|
// `reasoning.summary` is accepted only from gpt-5.4 onward; earlier Codex ids
|
|
89
133
|
// (gpt-5.1-codex, gpt-5.3-codex, gpt-5.3-codex-spark) reject it with
|
|
@@ -216,7 +260,7 @@ function stripImageDetails(input: InputItem[]): void {
|
|
|
216
260
|
|
|
217
261
|
export async function transformRequestBody(
|
|
218
262
|
body: RequestBody,
|
|
219
|
-
model: Model<
|
|
263
|
+
model: Model<"openai-codex-responses">,
|
|
220
264
|
options: CodexRequestOptions = {},
|
|
221
265
|
prompt?: { developerMessages: string[] },
|
|
222
266
|
): Promise<RequestBody> {
|
|
@@ -300,7 +344,7 @@ export async function transformRequestBody(
|
|
|
300
344
|
}
|
|
301
345
|
|
|
302
346
|
if (options.reasoningEffort !== undefined) {
|
|
303
|
-
const reasoningConfig = getReasoningConfig(model, options);
|
|
347
|
+
const reasoningConfig = getReasoningConfig(model, options.reasoningEffort, options);
|
|
304
348
|
body.reasoning = {
|
|
305
349
|
...body.reasoning,
|
|
306
350
|
...reasoningConfig,
|
|
@@ -695,13 +695,19 @@ export interface OpenAICompatPolicy {
|
|
|
695
695
|
};
|
|
696
696
|
}
|
|
697
697
|
|
|
698
|
-
|
|
698
|
+
/**
|
|
699
|
+
* Map a user-facing effort to the provider wire value: explicit compat
|
|
700
|
+
* override first, then the model's baked `thinking.effortMap`, else identity.
|
|
701
|
+
* Shared by the chat-completions/Responses policy resolver and the Codex
|
|
702
|
+
* request transformer.
|
|
703
|
+
*/
|
|
704
|
+
export function mapOpenAIReasoningEffort(
|
|
699
705
|
model: Pick<Model, "thinking">,
|
|
700
|
-
compat:
|
|
706
|
+
compat: { reasoningEffortMap?: Partial<Record<Effort, string>> } | undefined,
|
|
701
707
|
effort: string,
|
|
702
708
|
): string {
|
|
703
709
|
const level = effort as Effort;
|
|
704
|
-
return compat
|
|
710
|
+
return compat?.reasoningEffortMap?.[level] ?? model.thinking?.effortMap?.[level] ?? effort;
|
|
705
711
|
}
|
|
706
712
|
|
|
707
713
|
function isImplicitDisableWhenNotRequested(disableMode: OpenAIReasoningDisableMode): boolean {
|