@oh-my-pi/pi-ai 3.20.0 → 3.34.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/README.md +69 -12
- package/package.json +3 -10
- package/src/cli.ts +89 -89
- package/src/index.ts +2 -2
- package/src/models.generated.ts +871 -151
- package/src/models.ts +11 -17
- package/src/providers/anthropic.ts +92 -28
- package/src/providers/google-gemini-cli.ts +268 -133
- package/src/providers/google-shared.ts +48 -5
- package/src/providers/google-vertex.ts +13 -3
- package/src/providers/google.ts +13 -3
- package/src/providers/openai-codex/index.ts +7 -0
- package/src/providers/openai-codex/prompts/codex.ts +26 -59
- package/src/providers/openai-codex/prompts/pi-codex-bridge.ts +38 -31
- package/src/providers/openai-codex/prompts/system-prompt.ts +26 -0
- package/src/providers/openai-codex/request-transformer.ts +38 -203
- package/src/providers/openai-codex-responses.ts +91 -24
- package/src/providers/openai-completions.ts +33 -26
- package/src/providers/openai-responses.ts +1 -1
- package/src/providers/transorm-messages.ts +4 -3
- package/src/stream.ts +34 -25
- package/src/types.ts +21 -4
- package/src/utils/oauth/github-copilot.ts +38 -3
- package/src/utils/oauth/google-antigravity.ts +146 -55
- package/src/utils/oauth/google-gemini-cli.ts +146 -55
- package/src/utils/oauth/index.ts +5 -5
- package/src/utils/oauth/openai-codex.ts +129 -54
- package/src/utils/overflow.ts +1 -1
- package/src/bun-imports.d.ts +0 -14
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI Codex utilities - exported for use by coding-agent export
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { type CacheMetadata, getCodexInstructions, getModelFamily, type ModelFamily } from "./prompts/codex";
|
|
6
|
+
export { buildCodexPiBridge } from "./prompts/pi-codex-bridge";
|
|
7
|
+
export { buildCodexSystemPrompt, type CodexSystemPrompt } from "./prompts/system-prompt";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
// Bun text embed for fallback instructions
|
|
4
6
|
import FALLBACK_INSTRUCTIONS from "./codex-instructions.md" with { type: "text" };
|
|
5
7
|
|
|
6
8
|
const GITHUB_API_RELEASES = "https://api.github.com/repos/openai/codex/releases/latest";
|
|
@@ -41,17 +43,17 @@ export type CacheMetadata = {
|
|
|
41
43
|
url: string;
|
|
42
44
|
};
|
|
43
45
|
|
|
44
|
-
export function getModelFamily(
|
|
45
|
-
if (
|
|
46
|
+
export function getModelFamily(model: string): ModelFamily {
|
|
47
|
+
if (model.includes("gpt-5.2-codex") || model.includes("gpt 5.2 codex")) {
|
|
46
48
|
return "gpt-5.2-codex";
|
|
47
49
|
}
|
|
48
|
-
if (
|
|
50
|
+
if (model.includes("codex-max")) {
|
|
49
51
|
return "codex-max";
|
|
50
52
|
}
|
|
51
|
-
if (
|
|
53
|
+
if (model.includes("codex") || model.startsWith("codex-")) {
|
|
52
54
|
return "codex";
|
|
53
55
|
}
|
|
54
|
-
if (
|
|
56
|
+
if (model.includes("gpt-5.2")) {
|
|
55
57
|
return "gpt-5.2";
|
|
56
58
|
}
|
|
57
59
|
return "gpt-5.1";
|
|
@@ -93,8 +95,8 @@ async function getLatestReleaseTag(): Promise<string> {
|
|
|
93
95
|
throw new Error("Failed to determine latest release tag from GitHub");
|
|
94
96
|
}
|
|
95
97
|
|
|
96
|
-
export async function getCodexInstructions(
|
|
97
|
-
const modelFamily = getModelFamily(
|
|
98
|
+
export async function getCodexInstructions(model = "gpt-5.1-codex"): Promise<string> {
|
|
99
|
+
const modelFamily = getModelFamily(model);
|
|
98
100
|
const promptFile = PROMPT_FILES[modelFamily];
|
|
99
101
|
const cacheDir = getCacheDir();
|
|
100
102
|
const cacheFile = join(cacheDir, CACHE_FILES[modelFamily]);
|
|
@@ -106,15 +108,15 @@ export async function getCodexInstructions(normalizedModel = "gpt-5.1-codex"): P
|
|
|
106
108
|
let cachedTimestamp: number | null = null;
|
|
107
109
|
|
|
108
110
|
if (existsSync(cacheMetaFile)) {
|
|
109
|
-
const metadata = JSON.parse(readFileSync(cacheMetaFile, "
|
|
111
|
+
const metadata = JSON.parse(readFileSync(cacheMetaFile, "utf8")) as CacheMetadata;
|
|
110
112
|
cachedETag = metadata.etag;
|
|
111
113
|
cachedTag = metadata.tag;
|
|
112
114
|
cachedTimestamp = metadata.lastChecked;
|
|
113
115
|
}
|
|
114
116
|
|
|
115
|
-
const CACHE_TTL_MS =
|
|
117
|
+
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
116
118
|
if (cachedTimestamp && Date.now() - cachedTimestamp < CACHE_TTL_MS && existsSync(cacheFile)) {
|
|
117
|
-
return readFileSync(cacheFile, "
|
|
119
|
+
return readFileSync(cacheFile, "utf8");
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
const latestTag = await getLatestReleaseTag();
|
|
@@ -133,7 +135,7 @@ export async function getCodexInstructions(normalizedModel = "gpt-5.1-codex"): P
|
|
|
133
135
|
|
|
134
136
|
if (response.status === 304) {
|
|
135
137
|
if (existsSync(cacheFile)) {
|
|
136
|
-
return readFileSync(cacheFile, "
|
|
138
|
+
return readFileSync(cacheFile, "utf8");
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
|
|
@@ -141,8 +143,11 @@ export async function getCodexInstructions(normalizedModel = "gpt-5.1-codex"): P
|
|
|
141
143
|
const instructions = await response.text();
|
|
142
144
|
const newETag = response.headers.get("etag");
|
|
143
145
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
if (!existsSync(cacheDir)) {
|
|
147
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
writeFileSync(cacheFile, instructions, "utf8");
|
|
146
151
|
writeFileSync(
|
|
147
152
|
cacheMetaFile,
|
|
148
153
|
JSON.stringify({
|
|
@@ -151,7 +156,7 @@ export async function getCodexInstructions(normalizedModel = "gpt-5.1-codex"): P
|
|
|
151
156
|
lastChecked: Date.now(),
|
|
152
157
|
url: instructionsUrl,
|
|
153
158
|
} satisfies CacheMetadata),
|
|
154
|
-
"
|
|
159
|
+
"utf8",
|
|
155
160
|
);
|
|
156
161
|
|
|
157
162
|
return instructions;
|
|
@@ -166,52 +171,14 @@ export async function getCodexInstructions(normalizedModel = "gpt-5.1-codex"): P
|
|
|
166
171
|
|
|
167
172
|
if (existsSync(cacheFile)) {
|
|
168
173
|
console.error(`[openai-codex] Using cached ${modelFamily} instructions`);
|
|
169
|
-
return readFileSync(cacheFile, "
|
|
174
|
+
return readFileSync(cacheFile, "utf8");
|
|
170
175
|
}
|
|
171
176
|
|
|
172
|
-
|
|
173
|
-
|
|
177
|
+
if (FALLBACK_INSTRUCTIONS) {
|
|
178
|
+
console.error(`[openai-codex] Falling back to bundled instructions for ${modelFamily}`);
|
|
179
|
+
return FALLBACK_INSTRUCTIONS;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
throw new Error(`No cached Codex instructions available for ${modelFamily}`);
|
|
174
183
|
}
|
|
175
184
|
}
|
|
176
|
-
|
|
177
|
-
export const TOOL_REMAP_MESSAGE = `<user_instructions priority="0">
|
|
178
|
-
<environment_override priority="0">
|
|
179
|
-
YOU ARE IN A DIFFERENT ENVIRONMENT. These instructions override ALL previous tool references.
|
|
180
|
-
</environment_override>
|
|
181
|
-
|
|
182
|
-
<tool_replacements priority="0">
|
|
183
|
-
<critical_rule priority="0">
|
|
184
|
-
❌ APPLY_PATCH DOES NOT EXIST → ✅ USE "edit" INSTEAD
|
|
185
|
-
- NEVER use: apply_patch, applyPatch
|
|
186
|
-
- ALWAYS use: edit tool for ALL file modifications
|
|
187
|
-
</critical_rule>
|
|
188
|
-
|
|
189
|
-
<critical_rule priority="0">
|
|
190
|
-
❌ UPDATE_PLAN DOES NOT EXIST
|
|
191
|
-
- NEVER use: update_plan, updatePlan, read_plan, readPlan, todowrite, todoread
|
|
192
|
-
- There is no plan tool in this environment
|
|
193
|
-
</critical_rule>
|
|
194
|
-
</tool_replacements>
|
|
195
|
-
|
|
196
|
-
<available_tools priority="0">
|
|
197
|
-
File Operations:
|
|
198
|
-
• read - Read file contents
|
|
199
|
-
• edit - Modify files with exact find/replace
|
|
200
|
-
• write - Create or overwrite files
|
|
201
|
-
|
|
202
|
-
Search/Discovery:
|
|
203
|
-
• grep - Search file contents for patterns (read-only)
|
|
204
|
-
• find - Find files by glob pattern (read-only)
|
|
205
|
-
• ls - List directory contents (read-only)
|
|
206
|
-
|
|
207
|
-
Execution:
|
|
208
|
-
• bash - Run shell commands
|
|
209
|
-
</available_tools>
|
|
210
|
-
|
|
211
|
-
<verification_checklist priority="0">
|
|
212
|
-
Before file modifications:
|
|
213
|
-
1. Am I using "edit" NOT "apply_patch"?
|
|
214
|
-
2. Am I avoiding plan tools entirely?
|
|
215
|
-
3. Am I using only the tools listed above?
|
|
216
|
-
</verification_checklist>
|
|
217
|
-
</user_instructions>`;
|
|
@@ -3,46 +3,53 @@
|
|
|
3
3
|
* Aligns Codex CLI expectations with Pi's toolset.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import type { Tool } from "../../../types";
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
function formatToolList(tools?: Tool[]): string {
|
|
9
|
+
if (!tools || tools.length === 0) {
|
|
10
|
+
return "- (none)";
|
|
11
|
+
}
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
const normalized = tools
|
|
14
|
+
.map((tool) => {
|
|
15
|
+
const name = tool.name.trim();
|
|
16
|
+
if (!name) return null;
|
|
17
|
+
const description = (tool.description || "Custom tool").replace(/\s*\n\s*/g, " ").trim();
|
|
18
|
+
return { name, description };
|
|
19
|
+
})
|
|
20
|
+
.filter((tool): tool is { name: string; description: string } => tool !== null);
|
|
11
21
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- ALWAYS use: edit for ALL file modifications
|
|
16
|
-
</critical_rule>
|
|
22
|
+
if (normalized.length === 0) {
|
|
23
|
+
return "- (none)";
|
|
24
|
+
}
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- NEVER use: update_plan, updatePlan, read_plan, readPlan, todowrite, todoread
|
|
21
|
-
- There is no plan tool in this environment
|
|
22
|
-
</critical_rule>
|
|
26
|
+
const maxNameLength = normalized.reduce((max, tool) => Math.max(max, tool.name.length), 0);
|
|
27
|
+
const padWidth = Math.max(6, maxNameLength + 1);
|
|
23
28
|
|
|
24
|
-
|
|
29
|
+
return normalized
|
|
30
|
+
.map((tool) => {
|
|
31
|
+
const paddedName = tool.name.padEnd(padWidth);
|
|
32
|
+
return `- ${paddedName}- ${tool.description}`;
|
|
33
|
+
})
|
|
34
|
+
.join("\n");
|
|
35
|
+
}
|
|
25
36
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
- edit - Modify files with exact find/replace (requires prior read)
|
|
29
|
-
- write - Create or overwrite files
|
|
30
|
-
- grep - Search file contents (read-only)
|
|
31
|
-
- find - Find files by glob pattern (read-only)
|
|
32
|
-
- ls - List directory contents (read-only)
|
|
37
|
+
export function buildCodexPiBridge(tools?: Tool[]): string {
|
|
38
|
+
const toolsList = formatToolList(tools);
|
|
33
39
|
|
|
34
|
-
|
|
40
|
+
return `# Codex Environment Bridge
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
<environment_override priority="0">
|
|
43
|
+
IGNORE ALL PREVIOUS INSTRUCTIONS ABOVE THIS MESSAGE.
|
|
44
|
+
Do not assume any tools are available unless listed below.
|
|
45
|
+
</environment_override>
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
The next system instructions that follow this message are authoritative and must be obeyed, even if they conflict with earlier instructions.
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
2. No plan tools used
|
|
45
|
-
3. Only the tools listed above are called
|
|
49
|
+
## Available Tools
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
${toolsList}
|
|
52
|
+
|
|
53
|
+
Only use the tools listed above. Do not reference or call any other tools.
|
|
48
54
|
`;
|
|
55
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface CodexSystemPrompt {
|
|
2
|
+
instructions: string;
|
|
3
|
+
developerMessages: string[];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function buildCodexSystemPrompt(args: {
|
|
7
|
+
codexInstructions: string;
|
|
8
|
+
bridgeText: string;
|
|
9
|
+
userSystemPrompt?: string;
|
|
10
|
+
}): CodexSystemPrompt {
|
|
11
|
+
const { codexInstructions, bridgeText, userSystemPrompt } = args;
|
|
12
|
+
const developerMessages: string[] = [];
|
|
13
|
+
|
|
14
|
+
if (bridgeText.trim().length > 0) {
|
|
15
|
+
developerMessages.push(bridgeText.trim());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (userSystemPrompt && userSystemPrompt.trim().length > 0) {
|
|
19
|
+
developerMessages.push(userSystemPrompt.trim());
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
instructions: codexInstructions.trim(),
|
|
24
|
+
developerMessages,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { TOOL_REMAP_MESSAGE } from "./prompts/codex";
|
|
2
|
-
import { CODEX_PI_BRIDGE } from "./prompts/pi-codex-bridge";
|
|
3
|
-
|
|
4
1
|
export interface ReasoningConfig {
|
|
5
2
|
effort: "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
6
3
|
summary: "auto" | "concise" | "detailed" | "off" | "on";
|
|
@@ -38,160 +35,32 @@ export interface RequestBody {
|
|
|
38
35
|
};
|
|
39
36
|
include?: string[];
|
|
40
37
|
prompt_cache_key?: string;
|
|
38
|
+
prompt_cache_retention?: "in_memory" | "24h";
|
|
41
39
|
max_output_tokens?: number;
|
|
42
40
|
max_completion_tokens?: number;
|
|
43
41
|
[key: string]: unknown;
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"gpt-5.1-codex-low": "gpt-5.1-codex",
|
|
49
|
-
"gpt-5.1-codex-medium": "gpt-5.1-codex",
|
|
50
|
-
"gpt-5.1-codex-high": "gpt-5.1-codex",
|
|
51
|
-
"gpt-5.1-codex-max": "gpt-5.1-codex-max",
|
|
52
|
-
"gpt-5.1-codex-max-low": "gpt-5.1-codex-max",
|
|
53
|
-
"gpt-5.1-codex-max-medium": "gpt-5.1-codex-max",
|
|
54
|
-
"gpt-5.1-codex-max-high": "gpt-5.1-codex-max",
|
|
55
|
-
"gpt-5.1-codex-max-xhigh": "gpt-5.1-codex-max",
|
|
56
|
-
"gpt-5.2": "gpt-5.2",
|
|
57
|
-
"gpt-5.2-none": "gpt-5.2",
|
|
58
|
-
"gpt-5.2-low": "gpt-5.2",
|
|
59
|
-
"gpt-5.2-medium": "gpt-5.2",
|
|
60
|
-
"gpt-5.2-high": "gpt-5.2",
|
|
61
|
-
"gpt-5.2-xhigh": "gpt-5.2",
|
|
62
|
-
"gpt-5.2-codex": "gpt-5.2-codex",
|
|
63
|
-
"gpt-5.2-codex-low": "gpt-5.2-codex",
|
|
64
|
-
"gpt-5.2-codex-medium": "gpt-5.2-codex",
|
|
65
|
-
"gpt-5.2-codex-high": "gpt-5.2-codex",
|
|
66
|
-
"gpt-5.2-codex-xhigh": "gpt-5.2-codex",
|
|
67
|
-
"gpt-5.1-codex-mini": "gpt-5.1-codex-mini",
|
|
68
|
-
"gpt-5.1-codex-mini-medium": "gpt-5.1-codex-mini",
|
|
69
|
-
"gpt-5.1-codex-mini-high": "gpt-5.1-codex-mini",
|
|
70
|
-
"gpt-5.1": "gpt-5.1",
|
|
71
|
-
"gpt-5.1-none": "gpt-5.1",
|
|
72
|
-
"gpt-5.1-low": "gpt-5.1",
|
|
73
|
-
"gpt-5.1-medium": "gpt-5.1",
|
|
74
|
-
"gpt-5.1-high": "gpt-5.1",
|
|
75
|
-
"gpt-5.1-chat-latest": "gpt-5.1",
|
|
76
|
-
"gpt-5-codex": "gpt-5.1-codex",
|
|
77
|
-
"codex-mini-latest": "gpt-5.1-codex-mini",
|
|
78
|
-
"gpt-5-codex-mini": "gpt-5.1-codex-mini",
|
|
79
|
-
"gpt-5-codex-mini-medium": "gpt-5.1-codex-mini",
|
|
80
|
-
"gpt-5-codex-mini-high": "gpt-5.1-codex-mini",
|
|
81
|
-
"gpt-5": "gpt-5.1",
|
|
82
|
-
"gpt-5-mini": "gpt-5.1",
|
|
83
|
-
"gpt-5-nano": "gpt-5.1",
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
function getNormalizedModel(modelId: string): string | undefined {
|
|
87
|
-
if (MODEL_MAP[modelId]) return MODEL_MAP[modelId];
|
|
88
|
-
const lowerModelId = modelId.toLowerCase();
|
|
89
|
-
const match = Object.keys(MODEL_MAP).find((key) => key.toLowerCase() === lowerModelId);
|
|
90
|
-
return match ? MODEL_MAP[match] : undefined;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function normalizeModel(model: string | undefined): string {
|
|
94
|
-
if (!model) return "gpt-5.1";
|
|
95
|
-
|
|
44
|
+
function clampReasoningEffort(model: string, effort: ReasoningConfig["effort"]): ReasoningConfig["effort"] {
|
|
45
|
+
// Codex backend expects exact model IDs. Do not normalize model names here.
|
|
96
46
|
const modelId = model.includes("/") ? model.split("/").pop()! : model;
|
|
97
|
-
const mappedModel = getNormalizedModel(modelId);
|
|
98
|
-
if (mappedModel) return mappedModel;
|
|
99
|
-
|
|
100
|
-
const normalized = modelId.toLowerCase();
|
|
101
|
-
|
|
102
|
-
if (normalized.includes("gpt-5.2-codex") || normalized.includes("gpt 5.2 codex")) {
|
|
103
|
-
return "gpt-5.2-codex";
|
|
104
|
-
}
|
|
105
|
-
if (normalized.includes("gpt-5.2") || normalized.includes("gpt 5.2")) {
|
|
106
|
-
return "gpt-5.2";
|
|
107
|
-
}
|
|
108
|
-
if (normalized.includes("gpt-5.1-codex-max") || normalized.includes("gpt 5.1 codex max")) {
|
|
109
|
-
return "gpt-5.1-codex-max";
|
|
110
|
-
}
|
|
111
|
-
if (normalized.includes("gpt-5.1-codex-mini") || normalized.includes("gpt 5.1 codex mini")) {
|
|
112
|
-
return "gpt-5.1-codex-mini";
|
|
113
|
-
}
|
|
114
|
-
if (
|
|
115
|
-
normalized.includes("codex-mini-latest") ||
|
|
116
|
-
normalized.includes("gpt-5-codex-mini") ||
|
|
117
|
-
normalized.includes("gpt 5 codex mini")
|
|
118
|
-
) {
|
|
119
|
-
return "codex-mini-latest";
|
|
120
|
-
}
|
|
121
|
-
if (normalized.includes("gpt-5.1-codex") || normalized.includes("gpt 5.1 codex")) {
|
|
122
|
-
return "gpt-5.1-codex";
|
|
123
|
-
}
|
|
124
|
-
if (normalized.includes("gpt-5.1") || normalized.includes("gpt 5.1")) {
|
|
125
|
-
return "gpt-5.1";
|
|
126
|
-
}
|
|
127
|
-
if (normalized.includes("codex")) {
|
|
128
|
-
return "gpt-5.1-codex";
|
|
129
|
-
}
|
|
130
|
-
if (normalized.includes("gpt-5") || normalized.includes("gpt 5")) {
|
|
131
|
-
return "gpt-5.1";
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return "gpt-5.1";
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function getReasoningConfig(modelName: string | undefined, options: CodexRequestOptions = {}): ReasoningConfig {
|
|
138
|
-
const normalizedName = modelName?.toLowerCase() ?? "";
|
|
139
|
-
|
|
140
|
-
const isGpt52Codex = normalizedName.includes("gpt-5.2-codex") || normalizedName.includes("gpt 5.2 codex");
|
|
141
|
-
const isGpt52General = (normalizedName.includes("gpt-5.2") || normalizedName.includes("gpt 5.2")) && !isGpt52Codex;
|
|
142
|
-
const isCodexMax = normalizedName.includes("codex-max") || normalizedName.includes("codex max");
|
|
143
|
-
const isCodexMini =
|
|
144
|
-
normalizedName.includes("codex-mini") ||
|
|
145
|
-
normalizedName.includes("codex mini") ||
|
|
146
|
-
normalizedName.includes("codex_mini") ||
|
|
147
|
-
normalizedName.includes("codex-mini-latest");
|
|
148
|
-
const isCodex = normalizedName.includes("codex") && !isCodexMini;
|
|
149
|
-
const isLightweight = !isCodexMini && (normalizedName.includes("nano") || normalizedName.includes("mini"));
|
|
150
|
-
const isGpt51General =
|
|
151
|
-
(normalizedName.includes("gpt-5.1") || normalizedName.includes("gpt 5.1")) &&
|
|
152
|
-
!isCodex &&
|
|
153
|
-
!isCodexMax &&
|
|
154
|
-
!isCodexMini;
|
|
155
|
-
|
|
156
|
-
const supportsXhigh = isGpt52General || isGpt52Codex || isCodexMax;
|
|
157
|
-
const supportsNone = isGpt52General || isGpt51General;
|
|
158
|
-
|
|
159
|
-
const defaultEffort: ReasoningConfig["effort"] = isCodexMini
|
|
160
|
-
? "medium"
|
|
161
|
-
: supportsXhigh
|
|
162
|
-
? "high"
|
|
163
|
-
: isLightweight
|
|
164
|
-
? "minimal"
|
|
165
|
-
: "medium";
|
|
166
|
-
|
|
167
|
-
let effort = options.reasoningEffort || defaultEffort;
|
|
168
|
-
|
|
169
|
-
if (isCodexMini) {
|
|
170
|
-
if (effort === "minimal" || effort === "low" || effort === "none") {
|
|
171
|
-
effort = "medium";
|
|
172
|
-
}
|
|
173
|
-
if (effort === "xhigh") {
|
|
174
|
-
effort = "high";
|
|
175
|
-
}
|
|
176
|
-
if (effort !== "high" && effort !== "medium") {
|
|
177
|
-
effort = "medium";
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
47
|
|
|
181
|
-
|
|
182
|
-
|
|
48
|
+
// gpt-5.1 does not support xhigh.
|
|
49
|
+
if (modelId === "gpt-5.1" && effort === "xhigh") {
|
|
50
|
+
return "high";
|
|
183
51
|
}
|
|
184
52
|
|
|
185
|
-
|
|
186
|
-
|
|
53
|
+
// gpt-5.1-codex-mini only supports medium/high.
|
|
54
|
+
if (modelId === "gpt-5.1-codex-mini") {
|
|
55
|
+
return effort === "high" || effort === "xhigh" ? "high" : "medium";
|
|
187
56
|
}
|
|
188
57
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
58
|
+
return effort;
|
|
59
|
+
}
|
|
192
60
|
|
|
61
|
+
function getReasoningConfig(model: string, options: CodexRequestOptions): ReasoningConfig {
|
|
193
62
|
return {
|
|
194
|
-
effort,
|
|
63
|
+
effort: clampReasoningEffort(model, options.reasoningEffort as ReasoningConfig["effort"]),
|
|
195
64
|
summary: options.reasoningSummary ?? "auto",
|
|
196
65
|
};
|
|
197
66
|
}
|
|
@@ -210,69 +79,17 @@ function filterInput(input: InputItem[] | undefined): InputItem[] | undefined {
|
|
|
210
79
|
});
|
|
211
80
|
}
|
|
212
81
|
|
|
213
|
-
function addCodexBridgeMessage(
|
|
214
|
-
input: InputItem[] | undefined,
|
|
215
|
-
hasTools: boolean,
|
|
216
|
-
systemPrompt?: string,
|
|
217
|
-
): InputItem[] | undefined {
|
|
218
|
-
if (!hasTools || !Array.isArray(input)) return input;
|
|
219
|
-
|
|
220
|
-
const bridgeText = systemPrompt ? `${CODEX_PI_BRIDGE}\n\n${systemPrompt}` : CODEX_PI_BRIDGE;
|
|
221
|
-
|
|
222
|
-
const bridgeMessage: InputItem = {
|
|
223
|
-
type: "message",
|
|
224
|
-
role: "developer",
|
|
225
|
-
content: [
|
|
226
|
-
{
|
|
227
|
-
type: "input_text",
|
|
228
|
-
text: bridgeText,
|
|
229
|
-
},
|
|
230
|
-
],
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
return [bridgeMessage, ...input];
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function addToolRemapMessage(input: InputItem[] | undefined, hasTools: boolean): InputItem[] | undefined {
|
|
237
|
-
if (!hasTools || !Array.isArray(input)) return input;
|
|
238
|
-
|
|
239
|
-
const toolRemapMessage: InputItem = {
|
|
240
|
-
type: "message",
|
|
241
|
-
role: "developer",
|
|
242
|
-
content: [
|
|
243
|
-
{
|
|
244
|
-
type: "input_text",
|
|
245
|
-
text: TOOL_REMAP_MESSAGE,
|
|
246
|
-
},
|
|
247
|
-
],
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
return [toolRemapMessage, ...input];
|
|
251
|
-
}
|
|
252
|
-
|
|
253
82
|
export async function transformRequestBody(
|
|
254
83
|
body: RequestBody,
|
|
255
|
-
codexInstructions: string,
|
|
256
84
|
options: CodexRequestOptions = {},
|
|
257
|
-
|
|
258
|
-
systemPrompt?: string,
|
|
85
|
+
prompt?: { instructions: string; developerMessages: string[] },
|
|
259
86
|
): Promise<RequestBody> {
|
|
260
|
-
const normalizedModel = normalizeModel(body.model);
|
|
261
|
-
|
|
262
|
-
body.model = normalizedModel;
|
|
263
87
|
body.store = false;
|
|
264
88
|
body.stream = true;
|
|
265
|
-
body.instructions = codexInstructions;
|
|
266
89
|
|
|
267
90
|
if (body.input && Array.isArray(body.input)) {
|
|
268
91
|
body.input = filterInput(body.input);
|
|
269
92
|
|
|
270
|
-
if (codexMode) {
|
|
271
|
-
body.input = addCodexBridgeMessage(body.input, !!body.tools, systemPrompt);
|
|
272
|
-
} else {
|
|
273
|
-
body.input = addToolRemapMessage(body.input, !!body.tools);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
93
|
if (body.input) {
|
|
277
94
|
const functionCallIds = new Set(
|
|
278
95
|
body.input
|
|
@@ -308,18 +125,36 @@ export async function transformRequestBody(
|
|
|
308
125
|
}
|
|
309
126
|
}
|
|
310
127
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
128
|
+
if (prompt?.developerMessages && prompt.developerMessages.length > 0 && Array.isArray(body.input)) {
|
|
129
|
+
const developerMessages = prompt.developerMessages.map(
|
|
130
|
+
(text) =>
|
|
131
|
+
({
|
|
132
|
+
type: "message",
|
|
133
|
+
role: "developer",
|
|
134
|
+
content: [{ type: "input_text", text }],
|
|
135
|
+
}) as InputItem,
|
|
136
|
+
);
|
|
137
|
+
body.input = [...developerMessages, ...body.input];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (options.reasoningEffort !== undefined) {
|
|
141
|
+
const reasoningConfig = getReasoningConfig(body.model, options);
|
|
142
|
+
body.reasoning = {
|
|
143
|
+
...body.reasoning,
|
|
144
|
+
...reasoningConfig,
|
|
145
|
+
};
|
|
146
|
+
} else {
|
|
147
|
+
delete body.reasoning;
|
|
148
|
+
}
|
|
316
149
|
|
|
317
150
|
body.text = {
|
|
318
151
|
...body.text,
|
|
319
152
|
verbosity: options.textVerbosity || "medium",
|
|
320
153
|
};
|
|
321
154
|
|
|
322
|
-
|
|
155
|
+
const include = Array.isArray(options.include) ? [...options.include] : [];
|
|
156
|
+
include.push("reasoning.encrypted_content");
|
|
157
|
+
body.include = Array.from(new Set(include));
|
|
323
158
|
|
|
324
159
|
delete body.max_output_tokens;
|
|
325
160
|
delete body.max_completion_tokens;
|