@howaboua/pi-codex-conversion 1.0.18 → 1.0.20

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 CHANGED
@@ -4,16 +4,17 @@ Codex-oriented adapter for [Pi](https://github.com/badlogic/pi-mono).
4
4
 
5
5
  This package replaces Pi's default Codex/GPT experience with a narrower Codex-like surface while staying close to Pi's own runtime and prompt construction:
6
6
 
7
- - swaps active tools to `exec_command`, `write_stdin`, `apply_patch`, `view_image`, and native OpenAI Codex Responses `web_search` on `openai-codex`
7
+ - swaps active tools to `exec_command`, `write_stdin`, `apply_patch`, `view_image`, plus native OpenAI Codex Responses `web_search` and `image_generation` on `openai-codex`
8
+ - saves native Codex image-generation outputs into `.pi/openai-codex-images/` at the workspace/repo root and mirrors the newest image to `.pi/openai-codex-images/latest.png`
8
9
  - preserves Pi's composed system prompt and applies a narrow Codex-oriented delta on top
9
10
  - renders exec activity with Codex-style command and background-terminal labels
10
11
  - renders `apply_patch` calls with Codex-style `Added` / `Edited` / `Deleted` diff blocks and Pi-style colored diff lines
11
- - targets modern Pi tool/rendering APIs and is aligned with Pi `0.67.x`
12
+ - targets modern Pi tool/rendering APIs and is aligned with Pi `0.69.x`
12
13
 
13
14
  ![Available tools](./available-tools.png)
14
15
 
15
16
  > [!NOTE]
16
- > Native OpenAI Codex Responses web search runs silently. Pi does not expose native web-search usage events to extensions, so the adapter shows a one-time session notice instead of per-search tool-call history.
17
+ > Native OpenAI Codex Responses web search activity is surfaced as merged foldable status messages. Pi still does not expose native web-search usage as true tool-call rows.
17
18
 
18
19
  ## Active tools in adapter mode
19
20
 
@@ -22,8 +23,9 @@ When the adapter is active, the LLM sees these tools:
22
23
  - `exec_command` — shell execution with Codex-style `cmd` parameters and resumable sessions
23
24
  - `write_stdin` — continue or poll a running exec session
24
25
  - `apply_patch` — patch tool
25
- - `view_image` — image-only wrapper around Pi's native image reading, enabled only for image-capable models
26
26
  - `web_search` — native OpenAI Codex Responses web search, enabled only on the `openai-codex` provider
27
+ - `image_generation` — native OpenAI Codex Responses image generation, enabled only on image-capable `openai-codex` models
28
+ - `view_image` — image-only wrapper around Pi's native image reading, enabled only for image-capable models
27
29
 
28
30
  Notably:
29
31
 
@@ -61,7 +63,9 @@ npm run check
61
63
  - `write_stdin({ session_id, chars: "y\\n" })` renders like `Interacted with background terminal`
62
64
  - `view_image({ path: "/absolute/path/to/screenshot.png" })` is available on image-capable models
63
65
  - `web_search` is surfaced only on `openai-codex`, and the adapter rewrites it into the native OpenAI Responses `type: "web_search"` payload instead of executing a local function tool
64
- - when native web search is available, the adapter shows a one-time session notice; individual searches are not surfaced because Pi does not expose native web-search execution events to extensions
66
+ - `image_generation` is surfaced only on image-capable `openai-codex` models, and the adapter rewrites it into the native OpenAI Responses `type: "image_generation", output_format: "png"` payload instead of executing a local function tool
67
+ - native `image_generation` outputs are saved under `.pi/openai-codex-images/` at the workspace/repo root, with the newest image mirrored to `.pi/openai-codex-images/latest.png`
68
+ - when native web search is available, the adapter shows a one-time session notice and merged foldable search-activity messages instead of native tool-call rows
65
69
  - `apply_patch` partial failures stay inline in the patch row so successful and failed file entries can be seen together
66
70
 
67
71
  Raw command output is still available by expanding the tool result.
@@ -138,9 +142,10 @@ That keeps the prompt much closer to `pi-mono` while still steering the model to
138
142
  - When you switch away from those models, Pi restores the previous active tool set.
139
143
  - `view_image` resolves paths against the active session cwd and only exposes `detail: "original"` for Codex-family image-capable models.
140
144
  - `web_search` is exposed only for the `openai-codex` provider and is forwarded as the native OpenAI Codex Responses web search tool.
145
+ - `image_generation` is exposed only for image-capable `openai-codex` models and is forwarded as the native OpenAI Codex Responses image-generation tool.
146
+ - generated images are written under `.pi/openai-codex-images/` at the workspace/repo root, and the latest image is mirrored to `.pi/openai-codex-images/latest.png`.
141
147
  - `apply_patch` paths stay restricted to the current working directory.
142
148
  - partial `apply_patch` failures stay in the original patch block and highlight the failed entry instead of adding a second warning row.
143
- - `apply_patch` uses Pi's self-rendered tool shell mode for more stable large patch previews on current Pi versions.
144
149
  - `exec_command` / `write_stdin` use a custom PTY-backed session manager via `node-pty` for interactive sessions.
145
150
  - tiny `exec_command` waits are clamped for non-interactive commands so short runs do not burn an avoidable follow-up tool call.
146
151
  - empty `write_stdin` polls are clamped to a meaningful minimum wait so long-running processes are not repolled too aggressively.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@howaboua/pi-codex-conversion",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "Codex-oriented tool and prompt adapter for pi coding agent",
5
5
  "type": "module",
6
6
  "repository": {
@@ -51,19 +51,24 @@
51
51
  "access": "public"
52
52
  },
53
53
  "peerDependencies": {
54
- "@mariozechner/pi-coding-agent": "^0.67.0",
55
- "@mariozechner/pi-tui": "^0.67.0",
56
- "@sinclair/typebox": "*"
54
+ "@mariozechner/pi-ai": "^0.69.0",
55
+ "@mariozechner/pi-coding-agent": "^0.69.0",
56
+ "@mariozechner/pi-tui": "^0.69.0",
57
+ "typebox": "^1.1.24"
57
58
  },
58
59
  "devDependencies": {
59
- "@mariozechner/pi-coding-agent": "^0.67.3",
60
- "@mariozechner/pi-tui": "^0.67.3",
60
+ "@mariozechner/pi-ai": "^0.69.0",
61
+ "@mariozechner/pi-coding-agent": "^0.69.0",
62
+ "@mariozechner/pi-tui": "^0.69.0",
61
63
  "tsx": "^4.20.5",
64
+ "typebox": "^1.1.24",
62
65
  "typescript": "^5.9.3"
63
66
  },
64
67
  "dependencies": {
65
68
  "node-pty": "^1.1.0",
69
+ "partial-json": "^0.1.7",
66
70
  "tree-sitter-bash": "^0.25.1",
67
- "web-tree-sitter": "^0.26.7"
71
+ "web-tree-sitter": "^0.26.7",
72
+ "ws": "^8.20.0"
68
73
  }
69
74
  }
@@ -4,5 +4,6 @@ export const STATUS_TEXT = "\u001b[38;2;0;76;255mCodex adapter\u001b[0m";
4
4
  export const DEFAULT_TOOL_NAMES = ["read", "bash", "edit", "write"];
5
5
 
6
6
  export const CORE_ADAPTER_TOOL_NAMES = ["exec_command", "write_stdin", "apply_patch"];
7
+ export const IMAGE_GENERATION_TOOL_NAME = "image_generation";
7
8
  export const VIEW_IMAGE_TOOL_NAME = "view_image";
8
9
  export const WEB_SEARCH_TOOL_NAME = "web_search";
package/src/index.ts CHANGED
@@ -1,11 +1,25 @@
1
1
  import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
2
2
  import { getCodexRuntimeShell } from "./adapter/runtime-shell.ts";
3
- import { CORE_ADAPTER_TOOL_NAMES, DEFAULT_TOOL_NAMES, STATUS_KEY, STATUS_TEXT, VIEW_IMAGE_TOOL_NAME, WEB_SEARCH_TOOL_NAME } from "./adapter/tool-set.ts";
3
+ import {
4
+ CORE_ADAPTER_TOOL_NAMES,
5
+ DEFAULT_TOOL_NAMES,
6
+ IMAGE_GENERATION_TOOL_NAME,
7
+ STATUS_KEY,
8
+ STATUS_TEXT,
9
+ VIEW_IMAGE_TOOL_NAME,
10
+ WEB_SEARCH_TOOL_NAME,
11
+ } from "./adapter/tool-set.ts";
4
12
  import { clearApplyPatchRenderState, registerApplyPatchTool } from "./tools/apply-patch-tool.ts";
5
13
  import { isCodexLikeContext, isOpenAICodexContext } from "./adapter/codex-model.ts";
6
14
  import { createExecCommandTracker } from "./tools/exec-command-state.ts";
7
15
  import { registerExecCommandTool } from "./tools/exec-command-tool.ts";
8
16
  import { createExecSessionManager } from "./tools/exec-session-manager.ts";
17
+ import {
18
+ IMAGE_SAVE_DISPLAY_MESSAGE_TYPE,
19
+ WEB_SEARCH_ACTIVITY_MESSAGE_TYPE,
20
+ registerOpenAICodexCustomProvider,
21
+ } from "./providers/openai-codex-custom-provider.ts";
22
+ import { registerImageGenerationTool, rewriteNativeImageGenerationTool, supportsNativeImageGeneration } from "./tools/image-generation-tool.ts";
9
23
  import { buildCodexSystemPrompt, extractPiPromptSkills, type PromptSkill } from "./prompt/build-system-prompt.ts";
10
24
  import { registerViewImageTool, supportsOriginalImageDetail } from "./tools/view-image-tool.ts";
11
25
  import {
@@ -21,12 +35,13 @@ import { registerWriteStdinTool } from "./tools/write-stdin-tool.ts";
21
35
 
22
36
  interface AdapterState {
23
37
  enabled: boolean;
38
+ cwd: string;
24
39
  previousToolNames?: string[];
25
40
  promptSkills: PromptSkill[];
26
41
  webSearchNoticeShown: boolean;
27
42
  }
28
43
 
29
- const ADAPTER_TOOL_NAMES = [...CORE_ADAPTER_TOOL_NAMES, VIEW_IMAGE_TOOL_NAME, WEB_SEARCH_TOOL_NAME];
44
+ const ADAPTER_TOOL_NAMES = [...CORE_ADAPTER_TOOL_NAMES, WEB_SEARCH_TOOL_NAME, IMAGE_GENERATION_TOOL_NAME, VIEW_IMAGE_TOOL_NAME];
30
45
 
31
46
  function getCommandArg(args: unknown): string | undefined {
32
47
  if (!args || typeof args !== "object" || !("cmd" in args) || typeof args.cmd !== "string") {
@@ -47,12 +62,16 @@ function isToolCallOnlyAssistantMessage(message: unknown): boolean {
47
62
 
48
63
  export default function codexConversion(pi: ExtensionAPI) {
49
64
  const tracker = createExecCommandTracker();
50
- const state: AdapterState = { enabled: false, promptSkills: [], webSearchNoticeShown: false };
65
+ const state: AdapterState = { enabled: false, cwd: process.cwd(), promptSkills: [], webSearchNoticeShown: false };
51
66
  const sessions = createExecSessionManager();
52
67
 
68
+ registerOpenAICodexCustomProvider(pi, {
69
+ getCurrentCwd: () => state.cwd,
70
+ });
53
71
  registerApplyPatchTool(pi);
54
72
  registerExecCommandTool(pi, tracker, sessions);
55
73
  registerWriteStdinTool(pi, sessions);
74
+ registerImageGenerationTool(pi);
56
75
  registerWebSearchTool(pi);
57
76
  registerWebSearchSessionNoteRenderer(pi);
58
77
 
@@ -61,6 +80,7 @@ export default function codexConversion(pi: ExtensionAPI) {
61
80
  });
62
81
 
63
82
  pi.on("session_start", async (_event, ctx) => {
83
+ state.cwd = ctx.cwd;
64
84
  state.webSearchNoticeShown = false;
65
85
  clearApplyPatchRenderState();
66
86
  tracker.clear();
@@ -68,6 +88,7 @@ export default function codexConversion(pi: ExtensionAPI) {
68
88
  });
69
89
 
70
90
  pi.on("model_select", async (_event, ctx) => {
91
+ state.cwd = ctx.cwd;
71
92
  syncAdapter(pi, ctx, state);
72
93
  });
73
94
 
@@ -110,16 +131,23 @@ export default function codexConversion(pi: ExtensionAPI) {
110
131
  });
111
132
 
112
133
  pi.on("before_provider_request", async (event, ctx) => {
134
+ state.cwd = ctx.cwd;
113
135
  if (!isOpenAICodexContext(ctx)) {
114
136
  return undefined;
115
137
  }
116
- return rewriteNativeWebSearchTool(event.payload, ctx.model);
138
+ return rewriteNativeImageGenerationTool(rewriteNativeWebSearchTool(event.payload, ctx.model), ctx.model);
117
139
  });
118
140
 
119
141
  pi.on("context", async (event) => {
120
142
  return {
121
143
  messages: event.messages.filter(
122
- (message) => !(message.role === "custom" && message.customType === WEB_SEARCH_SESSION_NOTE_TYPE),
144
+ (message) =>
145
+ !(
146
+ message.role === "custom" &&
147
+ (message.customType === WEB_SEARCH_SESSION_NOTE_TYPE ||
148
+ message.customType === WEB_SEARCH_ACTIVITY_MESSAGE_TYPE ||
149
+ message.customType === IMAGE_SAVE_DISPLAY_MESSAGE_TYPE)
150
+ ),
123
151
  ),
124
152
  };
125
153
  });
@@ -169,12 +197,15 @@ function setStatus(ctx: ExtensionContext, enabled: boolean): void {
169
197
 
170
198
  function getAdapterToolNames(ctx: ExtensionContext): string[] {
171
199
  const toolNames = [...CORE_ADAPTER_TOOL_NAMES];
172
- if (Array.isArray(ctx.model?.input) && ctx.model.input.includes("image")) {
173
- toolNames.push(VIEW_IMAGE_TOOL_NAME);
174
- }
175
200
  if (supportsNativeWebSearch(ctx.model)) {
176
201
  toolNames.push(WEB_SEARCH_TOOL_NAME);
177
202
  }
203
+ if (supportsNativeImageGeneration(ctx.model)) {
204
+ toolNames.push(IMAGE_GENERATION_TOOL_NAME);
205
+ }
206
+ if (Array.isArray(ctx.model?.input) && ctx.model.input.includes("image")) {
207
+ toolNames.push(VIEW_IMAGE_TOOL_NAME);
208
+ }
178
209
  return toolNames;
179
210
  }
180
211
 
@@ -13,6 +13,7 @@ const CODEX_GUIDELINES = [
13
13
  "For short or non-interactive commands, prefer the default `exec_command` wait instead of a tiny `yield_time_ms` that forces an extra follow-up call.",
14
14
  "When polling a running exec session with empty `chars`, wait meaningfully between polls and do not repeatedly poll by reflex.",
15
15
  "Do not request `tty` unless interactive terminal behavior is required.",
16
+ "Native `image_generation` outputs are saved under `.pi/openai-codex-images/` and mirrored to `.pi/openai-codex-images/latest.png`. Use `view_image` only when pixel-level inspection is necessary.",
16
17
  ];
17
18
 
18
19
  function insertBeforeTrailingContext(prompt: string, section: string): string {