@oai404iao/pi-codex-minimal-tools 1.3.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/LICENSE +28 -0
- package/LICENSES/Apache-2.0.txt +201 -0
- package/LICENSES/OpenAI-Codex-NOTICE.txt +6 -0
- package/README.md +410 -0
- package/THIRD_PARTY_NOTICES.md +97 -0
- package/config.schema.json +174 -0
- package/models.schema.json +217 -0
- package/package.json +87 -0
- package/provenance/openai-codex-eb9dceba-reserved-tools.json +140 -0
- package/src/activation.ts +56 -0
- package/src/background-image-generation.ts +574 -0
- package/src/capabilities.ts +146 -0
- package/src/codex-http.ts +133 -0
- package/src/codex-request-profile.ts +45 -0
- package/src/codex-reserved-tools.ts +323 -0
- package/src/codex-wire-identity.ts +182 -0
- package/src/fast-mode.ts +124 -0
- package/src/glyphs.ts +70 -0
- package/src/index.ts +332 -0
- package/src/model-catalog/catalog.ts +636 -0
- package/src/model-catalog/default-models.json +252 -0
- package/src/model-catalog/runtime.ts +113 -0
- package/src/model-catalog/types.ts +95 -0
- package/src/native-compaction.ts +393 -0
- package/src/patch/apply.ts +338 -0
- package/src/patch/parser.ts +224 -0
- package/src/patch/render.ts +201 -0
- package/src/provider-headers.ts +54 -0
- package/src/provider-native-tools.ts +71 -0
- package/src/provider-shim.ts +4338 -0
- package/src/providers/codex-apply-patch-tool.ts +23 -0
- package/src/providers/codex-apply-patch.lark +19 -0
- package/src/providers/openai-responses-shared.ts +1463 -0
- package/src/settings.ts +247 -0
- package/src/tools/apply-patch.ts +84 -0
- package/src/tools/image-generation.ts +274 -0
- package/src/tools/view-image.ts +98 -0
- package/src/tools/web-search.ts +524 -0
- package/src/utils/images.ts +73 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { getCapabilities, Image, Text, type Component } from "@earendil-works/pi-tui";
|
|
3
|
+
import { hasConfiguredModelsLoaded } from "./activation.js";
|
|
4
|
+
import { registerBackgroundImageGenerationCommand } from "./background-image-generation.js";
|
|
5
|
+
import {
|
|
6
|
+
computeNextActiveTools,
|
|
7
|
+
computeToolCapabilities,
|
|
8
|
+
modelKey,
|
|
9
|
+
NATIVE_MUTATION_TOOL_NAMES,
|
|
10
|
+
PACKAGE_TOOL_NAMES,
|
|
11
|
+
type ModelLike,
|
|
12
|
+
type NativeMutationToolName,
|
|
13
|
+
} from "./capabilities.js";
|
|
14
|
+
import {
|
|
15
|
+
registerOpenAIResponsesProviders,
|
|
16
|
+
type OpenAIResponsesProviderController,
|
|
17
|
+
} from "./provider-shim.js";
|
|
18
|
+
import { rewriteNativeOpenAiTools } from "./provider-native-tools.js";
|
|
19
|
+
import { configPath, loadSettings, settingsDiagnostics } from "./settings.js";
|
|
20
|
+
import {
|
|
21
|
+
modelCatalogDiagnostics,
|
|
22
|
+
modelsPath,
|
|
23
|
+
resolveModelProfile,
|
|
24
|
+
} from "./model-catalog/catalog.js";
|
|
25
|
+
import { loadModelSettings } from "./model-catalog/runtime.js";
|
|
26
|
+
import { createApplyPatchToolDefinition } from "./tools/apply-patch.js";
|
|
27
|
+
import { createImageGenerationToolDefinition } from "./tools/image-generation.js";
|
|
28
|
+
import { createWebSearchToolDefinition } from "./tools/web-search.js";
|
|
29
|
+
import { viewImage, viewImageToolSchema, type ValidatedImage, type ViewImageInput } from "./tools/view-image.js";
|
|
30
|
+
import { glyphs } from "./glyphs.js";
|
|
31
|
+
import { resolveCodexRequestProfile } from "./codex-request-profile.js";
|
|
32
|
+
import { registerNativeCompaction } from "./native-compaction.js";
|
|
33
|
+
import { registerFastMode, resolveFastModeServiceTier } from "./fast-mode.js";
|
|
34
|
+
|
|
35
|
+
const INSTALL_SYMBOL = Symbol.for("pi-codex-minimal-tools.installed");
|
|
36
|
+
|
|
37
|
+
function terminalImageProtocol(): "kitty" | "iterm2" | null {
|
|
38
|
+
return getCapabilities().images ?? null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function formatBytes(bytes: number): string {
|
|
42
|
+
if (!Number.isFinite(bytes) || bytes < 0) return "unknown size";
|
|
43
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
44
|
+
if (bytes < 1024 * 1024) return `${Math.round(bytes / 102.4) / 10}K`;
|
|
45
|
+
return `${Math.round(bytes / (1024 * 102.4)) / 10}M`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function viewImageCallText(args: ViewImageInput | undefined, theme: any): string {
|
|
49
|
+
const path = typeof args?.path === "string" ? args.path : "image";
|
|
50
|
+
const detail = args?.detail && args.detail !== "auto" ? ` ${theme.fg("dim", `${glyphs().dot.trim()} ${args.detail}`)}` : "";
|
|
51
|
+
return `${theme.fg("accent", glyphs().bullet)}${theme.fg("text", theme.bold("View Image "))}${theme.fg("accent", path)}${detail}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function viewImageResultText(details: ValidatedImage | undefined, theme: any): string {
|
|
55
|
+
if (!details) return `${theme.fg("accent", glyphs().bullet)}${theme.fg("text", theme.bold("View Image"))}${theme.fg("dim", `${glyphs().dot}image loaded`)}`;
|
|
56
|
+
const type = details.mimeType.replace(/^image\//, "").toUpperCase();
|
|
57
|
+
const protocol = terminalImageProtocol();
|
|
58
|
+
const preview = protocol ? theme.fg("success", `inline ${protocol}`) : theme.fg("warning", "fallback");
|
|
59
|
+
return `${theme.fg("accent", glyphs().bullet)}${theme.fg("text", theme.bold("View Image "))}${theme.fg("accent", details.displayPath)}${theme.fg("dim", glyphs().dot)}${theme.fg("success", type)}${theme.fg("dim", `${glyphs().dot}${formatBytes(details.sizeBytes)}${glyphs().dot}`)}${preview}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function emptyComponent(): Component {
|
|
63
|
+
return { invalidate() {}, render: () => [] };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function textComponent(text: string): Component {
|
|
67
|
+
return new Text(text, 0, 0);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function viewImageResultComponent(result: any, options: any, theme: any, context: any): Component {
|
|
71
|
+
if (options?.isPartial) return emptyComponent();
|
|
72
|
+
const details = result?.details as ValidatedImage | undefined;
|
|
73
|
+
const imagePart = result?.content?.find?.((part: any) => part?.type === "image" && typeof part.data === "string" && typeof part.mimeType === "string");
|
|
74
|
+
const header = textComponent(viewImageResultText(details, theme));
|
|
75
|
+
if (!imagePart) return header;
|
|
76
|
+
const imageTheme = { fallbackColor: (text: string) => theme.fg("dim", text) };
|
|
77
|
+
const maxHeightCells = options?.expanded ? 28 : 18;
|
|
78
|
+
const image = new Image(imagePart.data, imagePart.mimeType, imageTheme, { maxWidthCells: 80, maxHeightCells, filename: details?.displayPath });
|
|
79
|
+
return {
|
|
80
|
+
invalidate() {
|
|
81
|
+
header.invalidate();
|
|
82
|
+
image.invalidate();
|
|
83
|
+
},
|
|
84
|
+
render(width: number): string[] {
|
|
85
|
+
return [...header.render(width), ...image.render(width)];
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function contextModel(ctx: ExtensionContext): ModelLike | undefined {
|
|
91
|
+
return ctx.model as ModelLike | undefined;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
type SuppressedMutationTools = Map<NativeMutationToolName, number>;
|
|
95
|
+
|
|
96
|
+
function captureSuppressedMutationTools(
|
|
97
|
+
activeTools: readonly string[],
|
|
98
|
+
removedTools: readonly string[],
|
|
99
|
+
suppressed: SuppressedMutationTools,
|
|
100
|
+
): void {
|
|
101
|
+
for (const name of NATIVE_MUTATION_TOOL_NAMES) {
|
|
102
|
+
if (!removedTools.includes(name) || suppressed.has(name)) continue;
|
|
103
|
+
const index = activeTools.indexOf(name);
|
|
104
|
+
if (index >= 0) suppressed.set(name, index);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function restoreSuppressedMutationTools(activeTools: readonly string[], suppressed: SuppressedMutationTools): string[] {
|
|
109
|
+
if (suppressed.size === 0) return [...activeTools];
|
|
110
|
+
|
|
111
|
+
const restored = [...activeTools];
|
|
112
|
+
for (const [name, index] of [...suppressed.entries()].sort(([, left], [, right]) => left - right)) {
|
|
113
|
+
if (!restored.includes(name)) restored.splice(Math.min(index, restored.length), 0, name);
|
|
114
|
+
}
|
|
115
|
+
suppressed.clear();
|
|
116
|
+
return restored;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function syncActiveTools(
|
|
120
|
+
pi: ExtensionAPI,
|
|
121
|
+
ctx: ExtensionContext,
|
|
122
|
+
toolsRegistered: boolean,
|
|
123
|
+
suppressedMutationTools: SuppressedMutationTools,
|
|
124
|
+
): void {
|
|
125
|
+
const active = pi.getActiveTools?.() ?? [];
|
|
126
|
+
const settings = loadSettings(ctx.cwd);
|
|
127
|
+
const supportedModelsLoaded = hasConfiguredModelsLoaded(ctx, settings);
|
|
128
|
+
if (!toolsRegistered || !supportedModelsLoaded) {
|
|
129
|
+
const next = restoreSuppressedMutationTools(
|
|
130
|
+
active.filter((name) => !PACKAGE_TOOL_NAMES.includes(name as never)),
|
|
131
|
+
suppressedMutationTools,
|
|
132
|
+
);
|
|
133
|
+
if (next.join("\0") !== active.join("\0")) pi.setActiveTools(next);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const next = computeNextActiveTools(active, contextModel(ctx), settings);
|
|
137
|
+
captureSuppressedMutationTools(active, next.removed, suppressedMutationTools);
|
|
138
|
+
const activeTools = next.activeTools.includes("apply_patch")
|
|
139
|
+
? next.activeTools
|
|
140
|
+
: restoreSuppressedMutationTools(next.activeTools, suppressedMutationTools);
|
|
141
|
+
if (activeTools.join("\0") !== active.join("\0")) pi.setActiveTools(activeTools);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function statusLines(pi: ExtensionAPI, ctx: ExtensionContext): string[] {
|
|
145
|
+
const settings = loadSettings(ctx.cwd);
|
|
146
|
+
const model = contextModel(ctx);
|
|
147
|
+
const modelSettings = loadModelSettings(model, ctx.cwd, settings);
|
|
148
|
+
const capabilities = computeToolCapabilities(model, settings);
|
|
149
|
+
const requestProfile = resolveCodexRequestProfile(modelSettings.requestProfile);
|
|
150
|
+
const modelProfile = modelSettings.modelProfile;
|
|
151
|
+
const active = new Set(pi.getActiveTools?.() ?? []);
|
|
152
|
+
const fastModeTier = resolveFastModeServiceTier(modelSettings, model);
|
|
153
|
+
return [
|
|
154
|
+
"Codex Minimal Tools",
|
|
155
|
+
`model: ${modelKey(model)}`,
|
|
156
|
+
`config: ${configPath()}`,
|
|
157
|
+
`models: ${modelsPath()}`,
|
|
158
|
+
`model profile: ${modelProfile ? `${modelProfile.sources.join("+")} #${modelProfile.profileHash}` : "(none)"}`,
|
|
159
|
+
`configured models loaded: ${hasConfiguredModelsLoaded(ctx, settings)}`,
|
|
160
|
+
`enabled: ${settings.enabled}`,
|
|
161
|
+
`autoEnable: ${settings.autoEnable}`,
|
|
162
|
+
`provider shim: ${modelSettings.providerShimActive ? "active" : "inactive"}`,
|
|
163
|
+
`responses endpoint: ${modelSettings.apiKeyMode ? "openai" : "codex"}`,
|
|
164
|
+
`responses transport: ${modelSettings.openaiTransport}`,
|
|
165
|
+
`Responses WebSocket prewarm: ${modelSettings.openaiWebSocketPrewarm}`,
|
|
166
|
+
`fast mode: ${settings.fastMode ? modelSettings.fastServiceTier ?? "on (unsupported)" : "off"}${fastModeTier ? ", active" : ""}`,
|
|
167
|
+
`compaction: ${modelSettings.compactionMode}`,
|
|
168
|
+
`request profile: ${requestProfile.responsesMode}/${requestProfile.patchTransport}, summary=${requestProfile.reasoningSummary}, system=${requestProfile.systemPromptPlacement}, hosted=${requestProfile.supportsHostedTools}, parallel=${requestProfile.supportsParallelTools}`,
|
|
169
|
+
`web search: ${modelSettings.webSearchImplementation ?? "off"}`,
|
|
170
|
+
`image generation: ${modelSettings.imageGenerationImplementation ?? "off"}`,
|
|
171
|
+
`legacy additionalModelIds: ${settings.additionalModelIds.length > 0 ? settings.additionalModelIds.join(", ") : "(none)"}`,
|
|
172
|
+
`apiKeyMode: ${modelSettings.apiKeyMode}`,
|
|
173
|
+
`native provider shim: ${settings.enabled ? "registered" : "disabled"}`,
|
|
174
|
+
"tools:",
|
|
175
|
+
...Object.entries(capabilities).map(([name, capability]) => `- ${name}: ${capability.enabled ? "supported" : "disabled"}${active.has(name) ? ", active" : ""} — ${capability.reason}`),
|
|
176
|
+
];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function registerDiagnosticCommand(pi: ExtensionAPI): void {
|
|
180
|
+
const showDoctor = (ctx: ExtensionCommandContext) => {
|
|
181
|
+
const settings = loadSettings(ctx.cwd);
|
|
182
|
+
const lines = statusLines(pi, ctx as ExtensionContext);
|
|
183
|
+
lines.push(`image output dir: ${settings.imageOutputDir}`);
|
|
184
|
+
lines.push(`OPENAI_API_KEY: ${process.env.OPENAI_API_KEY ? "present" : "not set"}`);
|
|
185
|
+
const diagnostics = settingsDiagnostics();
|
|
186
|
+
if (diagnostics.length > 0) lines.push("settings diagnostics:", ...diagnostics.map((line) => `- ${line}`));
|
|
187
|
+
const catalogDiagnostics = modelCatalogDiagnostics();
|
|
188
|
+
if (catalogDiagnostics.length > 0) lines.push("model catalog diagnostics:", ...catalogDiagnostics.map((line) => `- ${line}`));
|
|
189
|
+
const profileDiagnostics = loadModelSettings(contextModel(ctx), ctx.cwd, settings)
|
|
190
|
+
.modelProfile?.diagnostics
|
|
191
|
+
.filter((line) => !catalogDiagnostics.includes(line)) ?? [];
|
|
192
|
+
if (profileDiagnostics.length > 0) {
|
|
193
|
+
lines.push("active model profile diagnostics:", ...profileDiagnostics.map((line) => `- ${line}`));
|
|
194
|
+
}
|
|
195
|
+
ctx.ui.notify(lines.join("\n"), "info");
|
|
196
|
+
};
|
|
197
|
+
pi.registerCommand("codex-minimal-tools", {
|
|
198
|
+
description: "Show Codex Minimal Tools status. Usage: /codex-minimal-tools | /codex-minimal-tools:doctor",
|
|
199
|
+
handler: async (args: string, ctx) => {
|
|
200
|
+
const subcommand = args.trim().split(/\s+/, 1)[0]?.toLowerCase();
|
|
201
|
+
if (subcommand === "doctor") {
|
|
202
|
+
showDoctor(ctx);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (!subcommand) {
|
|
206
|
+
ctx.ui.notify(statusLines(pi, ctx as ExtensionContext).join("\n"), "info");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
ctx.ui.notify(statusLines(pi, ctx as ExtensionContext).join("\n"), "info");
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
pi.registerCommand("codex-minimal-tools:doctor", {
|
|
213
|
+
description: "Run lightweight self-checks",
|
|
214
|
+
handler: async (_args: string, ctx) => showDoctor(ctx),
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function registerTools(
|
|
219
|
+
pi: ExtensionAPI,
|
|
220
|
+
providerController?: OpenAIResponsesProviderController,
|
|
221
|
+
): void {
|
|
222
|
+
pi.registerTool(createImageGenerationToolDefinition({
|
|
223
|
+
loadSettings: (cwd, model) => loadModelSettings(model, cwd),
|
|
224
|
+
getCurrentTurnId: (sessionId) => providerController?.getCurrentTurnId(sessionId),
|
|
225
|
+
}) as never);
|
|
226
|
+
pi.registerTool(createWebSearchToolDefinition({
|
|
227
|
+
getCurrentTurnId: (sessionId) => providerController?.getCurrentTurnId(sessionId),
|
|
228
|
+
}) as never);
|
|
229
|
+
pi.registerTool({
|
|
230
|
+
renderShell: "self",
|
|
231
|
+
name: "view_image",
|
|
232
|
+
label: "View Image",
|
|
233
|
+
description: "Inspect a local image file by returning image content to the model. Relative paths resolve against ctx.cwd; a leading @ is accepted.",
|
|
234
|
+
promptSnippet: "Inspect local image files by path.",
|
|
235
|
+
promptGuidelines: ["Use view_image when you need to inspect a local image file; pass the path in the path argument."],
|
|
236
|
+
parameters: viewImageToolSchema,
|
|
237
|
+
async execute(_toolCallId: string, params: ViewImageInput, _signal: AbortSignal | undefined, _onUpdate: unknown, ctx: ExtensionContext) {
|
|
238
|
+
const settings = loadSettings(ctx.cwd);
|
|
239
|
+
return viewImage(params, ctx.cwd, { workspaceOnly: settings.viewImageWorkspaceOnly }) as never;
|
|
240
|
+
},
|
|
241
|
+
renderCall(args: ViewImageInput, theme: any, context: any) {
|
|
242
|
+
if (context?.executionStarted && !context?.isPartial) return emptyComponent();
|
|
243
|
+
return textComponent(viewImageCallText(args, theme));
|
|
244
|
+
},
|
|
245
|
+
renderResult(result: any, options: any, theme: any, context: any) {
|
|
246
|
+
return viewImageResultComponent(result, options, theme, context);
|
|
247
|
+
},
|
|
248
|
+
} as never);
|
|
249
|
+
pi.registerTool(createApplyPatchToolDefinition({
|
|
250
|
+
deferRendering: loadSettings().deferApplyPatchRendering,
|
|
251
|
+
}) as never);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export default function codexMinimalTools(pi: ExtensionAPI): void {
|
|
255
|
+
const guard = pi as unknown as Record<PropertyKey, unknown>;
|
|
256
|
+
if (guard[INSTALL_SYMBOL]) return;
|
|
257
|
+
guard[INSTALL_SYMBOL] = true;
|
|
258
|
+
|
|
259
|
+
let currentCwd = process.cwd();
|
|
260
|
+
let toolsRegistered = false;
|
|
261
|
+
let providerController: OpenAIResponsesProviderController | undefined;
|
|
262
|
+
const suppressedMutationTools: SuppressedMutationTools = new Map();
|
|
263
|
+
const ensureToolsRegistered = (ctx: ExtensionContext): boolean => {
|
|
264
|
+
currentCwd = ctx.cwd;
|
|
265
|
+
if (toolsRegistered) return true;
|
|
266
|
+
const settings = loadSettings(ctx.cwd);
|
|
267
|
+
const supportedModelsLoaded = hasConfiguredModelsLoaded(ctx, settings);
|
|
268
|
+
if (!settings.enabled || !supportedModelsLoaded) return false;
|
|
269
|
+
registerTools(pi, providerController);
|
|
270
|
+
toolsRegistered = true;
|
|
271
|
+
return true;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
275
|
+
syncActiveTools(pi, ctx, ensureToolsRegistered(ctx), suppressedMutationTools);
|
|
276
|
+
});
|
|
277
|
+
pi.on("model_select", async (_event, ctx) => {
|
|
278
|
+
syncActiveTools(pi, ctx, ensureToolsRegistered(ctx), suppressedMutationTools);
|
|
279
|
+
});
|
|
280
|
+
pi.on("thinking_level_select", async (_event, ctx) => {
|
|
281
|
+
syncActiveTools(pi, ctx, ensureToolsRegistered(ctx), suppressedMutationTools);
|
|
282
|
+
});
|
|
283
|
+
pi.on("session_shutdown", async () => {
|
|
284
|
+
const active = pi.getActiveTools?.() ?? [];
|
|
285
|
+
const restored = restoreSuppressedMutationTools(active, suppressedMutationTools);
|
|
286
|
+
if (restored.join("\0") !== active.join("\0")) pi.setActiveTools(restored);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
const initialSettings = loadSettings(currentCwd);
|
|
290
|
+
if (initialSettings.enabled) {
|
|
291
|
+
providerController = registerOpenAIResponsesProviders(pi, { getCurrentCwd: () => currentCwd });
|
|
292
|
+
registerNativeCompaction(pi, providerController);
|
|
293
|
+
registerBackgroundImageGenerationCommand(pi);
|
|
294
|
+
// Pi renders the target transcript before session_start when switching
|
|
295
|
+
// sessions. Register definitions during extension load so resumed tool
|
|
296
|
+
// rows can resolve their custom renderers instead of falling back to raw
|
|
297
|
+
// argument JSON. syncActiveTools still controls model-specific activation.
|
|
298
|
+
registerTools(pi, providerController);
|
|
299
|
+
toolsRegistered = true;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
registerDiagnosticCommand(pi);
|
|
303
|
+
registerFastMode(pi);
|
|
304
|
+
|
|
305
|
+
pi.on("before_provider_request", (event, ctx) => {
|
|
306
|
+
currentCwd = ctx.cwd;
|
|
307
|
+
const settings = loadSettings(ctx.cwd);
|
|
308
|
+
const model = contextModel(ctx);
|
|
309
|
+
const modelSettings = loadModelSettings(model, ctx.cwd, settings);
|
|
310
|
+
const profile = resolveModelProfile(model, { settings });
|
|
311
|
+
if (
|
|
312
|
+
!settings.enabled
|
|
313
|
+
|| !profile?.effective.enabled
|
|
314
|
+
|| !modelSettings.providerShimActive
|
|
315
|
+
|| !modelSettings.nativeProviderTools
|
|
316
|
+
) return undefined;
|
|
317
|
+
const capabilities = computeToolCapabilities(contextModel(ctx), settings);
|
|
318
|
+
const webSearch = profile.effective.tools.webSearch;
|
|
319
|
+
const result = rewriteNativeOpenAiTools(event.payload, {
|
|
320
|
+
imageModel: settings.imageModel,
|
|
321
|
+
imageGeneration: modelSettings.imageGenerationImplementation ?? false,
|
|
322
|
+
webSearch: capabilities.web_search.enabled
|
|
323
|
+
&& webSearch
|
|
324
|
+
? {
|
|
325
|
+
implementation: webSearch.implementation,
|
|
326
|
+
contentTypes: webSearch.contentTypes,
|
|
327
|
+
}
|
|
328
|
+
: false,
|
|
329
|
+
});
|
|
330
|
+
return result.rewritten.length > 0 ? result.payload : undefined;
|
|
331
|
+
});
|
|
332
|
+
}
|