@howaboua/pi-codex-conversion 1.5.5-dev.25.f80a775 → 1.5.5-dev.26.0f1b086
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 +6 -2
- package/package.json +1 -1
- package/src/adapter/activation.ts +37 -5
- package/src/adapter/config.ts +3 -0
- package/src/adapter/skills.ts +8 -0
- package/src/adapter/tool-set.ts +5 -2
- package/src/codex-settings/ui.ts +17 -3
- package/src/index.ts +11 -6
- package/src/providers/openai-codex-custom-provider.ts +2 -1
- package/src/tools/web-search-tool.ts +22 -9
- package/vendor/apply-patch/win32-arm64/apply_patch.exe +0 -0
- package/vendor/apply-patch/win32-x64/apply_patch.exe +0 -0
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ When the adapter is active, the LLM sees these tools:
|
|
|
26
26
|
- `exec_command` — shell execution with Codex-style `cmd` parameters and resumable sessions
|
|
27
27
|
- `write_stdin` — continue or poll a running exec session
|
|
28
28
|
- `apply_patch` — patch tool
|
|
29
|
-
- `
|
|
29
|
+
- `web.run` — native OpenAI Codex Responses web search, enabled only on the `openai-codex` provider
|
|
30
30
|
- `image_generation` — native OpenAI Codex Responses image generation, enabled only on image-capable `openai-codex` models
|
|
31
31
|
- `view_image` — image-only wrapper around Pi's native image reading, enabled only for image-capable models
|
|
32
32
|
|
|
@@ -50,6 +50,10 @@ Use `/codex` to change adapter settings.
|
|
|
50
50
|
|
|
51
51
|
Settings are saved globally in `~/.pi/agent/pi-codex-conversion.json`.
|
|
52
52
|
|
|
53
|
+
The settings UI also has an **Overrides** tab. These options intentionally do not have `/codex ...` command shortcuts:
|
|
54
|
+
|
|
55
|
+
- add only the Pi `apply_patch` tool for GPT/Codex models while keeping Pi's default toolkit, prompt, provider behavior, and compaction flow
|
|
56
|
+
|
|
53
57
|
When `all` is on, non-Codex providers get the shell, patch, skill, and prompt-adapter behavior, but keep their normal Pi provider path. Native web search, native image generation, and priority service tier stay limited to the OpenAI Codex provider. Verbosity is applied to Responses API providers.
|
|
54
58
|
|
|
55
59
|
The footer shows the active state, for example:
|
|
@@ -83,7 +87,7 @@ Raw command output is still available by expanding the tool result.
|
|
|
83
87
|
- `exec_command` and `write_stdin` use a PTY-backed session manager for interactive commands and long-running processes.
|
|
84
88
|
- `apply_patch` accepts absolute paths as-is and resolves relative paths against the current working directory.
|
|
85
89
|
- Shell `apply_patch` is also available inside `exec_command`, but the dedicated `apply_patch` tool is preferred unless you are chaining edits with other shell steps.
|
|
86
|
-
- Native `
|
|
90
|
+
- Native `web.run` and `image_generation` are forwarded to OpenAI Codex Responses tools rather than executed as local function tools.
|
|
87
91
|
|
|
88
92
|
## Development checkout
|
|
89
93
|
|
package/package.json
CHANGED
|
@@ -3,21 +3,27 @@ import { isCodexLikeContext, isOpenAICodexContext, isResponsesContext } from "./
|
|
|
3
3
|
import type { CodexConversionConfig } from "./config.ts";
|
|
4
4
|
import type { AdapterState } from "./state.ts";
|
|
5
5
|
import {
|
|
6
|
+
APPLY_PATCH_TOOL_NAME,
|
|
6
7
|
CORE_ADAPTER_TOOL_NAMES,
|
|
7
8
|
DEFAULT_TOOL_NAMES,
|
|
8
9
|
IMAGE_GENERATION_TOOL_NAME,
|
|
10
|
+
APPLY_PATCH_ONLY_STATUS_TEXT,
|
|
9
11
|
STATUS_KEY,
|
|
10
12
|
VIEW_IMAGE_TOOL_NAME,
|
|
11
13
|
WEB_SEARCH_TOOL_NAME,
|
|
14
|
+
SHELL_ADAPTER_TOOL_NAMES,
|
|
12
15
|
buildStatusText,
|
|
13
16
|
} from "./tool-set.ts";
|
|
14
17
|
import { supportsNativeImageGeneration } from "../tools/image-generation-tool.ts";
|
|
15
18
|
import { supportsNativeWebSearch } from "../tools/web-search-tool.ts";
|
|
16
19
|
|
|
17
20
|
const ADAPTER_TOOL_NAMES = [...CORE_ADAPTER_TOOL_NAMES, WEB_SEARCH_TOOL_NAME, IMAGE_GENERATION_TOOL_NAME, VIEW_IMAGE_TOOL_NAME];
|
|
18
|
-
const ALWAYS_OWNED_ADAPTER_TOOL_NAMES = [...CORE_ADAPTER_TOOL_NAMES, VIEW_IMAGE_TOOL_NAME];
|
|
19
21
|
|
|
20
22
|
export function syncAdapter(pi: ExtensionAPI, ctx: ExtensionContext, state: AdapterState): void {
|
|
23
|
+
if (shouldUseApplyPatchOnly(ctx, state.config)) {
|
|
24
|
+
enableApplyPatchOnly(pi, ctx, state);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
21
27
|
if (shouldUseCodexAdapter(ctx, state.config)) {
|
|
22
28
|
enableAdapter(pi, ctx, state);
|
|
23
29
|
} else {
|
|
@@ -26,9 +32,28 @@ export function syncAdapter(pi: ExtensionAPI, ctx: ExtensionContext, state: Adap
|
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
export function shouldUseCodexAdapter(ctx: ExtensionContext, config: CodexConversionConfig): boolean {
|
|
35
|
+
if (config.applyPatchOnly) return false;
|
|
29
36
|
return config.useOnAllModels || isCodexLikeContext(ctx);
|
|
30
37
|
}
|
|
31
38
|
|
|
39
|
+
export function shouldUseApplyPatchOnly(ctx: ExtensionContext, config: CodexConversionConfig): boolean {
|
|
40
|
+
return config.applyPatchOnly && isCodexLikeContext(ctx);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function enableApplyPatchOnly(pi: ExtensionAPI, ctx: ExtensionContext, state: AdapterState): void {
|
|
44
|
+
const adapterOwnedTools = [APPLY_PATCH_TOOL_NAME];
|
|
45
|
+
if (!state.enabled || state.adapterOwnedToolNames?.some((toolName) => toolName !== APPLY_PATCH_TOOL_NAME)) {
|
|
46
|
+
const restoredBase = state.enabled
|
|
47
|
+
? restoreTools(state.previousToolNames && state.previousToolNames.length > 0 ? state.previousToolNames : DEFAULT_TOOL_NAMES, pi.getActiveTools(), state.adapterOwnedToolNames ?? ADAPTER_TOOL_NAMES)
|
|
48
|
+
: stripAdapterTools(pi.getActiveTools(), ADAPTER_TOOL_NAMES);
|
|
49
|
+
state.previousToolNames = restoredBase;
|
|
50
|
+
state.enabled = true;
|
|
51
|
+
}
|
|
52
|
+
state.adapterOwnedToolNames = adapterOwnedTools;
|
|
53
|
+
pi.setActiveTools(mergeToolNames(state.previousToolNames ?? DEFAULT_TOOL_NAMES, adapterOwnedTools));
|
|
54
|
+
setApplyPatchOnlyStatus(ctx, state.config);
|
|
55
|
+
}
|
|
56
|
+
|
|
32
57
|
function enableAdapter(pi: ExtensionAPI, ctx: ExtensionContext, state: AdapterState): void {
|
|
33
58
|
const currentAdapterOwnedTools = getAdapterOwnedToolNames(state.config);
|
|
34
59
|
const adapterOwnedTools = state.enabled ? mergeToolNames(state.adapterOwnedToolNames ?? currentAdapterOwnedTools, currentAdapterOwnedTools) : currentAdapterOwnedTools;
|
|
@@ -69,14 +94,19 @@ function setStatus(ctx: ExtensionContext, enabled: boolean, config: CodexConvers
|
|
|
69
94
|
ctx.ui.setStatus(STATUS_KEY, enabled ? buildStatusText(statusConfig) : undefined);
|
|
70
95
|
}
|
|
71
96
|
|
|
97
|
+
function setApplyPatchOnlyStatus(ctx: ExtensionContext, config: CodexConversionConfig): void {
|
|
98
|
+
if (!ctx.hasUI) return;
|
|
99
|
+
ctx.ui.setStatus(STATUS_KEY, config.statusLine ? APPLY_PATCH_ONLY_STATUS_TEXT : undefined);
|
|
100
|
+
}
|
|
101
|
+
|
|
72
102
|
function getStatusConfig(ctx: ExtensionContext, config: CodexConversionConfig): Parameters<typeof buildStatusText>[0] {
|
|
73
103
|
const showOpenAICodexFlags = isOpenAICodexContext(ctx);
|
|
74
104
|
const showResponsesVerbosity = isResponsesContext(ctx);
|
|
75
105
|
return {
|
|
76
106
|
useOnAllModels: config.useOnAllModels,
|
|
77
107
|
fast: showOpenAICodexFlags && config.fast,
|
|
78
|
-
webSearch: showOpenAICodexFlags && config.webSearch && supportsNativeWebSearch(ctx.model),
|
|
79
|
-
imageGeneration: showOpenAICodexFlags && config.imageGeneration && supportsNativeImageGeneration(ctx.model),
|
|
108
|
+
webSearch: showOpenAICodexFlags && !config.applyPatchOnly && config.webSearch && supportsNativeWebSearch(ctx.model),
|
|
109
|
+
imageGeneration: showOpenAICodexFlags && !config.applyPatchOnly && config.imageGeneration && supportsNativeImageGeneration(ctx.model),
|
|
80
110
|
compaction: { enabled: Boolean(config.responsesCompaction), model: config.compactionModel, reasoning: config.compactionReasoning },
|
|
81
111
|
...(showResponsesVerbosity ? { verbosity: config.verbosity } : {}),
|
|
82
112
|
};
|
|
@@ -98,7 +128,9 @@ function getAdapterToolNames(ctx: ExtensionContext, config: CodexConversionConfi
|
|
|
98
128
|
|
|
99
129
|
function getAdapterOwnedToolNames(config: CodexConversionConfig): string[] {
|
|
100
130
|
return [
|
|
101
|
-
...
|
|
131
|
+
...SHELL_ADAPTER_TOOL_NAMES,
|
|
132
|
+
APPLY_PATCH_TOOL_NAME,
|
|
133
|
+
VIEW_IMAGE_TOOL_NAME,
|
|
102
134
|
...(config.webSearch ? [WEB_SEARCH_TOOL_NAME] : []),
|
|
103
135
|
...(config.imageGeneration ? [IMAGE_GENERATION_TOOL_NAME] : []),
|
|
104
136
|
];
|
|
@@ -109,7 +141,7 @@ function mergeToolNames(...toolNameGroups: string[][]): string[] {
|
|
|
109
141
|
}
|
|
110
142
|
|
|
111
143
|
export function mergeAdapterTools(activeTools: string[], adapterTools: string[], adapterOwnedTools: string[] = adapterTools): string[] {
|
|
112
|
-
const ownedTools = new Set([...
|
|
144
|
+
const ownedTools = new Set([...CORE_ADAPTER_TOOL_NAMES, ...adapterTools, ...adapterOwnedTools]);
|
|
113
145
|
const preservedTools = activeTools.filter((toolName) => !DEFAULT_TOOL_NAMES.includes(toolName) && !ownedTools.has(toolName));
|
|
114
146
|
return [...adapterTools, ...preservedTools];
|
|
115
147
|
}
|
package/src/adapter/config.ts
CHANGED
|
@@ -10,6 +10,7 @@ export const COMPACTION_MODELS: readonly CompactionModel[] = ["gpt-5.5", "gpt-5.
|
|
|
10
10
|
export const COMPACTION_REASONING_LEVELS: readonly CompactionReasoning[] = ["current", "minimal", "low", "medium", "high", "xhigh"];
|
|
11
11
|
|
|
12
12
|
export interface CodexConversionConfig {
|
|
13
|
+
applyPatchOnly: boolean;
|
|
13
14
|
fast: boolean;
|
|
14
15
|
imageGeneration: boolean;
|
|
15
16
|
compactionModel: CompactionModel;
|
|
@@ -23,6 +24,7 @@ export interface CodexConversionConfig {
|
|
|
23
24
|
|
|
24
25
|
export const CODEX_CONVERSION_CONFIG_BASENAME = "pi-codex-conversion.json";
|
|
25
26
|
export const DEFAULT_CODEX_CONVERSION_CONFIG: CodexConversionConfig = {
|
|
27
|
+
applyPatchOnly: false,
|
|
26
28
|
fast: false,
|
|
27
29
|
imageGeneration: true,
|
|
28
30
|
compactionModel: "gpt-5.5",
|
|
@@ -68,6 +70,7 @@ export function readCodexConversionConfig(configPath: string = getCodexConversio
|
|
|
68
70
|
const parsed = JSON.parse(readFileSync(configPath, "utf-8")) as unknown;
|
|
69
71
|
if (!isObject(parsed)) return { ...DEFAULT_CODEX_CONVERSION_CONFIG };
|
|
70
72
|
return {
|
|
73
|
+
applyPatchOnly: typeof parsed.applyPatchOnly === "boolean" ? parsed.applyPatchOnly : DEFAULT_CODEX_CONVERSION_CONFIG.applyPatchOnly,
|
|
71
74
|
fast: typeof parsed.fast === "boolean" ? parsed.fast : DEFAULT_CODEX_CONVERSION_CONFIG.fast,
|
|
72
75
|
imageGeneration: typeof parsed.imageGeneration === "boolean" ? parsed.imageGeneration : DEFAULT_CODEX_CONVERSION_CONFIG.imageGeneration,
|
|
73
76
|
compactionModel: normalizeCompactionModel(parsed.compactionModel) ?? DEFAULT_CODEX_CONVERSION_CONFIG.compactionModel,
|
package/src/adapter/skills.ts
CHANGED
|
@@ -15,3 +15,11 @@ export function getCodexSkillPaths(cwd: string, home: string = homedir()): strin
|
|
|
15
15
|
}
|
|
16
16
|
return skillPaths.filter((path) => existsSync(path));
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
export function hasNoSkillsFlag(argv: readonly string[] = process.argv): boolean {
|
|
20
|
+
for (const arg of argv) {
|
|
21
|
+
if (arg === "--") return false;
|
|
22
|
+
if (arg === "--no-skills" || arg === "-ns") return true;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
package/src/adapter/tool-set.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export const STATUS_KEY = "codex-adapter";
|
|
2
2
|
export const STATUS_TEXT = "\u001b[38;2;0;76;255mCodex adapter\u001b[0m";
|
|
3
|
+
export const APPLY_PATCH_ONLY_STATUS_TEXT = `${STATUS_TEXT} • apply patch only`;
|
|
3
4
|
|
|
4
5
|
export function buildStatusText(options: { verbosity?: string; webSearch: boolean; imageGeneration: boolean; fast: boolean; useOnAllModels: boolean; compaction?: { enabled: boolean; model: string; reasoning: string } }): string {
|
|
5
6
|
const extras = [
|
|
@@ -17,7 +18,9 @@ export function buildStatusText(options: { verbosity?: string; webSearch: boolea
|
|
|
17
18
|
|
|
18
19
|
export const DEFAULT_TOOL_NAMES = ["read", "bash", "edit", "write"];
|
|
19
20
|
|
|
20
|
-
export const
|
|
21
|
+
export const SHELL_ADAPTER_TOOL_NAMES = ["exec_command", "write_stdin"];
|
|
22
|
+
export const APPLY_PATCH_TOOL_NAME = "apply_patch";
|
|
23
|
+
export const CORE_ADAPTER_TOOL_NAMES = [...SHELL_ADAPTER_TOOL_NAMES, APPLY_PATCH_TOOL_NAME];
|
|
21
24
|
export const IMAGE_GENERATION_TOOL_NAME = "image_generation";
|
|
22
25
|
export const VIEW_IMAGE_TOOL_NAME = "view_image";
|
|
23
|
-
export const WEB_SEARCH_TOOL_NAME = "
|
|
26
|
+
export const WEB_SEARCH_TOOL_NAME = "web.run";
|
package/src/codex-settings/ui.ts
CHANGED
|
@@ -17,9 +17,9 @@ export interface CodexSettingsScreenOptions {
|
|
|
17
17
|
initialTab?: SettingsTab;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
type SettingsTab = "general" | "compaction";
|
|
20
|
+
type SettingsTab = "general" | "compaction" | "overrides";
|
|
21
21
|
|
|
22
|
-
const TAB_ORDER: readonly SettingsTab[] = ["general", "compaction"];
|
|
22
|
+
const TAB_ORDER: readonly SettingsTab[] = ["general", "compaction", "overrides"];
|
|
23
23
|
|
|
24
24
|
export async function openCodexSettingsScreen(ctx: ExtensionContext, options: CodexSettingsScreenOptions): Promise<void> {
|
|
25
25
|
let draft = { ...options.initialConfig };
|
|
@@ -46,6 +46,7 @@ export async function openCodexSettingsScreen(ctx: ExtensionContext, options: Co
|
|
|
46
46
|
formatTabs(activeTab, theme),
|
|
47
47
|
rule(width, theme, "borderMuted"),
|
|
48
48
|
...(activeTab === "compaction" ? formatCompactionNotes(theme) : []),
|
|
49
|
+
...(activeTab === "overrides" ? formatOverridesNotes(theme) : []),
|
|
49
50
|
"",
|
|
50
51
|
...settingsList.render(width),
|
|
51
52
|
rule(width, theme, "borderMuted"),
|
|
@@ -74,6 +75,12 @@ function formatCompactionNotes(theme: Theme): string[] {
|
|
|
74
75
|
];
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
function formatOverridesNotes(theme: Theme): string[] {
|
|
79
|
+
return [
|
|
80
|
+
theme.fg("dim", " Advanced tool-surface overrides."),
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
|
|
77
84
|
function rule(width: number, theme: Theme, color: "accent" | "borderMuted"): string {
|
|
78
85
|
return theme.fg(color, "─".repeat(Math.max(0, width)));
|
|
79
86
|
}
|
|
@@ -110,6 +117,12 @@ function buildItems(tab: SettingsTab, draft: CodexConversionConfig): SettingItem
|
|
|
110
117
|
];
|
|
111
118
|
}
|
|
112
119
|
|
|
120
|
+
if (tab === "overrides") {
|
|
121
|
+
return [
|
|
122
|
+
{ id: "applyPatchOnly", label: "Apply patch only", currentValue: draft.applyPatchOnly ? "on" : "off", values: ["off", "on"] },
|
|
123
|
+
];
|
|
124
|
+
}
|
|
125
|
+
|
|
113
126
|
return [
|
|
114
127
|
{ id: "useOnAllModels", label: "Use on all models", currentValue: draft.useOnAllModels ? "on" : "off", values: ["off", "on"] },
|
|
115
128
|
{ id: "statusLine", label: "Statusline", currentValue: draft.statusLine ? "on" : "off", values: ["off", "on"] },
|
|
@@ -122,6 +135,7 @@ function buildItems(tab: SettingsTab, draft: CodexConversionConfig): SettingItem
|
|
|
122
135
|
|
|
123
136
|
function applySettingChange(id: string, value: string, draft: CodexConversionConfig): CodexConversionConfig {
|
|
124
137
|
const nextDraft = { ...draft };
|
|
138
|
+
if (id === "applyPatchOnly") nextDraft.applyPatchOnly = value === "on";
|
|
125
139
|
if (id === "useOnAllModels") nextDraft.useOnAllModels = value === "on";
|
|
126
140
|
if (id === "statusLine") nextDraft.statusLine = value === "on";
|
|
127
141
|
if (id === "fast") nextDraft.fast = value === "on";
|
|
@@ -136,7 +150,7 @@ function applySettingChange(id: string, value: string, draft: CodexConversionCon
|
|
|
136
150
|
|
|
137
151
|
function formatTabs(activeTab: SettingsTab, theme: Theme): string {
|
|
138
152
|
const renderTab = (tab: SettingsTab, label: string) => activeTab === tab ? theme.bold(label) : theme.fg("dim", label);
|
|
139
|
-
return ` ${renderTab("general", "General")} ${theme.fg("dim", "/")} ${renderTab("compaction", "Compaction")}`;
|
|
153
|
+
return ` ${renderTab("general", "General")} ${theme.fg("dim", "/")} ${renderTab("compaction", "Compaction")} ${theme.fg("dim", "/")} ${renderTab("overrides", "Overrides")}`;
|
|
140
154
|
}
|
|
141
155
|
|
|
142
156
|
function formatLinks(theme: Theme): string[] {
|
package/src/index.ts
CHANGED
|
@@ -18,9 +18,10 @@ import { rewriteCodexProviderRequest } from "./adapter/provider-request.ts";
|
|
|
18
18
|
import { handleCodexSessionBeforeCompact } from "./adapter/compaction.ts";
|
|
19
19
|
import { isNativeCompactionDetails, NATIVE_COMPACTION_DISPLAY_MESSAGE_TYPE, NATIVE_COMPACTION_DISPLAY_TEXT } from "./adapter/types.ts";
|
|
20
20
|
import { isAdapterContextExcludedCustomMessage } from "./adapter/context-filter.ts";
|
|
21
|
-
import { getCodexSkillPaths } from "./adapter/skills.ts";
|
|
21
|
+
import { getCodexSkillPaths, hasNoSkillsFlag } from "./adapter/skills.ts";
|
|
22
22
|
import type { AdapterState } from "./adapter/state.ts";
|
|
23
23
|
import { registerCodexCommand } from "./codex-settings/command.ts";
|
|
24
|
+
import { WEB_SEARCH_TOOL_NAME } from "./adapter/tool-set.ts";
|
|
24
25
|
|
|
25
26
|
function getCommandArg(args: unknown): string | undefined {
|
|
26
27
|
if (!args || typeof args !== "object" || !("cmd" in args) || typeof args.cmd !== "string") {
|
|
@@ -44,13 +45,16 @@ export default function codexConversion(pi: ExtensionAPI) {
|
|
|
44
45
|
const tracker = createExecCommandTracker();
|
|
45
46
|
const state: AdapterState = { enabled: false, cwd: process.cwd(), promptSkills: [], config: readCodexConversionConfig() };
|
|
46
47
|
const sessions = createExecSessionManager();
|
|
47
|
-
|
|
48
|
+
const registeredNativeWebSearchTools = new Set<string>();
|
|
48
49
|
let nativeImageGenerationRegistered = false;
|
|
49
50
|
|
|
50
51
|
function ensureOptionalNativeToolsRegistered(config = state.config): void {
|
|
51
|
-
if (config.webSearch
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
if (config.webSearch) {
|
|
53
|
+
const webSearchToolName = WEB_SEARCH_TOOL_NAME;
|
|
54
|
+
if (!registeredNativeWebSearchTools.has(webSearchToolName)) {
|
|
55
|
+
registerWebSearchTool(pi, webSearchToolName);
|
|
56
|
+
registeredNativeWebSearchTools.add(webSearchToolName);
|
|
57
|
+
}
|
|
54
58
|
}
|
|
55
59
|
if (config.imageGeneration && !nativeImageGenerationRegistered) {
|
|
56
60
|
registerImageGenerationTool(pi);
|
|
@@ -93,6 +97,7 @@ export default function codexConversion(pi: ExtensionAPI) {
|
|
|
93
97
|
});
|
|
94
98
|
|
|
95
99
|
pi.on("resources_discover", async (event) => {
|
|
100
|
+
if (hasNoSkillsFlag()) return undefined;
|
|
96
101
|
const skillPaths = getCodexSkillPaths(event.cwd);
|
|
97
102
|
return skillPaths.length > 0 ? { skillPaths } : undefined;
|
|
98
103
|
});
|
|
@@ -134,7 +139,7 @@ export default function codexConversion(pi: ExtensionAPI) {
|
|
|
134
139
|
if (!shouldUseCodexAdapter(ctx, state.config)) {
|
|
135
140
|
return undefined;
|
|
136
141
|
}
|
|
137
|
-
const skills = resolvePromptSkills(event.systemPromptOptions?.skills, state.promptSkills);
|
|
142
|
+
const skills = hasNoSkillsFlag() ? [] : resolvePromptSkills(event.systemPromptOptions?.skills, state.promptSkills);
|
|
138
143
|
return {
|
|
139
144
|
systemPrompt: buildCodexSystemPrompt(event.systemPrompt, {
|
|
140
145
|
skills,
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
CODEX_TOOL_CALL_PROVIDERS,
|
|
21
21
|
processResponsesStream,
|
|
22
22
|
} from "./openai-responses-shared.ts";
|
|
23
|
+
import { WEB_SEARCH_TOOL_NAME } from "../adapter/tool-set.ts";
|
|
23
24
|
|
|
24
25
|
const DEFAULT_CODEX_BASE_URL = "https://chatgpt.com/backend-api";
|
|
25
26
|
const JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
@@ -550,7 +551,7 @@ export function buildRequestBody<TApi extends Api>(model: Model<TApi>, context:
|
|
|
550
551
|
|
|
551
552
|
if (context.tools && context.tools.length > 0) {
|
|
552
553
|
body.tools = convertResponsesTools(context.tools, { strict: null });
|
|
553
|
-
const hasWebSearchTool = context.tools.some((tool) => tool.name ===
|
|
554
|
+
const hasWebSearchTool = context.tools.some((tool) => tool.name === WEB_SEARCH_TOOL_NAME);
|
|
554
555
|
if (hasWebSearchTool) {
|
|
555
556
|
body.include.push("web_search_call.action.sources", "web_search_call.results");
|
|
556
557
|
}
|
|
@@ -2,10 +2,11 @@ import type { ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-w
|
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
import { Container, Text } from "@earendil-works/pi-tui";
|
|
4
4
|
import { isOpenAICodexModel } from "../adapter/codex-model.ts";
|
|
5
|
+
import { WEB_SEARCH_TOOL_NAME } from "../adapter/tool-set.ts";
|
|
5
6
|
|
|
6
|
-
export const WEB_SEARCH_UNSUPPORTED_MESSAGE = "
|
|
7
|
+
export const WEB_SEARCH_UNSUPPORTED_MESSAGE = "web.run is only available with the openai-codex provider";
|
|
7
8
|
const WEB_SEARCH_LOCAL_EXECUTION_MESSAGE =
|
|
8
|
-
"
|
|
9
|
+
"web.run is a native openai-codex provider tool and should not execute locally";
|
|
9
10
|
export const WEB_SEARCH_SESSION_NOTE_TYPE = "codex-web-search-session-note";
|
|
10
11
|
const WEB_SEARCH_MULTIMODAL_CONTENT_TYPES = ["text", "image"] as const;
|
|
11
12
|
|
|
@@ -20,6 +21,7 @@ interface FunctionToolPayload {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
interface ResponsesPayload {
|
|
24
|
+
include?: unknown;
|
|
23
25
|
tools?: unknown[];
|
|
24
26
|
[key: string]: unknown;
|
|
25
27
|
}
|
|
@@ -43,7 +45,7 @@ export function supportsMultimodalNativeWebSearch(model: ExtensionContext["model
|
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
function isWebSearchFunctionTool(tool: unknown): tool is FunctionToolPayload {
|
|
46
|
-
return !!tool && typeof tool === "object" && (tool as FunctionToolPayload).type === "function" && (tool as FunctionToolPayload).name ===
|
|
48
|
+
return !!tool && typeof tool === "object" && (tool as FunctionToolPayload).type === "function" && (tool as FunctionToolPayload).name === WEB_SEARCH_TOOL_NAME;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
function createEmptyResultComponent(): Container {
|
|
@@ -80,17 +82,28 @@ export function rewriteNativeWebSearchTool(payload: unknown, model: ExtensionCon
|
|
|
80
82
|
if (!rewritten) {
|
|
81
83
|
return payload;
|
|
82
84
|
}
|
|
85
|
+
const existingInclude: unknown[] = Array.isArray((payload as ResponsesPayload).include)
|
|
86
|
+
? [...((payload as ResponsesPayload).include as unknown[])]
|
|
87
|
+
: [];
|
|
88
|
+
const include = [
|
|
89
|
+
...existingInclude,
|
|
90
|
+
...[
|
|
91
|
+
"web_search_call.action.sources",
|
|
92
|
+
"web_search_call.results",
|
|
93
|
+
].filter((item) => !existingInclude.includes(item)),
|
|
94
|
+
];
|
|
83
95
|
|
|
84
96
|
return {
|
|
85
97
|
...(payload as ResponsesPayload),
|
|
98
|
+
include,
|
|
86
99
|
tools: nextTools,
|
|
87
100
|
};
|
|
88
101
|
}
|
|
89
102
|
|
|
90
|
-
export function createWebSearchTool(): ToolDefinition<typeof WEB_SEARCH_PARAMETERS> {
|
|
103
|
+
export function createWebSearchTool(name: string = WEB_SEARCH_TOOL_NAME): ToolDefinition<typeof WEB_SEARCH_PARAMETERS> {
|
|
91
104
|
return {
|
|
92
|
-
name
|
|
93
|
-
label:
|
|
105
|
+
name,
|
|
106
|
+
label: name,
|
|
94
107
|
description:
|
|
95
108
|
"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.",
|
|
96
109
|
promptSnippet:
|
|
@@ -104,7 +117,7 @@ export function createWebSearchTool(): ToolDefinition<typeof WEB_SEARCH_PARAMETE
|
|
|
104
117
|
throw new Error(WEB_SEARCH_LOCAL_EXECUTION_MESSAGE);
|
|
105
118
|
},
|
|
106
119
|
renderCall(_args, theme) {
|
|
107
|
-
return new Text(`${theme.fg("toolTitle", theme.bold(
|
|
120
|
+
return new Text(`${theme.fg("toolTitle", theme.bold(name))}`, 0, 0);
|
|
108
121
|
},
|
|
109
122
|
renderResult(result, { expanded }, theme) {
|
|
110
123
|
if (!expanded) {
|
|
@@ -117,6 +130,6 @@ export function createWebSearchTool(): ToolDefinition<typeof WEB_SEARCH_PARAMETE
|
|
|
117
130
|
};
|
|
118
131
|
}
|
|
119
132
|
|
|
120
|
-
export function registerWebSearchTool(pi: ExtensionAPI): void {
|
|
121
|
-
pi.registerTool(createWebSearchTool());
|
|
133
|
+
export function registerWebSearchTool(pi: ExtensionAPI, name: string = WEB_SEARCH_TOOL_NAME): void {
|
|
134
|
+
pi.registerTool(createWebSearchTool(name));
|
|
122
135
|
}
|
|
Binary file
|
|
Binary file
|