hffmnnj.generate-image 0.1.0 → 0.1.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.
package/README.md CHANGED
@@ -68,7 +68,7 @@ return await tools.generate_image({
68
68
  });
69
69
  ```
70
70
 
71
- Only the prompt and the listed reference images are sent. Session history is not included. The tool writes one new PNG inside the session project and returns its path, `file://` URI, actual dimensions, byte size, and `image/png` file content. It never overwrites an existing file.
71
+ Only the prompt and the listed reference images are sent. Session history is not included. The tool writes one new PNG inside the session project and returns its path, `file://` URI, actual dimensions, byte size, and one inline `image/png` attachment for chat. It never overwrites an existing file.
72
72
 
73
73
  ## Parameters
74
74
 
@@ -97,6 +97,8 @@ Set `responsesModel` in plugin options, not in `tools.generate_image` input. A s
97
97
 
98
98
  The result contains `path`, `uri`, `model`, `quality`, `requestedSize`, `action`, `mime: "image/png"`, actual `width`, `height`, `bytes`, and `transparent` (whether the returned PNG has alpha). If the backend resolves to a different size than requested, `warning` says so and the actual resolution is preserved.
99
99
 
100
+ The PNG is delivered once as native file content, using the same validated bytes saved on disk. Structured output contains metadata only, never image bytes or a base64 string. Code Mode forwards the attachment separately, so callers should return the result as shown above rather than read and attach the saved image again. Clients that render native image attachments can display it directly in chat. This is one multimodal image, not zero image-token usage; it is not a display-only attachment.
101
+
100
102
  There is no `transparent` input and no chroma-key or green-screen processing. Alpha is preserved when the provider returns it, but it cannot be requested.
101
103
 
102
104
  ## Platform and file safety
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hffmnnj.generate-image",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Native OpenCode V2 image generation using its active ChatGPT OAuth connection",
5
5
  "type": "module",
6
6
  "exports": { ".": "./src/index.ts" },
package/src/index.ts CHANGED
@@ -53,10 +53,10 @@ export async function registerImages(ctx: Plugin.Context, backend?: ImageBackend
53
53
  { resolve: () => resolveImageCredential(ctx) }, undefined,
54
54
  parsed.data.responsesModel ?? (session.model?.providerID === "openai" ? session.model.id : DEFAULT_RESPONSES_MODEL),
55
55
  ));
56
- const output = await invocationService.generate(session.location.directory, input, signal, ctx.location.project.directory);
56
+ const { output, png } = await invocationService.generateWithImage(session.location.directory, input, signal, ctx.location.project.directory);
57
57
  return { output, content: [
58
- { type: "text", text: JSON.stringify(output) },
59
- { type: "file", uri: output.uri, mime: "image/png" },
58
+ // Code Mode forwards native files separately from metadata-only output.
59
+ { type: "file", uri: `data:image/png;base64,${png.toString("base64")}`, mime: "image/png" },
60
60
  ] };
61
61
  } catch (error) { throw new ToolError({ message: safeMessage(error) }); }
62
62
  },
package/src/service.ts CHANGED
@@ -10,6 +10,10 @@ export class ImageService {
10
10
  constructor(private readonly backend: ImageBackend) {}
11
11
 
12
12
  async generate(root: string, rawInput: ImageInput, signal: AbortSignal, projectDirectory = root): Promise<ImageOutput> {
13
+ return (await this.generateWithImage(root, rawInput, signal, projectDirectory)).output;
14
+ }
15
+
16
+ async generateWithImage(root: string, rawInput: ImageInput, signal: AbortSignal, projectDirectory = root): Promise<{ output: ImageOutput; png: Buffer }> {
13
17
  const parsed = imageInputSchema.safeParse(rawInput);
14
18
  if (!parsed.success) throw new ImageError("Invalid image input. Check prompt, model, quality, size, action and project-relative image paths.");
15
19
  const input = parsed.data;
@@ -39,13 +43,14 @@ export class ImageService {
39
43
  const image = await normalizeImage(generated, false, signal);
40
44
  checkSignal(signal);
41
45
  await files.save(outputName, image.png, signal);
42
- return {
46
+ const output: ImageOutput = {
43
47
  path, uri: pathToFileURL(path).href, model: input.model, quality: input.quality, requestedSize: input.size,
44
48
  action: input.action, mime: "image/png", width: image.width, height: image.height,
45
49
  bytes: image.png.length, transparent: image.transparent,
46
50
  ...(input.size !== "auto" && input.size !== `${image.width}x${image.height}`
47
51
  ? { warning: `Requested ${input.size}; backend returned ${image.width}x${image.height}. Actual resolution preserved.` } : {}),
48
52
  };
53
+ return { output, png: image.png };
49
54
  } finally { await files.close(); }
50
55
  }
51
56
  }