pi-openai-toolkit 0.14.3 → 0.14.5
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 +135 -175
- package/README.zh.md +135 -175
- package/docs/internals.md +73 -0
- package/extensions/auto-mode.ts +1 -1
- package/extensions/codex-astra.ts +1 -1
- package/extensions/compaction.ts +1 -1
- package/extensions/image-generation.ts +1 -1
- package/extensions/web-search.ts +1 -1
- package/package.json +127 -126
- package/src/config.ts +621 -582
- package/src/context-management/codex-provider.ts +260 -262
- package/src/context-management/history-notes.ts +325 -319
- package/src/context-management/tools.ts +5 -3
- package/src/context-management/types.ts +161 -160
- package/src/extension-runtime.ts +9 -5
- package/src/image-generation/extension.ts +19 -2
- package/src/image-generation/protocol.ts +473 -405
- package/src/image-generation/service.ts +249 -243
- package/src/image-generation/types.ts +189 -184
- package/src/responses-headers.ts +108 -108
- package/src/runtime.ts +477 -477
- package/src/types.ts +18 -0
- package/src/web-search/prompt.ts +1 -1
|
@@ -85,6 +85,7 @@ export function createContextManagementTools(
|
|
|
85
85
|
pi: ExtensionAPI,
|
|
86
86
|
manager: CodexContextWindowManager,
|
|
87
87
|
isActive: (ctx: ExtensionContext) => Promise<boolean> | boolean,
|
|
88
|
+
getGatewayModels: () => readonly string[] = () => [],
|
|
88
89
|
): ContextManagementTools {
|
|
89
90
|
const assertActive = async (ctx: ExtensionContext): Promise<void> => {
|
|
90
91
|
if (!(await isActive(ctx))) throw new Error("remote-context-inactive");
|
|
@@ -142,7 +143,7 @@ export function createContextManagementTools(
|
|
|
142
143
|
],
|
|
143
144
|
execute: async (_id, params, _signal, _update, ctx) => {
|
|
144
145
|
await assertActive(ctx);
|
|
145
|
-
return executeHistoryNotesTool("history", params.action, params as Record<string, unknown>, ctx, _signal);
|
|
146
|
+
return executeHistoryNotesTool("history", params.action, params as Record<string, unknown>, ctx, _signal, getGatewayModels());
|
|
146
147
|
},
|
|
147
148
|
};
|
|
148
149
|
const notes: ToolDefinition<typeof NOTES_PARAMETERS, CodexHistoryNotesDetails> = {
|
|
@@ -161,7 +162,7 @@ export function createContextManagementTools(
|
|
|
161
162
|
executionMode: "sequential",
|
|
162
163
|
execute: async (_id, params, _signal, _update, ctx) => {
|
|
163
164
|
await assertActive(ctx);
|
|
164
|
-
return executeHistoryNotesTool("notes", params.action, params as Record<string, unknown>, ctx, _signal);
|
|
165
|
+
return executeHistoryNotesTool("notes", params.action, params as Record<string, unknown>, ctx, _signal, getGatewayModels());
|
|
165
166
|
},
|
|
166
167
|
};
|
|
167
168
|
return { newContext, getContextRemaining, history, notes };
|
|
@@ -293,9 +294,10 @@ export function registerContextManagementTools(
|
|
|
293
294
|
pi: ExtensionAPI,
|
|
294
295
|
manager: CodexContextWindowManager,
|
|
295
296
|
isActive: (ctx: ExtensionContext) => Promise<boolean> | boolean,
|
|
297
|
+
getGatewayModels?: () => readonly string[],
|
|
296
298
|
): ContextManagementToolController {
|
|
297
299
|
const controller = new ContextManagementToolController(pi);
|
|
298
|
-
controller.register(createContextManagementTools(pi, manager, isActive));
|
|
300
|
+
controller.register(createContextManagementTools(pi, manager, isActive, getGatewayModels));
|
|
299
301
|
return controller;
|
|
300
302
|
}
|
|
301
303
|
|
|
@@ -1,160 +1,161 @@
|
|
|
1
|
-
import type { ContextManagementMode } from "../types";
|
|
2
|
-
|
|
3
|
-
export type { ContextManagementMode };
|
|
4
|
-
|
|
5
|
-
export const CONTEXT_MANAGEMENT_PROTOCOL = 1 as const;
|
|
6
|
-
export const CODEX_CONTEXT_WINDOW_MESSAGE_TYPE = "codex-context-window" as const;
|
|
7
|
-
export const CONTEXT_WINDOW_COMPACTION_STRATEGY = "codex-context-window" as const;
|
|
8
|
-
export const CONTEXT_WINDOW_REMINDER_THRESHOLD = 6_144;
|
|
9
|
-
export const CONTEXT_WINDOW_FALLBACK_BUFFER = 16_384;
|
|
10
|
-
|
|
11
|
-
export type ContextManagementMessageKind = "window" | "reminder" | "fallback";
|
|
12
|
-
|
|
13
|
-
export type ContextWindowIdentity = {
|
|
14
|
-
firstWindowId: string;
|
|
15
|
-
currentWindowId: string;
|
|
16
|
-
previousWindowId?: string;
|
|
17
|
-
windowNumber: number;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export type CodexContextManagementMessageDetails = {
|
|
21
|
-
protocol: typeof CONTEXT_MANAGEMENT_PROTOCOL;
|
|
22
|
-
id: string;
|
|
23
|
-
sessionId?: string;
|
|
24
|
-
contextManagement: ContextWindowIdentity & {
|
|
25
|
-
protocol: typeof CONTEXT_MANAGEMENT_PROTOCOL;
|
|
26
|
-
kind: ContextManagementMessageKind;
|
|
27
|
-
trimPreviousWindow?: true;
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export type ContextWindowCompactionDetails = {
|
|
32
|
-
protocol: typeof CONTEXT_MANAGEMENT_PROTOCOL;
|
|
33
|
-
strategy: typeof CONTEXT_WINDOW_COMPACTION_STRATEGY;
|
|
34
|
-
windowId?: string;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export type RemoteContextFailureReason =
|
|
38
|
-
| "context-management-inactive"
|
|
39
|
-
| "unsupported-model"
|
|
40
|
-
| "unsupported-api"
|
|
41
|
-
| "unsupported-backend"
|
|
42
|
-
| "auth-resolution-failed"
|
|
43
|
-
| "missing-token"
|
|
44
|
-
| "missing-api-key"
|
|
45
|
-
| "missing-account-id"
|
|
46
|
-
| "missing-base-url"
|
|
47
|
-
| "invalid-account-token"
|
|
48
|
-
| "backend-timeout"
|
|
49
|
-
| "aborted"
|
|
50
|
-
| "http-error"
|
|
51
|
-
| "invalid-json"
|
|
52
|
-
| "invalid-response"
|
|
53
|
-
| "protocol-error";
|
|
54
|
-
|
|
55
|
-
export type NativeCodexContextProvider = {
|
|
56
|
-
kind: "native-codex";
|
|
57
|
-
route: "openai-codex";
|
|
58
|
-
provider: "openai-codex";
|
|
59
|
-
api: "openai-codex-responses";
|
|
60
|
-
model: string;
|
|
61
|
-
baseUrl: string;
|
|
62
|
-
token: string;
|
|
63
|
-
accountId: string;
|
|
64
|
-
headers: Record<string, string>;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export type GatewayCodexContextProvider = {
|
|
68
|
-
kind: "codex-gateway";
|
|
69
|
-
route: "codex-gateway";
|
|
70
|
-
provider
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
| {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
| "
|
|
94
|
-
| "
|
|
95
|
-
| "
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
| "
|
|
100
|
-
| "
|
|
101
|
-
| "
|
|
102
|
-
| "
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
| {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return
|
|
125
|
-
|
|
126
|
-
isNonEmptyString(value.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
(value.windowNumber
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
value
|
|
157
|
-
value.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
1
|
+
import type { ContextManagementMode } from "../types";
|
|
2
|
+
|
|
3
|
+
export type { ContextManagementMode };
|
|
4
|
+
|
|
5
|
+
export const CONTEXT_MANAGEMENT_PROTOCOL = 1 as const;
|
|
6
|
+
export const CODEX_CONTEXT_WINDOW_MESSAGE_TYPE = "codex-context-window" as const;
|
|
7
|
+
export const CONTEXT_WINDOW_COMPACTION_STRATEGY = "codex-context-window" as const;
|
|
8
|
+
export const CONTEXT_WINDOW_REMINDER_THRESHOLD = 6_144;
|
|
9
|
+
export const CONTEXT_WINDOW_FALLBACK_BUFFER = 16_384;
|
|
10
|
+
|
|
11
|
+
export type ContextManagementMessageKind = "window" | "reminder" | "fallback";
|
|
12
|
+
|
|
13
|
+
export type ContextWindowIdentity = {
|
|
14
|
+
firstWindowId: string;
|
|
15
|
+
currentWindowId: string;
|
|
16
|
+
previousWindowId?: string;
|
|
17
|
+
windowNumber: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type CodexContextManagementMessageDetails = {
|
|
21
|
+
protocol: typeof CONTEXT_MANAGEMENT_PROTOCOL;
|
|
22
|
+
id: string;
|
|
23
|
+
sessionId?: string;
|
|
24
|
+
contextManagement: ContextWindowIdentity & {
|
|
25
|
+
protocol: typeof CONTEXT_MANAGEMENT_PROTOCOL;
|
|
26
|
+
kind: ContextManagementMessageKind;
|
|
27
|
+
trimPreviousWindow?: true;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type ContextWindowCompactionDetails = {
|
|
32
|
+
protocol: typeof CONTEXT_MANAGEMENT_PROTOCOL;
|
|
33
|
+
strategy: typeof CONTEXT_WINDOW_COMPACTION_STRATEGY;
|
|
34
|
+
windowId?: string;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type RemoteContextFailureReason =
|
|
38
|
+
| "context-management-inactive"
|
|
39
|
+
| "unsupported-model"
|
|
40
|
+
| "unsupported-api"
|
|
41
|
+
| "unsupported-backend"
|
|
42
|
+
| "auth-resolution-failed"
|
|
43
|
+
| "missing-token"
|
|
44
|
+
| "missing-api-key"
|
|
45
|
+
| "missing-account-id"
|
|
46
|
+
| "missing-base-url"
|
|
47
|
+
| "invalid-account-token"
|
|
48
|
+
| "backend-timeout"
|
|
49
|
+
| "aborted"
|
|
50
|
+
| "http-error"
|
|
51
|
+
| "invalid-json"
|
|
52
|
+
| "invalid-response"
|
|
53
|
+
| "protocol-error";
|
|
54
|
+
|
|
55
|
+
export type NativeCodexContextProvider = {
|
|
56
|
+
kind: "native-codex";
|
|
57
|
+
route: "openai-codex";
|
|
58
|
+
provider: "openai-codex";
|
|
59
|
+
api: "openai-codex-responses";
|
|
60
|
+
model: string;
|
|
61
|
+
baseUrl: string;
|
|
62
|
+
token: string;
|
|
63
|
+
accountId: string;
|
|
64
|
+
headers: Record<string, string>;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export type GatewayCodexContextProvider = {
|
|
68
|
+
kind: "codex-gateway";
|
|
69
|
+
route: "codex-gateway";
|
|
70
|
+
/** Operator-defined provider name; matched via compaction.gatewayContextModels. */
|
|
71
|
+
provider: string;
|
|
72
|
+
api: "openai-responses";
|
|
73
|
+
model: string;
|
|
74
|
+
baseUrl: string;
|
|
75
|
+
apiKey: string;
|
|
76
|
+
headers: Record<string, string>;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export type CodexContextProvider = NativeCodexContextProvider | GatewayCodexContextProvider;
|
|
80
|
+
|
|
81
|
+
export type CodexContextProviderResolution =
|
|
82
|
+
| { ok: true; provider: CodexContextProvider }
|
|
83
|
+
| {
|
|
84
|
+
ok: false;
|
|
85
|
+
reason: RemoteContextFailureReason;
|
|
86
|
+
provider?: string;
|
|
87
|
+
api?: string;
|
|
88
|
+
model?: string;
|
|
89
|
+
baseUrl?: string;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type HistoryAction =
|
|
93
|
+
| "list_windows"
|
|
94
|
+
| "list_items"
|
|
95
|
+
| "read_item"
|
|
96
|
+
| "search_contents";
|
|
97
|
+
|
|
98
|
+
export type NotesAction =
|
|
99
|
+
| "list_files_by_prefix"
|
|
100
|
+
| "read_file"
|
|
101
|
+
| "search_contents"
|
|
102
|
+
| "append_to_file"
|
|
103
|
+
| "write_file";
|
|
104
|
+
|
|
105
|
+
export type HistoryNotesResponse = Record<string, unknown>;
|
|
106
|
+
|
|
107
|
+
export type HistoryNotesResult =
|
|
108
|
+
| { ok: true; value: HistoryNotesResponse }
|
|
109
|
+
| {
|
|
110
|
+
ok: false;
|
|
111
|
+
reason: Exclude<RemoteContextFailureReason, "context-management-inactive" | "unsupported-model" | "unsupported-api">;
|
|
112
|
+
status?: number;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
116
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function isNonEmptyString(value: unknown): value is string {
|
|
120
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function isContextWindowIdentity(value: unknown): value is ContextWindowIdentity {
|
|
124
|
+
if (!isRecord(value)) return false;
|
|
125
|
+
return (
|
|
126
|
+
isNonEmptyString(value.firstWindowId) &&
|
|
127
|
+
isNonEmptyString(value.currentWindowId) &&
|
|
128
|
+
(value.previousWindowId === undefined || isNonEmptyString(value.previousWindowId)) &&
|
|
129
|
+
Number.isInteger(value.windowNumber) &&
|
|
130
|
+
(value.windowNumber as number) >= 0
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function isCodexContextManagementMessageDetails(
|
|
135
|
+
value: unknown,
|
|
136
|
+
): value is CodexContextManagementMessageDetails {
|
|
137
|
+
if (!isRecord(value) || value.protocol !== CONTEXT_MANAGEMENT_PROTOCOL || !isNonEmptyString(value.id)) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
if (value.sessionId !== undefined && !isNonEmptyString(value.sessionId)) return false;
|
|
141
|
+
if (!isRecord(value.contextManagement) || value.contextManagement.protocol !== CONTEXT_MANAGEMENT_PROTOCOL) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
const context = value.contextManagement;
|
|
145
|
+
if (!isRecord(context)) return false;
|
|
146
|
+
const trimPreviousWindow = context.trimPreviousWindow;
|
|
147
|
+
return (
|
|
148
|
+
(context.kind === "window" || context.kind === "reminder" || context.kind === "fallback") &&
|
|
149
|
+
isContextWindowIdentity(context) &&
|
|
150
|
+
(trimPreviousWindow === undefined || trimPreviousWindow === true)
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function isContextWindowCompactionDetails(value: unknown): value is ContextWindowCompactionDetails {
|
|
155
|
+
return (
|
|
156
|
+
isRecord(value) &&
|
|
157
|
+
value.protocol === CONTEXT_MANAGEMENT_PROTOCOL &&
|
|
158
|
+
value.strategy === CONTEXT_WINDOW_COMPACTION_STRATEGY &&
|
|
159
|
+
(value.windowId === undefined || isNonEmptyString(value.windowId))
|
|
160
|
+
);
|
|
161
|
+
}
|
package/src/extension-runtime.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
isNativeCodexModel,
|
|
15
15
|
} from "./context-management/codex-provider";
|
|
16
16
|
import { routeContextNamespaceToolMessage } from "./context-management/namespace-tools";
|
|
17
|
+
import { loadHistoryNotesThreadHint } from "./context-management/history-notes";
|
|
17
18
|
import { CodexContextWindowManager } from "./context-management/window-manager";
|
|
18
19
|
import { registerContextManagementTools } from "./context-management/tools";
|
|
19
20
|
import { writeDebugArtifact, writeReplayFailureArtifact } from "./debug";
|
|
@@ -109,7 +110,7 @@ async function isRemoteContextActive(
|
|
|
109
110
|
model: ExtensionContext["model"] = ctx.model,
|
|
110
111
|
): Promise<boolean> {
|
|
111
112
|
if (!config.enabled || config.contextManagement !== "remote") return false;
|
|
112
|
-
const resolution = await resolveCodexContextProvider(ctx, model);
|
|
113
|
+
const resolution = await resolveCodexContextProvider(ctx, model, config.gatewayContextModels);
|
|
113
114
|
return resolution.ok;
|
|
114
115
|
}
|
|
115
116
|
|
|
@@ -118,7 +119,7 @@ function isCodexContextModel(
|
|
|
118
119
|
config: CompactionConfig,
|
|
119
120
|
): boolean {
|
|
120
121
|
return config.contextManagement === "remote"
|
|
121
|
-
&& (isNativeCodexModel(model) || isCodexGatewayModel(model));
|
|
122
|
+
&& (isNativeCodexModel(model) || isCodexGatewayModel(model, config.gatewayContextModels));
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
function notifyRemoteContextFailure(ctx: ExtensionContext, reason: string): void {
|
|
@@ -759,7 +760,9 @@ export default function registerCompactionExtension(
|
|
|
759
760
|
overrides: Partial<CompactionDependencies> = {},
|
|
760
761
|
) {
|
|
761
762
|
const loadConfig = overrides.loadConfig ?? loadToolkitConfig;
|
|
762
|
-
const contextWindows = overrides.contextWindows ?? new CodexContextWindowManager()
|
|
763
|
+
const contextWindows = overrides.contextWindows ?? new CodexContextWindowManager((ctx, signal) =>
|
|
764
|
+
loadHistoryNotesThreadHint(ctx, signal, loadConfig().config.compaction.gatewayContextModels)
|
|
765
|
+
);
|
|
763
766
|
const dependencies: CompactionDependencies = {
|
|
764
767
|
loadConfig,
|
|
765
768
|
remoteCompact: executeRemoteV2Compaction,
|
|
@@ -775,6 +778,7 @@ export default function registerCompactionExtension(
|
|
|
775
778
|
const config = dependencies.loadConfig().config.compaction;
|
|
776
779
|
return tools.isRegistered && await isRemoteContextActive(ctx, config);
|
|
777
780
|
},
|
|
781
|
+
() => dependencies.loadConfig().config.compaction.gatewayContextModels,
|
|
778
782
|
);
|
|
779
783
|
const remoteContextActive: RemoteContextActive = async (ctx, config, model = ctx.model) =>
|
|
780
784
|
tools.isRegistered && await isRemoteContextActive(ctx, config, model);
|
|
@@ -807,7 +811,7 @@ export default function registerCompactionExtension(
|
|
|
807
811
|
activationReason = "tool-name-conflict";
|
|
808
812
|
notifyRemoteContextFailure(ctx, activationReason);
|
|
809
813
|
} else {
|
|
810
|
-
const remoteResolution = await resolveCodexContextProvider(ctx, ctx.model);
|
|
814
|
+
const remoteResolution = await resolveCodexContextProvider(ctx, ctx.model, config.gatewayContextModels);
|
|
811
815
|
activationReason = remoteResolution.ok ? "codex-context-unavailable" : remoteResolution.reason;
|
|
812
816
|
notifyRemoteContextFailure(ctx, activationReason);
|
|
813
817
|
}
|
|
@@ -874,7 +878,7 @@ export default function registerCompactionExtension(
|
|
|
874
878
|
const config = dependencies.loadConfig().config.compaction;
|
|
875
879
|
if (!isCodexContextModel(ctx.model, config)) return;
|
|
876
880
|
if (!(await remoteContextActive(ctx, config))) return;
|
|
877
|
-
const provider = await resolveCodexContextProvider(ctx, ctx.model);
|
|
881
|
+
const provider = await resolveCodexContextProvider(ctx, ctx.model, config.gatewayContextModels);
|
|
878
882
|
if (provider.ok && provider.provider.kind === "codex-gateway") {
|
|
879
883
|
const sessionId = getSessionId(ctx);
|
|
880
884
|
const gatewayHeaders = codexContextProviderHeaders(provider.provider, {
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
IMAGE_GENERATION_QUALITIES,
|
|
9
9
|
IMAGE_GENERATION_SIZES,
|
|
10
10
|
IMAGE_GENERATION_TOOL_NAME,
|
|
11
|
+
MAX_IMAGE_MODEL_ID_CHARS,
|
|
11
12
|
MAX_IMAGE_PATH_CHARS,
|
|
12
13
|
MAX_IMAGE_PROMPT_CHARS,
|
|
13
14
|
MAX_REFERENCE_IMAGE_COUNT,
|
|
@@ -65,6 +66,21 @@ const GenerateImageParameters = Type.Object(
|
|
|
65
66
|
description: "Requested image quality, or auto.",
|
|
66
67
|
}),
|
|
67
68
|
),
|
|
69
|
+
model: Type.Optional(
|
|
70
|
+
Type.Union(
|
|
71
|
+
[
|
|
72
|
+
Type.Null(),
|
|
73
|
+
Type.String({
|
|
74
|
+
minLength: 1,
|
|
75
|
+
maxLength: MAX_IMAGE_MODEL_ID_CHARS,
|
|
76
|
+
}),
|
|
77
|
+
],
|
|
78
|
+
{
|
|
79
|
+
description:
|
|
80
|
+
"Use null to accept the default image model, which is the first entry of imageGeneration.models; otherwise provide another model id exactly as it appears in that configured list.",
|
|
81
|
+
},
|
|
82
|
+
),
|
|
83
|
+
),
|
|
68
84
|
},
|
|
69
85
|
{ additionalProperties: false },
|
|
70
86
|
);
|
|
@@ -98,14 +114,15 @@ export function registerImageGenerationExtension(
|
|
|
98
114
|
name: IMAGE_GENERATION_TOOL_NAME,
|
|
99
115
|
label: "OpenAI Generate Image",
|
|
100
116
|
description:
|
|
101
|
-
"Generate a PNG image, or edit from one to five user-approved local reference images, through the current Responses-capable model and
|
|
102
|
-
promptSnippet: "Generate or edit PNG images through the current Responses-capable model and
|
|
117
|
+
"Generate a PNG image, or edit from one to five user-approved local reference images, through the current Responses-capable model and a configured hosted image_generation model. This is a paid provider operation.",
|
|
118
|
+
promptSnippet: "Generate or edit PNG images through the current Responses-capable model and a configured imageGeneration.models entry.",
|
|
103
119
|
promptGuidelines: [
|
|
104
120
|
"Use openai_generate_image when the user explicitly asks to create, draw, render, or edit a raster image and the active model speaks a Responses API.",
|
|
105
121
|
"Do not call openai_generate_image speculatively: it consumes the user's provider or gateway image quota.",
|
|
106
122
|
"Keep the image prompt faithful to the user's requested subject and constraints; do not invent unrequested style details.",
|
|
107
123
|
"Set referenceImagePaths to null unless the user explicitly identified local files; never invent paths or placeholder strings, and remember upload requires user approval.",
|
|
108
124
|
"Set outputPath to null unless the user explicitly asks for a destination; never invent a destination or placeholder string, and otherwise use the default Pi agent artifact.",
|
|
125
|
+
"Set model to null unless the user named an image model configured in imageGeneration.models; never invent or guess a model id, and remember an unlisted model fails before the paid request.",
|
|
109
126
|
"Do not substitute Python, browser automation, shell scripts, or unrelated image tools for an eligible image request.",
|
|
110
127
|
],
|
|
111
128
|
parameters: GenerateImageParameters,
|