@goodandready/dsh-image-gen 0.10.28 → 0.10.30

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/client.js CHANGED
@@ -2021,7 +2021,7 @@ window.__ModuleLoader__.load({
2021
2021
  }
2022
2022
 
2023
2023
  // -------------------------------------------------------------- Registration & Apply
2024
- const inject = ['slots', 'settingsScope', 'locale', 'sessions']
2024
+ const inject = ['slots', 'configForms', 'locale', 'sessions']
2025
2025
 
2026
2026
  function apply(ctx) {
2027
2027
  if (ctx.locale && typeof ctx.locale.define === 'function') {
@@ -2032,7 +2032,7 @@ window.__ModuleLoader__.load({
2032
2032
  let card
2033
2033
  const cardOnce = () => {
2034
2034
  if (card === undefined) {
2035
- const scope = ((ctx.get && ctx.get('lanSettings')) || ctx.settingsScope).bind({ namespace: SETTINGS_NS })
2035
+ const scope = ((ctx.get && ctx.get('lanSettings')) || ctx.configForms).get(SETTINGS_NS)
2036
2036
  card = new FalSettingsCardController(scope)
2037
2037
  }
2038
2038
  return card
package/lib/index.js CHANGED
@@ -469,7 +469,7 @@ export function apply(ctx, config) {
469
469
  // Content-addressed: the bytes behind an id never change.
470
470
  'Cache-Control': 'public, max-age=31536000, immutable',
471
471
  })
472
- res.end(Buffer.from(stored.data))
472
+ res.end(Buffer.isBuffer(stored.data) ? stored.data : Buffer.from(stored.data))
473
473
  } catch (error) {
474
474
  res.writeHead(404, { 'Content-Type': 'application/json' })
475
475
  res.end(JSON.stringify({ error: 'image not found or reference mismatch' }))
@@ -15,6 +15,12 @@ export function createGeminiGenerator(deps, job) {
15
15
  async function gemini(seedArg = seed, promptArg = prompt) {
16
16
  const key = await resolveKey(cfg.geminiKeyEnv)
17
17
  const model = cfg.geminiModel || 'gemini-2.0-flash-exp-image-generation'
18
+ const timeoutSignal = typeof AbortSignal !== 'undefined' && AbortSignal.timeout
19
+ ? AbortSignal.timeout(cfg.timeoutMs || 120000)
20
+ : undefined
21
+ const effectiveSignal = signal && timeoutSignal && AbortSignal.any
22
+ ? AbortSignal.any([signal, timeoutSignal])
23
+ : (signal || timeoutSignal)
18
24
  const res = await fetchImpl(`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${encodeURIComponent(key)}`, {
19
25
  method: 'POST',
20
26
  headers: { 'Content-Type': 'application/json' },
@@ -22,7 +28,7 @@ export function createGeminiGenerator(deps, job) {
22
28
  contents: [{ parts: [{ text: promptArg }] }],
23
29
  generationConfig: { responseModalities: ['IMAGE'], ...(quality !== undefined ? { imageConfig: { imageQuality: quality } } : {}), ...(style !== undefined ? { imageConfig: { imageStyle: style } } : {}) },
24
30
  }),
25
- signal,
31
+ signal: effectiveSignal,
26
32
  })
27
33
  const data = await res.json().catch(() => ({}))
28
34
  if (!res.ok) {
@@ -16,6 +16,12 @@ export function createSeedreamGenerator(deps, job) {
16
16
  async function seedream(seedArg = seed, promptArg = prompt) {
17
17
  const key = await resolveKey(cfg.seedreamKeyEnv)
18
18
  const base = (cfg.seedreamBaseURL || 'https://api.bytedanceapi.com/v1').replace(/\/+$/, '')
19
+ const timeoutSignal = typeof AbortSignal !== 'undefined' && AbortSignal.timeout
20
+ ? AbortSignal.timeout(cfg.timeoutMs || 120000)
21
+ : undefined
22
+ const effectiveSignal = signal && timeoutSignal && AbortSignal.any
23
+ ? AbortSignal.any([signal, timeoutSignal])
24
+ : (signal || timeoutSignal)
19
25
  const res = await fetchImpl(`${base}/images/generations`, {
20
26
  method: 'POST',
21
27
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${key}` },
@@ -28,7 +34,7 @@ export function createSeedreamGenerator(deps, job) {
28
34
  ...(quality !== undefined ? { quality } : {}),
29
35
  ...(style !== undefined ? { style } : {}),
30
36
  }),
31
- signal,
37
+ signal: effectiveSignal,
32
38
  })
33
39
  const data = await res.json().catch(() => ({}))
34
40
  if (!res.ok) {
@@ -41,7 +47,7 @@ export function createSeedreamGenerator(deps, job) {
41
47
  return { bytes: Buffer.from(item.b64_json, 'base64'), mediaType: normalizeMediaType('image/png', format), width: 0, height: 0, seed: seedArg ?? 0, sourceUrl: '' }
42
48
  }
43
49
  if (!item.url) throw new Error('Seedream returned neither b64_json nor url')
44
- const dl = await fetchImpl(item.url, { signal })
50
+ const dl = await fetchImpl(item.url, { signal: effectiveSignal })
45
51
  if (!dl.ok) throw new Error(`Seedream download failed (HTTP ${dl.status})`)
46
52
  return { bytes: Buffer.from(await dl.arrayBuffer()), mediaType: normalizeMediaType('image/png', format), width: 0, height: 0, seed: seedArg ?? 0, sourceUrl: item.url }
47
53
  }
@@ -27,6 +27,8 @@ import {
27
27
  blendImagesFal,
28
28
  toLosslessJson,
29
29
  saveAttachmentSafe,
30
+ editImageDirect,
31
+ varyImageDirect,
30
32
  } from '../providers.js'
31
33
  import { resolveConversationImage, analyzeImageWithVision, buildDualOutputMarkdown } from '../resolve-image.js'
32
34
  import { sanitizeNegativePrompt, supportsNegativePrompt } from '../negative-sanitizer.js'
@@ -156,11 +158,10 @@ export function registerEditingTools(ctx, deps) {
156
158
  mask,
157
159
  strength,
158
160
  provider,
161
+ signal: exec?.signal,
159
162
  }
160
163
 
161
- const providers = makeProviders(deps, job)
162
- const fn = providers[provider] || providers.fal || providers.custom
163
- const gen = await fn(seed, effectivePrompt)
164
+ const gen = await editImageDirect(deps, job)
164
165
 
165
166
  const stem = args.output_name ? slugify(args.output_name) : `${source.name}-edit-${seed}`
166
167
  const name = `${stem}.${format}`
@@ -287,11 +288,10 @@ export function registerEditingTools(ctx, deps) {
287
288
  source,
288
289
  strength: variationStrength,
289
290
  provider,
291
+ signal: exec?.signal,
290
292
  }
291
293
 
292
- const providers = makeProviders(deps, job)
293
- const fn = providers[provider] || providers.fal || providers.custom
294
- const gen = await fn(currentSeed, promptText)
294
+ const gen = await varyImageDirect(deps, job)
295
295
 
296
296
  const stem = args.output_name
297
297
  ? `${slugify(args.output_name)}-var-${i + 1}`
@@ -432,6 +432,7 @@ export function registerEditingTools(ctx, deps) {
432
432
  source,
433
433
  strength,
434
434
  provider,
435
+ signal: exec?.signal,
435
436
  }
436
437
 
437
438
  const providers = makeProviders(deps, job)
@@ -6,13 +6,6 @@ import { mkdir, writeFile } from 'node:fs/promises'
6
6
  import {
7
7
  computeGenerationHash,
8
8
  IMAGE_SIZES,
9
- OUTPUT_FORMATS,
10
- PROVIDER_KEYS,
11
- buildSidecar,
12
- makeProviders,
13
- ASPECT_RATIOS,
14
- pixelDiff,
15
- normalizeCount,
16
9
  tryGenerate,
17
10
  fallbackOrder,
18
11
  embedPngMetadata,
@@ -6,13 +6,7 @@ import { mkdir, writeFile } from 'node:fs/promises'
6
6
  import {
7
7
  computeGenerationHash,
8
8
  IMAGE_SIZES,
9
- OUTPUT_FORMATS,
10
- PROVIDER_KEYS,
11
- buildSidecar,
12
- makeProviders,
13
- ASPECT_RATIOS,
14
9
  pixelDiff,
15
- normalizeCount,
16
10
  tryGenerate,
17
11
  fallbackOrder,
18
12
  embedPngMetadata,
@@ -76,7 +76,7 @@ export function registerPatternTools(ctx, deps) {
76
76
  resolveKey: (ref) => resolveApiKey(ctx, ref),
77
77
  cfg,
78
78
  }
79
- const job = { prompt, size, format, seed, provider }
79
+ const job = { prompt, size, format, seed, provider, signal: exec?.signal }
80
80
  const providers = makeProviders(pdeps, job)
81
81
  const fn = providers[provider] || providers.fal || providers.custom
82
82
  const gen = await fn(seed, prompt)
@@ -8,13 +8,6 @@ import { mkdir, writeFile } from 'node:fs/promises'
8
8
  import {
9
9
  computeGenerationHash,
10
10
  IMAGE_SIZES,
11
- OUTPUT_FORMATS,
12
- PROVIDER_KEYS,
13
- buildSidecar,
14
- makeProviders,
15
- ASPECT_RATIOS,
16
- pixelDiff,
17
- normalizeCount,
18
11
  tryGenerate,
19
12
  fallbackOrder,
20
13
  embedPngMetadata,
@@ -8,13 +8,6 @@ import { mkdir, writeFile } from 'node:fs/promises'
8
8
  import {
9
9
  computeGenerationHash,
10
10
  IMAGE_SIZES,
11
- OUTPUT_FORMATS,
12
- PROVIDER_KEYS,
13
- buildSidecar,
14
- makeProviders,
15
- ASPECT_RATIOS,
16
- pixelDiff,
17
- normalizeCount,
18
11
  tryGenerate,
19
12
  fallbackOrder,
20
13
  embedPngMetadata,
@@ -143,6 +143,7 @@ export function registerResponsiveTools(ctx, deps) {
143
143
  provider,
144
144
  ...(stylePreset ? { style: stylePreset, style_preset: stylePreset } : {}),
145
145
  ...(paletteColors ? { palette_colors: paletteColors } : {}),
146
+ signal: exec?.signal,
146
147
  }
147
148
  const providers = makeProviders(pdeps, job)
148
149
  const generators = Object.fromEntries(PROVIDER_KEYS.map((k) => [
@@ -129,6 +129,7 @@ export function registerSketchTools(ctx, deps) {
129
129
  source,
130
130
  strength,
131
131
  provider,
132
+ signal: exec?.signal,
132
133
  }
133
134
  const providers = makeProviders(pdeps, job)
134
135
  const fn = providers[provider] || providers.fal || providers.custom
@@ -90,7 +90,7 @@ export function registerSpritesheetTools(ctx, deps) {
90
90
  resolveKey: (ref) => resolveApiKey(ctx, ref),
91
91
  cfg,
92
92
  }
93
- const job = { prompt: prompts[i], size, format, seed: seed + i, provider }
93
+ const job = { prompt: prompts[i], size, format, seed: seed + i, provider, signal: exec?.signal }
94
94
  const providers = makeProviders(pdeps, job)
95
95
  const fn = providers[provider] || providers.fal || providers.custom
96
96
  const gen = await fn(seed + i, prompts[i])
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-image-gen",
3
- "version": "0.10.28",
4
- "description": "Image generation for DeepSeek Harness: a generate_image tool with pluggable providers — the FAL queue, any OpenAI-compatible images API, or a ChatGPT/Grok subscription with no API key at all. The picture is shown inline in the conversation; the model receives either a link (works with any chat model) or the image itself (needs dsh-vision-bridge or a vision-capable model).",
3
+ "version": "0.10.30",
4
+ "description": "Image generation for DeepSeek Harness: a generate_image tool with pluggable providers \u2014 the FAL queue, any OpenAI-compatible images API, or a ChatGPT/Grok subscription with no API key at all. The picture is shown inline in the conversation; the model receives either a link (works with any chat model) or the image itself (needs dsh-vision-bridge or a vision-capable model).",
5
5
  "keywords": [
6
6
  "deepseek-harness",
7
7
  "dsh",
@@ -52,7 +52,8 @@
52
52
  "platform": "web",
53
53
  "inject": [
54
54
  "@deepseek-ai/dsh-client-locale",
55
- "@deepseek-ai/dsh-client-ui-settings"
55
+ "@deepseek-ai/dsh-client-ui-settings",
56
+ "@deepseek-ai/dsh-client-ui-slots"
56
57
  ]
57
58
  }
58
59
  },