pi-openai-toolkit 0.20.7 → 0.21.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.
Files changed (55) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +83 -83
  3. package/README.md +8 -26
  4. package/README.zh.md +8 -26
  5. package/config.schema.json +278 -366
  6. package/docs/configuration.md +294 -310
  7. package/docs/internals.md +166 -175
  8. package/package.json +3 -13
  9. package/src/compact-client.ts +412 -389
  10. package/src/compaction-errors.ts +96 -0
  11. package/src/compaction-projection.ts +35 -35
  12. package/src/config/legacy.ts +519 -717
  13. package/src/config/migration.ts +103 -100
  14. package/src/config/notifications.ts +36 -28
  15. package/src/config/policy.ts +10 -18
  16. package/src/config/v2.ts +1167 -1380
  17. package/src/config.ts +310 -319
  18. package/src/context-management/codex-provider.ts +270 -270
  19. package/src/context-management/history-notes.ts +357 -357
  20. package/src/context-management/manual-compact.ts +0 -11
  21. package/src/context-management/tools.ts +371 -371
  22. package/src/context-management/types.ts +168 -168
  23. package/src/context-management/window-manager.ts +801 -801
  24. package/src/debug.ts +238 -237
  25. package/src/deferred-tool-carryover.ts +282 -282
  26. package/src/details-store.ts +151 -151
  27. package/src/extension-runtime.ts +1662 -1623
  28. package/src/image-generation/extension.ts +189 -189
  29. package/src/image-generation/protocol.ts +579 -579
  30. package/src/image-generation/types.ts +300 -300
  31. package/src/native-fallback.ts +4 -132
  32. package/src/payload-rewrite.ts +515 -518
  33. package/src/pi-context-hook.ts +117 -117
  34. package/src/remote-v2-client.ts +811 -814
  35. package/src/request-context-cache.ts +155 -155
  36. package/src/responses-headers.ts +180 -180
  37. package/src/runtime.ts +865 -832
  38. package/src/serializer.ts +882 -882
  39. package/src/supported-environment.ts +27 -27
  40. package/src/types.ts +565 -648
  41. package/src/web-search/alpha-client.ts +876 -876
  42. package/src/web-search/extension.ts +530 -530
  43. package/src/web-search/payload.ts +299 -299
  44. package/src/web-search/prompt.ts +60 -60
  45. package/src/web-search/types.ts +166 -166
  46. package/tsconfig.check.json +50 -54
  47. package/src/auto-mode/classifier.ts +0 -161
  48. package/src/auto-mode/extension.ts +0 -691
  49. package/src/auto-mode/model-selection-guard.ts +0 -52
  50. package/src/auto-mode/policy.ts +0 -146
  51. package/src/auto-mode/prompt.ts +0 -279
  52. package/src/auto-mode/reviewer.ts +0 -325
  53. package/src/auto-mode/tool-review-tui.ts +0 -211
  54. package/src/auto-mode/transcript.ts +0 -135
  55. package/src/auto-mode/types.ts +0 -137
@@ -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
+ };