pi-openai-toolkit 0.23.2 → 0.24.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 (54) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +83 -83
  3. package/README.md +4 -15
  4. package/README.zh.md +4 -15
  5. package/config.schema.json +264 -278
  6. package/docs/configuration.md +304 -306
  7. package/docs/internals.md +34 -120
  8. package/package.json +123 -136
  9. package/src/compact-client.ts +412 -412
  10. package/src/compaction-projection.ts +35 -35
  11. package/src/config/legacy.ts +469 -519
  12. package/src/config/migration.ts +115 -103
  13. package/src/config/notifications.ts +46 -36
  14. package/src/config/policy.ts +115 -116
  15. package/src/config/v2.ts +1128 -1167
  16. package/src/config.ts +320 -310
  17. package/src/debug.ts +238 -238
  18. package/src/deferred-tool-carryover.ts +282 -282
  19. package/src/details-store.ts +151 -151
  20. package/src/extension-runtime.ts +1095 -1919
  21. package/src/image-generation/extension.ts +189 -189
  22. package/src/image-generation/protocol.ts +579 -579
  23. package/src/image-generation/types.ts +300 -300
  24. package/src/native-fallback.ts +140 -152
  25. package/src/payload-rewrite.ts +515 -515
  26. package/src/pi-context-hook.ts +117 -117
  27. package/src/remote-v2-client.ts +811 -811
  28. package/src/request-context-cache.ts +155 -155
  29. package/src/responses-headers.ts +180 -180
  30. package/src/retired-remote-windows.ts +35 -0
  31. package/src/runtime.ts +875 -865
  32. package/src/serializer.ts +882 -882
  33. package/src/supported-environment.ts +27 -27
  34. package/src/types.ts +541 -565
  35. package/src/web-search/alpha-client.ts +876 -876
  36. package/src/web-search/extension.ts +530 -530
  37. package/src/web-search/payload.ts +299 -299
  38. package/src/web-search/prompt.ts +60 -60
  39. package/src/web-search/types.ts +166 -166
  40. package/tsconfig.check.json +50 -50
  41. package/src/context-management/codex-provider.ts +0 -270
  42. package/src/context-management/history-notes.ts +0 -357
  43. package/src/context-management/manual-compact.ts +0 -247
  44. package/src/context-management/messages.ts +0 -238
  45. package/src/context-management/namespace-tools.ts +0 -426
  46. package/src/context-management/responses-tools.ts +0 -238
  47. package/src/context-management/scoped-compaction.ts +0 -89
  48. package/src/context-management/tool-contract.ts +0 -62
  49. package/src/context-management/tools.ts +0 -371
  50. package/src/context-management/types.ts +0 -168
  51. package/src/context-management/window-budget.ts +0 -83
  52. package/src/context-management/window-bulk.ts +0 -155
  53. package/src/context-management/window-manager.ts +0 -912
  54. package/src/context-management/window-request.ts +0 -125
@@ -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
+ };