pi-openai-toolkit 0.21.1 → 0.22.1

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.
Files changed (42) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +83 -83
  3. package/README.md +8 -0
  4. package/README.zh.md +8 -0
  5. package/config.schema.json +278 -278
  6. package/docs/configuration.md +298 -298
  7. package/docs/internals.md +181 -166
  8. package/package.json +5 -1
  9. package/src/codex-fast/extension.ts +119 -0
  10. package/src/codex-fast/payload.ts +36 -0
  11. package/src/codex-fast/state.ts +25 -0
  12. package/src/compact-client.ts +412 -412
  13. package/src/compaction-projection.ts +35 -35
  14. package/src/config/migration.ts +103 -103
  15. package/src/config.ts +310 -310
  16. package/src/context-management/codex-provider.ts +270 -270
  17. package/src/context-management/history-notes.ts +357 -357
  18. package/src/context-management/tools.ts +371 -371
  19. package/src/context-management/types.ts +168 -168
  20. package/src/context-management/window-manager.ts +801 -801
  21. package/src/debug.ts +238 -238
  22. package/src/deferred-tool-carryover.ts +282 -282
  23. package/src/details-store.ts +151 -151
  24. package/src/extension-runtime.ts +1662 -1662
  25. package/src/image-generation/extension.ts +189 -189
  26. package/src/image-generation/protocol.ts +579 -579
  27. package/src/image-generation/types.ts +300 -300
  28. package/src/payload-rewrite.ts +515 -515
  29. package/src/pi-context-hook.ts +117 -117
  30. package/src/remote-v2-client.ts +811 -811
  31. package/src/request-context-cache.ts +155 -155
  32. package/src/responses-headers.ts +180 -180
  33. package/src/runtime.ts +865 -865
  34. package/src/serializer.ts +882 -882
  35. package/src/supported-environment.ts +27 -27
  36. package/src/types.ts +565 -565
  37. package/src/web-search/alpha-client.ts +876 -876
  38. package/src/web-search/extension.ts +530 -530
  39. package/src/web-search/payload.ts +299 -299
  40. package/src/web-search/prompt.ts +60 -60
  41. package/src/web-search/types.ts +166 -166
  42. package/tsconfig.check.json +50 -50
@@ -1,189 +1,189 @@
1
- import { StringEnum, Type, type Static } from "@earendil-works/pi-ai";
2
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
- import { loadToolkitConfig, resolveToolkitConfig } from "../config";
4
- import { notifyConfigIssues } from "../config/notifications";
5
- import { registerPhysicalModelObserver } from "../runtime";
6
- import { executeImageGeneration } from "./service";
7
- import { isImageGenerationEnabledForModel } from "./eligibility";
8
- import { renderImageGenerationResult } from "./render";
9
- import {
10
- IMAGE_GENERATION_QUALITIES,
11
- IMAGE_GENERATION_SIZES,
12
- IMAGE_GENERATION_TOOL_NAME,
13
- MAX_IMAGE_BATCH_SIZE,
14
- MAX_IMAGE_MODEL_ID_CHARS,
15
- MAX_IMAGE_PATH_CHARS,
16
- MAX_IMAGE_PROMPT_CHARS,
17
- MAX_REFERENCE_IMAGE_COUNT,
18
- ImageGenerationError,
19
- sanitizeImageDiagnostic,
20
- type ImageGenerationToolDetails,
21
- } from "./types";
22
-
23
- const registeredApis = new WeakSet<object>();
24
-
25
- const GenerateImageParameters = Type.Object(
26
- {
27
- prompt: Type.String({
28
- minLength: 1,
29
- maxLength: MAX_IMAGE_PROMPT_CHARS,
30
- description: "Image generation or edit prompt. Preserve the user's requested subject and constraints.",
31
- }),
32
- referenceImagePaths: Type.Optional(
33
- Type.Union(
34
- [
35
- Type.Null(),
36
- Type.Array(Type.String({ minLength: 1, maxLength: MAX_IMAGE_PATH_CHARS }), {
37
- minItems: 1,
38
- maxItems: MAX_REFERENCE_IMAGE_COUNT,
39
- }),
40
- ],
41
- {
42
- description:
43
- "Use null when the user did not explicitly identify reference images; otherwise provide one to five user-identified local image paths.",
44
- },
45
- ),
46
- ),
47
- outputPath: Type.Optional(
48
- Type.Union(
49
- [
50
- Type.Null(),
51
- Type.String({
52
- minLength: 1,
53
- maxLength: MAX_IMAGE_PATH_CHARS,
54
- }),
55
- ],
56
- {
57
- description:
58
- "Use null when the user did not explicitly request a destination; otherwise provide an explicit .png, .jpg, .jpeg, or .webp file path matching the provider output format.",
59
- },
60
- ),
61
- ),
62
- size: Type.Optional(
63
- StringEnum(IMAGE_GENERATION_SIZES, {
64
- description: "Requested raster-image dimensions, or auto.",
65
- }),
66
- ),
67
- quality: Type.Optional(
68
- StringEnum(IMAGE_GENERATION_QUALITIES, {
69
- description: "Requested image quality, or auto.",
70
- }),
71
- ),
72
- model: Type.Optional(
73
- Type.Union(
74
- [
75
- Type.Null(),
76
- Type.String({
77
- minLength: 1,
78
- maxLength: MAX_IMAGE_MODEL_ID_CHARS,
79
- }),
80
- ],
81
- {
82
- description:
83
- "Use null to accept the default image model, configured by imageGeneration.defaultModel; otherwise provide another model id exactly as it appears in that configured list.",
84
- },
85
- ),
86
- ),
87
- batchSize: Type.Optional(
88
- Type.Union(
89
- [
90
- Type.Null(),
91
- Type.Integer({ minimum: 1, maximum: MAX_IMAGE_BATCH_SIZE }),
92
- ],
93
- {
94
- description:
95
- "Run this many independent image requests concurrently (1-10). Batch requests use generated artifacts and cannot set outputPath.",
96
- },
97
- ),
98
- ),
99
- },
100
- { additionalProperties: false },
101
- );
102
-
103
- type GenerateImageToolParams = Static<typeof GenerateImageParameters>;
104
-
105
- function syncImageGenerationTool(
106
- pi: ExtensionAPI,
107
- model: Parameters<typeof isImageGenerationEnabledForModel>[0],
108
- config: Parameters<typeof isImageGenerationEnabledForModel>[1],
109
- ): void {
110
- const eligible = isImageGenerationEnabledForModel(model, config);
111
- const activeTools = pi.getActiveTools();
112
- const active = activeTools.includes(IMAGE_GENERATION_TOOL_NAME);
113
- if (eligible && !active) {
114
- pi.setActiveTools([...activeTools, IMAGE_GENERATION_TOOL_NAME]);
115
- } else if (!eligible && active) {
116
- pi.setActiveTools(activeTools.filter((name) => name !== IMAGE_GENERATION_TOOL_NAME));
117
- }
118
- }
119
-
120
- export function registerImageGenerationExtension(
121
- pi: ExtensionAPI,
122
- loadConfig: typeof loadToolkitConfig = loadToolkitConfig,
123
- executeImage: typeof executeImageGeneration = executeImageGeneration,
124
- ): void {
125
- if (registeredApis.has(pi)) return;
126
- registeredApis.add(pi);
127
- registerPhysicalModelObserver(pi);
128
-
129
- pi.registerTool<typeof GenerateImageParameters, ImageGenerationToolDetails, Record<string, never>>({
130
- name: IMAGE_GENERATION_TOOL_NAME,
131
- label: "OpenAI Generate Image",
132
- description:
133
- "Generate raster images, or edit from one to five user-approved local reference images, through an independent Images API request using a configured image model. PNG, JPEG, and WebP responses are validated and saved in their actual format. This is a paid provider operation; batchSize runs independent requests concurrently.",
134
- promptSnippet: "Generate or edit raster images through an independent Images API request and a configured imageGeneration.allowedModels entry.",
135
- promptGuidelines: [
136
- "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.",
137
- "Do not call openai_generate_image speculatively: it consumes the user's provider or gateway image quota.",
138
- "Keep the image prompt faithful to the user's requested subject and constraints; do not invent unrequested style details.",
139
- "Set referenceImagePaths to null unless the user explicitly identified local files; never invent paths or placeholder strings, and remember upload requires user approval.",
140
- "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.",
141
- "Set model to null unless the user named an image model configured in imageGeneration.allowedModels; never invent or guess a model id, and remember an unlisted model fails before the paid request.",
142
- "Use batchSize only when the user asks for multiple variants; each batch item is an independent paid request, and batchSize cannot be combined with outputPath.",
143
- "Do not substitute Python, browser automation, shell scripts, or unrelated image tools for an eligible image request.",
144
- ],
145
- parameters: GenerateImageParameters,
146
- executionMode: "sequential",
147
- async execute(toolCallId, params: GenerateImageToolParams, signal, _onUpdate, ctx) {
148
- try {
149
- const result = await executeImage({
150
- params,
151
- toolCallId,
152
- signal,
153
- ctx,
154
- });
155
- return {
156
- content: [{ type: "text", text: result.text }],
157
- details: result.details,
158
- };
159
- } catch (error) {
160
- if (error instanceof ImageGenerationError) {
161
- throw new Error(error.message);
162
- }
163
- throw new Error(
164
- sanitizeImageDiagnostic(error instanceof Error ? error.message : error, "Image generation failed."),
165
- );
166
- }
167
- },
168
- renderResult: renderImageGenerationResult,
169
- });
170
-
171
- const synchronize = (ctx: Parameters<typeof executeImageGeneration>[0]["ctx"], model = ctx.model) => {
172
- const resolved = resolveToolkitConfig(loadConfig(), model);
173
- notifyConfigIssues(ctx, resolved);
174
- const valid = !resolved.invalidFeatures.some((feature) => feature === "imageGeneration" || feature === "compatibility");
175
- syncImageGenerationTool(pi, model, { ...resolved.config.imageGeneration, enabled: valid && resolved.policy.imageGeneration.enabled });
176
- };
177
- pi.on("session_start", (_event, ctx) => synchronize(ctx));
178
- pi.on("model_select", (event, ctx) => synchronize(ctx, event.model));
179
- pi.on("before_agent_start", (_event, ctx) => synchronize(ctx));
180
- }
181
-
182
- export default function imageGenerationExtension(pi: ExtensionAPI): void {
183
- registerImageGenerationExtension(pi);
184
- }
185
-
186
- export const _extensionTest = {
187
- GenerateImageParameters,
188
- syncImageGenerationTool,
189
- };
1
+ import { StringEnum, Type, type Static } from "@earendil-works/pi-ai";
2
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
+ import { loadToolkitConfig, resolveToolkitConfig } from "../config";
4
+ import { notifyConfigIssues } from "../config/notifications";
5
+ import { registerPhysicalModelObserver } from "../runtime";
6
+ import { executeImageGeneration } from "./service";
7
+ import { isImageGenerationEnabledForModel } from "./eligibility";
8
+ import { renderImageGenerationResult } from "./render";
9
+ import {
10
+ IMAGE_GENERATION_QUALITIES,
11
+ IMAGE_GENERATION_SIZES,
12
+ IMAGE_GENERATION_TOOL_NAME,
13
+ MAX_IMAGE_BATCH_SIZE,
14
+ MAX_IMAGE_MODEL_ID_CHARS,
15
+ MAX_IMAGE_PATH_CHARS,
16
+ MAX_IMAGE_PROMPT_CHARS,
17
+ MAX_REFERENCE_IMAGE_COUNT,
18
+ ImageGenerationError,
19
+ sanitizeImageDiagnostic,
20
+ type ImageGenerationToolDetails,
21
+ } from "./types";
22
+
23
+ const registeredApis = new WeakSet<object>();
24
+
25
+ const GenerateImageParameters = Type.Object(
26
+ {
27
+ prompt: Type.String({
28
+ minLength: 1,
29
+ maxLength: MAX_IMAGE_PROMPT_CHARS,
30
+ description: "Image generation or edit prompt. Preserve the user's requested subject and constraints.",
31
+ }),
32
+ referenceImagePaths: Type.Optional(
33
+ Type.Union(
34
+ [
35
+ Type.Null(),
36
+ Type.Array(Type.String({ minLength: 1, maxLength: MAX_IMAGE_PATH_CHARS }), {
37
+ minItems: 1,
38
+ maxItems: MAX_REFERENCE_IMAGE_COUNT,
39
+ }),
40
+ ],
41
+ {
42
+ description:
43
+ "Use null when the user did not explicitly identify reference images; otherwise provide one to five user-identified local image paths.",
44
+ },
45
+ ),
46
+ ),
47
+ outputPath: Type.Optional(
48
+ Type.Union(
49
+ [
50
+ Type.Null(),
51
+ Type.String({
52
+ minLength: 1,
53
+ maxLength: MAX_IMAGE_PATH_CHARS,
54
+ }),
55
+ ],
56
+ {
57
+ description:
58
+ "Use null when the user did not explicitly request a destination; otherwise provide an explicit .png, .jpg, .jpeg, or .webp file path matching the provider output format.",
59
+ },
60
+ ),
61
+ ),
62
+ size: Type.Optional(
63
+ StringEnum(IMAGE_GENERATION_SIZES, {
64
+ description: "Requested raster-image dimensions, or auto.",
65
+ }),
66
+ ),
67
+ quality: Type.Optional(
68
+ StringEnum(IMAGE_GENERATION_QUALITIES, {
69
+ description: "Requested image quality, or auto.",
70
+ }),
71
+ ),
72
+ model: Type.Optional(
73
+ Type.Union(
74
+ [
75
+ Type.Null(),
76
+ Type.String({
77
+ minLength: 1,
78
+ maxLength: MAX_IMAGE_MODEL_ID_CHARS,
79
+ }),
80
+ ],
81
+ {
82
+ description:
83
+ "Use null to accept the default image model, configured by imageGeneration.defaultModel; otherwise provide another model id exactly as it appears in that configured list.",
84
+ },
85
+ ),
86
+ ),
87
+ batchSize: Type.Optional(
88
+ Type.Union(
89
+ [
90
+ Type.Null(),
91
+ Type.Integer({ minimum: 1, maximum: MAX_IMAGE_BATCH_SIZE }),
92
+ ],
93
+ {
94
+ description:
95
+ "Run this many independent image requests concurrently (1-10). Batch requests use generated artifacts and cannot set outputPath.",
96
+ },
97
+ ),
98
+ ),
99
+ },
100
+ { additionalProperties: false },
101
+ );
102
+
103
+ type GenerateImageToolParams = Static<typeof GenerateImageParameters>;
104
+
105
+ function syncImageGenerationTool(
106
+ pi: ExtensionAPI,
107
+ model: Parameters<typeof isImageGenerationEnabledForModel>[0],
108
+ config: Parameters<typeof isImageGenerationEnabledForModel>[1],
109
+ ): void {
110
+ const eligible = isImageGenerationEnabledForModel(model, config);
111
+ const activeTools = pi.getActiveTools();
112
+ const active = activeTools.includes(IMAGE_GENERATION_TOOL_NAME);
113
+ if (eligible && !active) {
114
+ pi.setActiveTools([...activeTools, IMAGE_GENERATION_TOOL_NAME]);
115
+ } else if (!eligible && active) {
116
+ pi.setActiveTools(activeTools.filter((name) => name !== IMAGE_GENERATION_TOOL_NAME));
117
+ }
118
+ }
119
+
120
+ export function registerImageGenerationExtension(
121
+ pi: ExtensionAPI,
122
+ loadConfig: typeof loadToolkitConfig = loadToolkitConfig,
123
+ executeImage: typeof executeImageGeneration = executeImageGeneration,
124
+ ): void {
125
+ if (registeredApis.has(pi)) return;
126
+ registeredApis.add(pi);
127
+ registerPhysicalModelObserver(pi);
128
+
129
+ pi.registerTool<typeof GenerateImageParameters, ImageGenerationToolDetails, Record<string, never>>({
130
+ name: IMAGE_GENERATION_TOOL_NAME,
131
+ label: "OpenAI Generate Image",
132
+ description:
133
+ "Generate raster images, or edit from one to five user-approved local reference images, through an independent Images API request using a configured image model. PNG, JPEG, and WebP responses are validated and saved in their actual format. This is a paid provider operation; batchSize runs independent requests concurrently.",
134
+ promptSnippet: "Generate or edit raster images through an independent Images API request and a configured imageGeneration.allowedModels entry.",
135
+ promptGuidelines: [
136
+ "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.",
137
+ "Do not call openai_generate_image speculatively: it consumes the user's provider or gateway image quota.",
138
+ "Keep the image prompt faithful to the user's requested subject and constraints; do not invent unrequested style details.",
139
+ "Set referenceImagePaths to null unless the user explicitly identified local files; never invent paths or placeholder strings, and remember upload requires user approval.",
140
+ "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.",
141
+ "Set model to null unless the user named an image model configured in imageGeneration.allowedModels; never invent or guess a model id, and remember an unlisted model fails before the paid request.",
142
+ "Use batchSize only when the user asks for multiple variants; each batch item is an independent paid request, and batchSize cannot be combined with outputPath.",
143
+ "Do not substitute Python, browser automation, shell scripts, or unrelated image tools for an eligible image request.",
144
+ ],
145
+ parameters: GenerateImageParameters,
146
+ executionMode: "sequential",
147
+ async execute(toolCallId, params: GenerateImageToolParams, signal, _onUpdate, ctx) {
148
+ try {
149
+ const result = await executeImage({
150
+ params,
151
+ toolCallId,
152
+ signal,
153
+ ctx,
154
+ });
155
+ return {
156
+ content: [{ type: "text", text: result.text }],
157
+ details: result.details,
158
+ };
159
+ } catch (error) {
160
+ if (error instanceof ImageGenerationError) {
161
+ throw new Error(error.message);
162
+ }
163
+ throw new Error(
164
+ sanitizeImageDiagnostic(error instanceof Error ? error.message : error, "Image generation failed."),
165
+ );
166
+ }
167
+ },
168
+ renderResult: renderImageGenerationResult,
169
+ });
170
+
171
+ const synchronize = (ctx: Parameters<typeof executeImageGeneration>[0]["ctx"], model = ctx.model) => {
172
+ const resolved = resolveToolkitConfig(loadConfig(), model);
173
+ notifyConfigIssues(ctx, resolved);
174
+ const valid = !resolved.invalidFeatures.some((feature) => feature === "imageGeneration" || feature === "compatibility");
175
+ syncImageGenerationTool(pi, model, { ...resolved.config.imageGeneration, enabled: valid && resolved.policy.imageGeneration.enabled });
176
+ };
177
+ pi.on("session_start", (_event, ctx) => synchronize(ctx));
178
+ pi.on("model_select", (event, ctx) => synchronize(ctx, event.model));
179
+ pi.on("before_agent_start", (_event, ctx) => synchronize(ctx));
180
+ }
181
+
182
+ export default function imageGenerationExtension(pi: ExtensionAPI): void {
183
+ registerImageGenerationExtension(pi);
184
+ }
185
+
186
+ export const _extensionTest = {
187
+ GenerateImageParameters,
188
+ syncImageGenerationTool,
189
+ };