oira666_pi-image-generation 0.0.4 → 0.1.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/README.md CHANGED
@@ -1,12 +1,27 @@
1
1
  # pi-image-generation
2
2
 
3
- Tested against Pi 1.4.0.
3
+ Tested against Pi 1.5.0.
4
4
 
5
5
  ```sh
6
6
  pi install npm:oira666_pi-image-generation
7
7
  ```
8
8
 
9
- Generate and edit PNG images with the `image_gen` tool. Without settings, the extension uses the stored `openai-codex` subscription login, as before.
9
+ Generate and edit PNG images with GPT Image 2.6 using the `image_gen` tool. Without settings, the extension uses the stored `openai-codex` subscription login, as before.
10
+
11
+ ## Model selection
12
+
13
+ Sunburst (`gpt-image-2.6-sunburst`) is the default for better quality. Flare (`gpt-image-2.6-flare`) is faster but lower quality. The agent should use Flare only when you explicitly ask for Flare or faster generation, never as an automatic fallback.
14
+
15
+ The optional `model` argument applies to both generation and reference-image editing:
16
+
17
+ ```json
18
+ {
19
+ "prompt": "A blue ceramic vase on a white background",
20
+ "model": "gpt-image-2.6-flare"
21
+ }
22
+ ```
23
+
24
+ Omit `model` to use Sunburst. The extension sends the full model ID instead of relying on the unspecified `gpt-image-2.6` alias.
10
25
 
11
26
  ## Credentials
12
27
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oira666_pi-image-generation",
3
- "version": "0.0.4",
3
+ "version": "0.1.0",
4
4
  "description": "Image generation and reference-image editing for pi.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -29,14 +29,14 @@
29
29
  "node": ">=22"
30
30
  },
31
31
  "peerDependencies": {
32
- "@earendil-works/pi-coding-agent": ">=1.4.0",
32
+ "@earendil-works/pi-coding-agent": ">=1.5.0",
33
33
  "typebox": "*"
34
34
  },
35
35
  "dependencies": {
36
36
  "pngjs": "^7.0.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@earendil-works/pi-coding-agent": "^1.4.0",
39
+ "@earendil-works/pi-coding-agent": "^1.5.0",
40
40
  "@types/node": "^22.0.0",
41
41
  "@types/pngjs": "^6.0.5",
42
42
  "tsx": "^4.20.0",
@@ -17,6 +17,7 @@ Use `image_gen` for new raster artwork, image edits, and variations. The tool is
17
17
 
18
18
  ## Tool arguments
19
19
 
20
+ - `model`: optional, either `gpt-image-2.6-sunburst` or `gpt-image-2.6-flare`. Sunburst is the default for better quality. Flare is faster but lower quality. Use Flare only when the user explicitly asks for Flare or faster generation. Do not choose it automatically for drafts, simple images, retries, or edits, and never switch models after an error without permission.
20
21
  - `prompt`: a complete brief, up to 16,000 characters. Include exact text, reference roles, required details, and exclusions.
21
22
  - `referenced_image_paths`: one to five local PNG, JPEG, or WebP paths, in the same order used by the prompt. Relative paths use the project directory. These are uploaded to the image service for the requested edit.
22
23
  - `num_last_images_to_include`: one to five recent images from the current conversation branch. The selected images are supplied oldest first. This includes user attachments, images read by tools, and generated images. Unrelated recent images can enter this window, so explicit paths are safer for long workflows.
@@ -24,7 +25,7 @@ Use `image_gen` for new raster artwork, image edits, and variations. The tool is
24
25
 
25
26
  Choose either `referenced_image_paths` or `num_last_images_to_include`, never both. Do not pass an empty reference list. References must be at most 32 MiB each and 50 MiB combined. The tool accepts local paths, not arbitrary remote URLs.
26
27
 
27
- There are no separate model, size, quality, seed, mask, or batch arguments. Put framing, proportions, detail, and transparency requirements in the prompt. Do not promise exact dimensions, reproducible seeds, or pixel-perfect preservation. The backend decides the output dimensions and quality.
28
+ There are no separate size, quality, seed, mask, or batch arguments. Put framing, proportions, detail, and transparency requirements in the prompt. Do not promise exact dimensions, reproducible seeds, or pixel-perfect preservation. The backend decides the output dimensions and quality.
28
29
 
29
30
  ## Workflow
30
31
 
package/src/backend.ts CHANGED
@@ -2,7 +2,15 @@ import { randomUUID } from "node:crypto";
2
2
  import { PNG } from "pngjs";
3
3
  import type { ImageAuth } from "./auth.ts";
4
4
 
5
- export const IMAGE_MODEL = "gpt-image-2";
5
+ export const IMAGE_MODELS = ["gpt-image-2.6-sunburst", "gpt-image-2.6-flare"] as const;
6
+ export type ImageModel = typeof IMAGE_MODELS[number];
7
+ export const DEFAULT_IMAGE_MODEL = IMAGE_MODELS[0];
8
+
9
+ export function resolveImageModel(value: unknown): ImageModel {
10
+ if (value === undefined) return DEFAULT_IMAGE_MODEL;
11
+ if (value === IMAGE_MODELS[0] || value === IMAGE_MODELS[1]) return value;
12
+ throw new Error("Image model must be gpt-image-2.6-sunburst or gpt-image-2.6-flare.");
13
+ }
6
14
  const BASE_URL = "https://chatgpt.com/backend-api/codex";
7
15
  const API_BASE_URL = "https://api.openai.com/v1";
8
16
  export const MAX_IMAGE_BYTES = 32 * 1024 * 1024;
@@ -10,6 +18,7 @@ const MAX_RESPONSE_BYTES = 48 * 1024 * 1024;
10
18
 
11
19
  export interface ImageRequest {
12
20
  prompt: string;
21
+ model?: ImageModel;
13
22
  images?: string[];
14
23
  }
15
24
 
@@ -98,7 +107,7 @@ export async function requestImage(
98
107
  const editing = !!request.images?.length;
99
108
  const apiKeyAuth = "apiKey" in auth;
100
109
  const fields = {
101
- model: IMAGE_MODEL,
110
+ model: resolveImageModel(request.model),
102
111
  prompt: request.prompt,
103
112
  background: "auto",
104
113
  quality: "auto",
package/src/index.ts CHANGED
@@ -3,10 +3,14 @@ import { Type } from "typebox";
3
3
  import { resizeImage, type ExtensionAPI, type ExtensionContext, type ToolDefinition } from "@earendil-works/pi-coding-agent";
4
4
  import { hasImageAuth, offWarning, resolveImageAuth } from "./auth.ts";
5
5
  import { loadImageSettings } from "./settings.ts";
6
- import { IMAGE_MODEL, requestImage } from "./backend.ts";
6
+ import { DEFAULT_IMAGE_MODEL, IMAGE_MODELS, requestImage, resolveImageModel } from "./backend.ts";
7
7
  import { loadReferences, prepareOutput, saveImage } from "./images.ts";
8
8
 
9
9
  const parameters = Type.Object({
10
+ model: Type.Optional(Type.Union([Type.Literal(IMAGE_MODELS[0]), Type.Literal(IMAGE_MODELS[1])], {
11
+ default: DEFAULT_IMAGE_MODEL,
12
+ description: "Sunburst is the default for better quality. Flare is faster but lower quality; use it only when the user explicitly asks for Flare or faster generation.",
13
+ })),
10
14
  prompt: Type.String({ minLength: 1, maxLength: 16000, description: "Complete image brief, including reference-image roles and details that must not change." }),
11
15
  referenced_image_paths: Type.Optional(Type.Array(Type.String({ minLength: 1 }), {
12
16
  minItems: 1, maxItems: 5, description: "Local PNG/JPEG/WebP references, in prompt order. Relative paths resolve against the project. Do not combine with num_last_images_to_include.",
@@ -67,11 +71,12 @@ export default function imageGeneration(pi: ExtensionAPI): void {
67
71
  const tool: ToolDefinition<typeof parameters> = {
68
72
  name: "image_gen",
69
73
  label: "Generate image",
70
- description: "Generate or edit one raster image using the configured OpenAI provider or API key. Accepts up to five local or recent-conversation reference images for consistent edits and variants. Saves a new PNG and returns a preview when possible. Uses openai-codex by default; credentials can be overridden in pi-image-generation-settings.json. Reference limits: 32 MiB each, 50 MiB combined; 4-minute request timeout. Load the imagegen skill first.",
74
+ description: "Generate or edit one raster image using the configured OpenAI provider or API key. Accepts up to five local or recent-conversation reference images for consistent edits and variants. Saves a new PNG and returns a preview when possible. Defaults to GPT Image 2.6 Sunburst; Flare is faster but lower quality and only for explicit user requests. Uses openai-codex by default; credentials can be overridden in pi-image-generation-settings.json. Reference limits: 32 MiB each, 50 MiB combined; 4-minute request timeout. Load the imagegen skill first.",
71
75
  promptSnippet: "Generate images or edit them using local or recent image references",
72
76
  promptGuidelines: [
73
77
  "Before using image_gen, read the imagegen skill. Reuse reference images and state what must remain unchanged for consistent edits.",
74
78
  "Use image_gen for requested raster artwork, not SVG placeholders. Prefer native code edits for existing vector assets.",
79
+ "Default to Sunburst. Use Flare only when the user explicitly requests Flare or faster generation; it trades quality for speed. Never switch models automatically after an error.",
75
80
  ],
76
81
  parameters,
77
82
  async execute(_toolCallId, args, signal, onUpdate, ctx) {
@@ -79,6 +84,7 @@ export default function imageGeneration(pi: ExtensionAPI): void {
79
84
  const requestSignal = signal ? AbortSignal.any([signal, timeout]) : timeout;
80
85
  requestSignal.throwIfAborted();
81
86
  if (!args.prompt.trim()) throw new Error("The image prompt must not be blank.");
87
+ const model = resolveImageModel(args.model);
82
88
  const settings = await settingsFor(ctx);
83
89
  if (!hasImageAuth(settings, ctx.modelRegistry)) throw new Error(offWarning(settings) + " Check your image generation settings and login, then /reload.");
84
90
  const path = await prepareOutput(ctx.cwd, args.output_path);
@@ -89,7 +95,7 @@ export default function imageGeneration(pi: ExtensionAPI): void {
89
95
 
90
96
  let result;
91
97
  try {
92
- result = await requestImage(auth, { prompt: args.prompt, images }, requestSignal);
98
+ result = await requestImage(auth, { prompt: args.prompt, images, model }, requestSignal);
93
99
  } catch (error) {
94
100
  if (timeout.aborted && !signal?.aborted) {
95
101
  throw new Error("Image generation timed out after four minutes. It may still have consumed image allowance; no automatic retry was made.");
@@ -121,7 +127,7 @@ export default function imageGeneration(pi: ExtensionAPI): void {
121
127
  details: {
122
128
  savedPath,
123
129
  prompt: args.prompt,
124
- model: IMAGE_MODEL,
130
+ model,
125
131
  operation: images.length ? "edit" : "generate",
126
132
  referenceCount: images.length,
127
133
  },