@howaboua/pi-codex-conversion 1.0.5 → 1.0.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/package.json
CHANGED
package/src/patch/paths.ts
CHANGED
|
@@ -8,20 +8,17 @@ export function normalizePatchPath({ path }: { path: string }): string {
|
|
|
8
8
|
return withoutAt.replace(/^['"]|['"]$/g, "");
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
//
|
|
12
|
-
//
|
|
11
|
+
// Relative patch paths stay anchored to ctx.cwd. Absolute patch paths are
|
|
12
|
+
// accepted as-is so the adapter can match Codex-style path usage.
|
|
13
13
|
export function resolvePatchPath({ cwd, patchPath }: { cwd: string; patchPath: string }): string {
|
|
14
14
|
const normalized = normalizePatchPath({ path: patchPath });
|
|
15
15
|
if (!normalized) {
|
|
16
16
|
throw new DiffError("Patch path cannot be empty");
|
|
17
17
|
}
|
|
18
|
-
if (isAbsolute(normalized)) {
|
|
19
|
-
throw new DiffError("We do not support absolute paths.");
|
|
20
|
-
}
|
|
21
18
|
|
|
22
|
-
const absolutePath = resolve(cwd, normalized);
|
|
19
|
+
const absolutePath = isAbsolute(normalized) ? normalized : resolve(cwd, normalized);
|
|
23
20
|
const rel = relative(cwd, absolutePath);
|
|
24
|
-
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
21
|
+
if (!isAbsolute(normalized) && (rel.startsWith("..") || isAbsolute(rel))) {
|
|
25
22
|
throw new DiffError(`Path escapes working directory: ${normalized}`);
|
|
26
23
|
}
|
|
27
24
|
return absolutePath;
|
|
@@ -4,24 +4,12 @@ export interface PromptSkill {
|
|
|
4
4
|
filePath: string;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
const PI_INTRO =
|
|
8
|
-
"You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.";
|
|
9
|
-
const CODEX_INTRO =
|
|
10
|
-
"You are Codex running inside pi, a coding agent harness. Work directly in the user's workspace and finish the task end-to-end when feasible.";
|
|
11
|
-
|
|
12
7
|
const CODEX_GUIDELINES = [
|
|
13
8
|
"Use `parallel` only when tool calls are independent and can safely run at the same time.",
|
|
14
9
|
"Use `write_stdin` when an exec session returns `session_id`, and continue until `exit_code` is present.",
|
|
15
10
|
"Do not request `tty` unless interactive terminal behavior is required.",
|
|
16
11
|
];
|
|
17
12
|
|
|
18
|
-
function rewriteIntro(prompt: string): string {
|
|
19
|
-
if (!prompt.startsWith(PI_INTRO)) {
|
|
20
|
-
return prompt;
|
|
21
|
-
}
|
|
22
|
-
return `${CODEX_INTRO}${prompt.slice(PI_INTRO.length)}`;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
13
|
function insertBeforeTrailingContext(prompt: string, section: string): string {
|
|
26
14
|
const currentDateIndex = prompt.lastIndexOf("\nCurrent date:");
|
|
27
15
|
if (currentDateIndex !== -1) {
|
|
@@ -114,5 +102,5 @@ function injectGuidelines(prompt: string): string {
|
|
|
114
102
|
}
|
|
115
103
|
|
|
116
104
|
export function buildCodexSystemPrompt(basePrompt: string, options: { skills?: PromptSkill[]; shell?: string } = {}): string {
|
|
117
|
-
return injectShell(injectSkills(injectGuidelines(
|
|
105
|
+
return injectShell(injectSkills(injectGuidelines(basePrompt), options.skills ?? []), options.shell);
|
|
118
106
|
}
|
|
@@ -65,7 +65,7 @@ export interface ExecSessionManager {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
const DEFAULT_EXEC_YIELD_TIME_MS = 10_000;
|
|
68
|
-
const DEFAULT_WRITE_YIELD_TIME_MS =
|
|
68
|
+
const DEFAULT_WRITE_YIELD_TIME_MS = 10_000;
|
|
69
69
|
const DEFAULT_MAX_OUTPUT_TOKENS = 10_000;
|
|
70
70
|
const MIN_YIELD_TIME_MS = 250;
|
|
71
71
|
const MAX_YIELD_TIME_MS = 30_000;
|
|
@@ -292,18 +292,24 @@ export function createExecSessionManager(): ExecSessionManager {
|
|
|
292
292
|
notify(session);
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
function
|
|
296
|
-
if (session.
|
|
295
|
+
function waitForExitOrTimeout(session: ExecSession, yieldTimeMs: number): Promise<number> {
|
|
296
|
+
if (session.exitCode !== undefined && session.exitCode !== null) {
|
|
297
297
|
return Promise.resolve(0);
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
const startedAt = Date.now();
|
|
301
301
|
return new Promise((resolvePromise) => {
|
|
302
302
|
const onWake = () => {
|
|
303
|
+
if (session.exitCode === undefined || session.exitCode === null) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
303
306
|
cleanup();
|
|
304
307
|
resolvePromise(Date.now() - startedAt);
|
|
305
308
|
};
|
|
306
|
-
const timeout = setTimeout(
|
|
309
|
+
const timeout = setTimeout(() => {
|
|
310
|
+
cleanup();
|
|
311
|
+
resolvePromise(Date.now() - startedAt);
|
|
312
|
+
}, yieldTimeMs);
|
|
307
313
|
const cleanup = () => {
|
|
308
314
|
clearTimeout(timeout);
|
|
309
315
|
session.listeners.delete(onWake);
|
|
@@ -432,7 +438,7 @@ export function createExecSessionManager(): ExecSessionManager {
|
|
|
432
438
|
sessions.set(session.id, session);
|
|
433
439
|
rememberCommand(session.id, session.command);
|
|
434
440
|
|
|
435
|
-
const waitedMs = await
|
|
441
|
+
const waitedMs = await waitForExitOrTimeout(session, clampYieldTime(input.yield_time_ms, DEFAULT_EXEC_YIELD_TIME_MS));
|
|
436
442
|
return makeResult(session, waitedMs, input.max_output_tokens);
|
|
437
443
|
},
|
|
438
444
|
write: async (input) => {
|
|
@@ -450,7 +456,7 @@ export function createExecSessionManager(): ExecSessionManager {
|
|
|
450
456
|
}
|
|
451
457
|
const waitedMs =
|
|
452
458
|
session.exitCode === undefined
|
|
453
|
-
? await
|
|
459
|
+
? await waitForExitOrTimeout(session, clampYieldTime(input.yield_time_ms, DEFAULT_WRITE_YIELD_TIME_MS))
|
|
454
460
|
: 0;
|
|
455
461
|
return makeResult(session, waitedMs, input.max_output_tokens);
|
|
456
462
|
},
|
|
@@ -9,8 +9,12 @@ const WEB_SEARCH_LOCAL_EXECUTION_MESSAGE =
|
|
|
9
9
|
export const WEB_SEARCH_SESSION_NOTE_TYPE = "codex-web-search-session-note";
|
|
10
10
|
export const WEB_SEARCH_SESSION_NOTE_TEXT =
|
|
11
11
|
"Native OpenAI Codex web search is enabled for this session. Search runs silently and is not surfaced as a separate tool call.";
|
|
12
|
+
const WEB_SEARCH_MULTIMODAL_CONTENT_TYPES = ["text", "image"] as const;
|
|
12
13
|
|
|
13
|
-
const WEB_SEARCH_PARAMETERS = Type.
|
|
14
|
+
const WEB_SEARCH_PARAMETERS = Type.Unsafe<Record<string, never>>({
|
|
15
|
+
type: "object",
|
|
16
|
+
additionalProperties: false,
|
|
17
|
+
});
|
|
14
18
|
|
|
15
19
|
interface FunctionToolPayload {
|
|
16
20
|
type?: unknown;
|
|
@@ -22,6 +26,12 @@ interface ResponsesPayload {
|
|
|
22
26
|
[key: string]: unknown;
|
|
23
27
|
}
|
|
24
28
|
|
|
29
|
+
interface ResponsesWebSearchTool {
|
|
30
|
+
type: "web_search";
|
|
31
|
+
external_web_access: true;
|
|
32
|
+
search_content_types?: string[];
|
|
33
|
+
}
|
|
34
|
+
|
|
25
35
|
export function supportsNativeWebSearch(model: ExtensionContext["model"]): boolean {
|
|
26
36
|
return isOpenAICodexModel(model);
|
|
27
37
|
}
|
|
@@ -34,6 +44,14 @@ export function shouldShowWebSearchSessionNote(
|
|
|
34
44
|
return hasUI && !alreadyShown && supportsNativeWebSearch(model);
|
|
35
45
|
}
|
|
36
46
|
|
|
47
|
+
export function supportsMultimodalNativeWebSearch(model: ExtensionContext["model"]): boolean {
|
|
48
|
+
if (!supportsNativeWebSearch(model)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const id = (model?.id ?? "").toLowerCase();
|
|
52
|
+
return !id.includes("spark");
|
|
53
|
+
}
|
|
54
|
+
|
|
37
55
|
function isWebSearchFunctionTool(tool: unknown): tool is FunctionToolPayload {
|
|
38
56
|
return !!tool && typeof tool === "object" && (tool as FunctionToolPayload).type === "function" && (tool as FunctionToolPayload).name === "web_search";
|
|
39
57
|
}
|
|
@@ -55,10 +73,14 @@ export function rewriteNativeWebSearchTool(payload: unknown, model: ExtensionCon
|
|
|
55
73
|
}
|
|
56
74
|
rewritten = true;
|
|
57
75
|
// Match Codex's native tool shape rather than exposing a synthetic function tool.
|
|
58
|
-
|
|
76
|
+
const nativeTool: ResponsesWebSearchTool = {
|
|
59
77
|
type: "web_search",
|
|
60
78
|
external_web_access: true,
|
|
61
79
|
};
|
|
80
|
+
if (supportsMultimodalNativeWebSearch(model)) {
|
|
81
|
+
nativeTool.search_content_types = [...WEB_SEARCH_MULTIMODAL_CONTENT_TYPES];
|
|
82
|
+
}
|
|
83
|
+
return nativeTool;
|
|
62
84
|
});
|
|
63
85
|
|
|
64
86
|
if (!rewritten) {
|
|
@@ -75,8 +97,10 @@ export function createWebSearchTool(): ToolDefinition<typeof WEB_SEARCH_PARAMETE
|
|
|
75
97
|
return {
|
|
76
98
|
name: "web_search",
|
|
77
99
|
label: "web_search",
|
|
78
|
-
description:
|
|
79
|
-
|
|
100
|
+
description:
|
|
101
|
+
"Search the web for sources relevant to the current task. Use it when you need up-to-date information, external references, or broader context beyond the workspace.",
|
|
102
|
+
promptSnippet:
|
|
103
|
+
"Search the web for sources relevant to the current task. Use it when you need up-to-date information, external references, or broader context beyond the workspace.",
|
|
80
104
|
parameters: WEB_SEARCH_PARAMETERS,
|
|
81
105
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
82
106
|
if (!supportsNativeWebSearch(ctx.model)) {
|