zidane 6.2.0 → 6.2.7
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/dist/{acp-0JO-UBEv.js → acp-B_8CI9-1.js} +4 -4
- package/dist/{acp-0JO-UBEv.js.map → acp-B_8CI9-1.js.map} +1 -1
- package/dist/acp-cli.js +7 -7
- package/dist/acp.d.ts +1 -1
- package/dist/acp.js +1 -1
- package/dist/{agent-25moybsj.js → agent-DPO6GKX5.js} +87 -69
- package/dist/agent-DPO6GKX5.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +2 -2
- package/dist/{anthropic-CV_OSYVD.js → anthropic-J2tBjcSQ.js} +49 -27
- package/dist/anthropic-J2tBjcSQ.js.map +1 -0
- package/dist/{auth-D5FfJtLf.js → auth-Cexpxjfa.js} +7 -5
- package/dist/auth-Cexpxjfa.js.map +1 -0
- package/dist/{cache-telemetry-BKAwsNxm.js → cache-telemetry-KJ7B-_Gh.js} +8 -3
- package/dist/cache-telemetry-KJ7B-_Gh.js.map +1 -0
- package/dist/chat/pure.d.ts +3 -3
- package/dist/chat/pure.js +1 -1
- package/dist/chat.d.ts +11 -4
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +5 -5
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +1 -1
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +3 -3
- package/dist/{index-mUT8TI9j.d.ts → index-CNyYEOy0.d.ts} +110 -36
- package/dist/index-CNyYEOy0.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -9
- package/dist/{inline-autocomplete-w_O3SVtN.js → inline-autocomplete-BAwBcZtD.js} +12 -7
- package/dist/{inline-autocomplete-w_O3SVtN.js.map → inline-autocomplete-BAwBcZtD.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/{messages-Ce4yRjd3.js → messages-DEPX32kc.js} +2 -2
- package/dist/{messages-Ce4yRjd3.js.map → messages-DEPX32kc.js.map} +1 -1
- package/dist/openai-BcmYm0t4.js +579 -0
- package/dist/openai-BcmYm0t4.js.map +1 -0
- package/dist/{openai-compat-TA7aihJ-.js → openai-compat-LGAsBush.js} +25 -1
- package/dist/openai-compat-LGAsBush.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/anthropic.js +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/arcee.js +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/baseten.js +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/cerebras.js +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/local.js +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai-compat.js +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +1 -503
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/openrouter.js +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +1 -1
- package/dist/{providers-Dln69sQ_.js → providers-BM6VuE_i.js} +3 -3
- package/dist/{providers-Dln69sQ_.js.map → providers-BM6VuE_i.js.map} +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +5 -5
- package/dist/restate.d.ts +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/{session-D7JSEMME.js → session-Dc1v4Otm.js} +2 -2
- package/dist/{session-D7JSEMME.js.map → session-Dc1v4Otm.js.map} +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/session.js +2 -2
- package/dist/skills.d.ts +1 -1
- package/dist/{tool-formatters-DOcJz_J9.d.ts → tool-formatters-B7oWiy5m.d.ts} +2 -2
- package/dist/tool-formatters-B7oWiy5m.d.ts.map +1 -0
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-CzMMNrhJ.d.ts → transcript-anchors-BUZ915pM.d.ts} +2 -2
- package/dist/{transcript-anchors-CzMMNrhJ.d.ts.map → transcript-anchors-BUZ915pM.d.ts.map} +1 -1
- package/dist/{transcript-anchors-CO-WnuYQ.js → transcript-anchors-DtOaKu4d.js} +12 -4
- package/dist/{transcript-anchors-CO-WnuYQ.js.map → transcript-anchors-DtOaKu4d.js.map} +1 -1
- package/dist/tui.d.ts +17 -14
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +207 -33
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-CrCrJnvo.d.ts → turn-operations-2Ou_DkbC.d.ts} +3 -3
- package/dist/{turn-operations-CrCrJnvo.d.ts.map → turn-operations-2Ou_DkbC.d.ts.map} +1 -1
- package/dist/{turn-operations-D9p-y9EC.js → turn-operations-CXjRaltC.js} +72 -2
- package/dist/{turn-operations-D9p-y9EC.js.map → turn-operations-CXjRaltC.js.map} +1 -1
- package/dist/types-BIarq1qE.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/{xai-kGdhWmds.js → xai-BYAyEPiJ.js} +2 -2
- package/dist/{xai-kGdhWmds.js.map → xai-BYAyEPiJ.js.map} +1 -1
- package/docs/ARCHITECTURE.md +1 -1
- package/docs/EXTENSIONS.md +6 -5
- package/package.json +2 -1
- package/scripts/eval.ts +21 -3
- package/dist/agent-25moybsj.js.map +0 -1
- package/dist/anthropic-CV_OSYVD.js.map +0 -1
- package/dist/auth-D5FfJtLf.js.map +0 -1
- package/dist/cache-telemetry-BKAwsNxm.js.map +0 -1
- package/dist/index-mUT8TI9j.d.ts.map +0 -1
- package/dist/openai-compat-TA7aihJ-.js.map +0 -1
- package/dist/providers/openai.js.map +0 -1
- package/dist/tool-formatters-DOcJz_J9.d.ts.map +0 -1
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
import { i as documentBlockMarker, n as assertResolvedMediaBlock } from "./types-BIarq1qE.js";
|
|
2
|
+
import { c as classifyErrorPrelude, d as isRetryableHttpStatus, f as matchesContextExceeded, p as matchesToolPairingError } from "./errors-DJUxZg9b.js";
|
|
3
|
+
import { _ as userMessage, b as fillEstimatedCost, g as toolResultsMessage, s as assistantMessage, w as unsupportedMediaError, y as sanitizeToolSpecs } from "./openai-compat-LGAsBush.js";
|
|
4
|
+
import { renderSystemForWire } from "./prompt.js";
|
|
5
|
+
import { n as SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from "./messages-DEPX32kc.js";
|
|
6
|
+
import { i as resolveOAuthApiKey, t as extractRuntimeCredentials } from "./oauth-8LqbeI_Q.js";
|
|
7
|
+
import { stream } from "@earendil-works/pi-ai/api/openai-codex-responses";
|
|
8
|
+
import { getBuiltinModel } from "@earendil-works/pi-ai/providers/all";
|
|
9
|
+
//#region src/chat/openai-models.ts
|
|
10
|
+
/**
|
|
11
|
+
* GPT-5.6 line — Sol (flagship), Terra (balanced), Luna (cost-optimized).
|
|
12
|
+
* All three: 1.05M context, 128k max output, reasoning
|
|
13
|
+
* (none/low/medium/high/xhigh/max), vision. Rates are the short-context
|
|
14
|
+
* standard tier per MTok (long context above the threshold is priced
|
|
15
|
+
* higher, which the single-rate cost table can't express).
|
|
16
|
+
*
|
|
17
|
+
* See https://developers.openai.com/api/docs/models.
|
|
18
|
+
*/
|
|
19
|
+
const OPENAI_EXTRA_MODELS = [
|
|
20
|
+
{
|
|
21
|
+
id: "gpt-5.6-sol",
|
|
22
|
+
name: "GPT-5.6 Sol",
|
|
23
|
+
reasoning: true,
|
|
24
|
+
input: ["text", "image"],
|
|
25
|
+
cost: {
|
|
26
|
+
input: 5,
|
|
27
|
+
output: 30,
|
|
28
|
+
cacheRead: .5,
|
|
29
|
+
cacheWrite: 6.25
|
|
30
|
+
},
|
|
31
|
+
contextWindow: 1047576,
|
|
32
|
+
maxTokens: 128e3,
|
|
33
|
+
provider: "openai"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "gpt-5.6-terra",
|
|
37
|
+
name: "GPT-5.6 Terra",
|
|
38
|
+
reasoning: true,
|
|
39
|
+
input: ["text", "image"],
|
|
40
|
+
cost: {
|
|
41
|
+
input: 2.5,
|
|
42
|
+
output: 15,
|
|
43
|
+
cacheRead: .25,
|
|
44
|
+
cacheWrite: 3.125
|
|
45
|
+
},
|
|
46
|
+
contextWindow: 1047576,
|
|
47
|
+
maxTokens: 128e3,
|
|
48
|
+
provider: "openai"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: "gpt-5.6-luna",
|
|
52
|
+
name: "GPT-5.6 Luna",
|
|
53
|
+
reasoning: true,
|
|
54
|
+
input: ["text", "image"],
|
|
55
|
+
cost: {
|
|
56
|
+
input: 1,
|
|
57
|
+
output: 6,
|
|
58
|
+
cacheRead: .1,
|
|
59
|
+
cacheWrite: 1.25
|
|
60
|
+
},
|
|
61
|
+
contextWindow: 1047576,
|
|
62
|
+
maxTokens: 128e3,
|
|
63
|
+
provider: "openai"
|
|
64
|
+
}
|
|
65
|
+
];
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/providers/openai.ts
|
|
68
|
+
const PROVIDER_ID = "openai-codex";
|
|
69
|
+
const DEFAULT_MODEL = "gpt-5.5";
|
|
70
|
+
const MODEL_ALIASES = { "gpt-5.6": "gpt-5.6-sol" };
|
|
71
|
+
const lookupModel = getBuiltinModel;
|
|
72
|
+
function resolveModel(modelId) {
|
|
73
|
+
const model = lookupModel(PROVIDER_ID, modelId);
|
|
74
|
+
if (model) return model;
|
|
75
|
+
const fallback = lookupModel(PROVIDER_ID, DEFAULT_MODEL);
|
|
76
|
+
if (!fallback) throw new Error(`OpenAI Codex model registry is missing the default model: ${DEFAULT_MODEL}`);
|
|
77
|
+
const canonicalId = MODEL_ALIASES[modelId] ?? modelId;
|
|
78
|
+
const extra = OPENAI_EXTRA_MODELS.find((m) => m.id === canonicalId);
|
|
79
|
+
if (extra?.cost) return {
|
|
80
|
+
...fallback,
|
|
81
|
+
id: modelId,
|
|
82
|
+
name: extra.name ?? modelId,
|
|
83
|
+
cost: {
|
|
84
|
+
input: extra.cost.input,
|
|
85
|
+
output: extra.cost.output,
|
|
86
|
+
cacheRead: extra.cost.cacheRead ?? 0,
|
|
87
|
+
cacheWrite: extra.cost.cacheWrite ?? 0
|
|
88
|
+
},
|
|
89
|
+
contextWindow: extra.contextWindow,
|
|
90
|
+
...extra.maxTokens !== void 0 ? { maxTokens: extra.maxTokens } : {}
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
...fallback,
|
|
94
|
+
id: modelId,
|
|
95
|
+
name: modelId
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function emptyUsage() {
|
|
99
|
+
return {
|
|
100
|
+
input: 0,
|
|
101
|
+
output: 0,
|
|
102
|
+
cacheRead: 0,
|
|
103
|
+
cacheWrite: 0,
|
|
104
|
+
totalTokens: 0,
|
|
105
|
+
cost: {
|
|
106
|
+
input: 0,
|
|
107
|
+
output: 0,
|
|
108
|
+
cacheRead: 0,
|
|
109
|
+
cacheWrite: 0,
|
|
110
|
+
total: 0
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function formatTools(tools) {
|
|
115
|
+
return sanitizeToolSpecs(tools, { profile: "openai" }).map((t) => ({
|
|
116
|
+
name: t.name,
|
|
117
|
+
description: t.description,
|
|
118
|
+
parameters: t.inputSchema
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
function documentMarker(doc) {
|
|
122
|
+
return documentBlockMarker(doc, "document omitted");
|
|
123
|
+
}
|
|
124
|
+
function piToolResultMessage(result, toolName = "") {
|
|
125
|
+
const content = typeof result.output === "string" ? [{
|
|
126
|
+
type: "text",
|
|
127
|
+
text: result.output
|
|
128
|
+
}] : result.output.map((block) => {
|
|
129
|
+
if (block.type === "image") {
|
|
130
|
+
assertResolvedMediaBlock(block, "OpenAI wire messages");
|
|
131
|
+
return {
|
|
132
|
+
type: "image",
|
|
133
|
+
data: block.data,
|
|
134
|
+
mimeType: block.mediaType
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (block.type === "audio") throw unsupportedMediaError("audio", "openai");
|
|
138
|
+
if (block.type === "video") throw unsupportedMediaError("video", "openai");
|
|
139
|
+
if (block.type === "document") {
|
|
140
|
+
assertResolvedMediaBlock(block, "OpenAI wire messages");
|
|
141
|
+
return {
|
|
142
|
+
type: "text",
|
|
143
|
+
text: documentMarker(block)
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
type: "text",
|
|
148
|
+
text: block.text
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
return {
|
|
152
|
+
role: "toolResult",
|
|
153
|
+
toolCallId: result.callId,
|
|
154
|
+
toolName,
|
|
155
|
+
content,
|
|
156
|
+
isError: result.isError ?? false,
|
|
157
|
+
timestamp: Date.now()
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function piUserMessage(content) {
|
|
161
|
+
for (const b of content) {
|
|
162
|
+
if (b.type === "audio") throw unsupportedMediaError("audio", "openai");
|
|
163
|
+
if (b.type === "video") throw unsupportedMediaError("video", "openai");
|
|
164
|
+
}
|
|
165
|
+
const textBlocks = content.filter((b) => b.type === "text");
|
|
166
|
+
const imageBlocks = content.filter((b) => b.type === "image");
|
|
167
|
+
const documentBlocks = content.filter((b) => b.type === "document");
|
|
168
|
+
if (imageBlocks.length === 0 && textBlocks.length === 0 && documentBlocks.length === 0) return null;
|
|
169
|
+
if (imageBlocks.length === 0 && documentBlocks.length === 0 && textBlocks.length === 1) return {
|
|
170
|
+
role: "user",
|
|
171
|
+
content: textBlocks[0].text,
|
|
172
|
+
timestamp: Date.now()
|
|
173
|
+
};
|
|
174
|
+
return {
|
|
175
|
+
role: "user",
|
|
176
|
+
content: [
|
|
177
|
+
...imageBlocks.map((img) => {
|
|
178
|
+
assertResolvedMediaBlock(img, "OpenAI wire messages");
|
|
179
|
+
return {
|
|
180
|
+
type: "image",
|
|
181
|
+
data: img.data,
|
|
182
|
+
mimeType: img.mediaType
|
|
183
|
+
};
|
|
184
|
+
}),
|
|
185
|
+
...documentBlocks.map((block) => {
|
|
186
|
+
assertResolvedMediaBlock(block, "OpenAI wire messages");
|
|
187
|
+
return {
|
|
188
|
+
type: "text",
|
|
189
|
+
text: documentMarker(block)
|
|
190
|
+
};
|
|
191
|
+
}),
|
|
192
|
+
...textBlocks.map((block) => ({
|
|
193
|
+
type: "text",
|
|
194
|
+
text: block.text
|
|
195
|
+
}))
|
|
196
|
+
],
|
|
197
|
+
timestamp: Date.now()
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function piAssistantMessage(content, modelId) {
|
|
201
|
+
const piContent = [];
|
|
202
|
+
for (const block of content) if (block.type === "text") piContent.push({
|
|
203
|
+
type: "text",
|
|
204
|
+
text: block.text
|
|
205
|
+
});
|
|
206
|
+
else if (block.type === "thinking") {
|
|
207
|
+
if (block.signatureProducer === "anthropic") continue;
|
|
208
|
+
piContent.push({
|
|
209
|
+
type: "thinking",
|
|
210
|
+
thinking: block.text,
|
|
211
|
+
thinkingSignature: block.signature
|
|
212
|
+
});
|
|
213
|
+
} else if (block.type === "tool_call") piContent.push({
|
|
214
|
+
type: "toolCall",
|
|
215
|
+
id: block.id,
|
|
216
|
+
name: block.name,
|
|
217
|
+
arguments: block.input
|
|
218
|
+
});
|
|
219
|
+
return {
|
|
220
|
+
role: "assistant",
|
|
221
|
+
content: piContent,
|
|
222
|
+
api: "openai-codex-responses",
|
|
223
|
+
provider: PROVIDER_ID,
|
|
224
|
+
model: modelId,
|
|
225
|
+
usage: emptyUsage(),
|
|
226
|
+
stopReason: "stop",
|
|
227
|
+
timestamp: Date.now()
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function toPiMessages(messages, modelId) {
|
|
231
|
+
const out = [];
|
|
232
|
+
for (let i = 0; i < messages.length; i++) {
|
|
233
|
+
const msg = messages[i];
|
|
234
|
+
const toolCalls = msg.content.filter((b) => b.type === "tool_call");
|
|
235
|
+
if (msg.role === "assistant" && toolCalls.length > 0) {
|
|
236
|
+
const next = messages[i + 1];
|
|
237
|
+
const nextToolResults = next?.role === "user" ? next.content.filter((b) => b.type === "tool_result") : [];
|
|
238
|
+
const resultById = new Map(nextToolResults.map((result) => [result.callId, result]));
|
|
239
|
+
let assistantContent = [];
|
|
240
|
+
for (const block of msg.content) {
|
|
241
|
+
assistantContent.push(block);
|
|
242
|
+
if (block.type !== "tool_call") continue;
|
|
243
|
+
out.push(piAssistantMessage(assistantContent, modelId));
|
|
244
|
+
assistantContent = [];
|
|
245
|
+
const result = resultById.get(block.id);
|
|
246
|
+
if (result) out.push(piToolResultMessage(result, block.name));
|
|
247
|
+
else out.push(piToolResultMessage({
|
|
248
|
+
type: "tool_result",
|
|
249
|
+
callId: block.id,
|
|
250
|
+
output: SYNTHETIC_TOOL_RESULT_PLACEHOLDER,
|
|
251
|
+
isError: true
|
|
252
|
+
}, block.name));
|
|
253
|
+
}
|
|
254
|
+
if (assistantContent.length > 0) out.push(piAssistantMessage(assistantContent, modelId));
|
|
255
|
+
if (next?.role === "user") {
|
|
256
|
+
const userMessage = piUserMessage(next.content.filter((block) => {
|
|
257
|
+
if (block.type !== "tool_result") return true;
|
|
258
|
+
return false;
|
|
259
|
+
}));
|
|
260
|
+
if (userMessage) out.push(userMessage);
|
|
261
|
+
i++;
|
|
262
|
+
}
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
if (msg.content.filter((b) => b.type === "tool_result").length > 0) {
|
|
266
|
+
const userMsg = msg.role === "user" ? piUserMessage(msg.content.filter((b) => b.type !== "tool_result")) : null;
|
|
267
|
+
if (userMsg) out.push(userMsg);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (msg.role === "user") {
|
|
271
|
+
const userMsg = piUserMessage(msg.content);
|
|
272
|
+
if (userMsg) out.push(userMsg);
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
out.push(piAssistantMessage(msg.content, modelId));
|
|
276
|
+
}
|
|
277
|
+
return out;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Map pi-ai's `StopReason` to the zidane `TurnFinishReason` union — the same
|
|
281
|
+
* native-stop-reason fidelity anthropic's `mapStopReason` / openai-compat's
|
|
282
|
+
* `mapOAIFinishReason` provide. Notably `length` (max-token truncation) is no
|
|
283
|
+
* longer misreported as a clean `stop`. `hasToolCalls` is the fallback for
|
|
284
|
+
* messages whose stop reason is missing or doesn't carry the tool-call signal.
|
|
285
|
+
*/
|
|
286
|
+
function mapCodexStopReason(stopReason, hasToolCalls) {
|
|
287
|
+
switch (stopReason) {
|
|
288
|
+
case "toolUse": return "tool-calls";
|
|
289
|
+
case "length": return "length";
|
|
290
|
+
case "error": return "error";
|
|
291
|
+
case "stop": return hasToolCalls ? "tool-calls" : "stop";
|
|
292
|
+
case "aborted": return "other";
|
|
293
|
+
default: return hasToolCalls ? "tool-calls" : "stop";
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function fromPiAssistantMessage(message) {
|
|
297
|
+
const content = [];
|
|
298
|
+
for (const block of message.content) if (block.type === "text") content.push({
|
|
299
|
+
type: "text",
|
|
300
|
+
text: block.text
|
|
301
|
+
});
|
|
302
|
+
else if (block.type === "thinking") {
|
|
303
|
+
const out = {
|
|
304
|
+
type: "thinking",
|
|
305
|
+
text: block.thinking
|
|
306
|
+
};
|
|
307
|
+
if (typeof block.thinkingSignature === "string") {
|
|
308
|
+
out.signature = block.thinkingSignature;
|
|
309
|
+
out.signatureProducer = "openai";
|
|
310
|
+
}
|
|
311
|
+
content.push(out);
|
|
312
|
+
} else if (block.type === "toolCall") content.push({
|
|
313
|
+
type: "tool_call",
|
|
314
|
+
id: block.id,
|
|
315
|
+
name: block.name,
|
|
316
|
+
input: block.arguments
|
|
317
|
+
});
|
|
318
|
+
return {
|
|
319
|
+
role: "assistant",
|
|
320
|
+
content
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function extractToolCalls(message) {
|
|
324
|
+
return message.content.filter((block) => block.type === "toolCall").map((block) => ({
|
|
325
|
+
id: block.id,
|
|
326
|
+
name: block.name,
|
|
327
|
+
input: block.arguments
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
function extractText(message) {
|
|
331
|
+
return message.content.filter((block) => block.type === "text").map((block) => block.text).join("");
|
|
332
|
+
}
|
|
333
|
+
function toTurnUsage(usage, finishReason, modelId) {
|
|
334
|
+
return fillEstimatedCost({
|
|
335
|
+
input: usage.input,
|
|
336
|
+
output: usage.output,
|
|
337
|
+
cacheRead: usage.cacheRead || void 0,
|
|
338
|
+
cacheCreation: usage.cacheWrite || void 0,
|
|
339
|
+
cost: usage.cost.total || void 0,
|
|
340
|
+
...finishReason ? { finishReason } : {},
|
|
341
|
+
modelId
|
|
342
|
+
}, "openai");
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Transient pi-ai error patterns worth a loop-level retry. pi-ai already retries
|
|
346
|
+
* 429 / 5xx pre-stream 3× internally (see `openai-codex-responses.js`); by the
|
|
347
|
+
* time the error reaches us, that budget is exhausted. The loop-level retry
|
|
348
|
+
* with its longer backoff is a second line of defense for capacity events
|
|
349
|
+
* that persist past pi-ai's short retry window, plus mid-stream emissions
|
|
350
|
+
* (pi-ai surfaces those as plain `Error`s with no status).
|
|
351
|
+
*
|
|
352
|
+
* Mirrors pi-ai's own `isRetryableError` regex so the two retry layers
|
|
353
|
+
* recognize the same failure modes.
|
|
354
|
+
*/
|
|
355
|
+
const TRANSIENT_OPENAI_MESSAGE_RE = /rate.?limit|overloaded|service.?unavailable|upstream.?connect|connection.?refused|gateway.?time.?out|temporarily.?unavailable/i;
|
|
356
|
+
/** Numeric HTTP status codes pi-ai sometimes attaches when bubbling structured errors. */
|
|
357
|
+
function isRetryableStatusCode(err) {
|
|
358
|
+
const status = err.status;
|
|
359
|
+
if (typeof status !== "number") return false;
|
|
360
|
+
return isRetryableHttpStatus(status);
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Classify an OpenAI Codex error. pi-ai surfaces errors either as thrown `Error`s
|
|
364
|
+
* (wrapping `event.error.errorMessage`) or via stream event types.
|
|
365
|
+
*
|
|
366
|
+
* Retryable hint is set when pi-ai's own retry budget is exhausted on a
|
|
367
|
+
* transient failure — pattern-matched against `message` since pi-ai strips
|
|
368
|
+
* structured fields on plain-Error throws. Set `behavior.retry.maxAttempts: 1`
|
|
369
|
+
* to disable the loop-level retry.
|
|
370
|
+
*/
|
|
371
|
+
function classifyOpenAIError(err) {
|
|
372
|
+
const prelude = classifyErrorPrelude(err);
|
|
373
|
+
if (prelude === "not-object") return null;
|
|
374
|
+
if (prelude === "aborted") return { kind: "aborted" };
|
|
375
|
+
const anyErr = err;
|
|
376
|
+
const message = anyErr.message ?? "";
|
|
377
|
+
const code = anyErr.code ?? anyErr.type;
|
|
378
|
+
if (code === "context_length_exceeded" || matchesContextExceeded(message)) return {
|
|
379
|
+
kind: "context_exceeded",
|
|
380
|
+
providerCode: code ?? "context_length_exceeded",
|
|
381
|
+
message
|
|
382
|
+
};
|
|
383
|
+
if (matchesToolPairingError(message)) return {
|
|
384
|
+
kind: "tool_pairing_corruption",
|
|
385
|
+
providerCode: code ?? "invalid_request_error",
|
|
386
|
+
message
|
|
387
|
+
};
|
|
388
|
+
if (message.length > 0) return {
|
|
389
|
+
kind: "provider_error",
|
|
390
|
+
providerCode: code,
|
|
391
|
+
message,
|
|
392
|
+
...isRetryableStatusCode(anyErr) || TRANSIENT_OPENAI_MESSAGE_RE.test(message) ? { retryable: true } : {}
|
|
393
|
+
};
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* A standard OpenAI API key usable against `api.openai.com` (for the exact
|
|
398
|
+
* token-count endpoint), or `null` when only a Codex-OAuth credential is
|
|
399
|
+
* available. Codex OAuth access tokens are JWTs (`eyJ…`) and are NOT valid
|
|
400
|
+
* bearers for the standard API; a real key looks like `sk-…` (but not the
|
|
401
|
+
* Anthropic `sk-ant-…` form). Checks `params.apiKey` then `OPENAI_API_KEY`.
|
|
402
|
+
*/
|
|
403
|
+
function pickStandardOpenAIKey(params) {
|
|
404
|
+
const candidates = [params?.apiKey, process.env.OPENAI_API_KEY];
|
|
405
|
+
for (const key of candidates) if (typeof key === "string" && key.startsWith("sk-") && !key.startsWith("sk-ant-")) return key;
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Convert canonical {@link SessionMessage}s to OpenAI Responses-API `input`
|
|
410
|
+
* items for the token-count endpoint. Only the text-bearing shape is needed
|
|
411
|
+
* here (the count path sends a tiny dummy message); images/tool-results are
|
|
412
|
+
* down-converted to text so the count never throws on an exotic block.
|
|
413
|
+
*/
|
|
414
|
+
function toResponsesInput(messages) {
|
|
415
|
+
return messages.map((msg) => {
|
|
416
|
+
const text = msg.content.map((b) => b.type === "text" ? b.text : "").filter(Boolean).join("\n");
|
|
417
|
+
const part = msg.role === "assistant" ? "output_text" : "input_text";
|
|
418
|
+
return {
|
|
419
|
+
role: msg.role === "assistant" ? "assistant" : "user",
|
|
420
|
+
content: [{
|
|
421
|
+
type: part,
|
|
422
|
+
text
|
|
423
|
+
}]
|
|
424
|
+
};
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
/** Convert pi-ai `PiTool` specs to Responses-API function tools. */
|
|
428
|
+
function toResponsesTools(tools) {
|
|
429
|
+
return tools.map((t) => {
|
|
430
|
+
const tool = t;
|
|
431
|
+
return {
|
|
432
|
+
type: "function",
|
|
433
|
+
name: tool.name,
|
|
434
|
+
description: tool.description,
|
|
435
|
+
parameters: tool.parameters
|
|
436
|
+
};
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
function applyPayloadOverrides(payload, options) {
|
|
440
|
+
const body = payload;
|
|
441
|
+
if (options.toolChoice) if (options.toolChoice.type === "tool" && options.toolChoice.name) body.tool_choice = {
|
|
442
|
+
type: "function",
|
|
443
|
+
name: options.toolChoice.name
|
|
444
|
+
};
|
|
445
|
+
else if (options.toolChoice.type === "required") body.tool_choice = "required";
|
|
446
|
+
else body.tool_choice = "auto";
|
|
447
|
+
return body;
|
|
448
|
+
}
|
|
449
|
+
function openai(params) {
|
|
450
|
+
const defaultModel = params?.defaultModel || DEFAULT_MODEL;
|
|
451
|
+
const baseCredentials = extractRuntimeCredentials(params);
|
|
452
|
+
let runtimeCredentials = baseCredentials ? {
|
|
453
|
+
...baseCredentials,
|
|
454
|
+
...params?.accountId ? { accountId: params.accountId } : {}
|
|
455
|
+
} : void 0;
|
|
456
|
+
return {
|
|
457
|
+
name: "openai",
|
|
458
|
+
meta: {
|
|
459
|
+
defaultModel,
|
|
460
|
+
isOAuth: true,
|
|
461
|
+
capabilities: {
|
|
462
|
+
vision: true,
|
|
463
|
+
imageInToolResult: true,
|
|
464
|
+
audio: false,
|
|
465
|
+
video: false
|
|
466
|
+
}
|
|
467
|
+
},
|
|
468
|
+
formatTools,
|
|
469
|
+
userMessage,
|
|
470
|
+
assistantMessage,
|
|
471
|
+
toolResultsMessage,
|
|
472
|
+
classifyError: classifyOpenAIError,
|
|
473
|
+
async countTokens(payload, signal) {
|
|
474
|
+
const standardKey = pickStandardOpenAIKey(params);
|
|
475
|
+
if (!standardKey) return null;
|
|
476
|
+
try {
|
|
477
|
+
const res = await fetch("https://api.openai.com/v1/responses/input_tokens", {
|
|
478
|
+
method: "POST",
|
|
479
|
+
headers: {
|
|
480
|
+
...params?.extraHeaders,
|
|
481
|
+
"authorization": `Bearer ${standardKey}`,
|
|
482
|
+
"content-type": "application/json"
|
|
483
|
+
},
|
|
484
|
+
body: JSON.stringify({
|
|
485
|
+
model: payload.model || defaultModel,
|
|
486
|
+
instructions: renderSystemForWire(payload.system),
|
|
487
|
+
input: toResponsesInput(payload.messages),
|
|
488
|
+
tools: toResponsesTools(payload.tools)
|
|
489
|
+
}),
|
|
490
|
+
...signal ? { signal } : {}
|
|
491
|
+
});
|
|
492
|
+
if (!res.ok) return null;
|
|
493
|
+
const json = await res.json();
|
|
494
|
+
return typeof json.input_tokens === "number" ? json.input_tokens : null;
|
|
495
|
+
} catch {
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
async stream(options, callbacks) {
|
|
500
|
+
const modelId = options.model || defaultModel;
|
|
501
|
+
const model = resolveModel(modelId);
|
|
502
|
+
const apiKey = await resolveOAuthApiKey({
|
|
503
|
+
provider: "openai",
|
|
504
|
+
providerId: PROVIDER_ID,
|
|
505
|
+
params: runtimeCredentials ? {
|
|
506
|
+
...params,
|
|
507
|
+
...runtimeCredentials
|
|
508
|
+
} : params,
|
|
509
|
+
envKey: "OPENAI_CODEX_API_KEY",
|
|
510
|
+
extraCredentialKeys: ["accountId"],
|
|
511
|
+
missingError: "No OpenAI Codex OAuth token found. Run `bun run auth --openai` first.",
|
|
512
|
+
refreshError: (reason) => `OpenAI Codex OAuth token refresh failed. Run \`bun run auth --openai\` again. ${reason}`
|
|
513
|
+
}, {
|
|
514
|
+
...callbacks,
|
|
515
|
+
async onOAuthRefresh(ctx) {
|
|
516
|
+
if (ctx.source === "params") runtimeCredentials = {
|
|
517
|
+
access: ctx.credentials.access,
|
|
518
|
+
refresh: ctx.credentials.refresh,
|
|
519
|
+
expires: ctx.credentials.expires,
|
|
520
|
+
...typeof ctx.credentials.accountId === "string" ? { accountId: ctx.credentials.accountId } : {}
|
|
521
|
+
};
|
|
522
|
+
await callbacks.onOAuthRefresh?.(ctx);
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
const context = {
|
|
526
|
+
systemPrompt: renderSystemForWire(options.system),
|
|
527
|
+
messages: toPiMessages(options.messages, modelId),
|
|
528
|
+
tools: options.tools
|
|
529
|
+
};
|
|
530
|
+
const supportsMaxEffort = modelId.startsWith("gpt-5.6");
|
|
531
|
+
const reasoningLevel = options.thinking && options.thinking !== "off" && options.thinking !== "adaptive" ? options.thinking === "max" && !supportsMaxEffort ? "xhigh" : options.thinking : void 0;
|
|
532
|
+
const stream$1 = stream(model, context, {
|
|
533
|
+
apiKey,
|
|
534
|
+
...options.maxTokens !== void 0 ? { maxTokens: options.maxTokens } : {},
|
|
535
|
+
signal: options.signal,
|
|
536
|
+
transport: params?.transport,
|
|
537
|
+
reasoningEffort: reasoningLevel,
|
|
538
|
+
reasoningSummary: reasoningLevel ? "auto" : void 0,
|
|
539
|
+
...options.modelOptions?.fast ? { serviceTier: "priority" } : {},
|
|
540
|
+
...params?.extraHeaders ? { headers: params.extraHeaders } : {},
|
|
541
|
+
onPayload: (payload) => applyPayloadOverrides(payload, options)
|
|
542
|
+
});
|
|
543
|
+
let finalMessage;
|
|
544
|
+
let text = "";
|
|
545
|
+
let thinking = "";
|
|
546
|
+
for await (const event of stream$1) if (event.type === "text_delta") {
|
|
547
|
+
text += event.delta;
|
|
548
|
+
callbacks.onText(event.delta);
|
|
549
|
+
} else if (event.type === "thinking_delta") {
|
|
550
|
+
thinking += event.delta;
|
|
551
|
+
callbacks.onThinking?.(event.delta);
|
|
552
|
+
} else if (event.type === "thinking_end") {
|
|
553
|
+
const delta = event.content.startsWith(thinking) ? event.content.slice(thinking.length) : thinking ? "" : event.content;
|
|
554
|
+
if (delta) {
|
|
555
|
+
thinking += delta;
|
|
556
|
+
callbacks.onThinking?.(delta);
|
|
557
|
+
}
|
|
558
|
+
} else if (event.type === "done") finalMessage = event.message;
|
|
559
|
+
else if (event.type === "error") throw new Error(event.error.errorMessage || "OpenAI Codex API error");
|
|
560
|
+
finalMessage ??= await stream$1.result();
|
|
561
|
+
text ||= extractText(finalMessage);
|
|
562
|
+
const toolCalls = extractToolCalls(finalMessage);
|
|
563
|
+
const assistantTurn = fromPiAssistantMessage(finalMessage);
|
|
564
|
+
const finishReason = mapCodexStopReason(finalMessage.stopReason, toolCalls.length > 0);
|
|
565
|
+
const usage = await toTurnUsage(finalMessage.usage, finishReason, modelId);
|
|
566
|
+
return {
|
|
567
|
+
assistantMessage: assistantTurn,
|
|
568
|
+
text,
|
|
569
|
+
toolCalls,
|
|
570
|
+
done: toolCalls.length === 0,
|
|
571
|
+
usage
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
//#endregion
|
|
577
|
+
export { OPENAI_EXTRA_MODELS as a, toPiMessages as i, mapCodexStopReason as n, openai as r, classifyOpenAIError as t };
|
|
578
|
+
|
|
579
|
+
//# sourceMappingURL=openai-BcmYm0t4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-BcmYm0t4.js","names":["getModel","stream","streamOpenAICodexResponses"],"sources":["../src/chat/openai-models.ts","../src/providers/openai.ts"],"sourcesContent":["/**\n * OpenAI models not (yet) bundled in `@earendil-works/pi-ai`'s registry.\n *\n * Same mechanism as `anthropic-models.ts`: pi-ai's static registry lags new\n * releases by a dep bump, so freshly-shipped models are listed here to show\n * in the picker, expose the reasoning knob, and get an accurate cost\n * estimate. Merged ahead of pi-ai's list in {@link modelsForDescriptor} and\n * de-duped by id, so once pi-ai catches up the bundled entry simply wins.\n */\n\nimport type { ModelInfo } from './providers'\n\n/**\n * GPT-5.6 line — Sol (flagship), Terra (balanced), Luna (cost-optimized).\n * All three: 1.05M context, 128k max output, reasoning\n * (none/low/medium/high/xhigh/max), vision. Rates are the short-context\n * standard tier per MTok (long context above the threshold is priced\n * higher, which the single-rate cost table can't express).\n *\n * See https://developers.openai.com/api/docs/models.\n */\nexport const OPENAI_EXTRA_MODELS: readonly ModelInfo[] = [\n {\n id: 'gpt-5.6-sol',\n name: 'GPT-5.6 Sol',\n reasoning: true,\n input: ['text', 'image'],\n cost: { input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 },\n contextWindow: 1_047_576,\n maxTokens: 128_000,\n provider: 'openai',\n },\n {\n id: 'gpt-5.6-terra',\n name: 'GPT-5.6 Terra',\n reasoning: true,\n input: ['text', 'image'],\n cost: { input: 2.5, output: 15, cacheRead: 0.25, cacheWrite: 3.125 },\n contextWindow: 1_047_576,\n maxTokens: 128_000,\n provider: 'openai',\n },\n {\n id: 'gpt-5.6-luna',\n name: 'GPT-5.6 Luna',\n reasoning: true,\n input: ['text', 'image'],\n cost: { input: 1, output: 6, cacheRead: 0.1, cacheWrite: 1.25 },\n contextWindow: 1_047_576,\n maxTokens: 128_000,\n provider: 'openai',\n },\n]\n","import type {\n AssistantMessage as PiAssistantMessage,\n Context as PiContext,\n Message as PiMessage,\n Model as PiModel,\n Tool as PiTool,\n Usage as PiUsage,\n} from '@earendil-works/pi-ai'\nimport type { Provider, StreamCallbacks, StreamOptions, ToolSpec, TurnResult } from '.'\nimport type { ClassifiedError } from '../errors'\nimport type { SessionContentBlock, SessionMessage, ToolResultDocumentContent, TurnFinishReason, TurnUsage } from '../types'\nimport type { OAuthParams } from './oauth'\nimport { stream as streamOpenAICodexResponses } from '@earendil-works/pi-ai/api/openai-codex-responses'\nimport { getBuiltinModel as getModel } from '@earendil-works/pi-ai/providers/all'\nimport { OPENAI_EXTRA_MODELS } from '../chat/openai-models'\nimport { classifyErrorPrelude, isRetryableHttpStatus, matchesContextExceeded, matchesToolPairingError } from '../errors'\nimport { unsupportedMediaError } from '../prompt'\nimport { SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from '../session/messages'\nimport { renderSystemForWire } from '../system-prompt'\nimport { assertResolvedMediaBlock, documentBlockMarker } from '../types'\nimport { fillEstimatedCost } from './cost'\nimport { extractRuntimeCredentials, resolveOAuthApiKey } from './oauth'\nimport {\n assistantMessage,\n toolResultsMessage,\n userMessage,\n} from './openai-compat'\nimport { sanitizeToolSpecs } from './schema-sanitize'\n\nconst PROVIDER_ID = 'openai-codex'\nconst DEFAULT_MODEL = 'gpt-5.5'\n\n// Metadata aliases for model ids OpenAI publishes as shorthand (e.g. `gpt-5.6`\n// → the Sol flagship). Used ONLY to resolve extra-model metadata (cost,\n// context window, output ceiling); the requested id is preserved on the wire,\n// which OpenAI accepts. Mirrors `openaiDescriptor.modelAliases` in the chat\n// layer (`src/chat/providers.ts`) — the provider layer can't import that\n// descriptor without a layering cycle. Keep the two in sync.\nconst MODEL_ALIASES: Readonly<Record<string, string>> = {\n 'gpt-5.6': 'gpt-5.6-sol',\n}\n\ntype CodexModel = PiModel<'openai-codex-responses'>\n\nexport interface OpenAIParams extends OAuthParams {\n accountId?: string\n defaultModel?: string\n transport?: 'sse' | 'websocket' | 'auto'\n /**\n * Extra HTTP headers merged into every request (the streaming Responses call\n * and the token-count endpoint). Use for routing/attribution headers a proxy\n * in front of the OpenAI Codex endpoint consumes. Merged with provider\n * defaults; pi-ai lets these override defaults, so avoid `authorization` /\n * `content-type` unless you intend to replace them.\n */\n extraHeaders?: Record<string, string>\n}\n\n// pi-ai's `getModel` is typed for `KnownProvider` × `keyof models[P]`;\n// we look up by free-form `modelId` (the registry holds string ids at\n// runtime) and let pi-ai's miss-throw fall through via the wider lookup.\nconst lookupModel = getModel as (provider: string, modelId: string) => CodexModel | undefined\n\nfunction resolveModel(modelId: string): CodexModel {\n const model = lookupModel(PROVIDER_ID, modelId)\n if (model)\n return model\n\n const fallback = lookupModel(PROVIDER_ID, DEFAULT_MODEL)\n if (!fallback)\n throw new Error(`OpenAI Codex model registry is missing the default model: ${DEFAULT_MODEL}`)\n\n // Models pi-ai doesn't bundle yet (e.g. the GPT-5.6 line) carry their own\n // metadata in OPENAI_EXTRA_MODELS. Splice it into the fallback so pi-ai's\n // usage accounting bills them at their real rates instead of the default\n // model's, and the real context window / output ceiling apply. Resolve\n // shorthand aliases (`gpt-5.6` → `gpt-5.6-sol`) for the lookup while keeping\n // the requested id on the wire — otherwise a session pinned to `gpt-5.6`\n // would silently bill at the gpt-5.5 fallback's rates.\n const canonicalId = MODEL_ALIASES[modelId] ?? modelId\n const extra = OPENAI_EXTRA_MODELS.find(m => m.id === canonicalId)\n if (extra?.cost) {\n return {\n ...fallback,\n id: modelId,\n name: extra.name ?? modelId,\n cost: {\n input: extra.cost.input,\n output: extra.cost.output,\n cacheRead: extra.cost.cacheRead ?? 0,\n cacheWrite: extra.cost.cacheWrite ?? 0,\n },\n contextWindow: extra.contextWindow,\n ...(extra.maxTokens !== undefined ? { maxTokens: extra.maxTokens } : {}),\n }\n }\n\n return { ...fallback, id: modelId, name: modelId }\n}\n\nfunction emptyUsage(): PiUsage {\n return {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n }\n}\n\nfunction formatTools(tools: ToolSpec[]): PiTool[] {\n // Codex's Responses API runs the same schema validator as the OpenAI\n // Chat Completions endpoint — apply the same sanitisation pass so MCP\n // tools with non-standard root shapes don't 400 here either.\n const sanitized = sanitizeToolSpecs(tools, { profile: 'openai' })\n return sanitized.map(t => ({\n name: t.name,\n description: t.description,\n parameters: t.inputSchema as PiTool['parameters'],\n }))\n}\n\nfunction documentMarker(doc: ToolResultDocumentContent): string {\n return documentBlockMarker(doc, 'document omitted')\n}\n\nfunction piToolResultMessage(\n result: Extract<SessionContentBlock, { type: 'tool_result' }>,\n toolName = '',\n): PiMessage {\n // pi-ai's ToolResultMessage natively accepts (TextContent | ImageContent)[].\n // Map zidane's canonical union directly — no flattening needed.\n const content = typeof result.output === 'string'\n ? [{ type: 'text' as const, text: result.output }]\n : result.output.map((block) => {\n if (block.type === 'image') {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'image' as const, data: block.data, mimeType: block.mediaType }\n }\n if (block.type === 'audio')\n throw unsupportedMediaError('audio', 'openai')\n if (block.type === 'video')\n throw unsupportedMediaError('video', 'openai')\n if (block.type === 'document') {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'text' as const, text: documentMarker(block) }\n }\n return { type: 'text' as const, text: block.text }\n })\n\n return {\n role: 'toolResult',\n toolCallId: result.callId,\n toolName,\n content,\n isError: result.isError ?? false,\n timestamp: Date.now(),\n }\n}\n\nfunction piUserMessage(\n content: SessionContentBlock[],\n): PiMessage | null {\n for (const b of content) {\n if (b.type === 'audio')\n throw unsupportedMediaError('audio', 'openai')\n if (b.type === 'video')\n throw unsupportedMediaError('video', 'openai')\n }\n\n const textBlocks = content.filter(b => b.type === 'text')\n const imageBlocks = content.filter(b => b.type === 'image')\n const documentBlocks = content.filter(b => b.type === 'document')\n\n if (imageBlocks.length === 0 && textBlocks.length === 0 && documentBlocks.length === 0)\n return null\n\n if (imageBlocks.length === 0 && documentBlocks.length === 0 && textBlocks.length === 1)\n return { role: 'user', content: textBlocks[0].text, timestamp: Date.now() }\n\n return {\n role: 'user',\n content: [\n ...imageBlocks.map((img) => {\n assertResolvedMediaBlock(img, 'OpenAI wire messages')\n return { type: 'image' as const, data: img.data, mimeType: img.mediaType }\n }),\n // NOTE: OpenAI's API natively accepts PDFs (Responses `input_file` /\n // Chat Completions `file`), but pi-ai's message content union is\n // text|image only — it has no file content type — so documents degrade to\n // a marker here. To forward PDFs to OpenAI, route via:\n // openaiCompat({ name: 'openai', apiKey, baseURL: 'https://api.openai.com/v1',\n // capabilities: { documents: true } })\n // which emits the `{type:'file'}` Chat Completions part directly. (That\n // path accepts application/pdf only; spreadsheets/.docx need the\n // Responses API, which would require an input_file content type in pi-ai.)\n ...documentBlocks.map((block) => {\n assertResolvedMediaBlock(block, 'OpenAI wire messages')\n return { type: 'text' as const, text: documentMarker(block) }\n }),\n ...textBlocks.map(block => ({ type: 'text' as const, text: block.text })),\n ],\n timestamp: Date.now(),\n }\n}\n\nfunction piAssistantMessage(\n content: SessionContentBlock[],\n modelId: string,\n): PiAssistantMessage {\n const piContent: PiAssistantMessage['content'] = []\n for (const block of content) {\n if (block.type === 'text') {\n piContent.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'thinking') {\n // Drop thinking blocks minted by another provider — Anthropic signatures\n // are not valid OpenAI `encrypted_content` and Responses API rejects them.\n if (block.signatureProducer === 'anthropic')\n continue\n piContent.push({ type: 'thinking', thinking: block.text, thinkingSignature: block.signature })\n }\n else if (block.type === 'tool_call') {\n piContent.push({ type: 'toolCall', id: block.id, name: block.name, arguments: block.input })\n }\n // `redacted_thinking` (Anthropic-only) and `provider_reasoning` (provider-\n // bound reasoning state) are intentionally dropped — Codex Responses\n // doesn't accept them.\n }\n\n return {\n role: 'assistant',\n content: piContent,\n api: 'openai-codex-responses',\n provider: PROVIDER_ID,\n model: modelId,\n usage: emptyUsage(),\n stopReason: 'stop',\n timestamp: Date.now(),\n }\n}\n\nexport function toPiMessages(messages: SessionMessage[], modelId: string): PiMessage[] {\n const out: PiMessage[] = []\n\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]\n const toolCalls = msg.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_call' }> => b.type === 'tool_call')\n\n if (msg.role === 'assistant' && toolCalls.length > 0) {\n const next = messages[i + 1]\n const nextToolResults = next?.role === 'user'\n ? next.content.filter((b): b is Extract<SessionContentBlock, { type: 'tool_result' }> => b.type === 'tool_result')\n : []\n const resultById = new Map(nextToolResults.map(result => [result.callId, result]))\n\n let assistantContent: SessionContentBlock[] = []\n for (const block of msg.content) {\n assistantContent.push(block)\n if (block.type !== 'tool_call')\n continue\n\n out.push(piAssistantMessage(assistantContent, modelId))\n assistantContent = []\n\n const result = resultById.get(block.id)\n if (result) {\n out.push(piToolResultMessage(result, block.name))\n }\n else {\n out.push(piToolResultMessage({\n type: 'tool_result',\n callId: block.id,\n output: SYNTHETIC_TOOL_RESULT_PLACEHOLDER,\n isError: true,\n }, block.name))\n }\n }\n if (assistantContent.length > 0)\n out.push(piAssistantMessage(assistantContent, modelId))\n\n if (next?.role === 'user') {\n const remainingUserContent = next.content.filter((block) => {\n if (block.type !== 'tool_result')\n return true\n // Orphan/duplicate tool results should already be removed by the\n // canonical repair pass. If one reaches this adapter, do not send it\n // as an unpaired provider message.\n return false\n })\n const userMessage = piUserMessage(remainingUserContent)\n if (userMessage)\n out.push(userMessage)\n i++\n }\n continue\n }\n\n const toolResults = msg.content.filter(b => b.type === 'tool_result')\n if (toolResults.length > 0) {\n const userMsg = msg.role === 'user'\n ? piUserMessage(msg.content.filter(b => b.type !== 'tool_result'))\n : null\n if (userMsg)\n out.push(userMsg)\n continue\n }\n\n if (msg.role === 'user') {\n const userMsg = piUserMessage(msg.content)\n if (userMsg)\n out.push(userMsg)\n continue\n }\n\n out.push(piAssistantMessage(msg.content, modelId))\n }\n\n return out\n}\n\n/**\n * Map pi-ai's `StopReason` to the zidane `TurnFinishReason` union — the same\n * native-stop-reason fidelity anthropic's `mapStopReason` / openai-compat's\n * `mapOAIFinishReason` provide. Notably `length` (max-token truncation) is no\n * longer misreported as a clean `stop`. `hasToolCalls` is the fallback for\n * messages whose stop reason is missing or doesn't carry the tool-call signal.\n */\nexport function mapCodexStopReason(stopReason: string | undefined, hasToolCalls: boolean): TurnFinishReason {\n switch (stopReason) {\n case 'toolUse':\n return 'tool-calls'\n case 'length':\n return 'length'\n case 'error':\n return 'error'\n case 'stop':\n return hasToolCalls ? 'tool-calls' : 'stop'\n case 'aborted':\n return 'other'\n default:\n return hasToolCalls ? 'tool-calls' : 'stop'\n }\n}\n\nfunction fromPiAssistantMessage(message: PiAssistantMessage): SessionMessage {\n const content: SessionContentBlock[] = []\n\n for (const block of message.content) {\n if (block.type === 'text') {\n content.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'thinking') {\n const out: Extract<SessionContentBlock, { type: 'thinking' }> = {\n type: 'thinking',\n text: block.thinking,\n }\n if (typeof block.thinkingSignature === 'string') {\n out.signature = block.thinkingSignature\n out.signatureProducer = 'openai'\n }\n content.push(out)\n }\n else if (block.type === 'toolCall') {\n content.push({ type: 'tool_call', id: block.id, name: block.name, input: block.arguments })\n }\n }\n\n return { role: 'assistant', content }\n}\n\nfunction extractToolCalls(message: PiAssistantMessage) {\n return message.content\n .filter(block => block.type === 'toolCall')\n .map(block => ({\n id: block.id,\n name: block.name,\n input: block.arguments as Record<string, unknown>,\n }))\n}\n\nfunction extractText(message: PiAssistantMessage): string {\n return message.content\n .filter((block): block is Extract<PiAssistantMessage['content'][number], { type: 'text' }> => block.type === 'text')\n .map(block => block.text)\n .join('')\n}\n\nfunction toTurnUsage(usage: PiUsage, finishReason: TurnFinishReason | undefined, modelId: string): Promise<TurnUsage> {\n return fillEstimatedCost({\n input: usage.input,\n output: usage.output,\n cacheRead: usage.cacheRead || undefined,\n cacheCreation: usage.cacheWrite || undefined,\n cost: usage.cost.total || undefined,\n ...(finishReason ? { finishReason } : {}),\n modelId,\n }, 'openai')\n}\n\n/**\n * Transient pi-ai error patterns worth a loop-level retry. pi-ai already retries\n * 429 / 5xx pre-stream 3× internally (see `openai-codex-responses.js`); by the\n * time the error reaches us, that budget is exhausted. The loop-level retry\n * with its longer backoff is a second line of defense for capacity events\n * that persist past pi-ai's short retry window, plus mid-stream emissions\n * (pi-ai surfaces those as plain `Error`s with no status).\n *\n * Mirrors pi-ai's own `isRetryableError` regex so the two retry layers\n * recognize the same failure modes.\n */\nconst TRANSIENT_OPENAI_MESSAGE_RE = /rate.?limit|overloaded|service.?unavailable|upstream.?connect|connection.?refused|gateway.?time.?out|temporarily.?unavailable/i\n\n/** Numeric HTTP status codes pi-ai sometimes attaches when bubbling structured errors. */\nfunction isRetryableStatusCode(err: object): boolean {\n const status = (err as { status?: unknown }).status\n if (typeof status !== 'number')\n return false\n return isRetryableHttpStatus(status)\n}\n\n/**\n * Classify an OpenAI Codex error. pi-ai surfaces errors either as thrown `Error`s\n * (wrapping `event.error.errorMessage`) or via stream event types.\n *\n * Retryable hint is set when pi-ai's own retry budget is exhausted on a\n * transient failure — pattern-matched against `message` since pi-ai strips\n * structured fields on plain-Error throws. Set `behavior.retry.maxAttempts: 1`\n * to disable the loop-level retry.\n */\nexport function classifyOpenAIError(err: unknown): ClassifiedError | null {\n const prelude = classifyErrorPrelude(err)\n if (prelude === 'not-object')\n return null\n if (prelude === 'aborted')\n return { kind: 'aborted' }\n\n const anyErr = err as { name?: string, message?: string, code?: string, type?: string }\n\n const message = anyErr.message ?? ''\n const code = anyErr.code ?? anyErr.type\n\n if (code === 'context_length_exceeded' || matchesContextExceeded(message)) {\n return {\n kind: 'context_exceeded',\n providerCode: code ?? 'context_length_exceeded',\n message,\n }\n }\n\n if (matchesToolPairingError(message)) {\n return {\n kind: 'tool_pairing_corruption',\n providerCode: code ?? 'invalid_request_error',\n message,\n }\n }\n\n // pi-ai wraps API errors in generic `Error` — treat as provider_error when we have a message.\n if (message.length > 0) {\n const retryable = isRetryableStatusCode(anyErr) || TRANSIENT_OPENAI_MESSAGE_RE.test(message)\n return {\n kind: 'provider_error',\n providerCode: code,\n message,\n ...(retryable ? { retryable: true } : {}),\n }\n }\n\n return null\n}\n\n/**\n * A standard OpenAI API key usable against `api.openai.com` (for the exact\n * token-count endpoint), or `null` when only a Codex-OAuth credential is\n * available. Codex OAuth access tokens are JWTs (`eyJ…`) and are NOT valid\n * bearers for the standard API; a real key looks like `sk-…` (but not the\n * Anthropic `sk-ant-…` form). Checks `params.apiKey` then `OPENAI_API_KEY`.\n */\nfunction pickStandardOpenAIKey(params?: OpenAIParams): string | null {\n const candidates = [params?.apiKey, process.env.OPENAI_API_KEY]\n for (const key of candidates) {\n if (typeof key === 'string' && key.startsWith('sk-') && !key.startsWith('sk-ant-'))\n return key\n }\n return null\n}\n\n/**\n * Convert canonical {@link SessionMessage}s to OpenAI Responses-API `input`\n * items for the token-count endpoint. Only the text-bearing shape is needed\n * here (the count path sends a tiny dummy message); images/tool-results are\n * down-converted to text so the count never throws on an exotic block.\n */\nfunction toResponsesInput(messages: SessionMessage[]): unknown[] {\n return messages.map((msg) => {\n const text = msg.content\n .map(b => (b.type === 'text' ? b.text : ''))\n .filter(Boolean)\n .join('\\n')\n const part = msg.role === 'assistant' ? 'output_text' : 'input_text'\n return { role: msg.role === 'assistant' ? 'assistant' : 'user', content: [{ type: part, text }] }\n })\n}\n\n/** Convert pi-ai `PiTool` specs to Responses-API function tools. */\nfunction toResponsesTools(tools: unknown[]): unknown[] {\n return tools.map((t) => {\n const tool = t as { name?: string, description?: string, parameters?: unknown }\n return {\n type: 'function',\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n }\n })\n}\n\nfunction applyPayloadOverrides(payload: unknown, options: StreamOptions): unknown {\n const body = payload as Record<string, unknown>\n\n if (options.toolChoice) {\n if (options.toolChoice.type === 'tool' && options.toolChoice.name)\n body.tool_choice = { type: 'function', name: options.toolChoice.name }\n else if (options.toolChoice.type === 'required')\n body.tool_choice = 'required'\n else\n body.tool_choice = 'auto'\n }\n\n return body\n}\n\nexport function openai(params?: OpenAIParams): Provider {\n const defaultModel = params?.defaultModel || DEFAULT_MODEL\n const baseCredentials = extractRuntimeCredentials(params)\n let runtimeCredentials = baseCredentials\n ? { ...baseCredentials, ...(params?.accountId ? { accountId: params.accountId } : {}) }\n : undefined\n\n return {\n name: 'openai',\n meta: {\n defaultModel,\n isOAuth: true,\n capabilities: {\n vision: true,\n imageInToolResult: true,\n // pi-ai's Codex Responses wire has no audio/video input content type.\n audio: false,\n video: false,\n },\n },\n formatTools,\n userMessage,\n assistantMessage,\n toolResultsMessage,\n classifyError: classifyOpenAIError,\n\n async countTokens(payload, signal): Promise<number | null> {\n // The exact count endpoint (`POST /v1/responses/input_tokens`) lives on\n // the standard OpenAI API and needs a standard `OPENAI_API_KEY` bearer.\n // This provider authenticates via Codex OAuth against the Codex backend,\n // whose token is NOT valid for that endpoint — so we only attempt the\n // count when a standard key is present (env or params.apiKey that isn't\n // an OAuth/JWT token). Otherwise return null → heuristic fallback.\n const standardKey = pickStandardOpenAIKey(params)\n if (!standardKey)\n return null\n try {\n const res = await fetch('https://api.openai.com/v1/responses/input_tokens', {\n method: 'POST',\n headers: {\n ...params?.extraHeaders,\n 'authorization': `Bearer ${standardKey}`,\n 'content-type': 'application/json',\n },\n // The Responses `input_tokens` endpoint takes the same shape as\n // `responses.create`: `instructions` (system), `input` (Responses\n // input items — NOT pi-ai messages), and function-shaped `tools`.\n body: JSON.stringify({\n model: payload.model || defaultModel,\n instructions: renderSystemForWire(payload.system),\n input: toResponsesInput(payload.messages),\n tools: toResponsesTools(payload.tools),\n }),\n ...(signal ? { signal } : {}),\n })\n if (!res.ok)\n return null\n const json = (await res.json()) as { input_tokens?: unknown }\n return typeof json.input_tokens === 'number' ? json.input_tokens : null\n }\n catch {\n return null\n }\n },\n\n async stream(options: StreamOptions, callbacks: StreamCallbacks): Promise<TurnResult> {\n const modelId = options.model || defaultModel\n const model = resolveModel(modelId)\n const apiKey = await resolveOAuthApiKey(\n {\n provider: 'openai',\n providerId: PROVIDER_ID,\n params: runtimeCredentials ? { ...params, ...runtimeCredentials } : params,\n envKey: 'OPENAI_CODEX_API_KEY',\n extraCredentialKeys: ['accountId'],\n missingError: 'No OpenAI Codex OAuth token found. Run `bun run auth --openai` first.',\n refreshError: reason => `OpenAI Codex OAuth token refresh failed. Run \\`bun run auth --openai\\` again. ${reason}`,\n },\n {\n ...callbacks,\n async onOAuthRefresh(ctx) {\n if (ctx.source === 'params') {\n runtimeCredentials = {\n access: ctx.credentials.access,\n refresh: ctx.credentials.refresh,\n expires: ctx.credentials.expires,\n ...(typeof ctx.credentials.accountId === 'string' ? { accountId: ctx.credentials.accountId } : {}),\n }\n }\n await callbacks.onOAuthRefresh?.(ctx)\n },\n },\n )\n // Codex's Responses API has no `cache_control` analogue, but the\n // system-prompt boundary marker is structural metadata that should\n // never reach the model. Strip it via `renderSystemForWire`; the\n // doctrine + env are collapsed into a single byte stream the model\n // sees as one logical prompt.\n const context: PiContext = {\n systemPrompt: renderSystemForWire(options.system),\n messages: toPiMessages(options.messages, modelId),\n tools: options.tools as PiTool[],\n }\n // OpenAI's `reasoning_effort` accepts minimal/low/medium/high/xhigh, and\n // the GPT-5.6 line adds a native `max` tier. Clamp `max` to `xhigh` on\n // older models only; `'adaptive'` degrades to no reasoning rather than\n // forwarding an unknown value the API would reject.\n const supportsMaxEffort = modelId.startsWith('gpt-5.6')\n const reasoningLevel\n = options.thinking && options.thinking !== 'off' && options.thinking !== 'adaptive'\n ? options.thinking === 'max' && !supportsMaxEffort ? 'xhigh' : options.thinking\n : undefined\n const stream = streamOpenAICodexResponses(model, context, {\n apiKey,\n ...(options.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),\n signal: options.signal,\n transport: params?.transport,\n // pi-ai's option type doesn't include GPT-5.6's `max` tier yet; the\n // wire accepts it, so widen past the stale type.\n reasoningEffort: reasoningLevel as Exclude<typeof reasoningLevel, 'max'>,\n reasoningSummary: reasoningLevel ? 'auto' : undefined,\n ...(options.modelOptions?.fast ? { serviceTier: 'priority' as const } : {}),\n ...(params?.extraHeaders ? { headers: params.extraHeaders } : {}),\n onPayload: payload => applyPayloadOverrides(payload, options),\n })\n\n let finalMessage: PiAssistantMessage | undefined\n let text = ''\n let thinking = ''\n\n for await (const event of stream) {\n if (event.type === 'text_delta') {\n text += event.delta\n callbacks.onText(event.delta)\n }\n else if (event.type === 'thinking_delta') {\n thinking += event.delta\n callbacks.onThinking?.(event.delta)\n }\n else if (event.type === 'thinking_end') {\n const delta = event.content.startsWith(thinking)\n ? event.content.slice(thinking.length)\n : (thinking ? '' : event.content)\n if (delta) {\n thinking += delta\n callbacks.onThinking?.(delta)\n }\n }\n else if (event.type === 'done') {\n finalMessage = event.message\n }\n else if (event.type === 'error') {\n throw new Error(event.error.errorMessage || 'OpenAI Codex API error')\n }\n }\n\n finalMessage ??= await stream.result()\n text ||= extractText(finalMessage)\n\n const toolCalls = extractToolCalls(finalMessage)\n const assistantTurn = fromPiAssistantMessage(finalMessage)\n const finishReason = mapCodexStopReason(finalMessage.stopReason, toolCalls.length > 0)\n const usage = await toTurnUsage(finalMessage.usage, finishReason, modelId)\n\n return {\n assistantMessage: assistantTurn,\n text,\n toolCalls,\n done: toolCalls.length === 0,\n usage,\n }\n },\n }\n}\n"],"mappings":"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"}
|