pi-openai-codex-compat 0.0.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +64 -0
- package/LICENSE +20 -0
- package/LICENSES/Apache-2.0.txt +201 -0
- package/LICENSES/pi-ai-MIT.txt +21 -0
- package/README.md +331 -0
- package/THIRD_PARTY_NOTICES.md +21 -0
- package/extensions/openai-codex-compat/apply-patch-diff-render.ts +436 -0
- package/extensions/openai-codex-compat/apply-patch-engine.ts +1004 -0
- package/extensions/openai-codex-compat/apply-patch-render.ts +133 -0
- package/extensions/openai-codex-compat/apply-patch.ts +142 -0
- package/extensions/openai-codex-compat/codex-protocol.ts +598 -0
- package/extensions/openai-codex-compat/codex-provider.ts +740 -0
- package/extensions/openai-codex-compat/codex-stream.ts +444 -0
- package/extensions/openai-codex-compat/codex-tool-surface.ts +186 -0
- package/extensions/openai-codex-compat/codex-transport.ts +855 -0
- package/extensions/openai-codex-compat/compaction-checkpoint.ts +304 -0
- package/extensions/openai-codex-compat/config.ts +268 -0
- package/extensions/openai-codex-compat/footer.ts +99 -0
- package/extensions/openai-codex-compat/image-generation-render.ts +166 -0
- package/extensions/openai-codex-compat/image-generation.ts +355 -0
- package/extensions/openai-codex-compat/index.ts +65 -0
- package/extensions/openai-codex-compat/model-policy.ts +67 -0
- package/extensions/openai-codex-compat/namespaced-tools.ts +43 -0
- package/extensions/openai-codex-compat/native-history.ts +78 -0
- package/extensions/openai-codex-compat/remote-compaction.ts +198 -0
- package/extensions/openai-codex-compat/request-options.ts +121 -0
- package/extensions/openai-codex-compat/responses-replay.ts +33 -0
- package/extensions/openai-codex-compat/settings-pane.ts +298 -0
- package/extensions/openai-codex-compat/tool-runtime.ts +32 -0
- package/extensions/openai-codex-compat/tools.ts +70 -0
- package/extensions/openai-codex-compat/vendor/pi-ai/README.md +15 -0
- package/extensions/openai-codex-compat/vendor/pi-ai/openai-responses-serialization.ts +660 -0
- package/extensions/openai-codex-compat/web-run-description.txt +105 -0
- package/extensions/openai-codex-compat/web-run-output.ts +172 -0
- package/extensions/openai-codex-compat/web-run-render.ts +681 -0
- package/extensions/openai-codex-compat/web-run-schema.ts +301 -0
- package/extensions/openai-codex-compat/web-run.ts +164 -0
- package/package.json +63 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
|
|
3
|
+
export type WebRunSearchQuery = {
|
|
4
|
+
q: string;
|
|
5
|
+
recency?: number | null;
|
|
6
|
+
domains?: string[] | null;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type WebRunCommands = {
|
|
10
|
+
search_query?: WebRunSearchQuery[] | null;
|
|
11
|
+
image_query?: WebRunSearchQuery[] | null;
|
|
12
|
+
open?: Array<{
|
|
13
|
+
ref_id: string;
|
|
14
|
+
lineno?: number | null;
|
|
15
|
+
}> | null;
|
|
16
|
+
click?: Array<{
|
|
17
|
+
ref_id: string;
|
|
18
|
+
id: number;
|
|
19
|
+
}> | null;
|
|
20
|
+
find?: Array<{
|
|
21
|
+
ref_id: string;
|
|
22
|
+
pattern: string;
|
|
23
|
+
}> | null;
|
|
24
|
+
screenshot?: Array<{
|
|
25
|
+
ref_id: string;
|
|
26
|
+
pageno: number;
|
|
27
|
+
}> | null;
|
|
28
|
+
finance?: Array<{
|
|
29
|
+
ticker: string;
|
|
30
|
+
type: "equity" | "fund" | "crypto" | "index";
|
|
31
|
+
market?: string | null;
|
|
32
|
+
}> | null;
|
|
33
|
+
weather?: Array<{
|
|
34
|
+
location: string;
|
|
35
|
+
start?: string | null;
|
|
36
|
+
duration?: number | null;
|
|
37
|
+
}> | null;
|
|
38
|
+
sports?: Array<{
|
|
39
|
+
tool?: "sports" | null;
|
|
40
|
+
fn: "schedule" | "standings";
|
|
41
|
+
league: "nba" | "wnba" | "nfl" | "nhl" | "mlb" | "epl" | "ncaamb" | "ncaawb" | "ipl";
|
|
42
|
+
team?: string | null;
|
|
43
|
+
opponent?: string | null;
|
|
44
|
+
date_from?: string | null;
|
|
45
|
+
date_to?: string | null;
|
|
46
|
+
num_games?: number | null;
|
|
47
|
+
locale?: string | null;
|
|
48
|
+
}> | null;
|
|
49
|
+
time?: Array<{
|
|
50
|
+
utc_offset: string;
|
|
51
|
+
}> | null;
|
|
52
|
+
response_length?: "short" | "medium" | "long" | null;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Exact post-normalization `SearchCommands` schema emitted by Codex at
|
|
57
|
+
* upstream commit bb5054fe47abe73ecbbd454751066a28c89f4bb9. Codex parses the
|
|
58
|
+
* generated schema through its Responses JSON-schema subset before transport,
|
|
59
|
+
* which drops unsupported annotations such as `format` and `minimum`.
|
|
60
|
+
*/
|
|
61
|
+
export const WEB_RUN_PARAMETERS = Type.Unsafe<WebRunCommands>({
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
click: {
|
|
65
|
+
type: "array",
|
|
66
|
+
description: "Open links from previously opened pages.",
|
|
67
|
+
items: {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {
|
|
70
|
+
id: {
|
|
71
|
+
type: "integer",
|
|
72
|
+
description: "Numbered link id to open.",
|
|
73
|
+
},
|
|
74
|
+
ref_id: {
|
|
75
|
+
type: "string",
|
|
76
|
+
description: "Reference id containing the numbered link.",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
required: ["id", "ref_id"],
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
finance: {
|
|
83
|
+
type: "array",
|
|
84
|
+
description: "Look up prices for the given stock symbols.",
|
|
85
|
+
items: {
|
|
86
|
+
type: "object",
|
|
87
|
+
properties: {
|
|
88
|
+
market: {
|
|
89
|
+
type: "string",
|
|
90
|
+
description: 'ISO 3166-1 alpha-3 country code, "OTC", or "" for cryptocurrency.',
|
|
91
|
+
},
|
|
92
|
+
ticker: {
|
|
93
|
+
type: "string",
|
|
94
|
+
description: "Ticker symbol to look up.",
|
|
95
|
+
},
|
|
96
|
+
type: {
|
|
97
|
+
type: "string",
|
|
98
|
+
description: "Asset type to look up.",
|
|
99
|
+
enum: ["equity", "fund", "crypto", "index"],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
required: ["ticker", "type"],
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
find: {
|
|
106
|
+
type: "array",
|
|
107
|
+
description: "Find text patterns in pages.",
|
|
108
|
+
items: {
|
|
109
|
+
type: "object",
|
|
110
|
+
properties: {
|
|
111
|
+
pattern: {
|
|
112
|
+
type: "string",
|
|
113
|
+
description: "Text pattern to find.",
|
|
114
|
+
},
|
|
115
|
+
ref_id: {
|
|
116
|
+
type: "string",
|
|
117
|
+
description: "Reference id or URL to search within.",
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
required: ["pattern", "ref_id"],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
image_query: {
|
|
124
|
+
type: "array",
|
|
125
|
+
description: "Query the image search engine for a given list of queries.",
|
|
126
|
+
items: {
|
|
127
|
+
type: "object",
|
|
128
|
+
properties: {
|
|
129
|
+
domains: {
|
|
130
|
+
type: "array",
|
|
131
|
+
description: "Whether to filter by a specific list of domains.",
|
|
132
|
+
items: {
|
|
133
|
+
type: "string",
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
q: {
|
|
137
|
+
type: "string",
|
|
138
|
+
description: "Search query.",
|
|
139
|
+
},
|
|
140
|
+
recency: {
|
|
141
|
+
type: "integer",
|
|
142
|
+
description: "Whether to filter by recency, as a number of recent days.",
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
required: ["q"],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
open: {
|
|
149
|
+
type: "array",
|
|
150
|
+
description: "Open pages by reference id or URL.",
|
|
151
|
+
items: {
|
|
152
|
+
type: "object",
|
|
153
|
+
properties: {
|
|
154
|
+
lineno: {
|
|
155
|
+
type: "integer",
|
|
156
|
+
description: "Line number to position the page at.",
|
|
157
|
+
},
|
|
158
|
+
ref_id: {
|
|
159
|
+
type: "string",
|
|
160
|
+
description: "Reference id or URL to open.",
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
required: ["ref_id"],
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
response_length: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Set the length of the response to be returned.",
|
|
169
|
+
enum: ["short", "medium", "long"],
|
|
170
|
+
},
|
|
171
|
+
screenshot: {
|
|
172
|
+
type: "array",
|
|
173
|
+
description: "Take screenshots of PDF pages.",
|
|
174
|
+
items: {
|
|
175
|
+
type: "object",
|
|
176
|
+
properties: {
|
|
177
|
+
pageno: {
|
|
178
|
+
type: "integer",
|
|
179
|
+
description: "Zero-indexed PDF page number.",
|
|
180
|
+
},
|
|
181
|
+
ref_id: {
|
|
182
|
+
type: "string",
|
|
183
|
+
description: "Reference id or URL to screenshot.",
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
required: ["pageno", "ref_id"],
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
search_query: {
|
|
190
|
+
type: "array",
|
|
191
|
+
description: "Query the internet search engine for a given list of queries.",
|
|
192
|
+
items: {
|
|
193
|
+
type: "object",
|
|
194
|
+
properties: {
|
|
195
|
+
domains: {
|
|
196
|
+
type: "array",
|
|
197
|
+
description: "Whether to filter by a specific list of domains.",
|
|
198
|
+
items: {
|
|
199
|
+
type: "string",
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
q: {
|
|
203
|
+
type: "string",
|
|
204
|
+
description: "Search query.",
|
|
205
|
+
},
|
|
206
|
+
recency: {
|
|
207
|
+
type: "integer",
|
|
208
|
+
description: "Whether to filter by recency, as a number of recent days.",
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
required: ["q"],
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
sports: {
|
|
215
|
+
type: "array",
|
|
216
|
+
description: "Look up sports schedules and standings.",
|
|
217
|
+
items: {
|
|
218
|
+
type: "object",
|
|
219
|
+
properties: {
|
|
220
|
+
date_from: {
|
|
221
|
+
type: "string",
|
|
222
|
+
description: "Start date in YYYY-MM-DD format.",
|
|
223
|
+
},
|
|
224
|
+
date_to: {
|
|
225
|
+
type: "string",
|
|
226
|
+
description: "End date in YYYY-MM-DD format.",
|
|
227
|
+
},
|
|
228
|
+
fn: {
|
|
229
|
+
type: "string",
|
|
230
|
+
description: "Sports function to call.",
|
|
231
|
+
enum: ["schedule", "standings"],
|
|
232
|
+
},
|
|
233
|
+
league: {
|
|
234
|
+
type: "string",
|
|
235
|
+
description: "League to look up.",
|
|
236
|
+
enum: ["nba", "wnba", "nfl", "nhl", "mlb", "epl", "ncaamb", "ncaawb", "ipl"],
|
|
237
|
+
},
|
|
238
|
+
locale: {
|
|
239
|
+
type: "string",
|
|
240
|
+
description: "Locale for the lookup.",
|
|
241
|
+
},
|
|
242
|
+
num_games: {
|
|
243
|
+
type: "integer",
|
|
244
|
+
description: "Number of games to return.",
|
|
245
|
+
},
|
|
246
|
+
opponent: {
|
|
247
|
+
type: "string",
|
|
248
|
+
description: "Opponent to use with `team` when narrowing the lookup.",
|
|
249
|
+
},
|
|
250
|
+
team: {
|
|
251
|
+
type: "string",
|
|
252
|
+
description:
|
|
253
|
+
"Team to look up, using the common 3 or 4 letter alias used in broadcasts.",
|
|
254
|
+
},
|
|
255
|
+
tool: {
|
|
256
|
+
type: "string",
|
|
257
|
+
description: "Tool name for sports requests.",
|
|
258
|
+
enum: ["sports"],
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
required: ["fn", "league"],
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
time: {
|
|
265
|
+
type: "array",
|
|
266
|
+
description: "Get time for the given UTC offsets.",
|
|
267
|
+
items: {
|
|
268
|
+
type: "object",
|
|
269
|
+
properties: {
|
|
270
|
+
utc_offset: {
|
|
271
|
+
type: "string",
|
|
272
|
+
description: 'UTC offset formatted like "+03:00".',
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
required: ["utc_offset"],
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
weather: {
|
|
279
|
+
type: "array",
|
|
280
|
+
description: "Look up weather forecasts.",
|
|
281
|
+
items: {
|
|
282
|
+
type: "object",
|
|
283
|
+
properties: {
|
|
284
|
+
duration: {
|
|
285
|
+
type: "integer",
|
|
286
|
+
description: "Number of days to return. Defaults to 7.",
|
|
287
|
+
},
|
|
288
|
+
location: {
|
|
289
|
+
type: "string",
|
|
290
|
+
description: 'Location in "Country, Area, City" format.',
|
|
291
|
+
},
|
|
292
|
+
start: {
|
|
293
|
+
type: "string",
|
|
294
|
+
description: "Start date in YYYY-MM-DD format. Defaults to today.",
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
required: ["location"],
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
});
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import type { Model } from "@earendil-works/pi-ai";
|
|
4
|
+
import {
|
|
5
|
+
approximateTokens,
|
|
6
|
+
isObject,
|
|
7
|
+
truncateMiddleWithTokenBudget,
|
|
8
|
+
type JsonRecord,
|
|
9
|
+
type ResponsesItem,
|
|
10
|
+
} from "./codex-protocol.ts";
|
|
11
|
+
import { requestCodexJson, type CodexJsonRequestOptions } from "./codex-transport.ts";
|
|
12
|
+
import type { CodexCompatConfig, WebSearchMode } from "./config.ts";
|
|
13
|
+
import type { CodexToolBackgroundResolver } from "./codex-tool-surface.ts";
|
|
14
|
+
import { DEFAULT_CONFIG } from "./config.ts";
|
|
15
|
+
import { WEB_RUN_TOOL_NAME } from "./namespaced-tools.ts";
|
|
16
|
+
import { isCodexModel } from "./request-options.ts";
|
|
17
|
+
import { codexToolAuthentication, codexToolHistory } from "./tool-runtime.ts";
|
|
18
|
+
import { renderWebRunCall, renderWebRunResult, type WebRunDetails } from "./web-run-render.ts";
|
|
19
|
+
import { WEB_RUN_PARAMETERS } from "./web-run-schema.ts";
|
|
20
|
+
|
|
21
|
+
const SEARCH_ENDPOINT = "alpha/search";
|
|
22
|
+
const SEARCH_OUTPUT_TOKEN_BUDGET = 2_500;
|
|
23
|
+
const ASSISTANT_CONTEXT_TOKEN_BUDGET = 1_000;
|
|
24
|
+
|
|
25
|
+
const WEB_RUN_DESCRIPTION = readFileSync(
|
|
26
|
+
new URL("./web-run-description.txt", import.meta.url),
|
|
27
|
+
"utf8",
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export type { WebRunDetails } from "./web-run-render.ts";
|
|
31
|
+
|
|
32
|
+
type ConfigResolver = (ctx: ExtensionContext) => CodexCompatConfig;
|
|
33
|
+
type JsonRequester = (
|
|
34
|
+
model: Model<any>,
|
|
35
|
+
path: string,
|
|
36
|
+
body: JsonRecord,
|
|
37
|
+
options: CodexJsonRequestOptions,
|
|
38
|
+
) => Promise<unknown>;
|
|
39
|
+
|
|
40
|
+
function visibleMessage(item: ResponsesItem): JsonRecord | undefined {
|
|
41
|
+
if (item.type !== undefined && item.type !== "message") return undefined;
|
|
42
|
+
if (item.role !== "user" && item.role !== "assistant") return undefined;
|
|
43
|
+
if (!Array.isArray(item.content)) return undefined;
|
|
44
|
+
|
|
45
|
+
const content = item.content
|
|
46
|
+
.filter(isObject)
|
|
47
|
+
.filter((part) =>
|
|
48
|
+
item.role === "user" ? part.type === "input_text" : part.type === "output_text",
|
|
49
|
+
)
|
|
50
|
+
.filter((part) => typeof part.text === "string")
|
|
51
|
+
.map((part) => ({ type: part.type, text: part.text }));
|
|
52
|
+
if (content.length === 0) return undefined;
|
|
53
|
+
return { type: "message", role: item.role, content };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function truncateAssistantMessages(messages: JsonRecord[]): JsonRecord[] {
|
|
57
|
+
let remaining = ASSISTANT_CONTEXT_TOKEN_BUDGET;
|
|
58
|
+
const result: JsonRecord[] = [];
|
|
59
|
+
|
|
60
|
+
for (const message of messages) {
|
|
61
|
+
if (message.role !== "assistant" || !Array.isArray(message.content)) {
|
|
62
|
+
result.push(message);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const content: JsonRecord[] = [];
|
|
67
|
+
for (const part of message.content.filter(isObject)) {
|
|
68
|
+
if (part.type !== "output_text" || typeof part.text !== "string" || remaining === 0) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const tokens = approximateTokens(part.text);
|
|
72
|
+
if (tokens <= remaining) {
|
|
73
|
+
content.push(part);
|
|
74
|
+
remaining -= tokens;
|
|
75
|
+
} else {
|
|
76
|
+
content.push({
|
|
77
|
+
...part,
|
|
78
|
+
text: truncateMiddleWithTokenBudget(part.text, remaining),
|
|
79
|
+
});
|
|
80
|
+
remaining = 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (content.length > 0) result.push({ ...message, content });
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Build the same two-user-turn text tail used by standalone Codex search. */
|
|
89
|
+
export function recentSearchInput(history: readonly ResponsesItem[]): JsonRecord[] | undefined {
|
|
90
|
+
const visible = history.map(visibleMessage).filter((item): item is JsonRecord => Boolean(item));
|
|
91
|
+
const latestUser = visible.findLastIndex((item) => item.role === "user");
|
|
92
|
+
if (latestUser < 0) return undefined;
|
|
93
|
+
|
|
94
|
+
const throughLatestUser = visible.slice(0, latestUser + 1);
|
|
95
|
+
const userIndexes = throughLatestUser
|
|
96
|
+
.map((item, index) => (item.role === "user" ? index : -1))
|
|
97
|
+
.filter((index) => index >= 0);
|
|
98
|
+
const start = userIndexes.at(-2) ?? userIndexes.at(-1);
|
|
99
|
+
if (start === undefined) return undefined;
|
|
100
|
+
return truncateAssistantMessages(throughLatestUser.slice(start));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function externalWebAccess(mode: WebSearchMode): boolean | "indexed" {
|
|
104
|
+
if (mode === "live") return true;
|
|
105
|
+
if (mode === "indexed") return "indexed";
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export default function registerWebRun(
|
|
110
|
+
pi: ExtensionAPI,
|
|
111
|
+
resolveConfig: ConfigResolver,
|
|
112
|
+
resolveToolBackground: CodexToolBackgroundResolver = () => DEFAULT_CONFIG.toolBackground,
|
|
113
|
+
requestJson: JsonRequester = requestCodexJson,
|
|
114
|
+
): void {
|
|
115
|
+
pi.registerTool({
|
|
116
|
+
name: WEB_RUN_TOOL_NAME,
|
|
117
|
+
label: WEB_RUN_TOOL_NAME,
|
|
118
|
+
description: WEB_RUN_DESCRIPTION,
|
|
119
|
+
parameters: WEB_RUN_PARAMETERS,
|
|
120
|
+
executionMode: "parallel",
|
|
121
|
+
renderShell: "self",
|
|
122
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
123
|
+
const model = ctx.model;
|
|
124
|
+
if (!isCodexModel(model)) {
|
|
125
|
+
throw new Error("web.run is available only with an OpenAI Codex model.");
|
|
126
|
+
}
|
|
127
|
+
const authentication = await codexToolAuthentication(ctx, model);
|
|
128
|
+
const config = resolveConfig(ctx);
|
|
129
|
+
const history = codexToolHistory(pi, ctx, model, config.imageDetail);
|
|
130
|
+
const input = recentSearchInput(history);
|
|
131
|
+
const body: JsonRecord = {
|
|
132
|
+
id: ctx.sessionManager.getSessionId(),
|
|
133
|
+
model: model.id,
|
|
134
|
+
...(input ? { input } : {}),
|
|
135
|
+
commands: params,
|
|
136
|
+
settings: {
|
|
137
|
+
allowed_callers: ["direct"],
|
|
138
|
+
external_web_access: externalWebAccess(config.webSearch),
|
|
139
|
+
},
|
|
140
|
+
max_output_tokens: SEARCH_OUTPUT_TOKEN_BUDGET,
|
|
141
|
+
};
|
|
142
|
+
const response = await requestJson(model, SEARCH_ENDPOINT, body, {
|
|
143
|
+
...authentication,
|
|
144
|
+
...(signal ? { signal } : {}),
|
|
145
|
+
});
|
|
146
|
+
if (!isObject(response) || typeof response["output"] !== "string") {
|
|
147
|
+
throw new Error("OpenAI Codex returned an invalid standalone web-search response.");
|
|
148
|
+
}
|
|
149
|
+
const results = Array.isArray(response["results"])
|
|
150
|
+
? response["results"].map((result) => structuredClone(result))
|
|
151
|
+
: undefined;
|
|
152
|
+
return {
|
|
153
|
+
content: [{ type: "text", text: response["output"] }],
|
|
154
|
+
details: (results ? { results } : {}) satisfies WebRunDetails,
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
renderCall(args, theme, context) {
|
|
158
|
+
return renderWebRunCall(args, theme, context, resolveToolBackground);
|
|
159
|
+
},
|
|
160
|
+
renderResult(result, options, theme, context) {
|
|
161
|
+
return renderWebRunResult(result, options, theme, context, resolveToolBackground);
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-openai-codex-compat",
|
|
3
|
+
"version": "0.0.1-alpha.0",
|
|
4
|
+
"description": "OpenAI Codex compatibility for Pi with native compaction, fast mode, and Codex-optimized capabilities",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pi-package"
|
|
7
|
+
],
|
|
8
|
+
"homepage": "https://github.com/2h2d-co/pi-openai-codex-compat#readme",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/2h2d-co/pi-openai-codex-compat/issues"
|
|
11
|
+
},
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": {
|
|
14
|
+
"name": "Kaan Ozdokmeci",
|
|
15
|
+
"email": "kaan@ozdokmeci.com",
|
|
16
|
+
"url": ""
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/2h2d-co/pi-openai-codex-compat.git"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"extensions/openai-codex-compat",
|
|
24
|
+
"README.md",
|
|
25
|
+
"CHANGELOG.md",
|
|
26
|
+
"LICENSE",
|
|
27
|
+
"LICENSES",
|
|
28
|
+
"THIRD_PARTY_NOTICES.md"
|
|
29
|
+
],
|
|
30
|
+
"type": "module",
|
|
31
|
+
"scripts": {
|
|
32
|
+
"check": "hk check --all --check",
|
|
33
|
+
"test": "node --test --test-concurrency=1 test/*.test.ts",
|
|
34
|
+
"fmt": "oxfmt",
|
|
35
|
+
"lint": "oxlint",
|
|
36
|
+
"lint:fix": "oxlint --fix"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@earendil-works/pi-ai": "0.83.0",
|
|
40
|
+
"@earendil-works/pi-coding-agent": "0.83.0",
|
|
41
|
+
"@earendil-works/pi-tui": "0.83.0",
|
|
42
|
+
"@types/node": "22.20.1",
|
|
43
|
+
"oxfmt": "0.60.0",
|
|
44
|
+
"oxlint": "1.75.0",
|
|
45
|
+
"oxlint-tsgolint": "7.0.2001",
|
|
46
|
+
"typebox": "1.3.7",
|
|
47
|
+
"typescript": "7.0.2"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@earendil-works/pi-ai": ">=0.83.0 <0.84.0",
|
|
51
|
+
"@earendil-works/pi-coding-agent": ">=0.83.0 <0.84.0",
|
|
52
|
+
"@earendil-works/pi-tui": ">=0.83.0 <0.84.0",
|
|
53
|
+
"typebox": "*"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=22.19.0"
|
|
57
|
+
},
|
|
58
|
+
"pi": {
|
|
59
|
+
"extensions": [
|
|
60
|
+
"./extensions/openai-codex-compat/index.ts"
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
}
|