dsh-image-gen 0.6.8 → 0.6.9

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/lib/index.js CHANGED
@@ -6077,6 +6077,33 @@ const DEFAULT_ZHIPU_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
6077
6077
  const DEFAULT_COMFYUI_BASE_URL = "http://127.0.0.1:8188";
6078
6078
  const DEFAULT_COMFYUI_TIMEOUT_MS = 3e5;
6079
6079
  const DEFAULT_COMFYUI_WORKFLOW_LABEL = "API workflow";
6080
+ /** Content types Ark's Seedream endpoint can return. */
6081
+ const ARK_OUTPUT_FORMATS = ["png", "jpeg"];
6082
+ /** Whether Ark stamps an "AI generated" watermark on the result. */
6083
+ const ARK_BACKGROUND_MODES = ["opaque", "transparent"];
6084
+ /**
6085
+ * Map the Ark output controls onto request-body fields.
6086
+ *
6087
+ * `background` is opt-in per call site because Ark restricts `transparent` to
6088
+ * image-to-image with a single alpha-bearing reference and rejects the whole
6089
+ * request otherwise:
6090
+ *
6091
+ * text-to-image + transparent → 400 InvalidParameter
6092
+ * "transparent background requires exactly one input image"
6093
+ *
6094
+ * So the generation endpoint must never carry it, and that caller passes
6095
+ * `{ background: false }`. `background: opaque` is never emitted anywhere: it
6096
+ * is already Ark's default, so sending it would change nothing while adding a
6097
+ * field only the edit path can act on.
6098
+ */
6099
+ function arkOutputBody(options, { background = true } = {}) {
6100
+ if (options === void 0) return {};
6101
+ const body = {};
6102
+ if (options.outputFormat !== void 0) body.output_format = options.outputFormat;
6103
+ if (options.watermark !== void 0) body.watermark = options.watermark;
6104
+ if (background && options.background === "transparent") body.background = "transparent";
6105
+ return body;
6106
+ }
6080
6107
  /** Default model names. */
6081
6108
  const DEFAULT_GOOGLE_MODEL = "gemini-3.1-flash-image";
6082
6109
  const DEFAULT_OPENAI_MODEL = "gpt-image-2";
@@ -6170,6 +6197,9 @@ const Config = z.object({
6170
6197
  openaiCompatEditExtra: z.dict(z.any()).default({}),
6171
6198
  seedreamBaseURL: z.string().default(DEFAULT_SEEDREAM_BASE_URL),
6172
6199
  seedreamModel: z.string().default(DEFAULT_SEEDREAM_MODEL),
6200
+ seedreamOutputFormat: z.union(ARK_OUTPUT_FORMATS).default("jpeg"),
6201
+ seedreamWatermark: z.boolean().default(true),
6202
+ seedreamBackground: z.union(ARK_BACKGROUND_MODES).default("opaque"),
6173
6203
  dashscopeEndpoint: z.string().default(DEFAULT_DASHSCOPE_ENDPOINT),
6174
6204
  dashscopeModel: z.string().default(DEFAULT_DASHSCOPE_MODEL),
6175
6205
  xaiBaseURL: z.string().default(DEFAULT_XAI_BASE_URL),
@@ -6214,13 +6244,21 @@ function resolveProvider(config) {
6214
6244
  editExtra: config.openaiCompatEditExtra ?? {}
6215
6245
  };
6216
6246
  }
6217
- case "seedream": return {
6218
- provider: "seedream",
6219
- apiKeyEnv: SEEDREAM_API_KEY_ENV,
6220
- model: config.seedreamModel ?? "doubao-seedream-5-0-260128",
6221
- baseURL: config.seedreamBaseURL ?? "https://ark.cn-beijing.volces.com/api/v3",
6222
- imageSize: "2K"
6223
- };
6247
+ case "seedream": {
6248
+ const seedreamBackground = config.seedreamBackground ?? "opaque";
6249
+ return {
6250
+ provider: "seedream",
6251
+ apiKeyEnv: SEEDREAM_API_KEY_ENV,
6252
+ model: config.seedreamModel ?? "doubao-seedream-5-0-260128",
6253
+ baseURL: config.seedreamBaseURL ?? "https://ark.cn-beijing.volces.com/api/v3",
6254
+ imageSize: "2K",
6255
+ arkOptions: {
6256
+ outputFormat: seedreamBackground === "transparent" ? "png" : config.seedreamOutputFormat ?? "jpeg",
6257
+ watermark: config.seedreamWatermark ?? true,
6258
+ background: seedreamBackground
6259
+ }
6260
+ };
6261
+ }
6224
6262
  case "dashscope": return {
6225
6263
  provider: "dashscope",
6226
6264
  apiKeyEnv: DASHSCOPE_API_KEY_ENV,
@@ -8118,7 +8156,10 @@ async function generateOpenAICompatibleImage(input) {
8118
8156
  model: input.model,
8119
8157
  prompt: input.prompt,
8120
8158
  size: input.size,
8121
- ...input.provider === "seedream" ? { response_format: "url" } : {}
8159
+ ...input.provider === "seedream" ? {
8160
+ response_format: "url",
8161
+ ...arkOutputBody(input.arkOptions, { background: false })
8162
+ } : {}
8122
8163
  })
8123
8164
  }), input.provider, input);
8124
8165
  }
@@ -8306,6 +8347,7 @@ async function editSeedreamImage(input) {
8306
8347
  prompt: input.prompt,
8307
8348
  image: input.sourceImages.map(toDataUrl$1),
8308
8349
  ...input.size === void 0 || input.size.length === 0 ? {} : { size: input.size },
8350
+ ...arkOutputBody(input.arkOptions),
8309
8351
  response_format: "b64_json"
8310
8352
  })
8311
8353
  });
@@ -20624,7 +20666,8 @@ async function generateFromStudio(ctx, config, input, signal, fallbackWorkspaceR
20624
20666
  sourceImages,
20625
20667
  size,
20626
20668
  maxBytes: ctx.attachments.imageLimits.maxImageBytes,
20627
- signal
20669
+ signal,
20670
+ arkOptions: wired.arkOptions
20628
20671
  }) : await generateOpenAICompatibleImage({
20629
20672
  provider: "seedream",
20630
20673
  apiKey: credential,
@@ -20633,7 +20676,8 @@ async function generateFromStudio(ctx, config, input, signal, fallbackWorkspaceR
20633
20676
  prompt: input.prompt,
20634
20677
  size,
20635
20678
  maxBytes: ctx.attachments.imageLimits.maxImageBytes,
20636
- signal
20679
+ signal,
20680
+ arkOptions: wired.arkOptions
20637
20681
  });
20638
20682
  output = size;
20639
20683
  } else {
@@ -21675,6 +21719,7 @@ function apply(ctx, config = {}) {
21675
21719
  }), active.provider, active.model, size, current(), exec, knownWorkspaceRoots);
21676
21720
  }
21677
21721
  const size = args.size ?? active.imageSize;
21722
+ const arkOptions = active.provider === "seedream" ? active.arkOptions : void 0;
21678
21723
  return saveGenerated(ctx, await generateOpenAICompatibleImage({
21679
21724
  provider: active.provider,
21680
21725
  apiKey: credential,
@@ -21683,7 +21728,8 @@ function apply(ctx, config = {}) {
21683
21728
  prompt: args.prompt,
21684
21729
  size,
21685
21730
  maxBytes: ctx.attachments.imageLimits.maxImageBytes,
21686
- signal: exec.signal
21731
+ signal: exec.signal,
21732
+ ...arkOptions === void 0 ? {} : { arkOptions }
21687
21733
  }), active.provider, active.model, size, current(), exec, knownWorkspaceRoots);
21688
21734
  },
21689
21735
  presentResult: (_args, result) => imagePresentation(result)
@@ -21862,7 +21908,8 @@ function apply(ctx, config = {}) {
21862
21908
  sourceImages,
21863
21909
  size,
21864
21910
  maxBytes: ctx.attachments.imageLimits.maxImageBytes,
21865
- signal: exec.signal
21911
+ signal: exec.signal,
21912
+ arkOptions: active.arkOptions
21866
21913
  }), active.provider, active.model, size, current(), exec, knownWorkspaceRoots);
21867
21914
  return saveGenerated(ctx, await editDashScopeImage({
21868
21915
  apiKey: credential,
@@ -28,6 +28,12 @@ interface ImageSettings {
28
28
  openaiCompatEditExtra?: Record<string, unknown>;
29
29
  seedreamBaseURL?: string;
30
30
  seedreamModel?: string;
31
+ /** Ark `output_format`; `png` is lossless and keeps an alpha channel. */
32
+ seedreamOutputFormat?: 'png' | 'jpeg';
33
+ /** Ark `watermark`; off removes the baked-in "AI generated" mark. */
34
+ seedreamWatermark?: boolean;
35
+ /** Ark `background`; `transparent` needs an alpha-bearing edit reference. */
36
+ seedreamBackground?: 'opaque' | 'transparent';
31
37
  dashscopeEndpoint?: string;
32
38
  dashscopeModel?: string;
33
39
  xaiBaseURL?: string;
@@ -81,7 +87,7 @@ interface ImageCardFace {
81
87
  locale?: LocaleService | undefined;
82
88
  promoted: boolean;
83
89
  }
84
- type SettingsCardProps = PropsRuntime<'settings.plugin.item'> & InjectFace<SettingsFace>;
90
+ type SettingsCardProps = PropsRuntime<'settings.plugins.tab'> & InjectFace<SettingsFace>;
85
91
  type ImageCardProps = PropsRuntime<'tool.call.toolview'> & InjectFace<ImageCardFace>;
86
92
  interface ImageResultNodeProps {
87
93
  node: {
@@ -1,7 +1,7 @@
1
1
  /** User-facing configuration for supported image providers. */
2
2
  import z from '@deepseek-ai/schemastery';
3
- import { DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, DEFAULT_XAI_BASE_URL, DEFAULT_XAI_MODEL, DEFAULT_ZHIPU_BASE_URL, DEFAULT_ZHIPU_MODEL, DASHSCOPE_API_KEY_ENV, GOOGLE_API_KEY_ENV, IMAGE_PROVIDERS, OPENAI_API_KEY_ENV, OPENAI_COMPAT_API_KEY_ENV, SEEDREAM_API_KEY_ENV, XAI_API_KEY_ENV, ZHIPU_API_KEY_ENV, activeComfyUIWorkflow, resolveComfyUIWorkflows, type ComfyUIWorkflowEntry, type ImageProvider } from './shared.js';
4
- export { DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, DEFAULT_XAI_BASE_URL, DEFAULT_XAI_MODEL, DEFAULT_ZHIPU_BASE_URL, DEFAULT_ZHIPU_MODEL, DASHSCOPE_API_KEY_ENV, GOOGLE_API_KEY_ENV, IMAGE_PROVIDERS, OPENAI_API_KEY_ENV, OPENAI_COMPAT_API_KEY_ENV, SEEDREAM_API_KEY_ENV, XAI_API_KEY_ENV, ZHIPU_API_KEY_ENV, activeComfyUIWorkflow, resolveComfyUIWorkflows, type ComfyUIWorkflowEntry, type ImageProvider, };
3
+ import { ARK_BACKGROUND_MODES, ARK_OUTPUT_FORMATS, DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, DEFAULT_XAI_BASE_URL, DEFAULT_XAI_MODEL, DEFAULT_ZHIPU_BASE_URL, DEFAULT_ZHIPU_MODEL, DASHSCOPE_API_KEY_ENV, GOOGLE_API_KEY_ENV, IMAGE_PROVIDERS, OPENAI_API_KEY_ENV, OPENAI_COMPAT_API_KEY_ENV, SEEDREAM_API_KEY_ENV, XAI_API_KEY_ENV, ZHIPU_API_KEY_ENV, activeComfyUIWorkflow, resolveComfyUIWorkflows, type ArkBackgroundMode, type ArkOutputFormat, type ArkOutputOptions, type ComfyUIWorkflowEntry, type ImageProvider } from './shared.js';
4
+ export { ARK_BACKGROUND_MODES, ARK_OUTPUT_FORMATS, DEFAULT_DASHSCOPE_ENDPOINT, DEFAULT_DASHSCOPE_MODEL, DEFAULT_COMFYUI_BASE_URL, DEFAULT_COMFYUI_TIMEOUT_MS, DEFAULT_COMFYUI_WORKFLOW_LABEL, DEFAULT_GOOGLE_ENDPOINT, DEFAULT_GOOGLE_MODEL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_SEEDREAM_BASE_URL, DEFAULT_SEEDREAM_MODEL, DEFAULT_XAI_BASE_URL, DEFAULT_XAI_MODEL, DEFAULT_ZHIPU_BASE_URL, DEFAULT_ZHIPU_MODEL, DASHSCOPE_API_KEY_ENV, GOOGLE_API_KEY_ENV, IMAGE_PROVIDERS, OPENAI_API_KEY_ENV, OPENAI_COMPAT_API_KEY_ENV, SEEDREAM_API_KEY_ENV, XAI_API_KEY_ENV, ZHIPU_API_KEY_ENV, activeComfyUIWorkflow, resolveComfyUIWorkflows, type ArkBackgroundMode, type ArkOutputFormat, type ArkOutputOptions, type ComfyUIWorkflowEntry, type ImageProvider, };
5
5
  /** Default workspace subfolder that receives generated image files. */
6
6
  export declare const DEFAULT_WORKSPACE_FOLDER = "dsh-image-gen";
7
7
  /** Google tool-level controls. */
@@ -34,6 +34,22 @@ export interface Config {
34
34
  openaiCompatEditExtra?: Record<string, unknown>;
35
35
  seedreamBaseURL?: string;
36
36
  seedreamModel?: string;
37
+ /**
38
+ * Ark `output_format`. Ark defaults to `jpeg`, which is lossy and cannot
39
+ * carry an alpha channel; `png` is lossless, so it survives later editing
40
+ * (e.g. background removal) without JPEG ringing around the subject.
41
+ */
42
+ seedreamOutputFormat?: ArkOutputFormat;
43
+ /**
44
+ * Ark `watermark`. Ark defaults to `true`, which bakes an "AI generated"
45
+ * mark into the bottom-right corner.
46
+ */
47
+ seedreamWatermark?: boolean;
48
+ /**
49
+ * Ark `background`. Only the edit path can honour `transparent`, and only
50
+ * when every reference image already carries an alpha channel.
51
+ */
52
+ seedreamBackground?: ArkBackgroundMode;
37
53
  dashscopeEndpoint?: string;
38
54
  dashscopeModel?: string;
39
55
  xaiBaseURL?: string;
@@ -85,6 +101,7 @@ export declare function resolveProvider(config: Config): {
85
101
  model: string;
86
102
  baseURL: string;
87
103
  imageSize: string;
104
+ arkOptions: ArkOutputOptions;
88
105
  } | {
89
106
  provider: 'dashscope';
90
107
  apiKeyEnv: string;
@@ -1,5 +1,6 @@
1
1
  /** OpenAI Images API and compatible response adapter. */
2
2
  import type { ImageMediaType } from '@deepseek-ai/dsh-attachment';
3
+ import { type ArkOutputOptions } from './shared.js';
3
4
  export interface GeneratedCompatibleImage {
4
5
  data: Uint8Array;
5
6
  mediaType: ImageMediaType;
@@ -17,6 +18,8 @@ export declare function generateOpenAICompatibleImage(input: {
17
18
  size: string;
18
19
  maxBytes: number;
19
20
  signal: AbortSignal;
21
+ /** Ark-only output controls; ignored by every other provider. */
22
+ arkOptions?: ArkOutputOptions;
20
23
  }): Promise<GeneratedCompatibleImage>;
21
24
  /** How the edits endpoint expects its request body (#41). */
22
25
  export type CompatEditFormat = 'multipart' | 'jsonImageUrlArray';
@@ -1,6 +1,7 @@
1
1
  /** Volcengine Ark Seedream image-editing adapter. */
2
2
  import type { ImageMediaType } from '@deepseek-ai/dsh-attachment';
3
3
  import type { GeneratedCompatibleImage } from './openai-compatible.js';
4
+ import { type ArkOutputOptions } from './shared.js';
4
5
  /** Edit one image through Ark ImageGenerations using a data-URL reference. */
5
6
  export declare function editSeedreamImage(input: {
6
7
  apiKey: string;
@@ -14,4 +15,10 @@ export declare function editSeedreamImage(input: {
14
15
  size?: string;
15
16
  maxBytes: number;
16
17
  signal: AbortSignal;
18
+ /**
19
+ * Ark output controls. The edit path is the only one Ark lets request a
20
+ * transparent background, and it requires every reference image to carry an
21
+ * alpha channel — see `arkOutputBody`.
22
+ */
23
+ arkOptions?: ArkOutputOptions;
17
24
  }): Promise<GeneratedCompatibleImage>;
@@ -247,6 +247,45 @@ export declare const DEFAULT_COMFYUI_BASE_URL = "http://127.0.0.1:8188";
247
247
  export declare const DEFAULT_COMFYUI_TIMEOUT_MS = 300000;
248
248
  export declare const DEFAULT_COMFYUI_WORKFLOW_LABEL = "API workflow";
249
249
  export declare const MAX_COMFYUI_WORKFLOW_BYTES: number;
250
+ /** Content types Ark's Seedream endpoint can return. */
251
+ export declare const ARK_OUTPUT_FORMATS: readonly ["png", "jpeg"];
252
+ /** Whether Ark stamps an "AI generated" watermark on the result. */
253
+ export declare const ARK_BACKGROUND_MODES: readonly ["opaque", "transparent"];
254
+ export type ArkOutputFormat = typeof ARK_OUTPUT_FORMATS[number];
255
+ export type ArkBackgroundMode = typeof ARK_BACKGROUND_MODES[number];
256
+ /**
257
+ * Ark (Seedream) output controls, shared by the generate and edit paths.
258
+ *
259
+ * Every field mirrors an Ark request-body field of the same meaning, and every
260
+ * default below reproduces Ark's own default — so an untouched configuration
261
+ * sends exactly what it sent before these options existed.
262
+ */
263
+ export interface ArkOutputOptions {
264
+ /** `output_format`. Ark defaults to `jpeg`; `png` is lossless and keeps an alpha channel. */
265
+ outputFormat?: ArkOutputFormat;
266
+ /** `watermark`. Ark defaults to `true`, which bakes an "AI generated" mark into the image. */
267
+ watermark?: boolean;
268
+ /** `background`. Ark defaults to `opaque`. */
269
+ background?: ArkBackgroundMode;
270
+ }
271
+ /**
272
+ * Map the Ark output controls onto request-body fields.
273
+ *
274
+ * `background` is opt-in per call site because Ark restricts `transparent` to
275
+ * image-to-image with a single alpha-bearing reference and rejects the whole
276
+ * request otherwise:
277
+ *
278
+ * text-to-image + transparent → 400 InvalidParameter
279
+ * "transparent background requires exactly one input image"
280
+ *
281
+ * So the generation endpoint must never carry it, and that caller passes
282
+ * `{ background: false }`. `background: opaque` is never emitted anywhere: it
283
+ * is already Ark's default, so sending it would change nothing while adding a
284
+ * field only the edit path can act on.
285
+ */
286
+ export declare function arkOutputBody(options: ArkOutputOptions | undefined, { background }?: {
287
+ background?: boolean;
288
+ }): Record<string, unknown>;
250
289
  /** Default model names. */
251
290
  export declare const DEFAULT_GOOGLE_MODEL = "gemini-3.1-flash-image";
252
291
  export declare const DEFAULT_OPENAI_MODEL = "gpt-image-2";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-image-gen",
3
- "version": "0.6.8",
3
+ "version": "0.6.9",
4
4
  "description": "Bring ChatGPT-like image generation to DeepSeek Harness — Gemini, OpenAI, Seedream, DashScope, local ComfyUI & more.",
5
5
  "type": "module",
6
6
  "author": "shanliuling",
@@ -66,7 +66,7 @@
66
66
  "engines": {
67
67
  "node": "^22.19.0 || >=24.0.0"
68
68
  },
69
- "license": "MIT",
69
+ "license": "Apache-2.0",
70
70
  "keywords": [
71
71
  "deepseek",
72
72
  "deepseek-harness",
@@ -16,7 +16,7 @@ description: Install, configure, verify, or remove the dsh-image-gen Bundle in a
16
16
  4. If pnpm blocks the Git dependency's `prepare` script, explain that the allowance executes repository code during installation. Add only the exact package key pnpm reports to the profile's `pnpm-workspace.yaml`, then retry after the user approves.
17
17
  5. Verify `dsh --profile <profile> --dump-config` contains the `dsh-image-gen` layer and `image-gen` row.
18
18
  6. Start the profile. If port 3080 is already in use, identify the existing DSH process before stopping anything.
19
- 7. In Settings > Plugins > Plugin configuration > Image generation, select a cloud Provider and save its API key, or select Local ComfyUI, enter its URL, and import a ComfyUI API Format workflow JSON containing `{{prompt}}`. Never print, read back, or commit a key.
19
+ 7. In Settings > Plugins > Image generation (DSH 0.1.5 and earlier: Settings > Plugins > Plugin Configuration > Image generation), select a cloud Provider and save its API key, or select Local ComfyUI, enter its URL, and import a ComfyUI API Format workflow JSON containing `{{prompt}}`. Never print, read back, or commit a key.
20
20
  8. Test with “生成一张戴墨镜的赛博朋克猫图片”. Confirm one `generate_image` call succeeds and its image renders in the conversation.
21
21
 
22
22
  For removal, run `dsh plugin --profile <profile> remove dsh-image-gen`. Do not delete the user's credentials unless they explicitly request it.