@goodandready/dsh-image-gen 0.10.13 → 0.10.14

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
@@ -274,6 +274,10 @@ export const Config = z.object({
274
274
  .number()
275
275
  .description('provider=local: CFG scale.')
276
276
  .default(7),
277
+ seedreamBaseURL: z
278
+ .string()
279
+ .description('provider=seedream: base URL, e.g. https://api.bytedanceapi.com/v1 or Volcengine Ark.')
280
+ .default('https://api.bytedanceapi.com/v1'),
277
281
  seedreamKeyEnv: z
278
282
  .string()
279
283
  .role('credential-ref')
@@ -1197,8 +1201,9 @@ export function apply(ctx, config) {
1197
1201
  },
1198
1202
  },
1199
1203
  async execute(args, exec) {
1200
- const source = await resolveSource(ctx, exec, args.image)
1201
- if (!source || !source.bytes) throw new Error('Source image not found: ' + args.image)
1204
+ try {
1205
+ const source = await resolveSource(ctx, exec, args.image)
1206
+ if (!source || !source.bytes) throw new Error('Source image not found: ' + args.image)
1202
1207
  const cfg = live()
1203
1208
  const res = await removeBackgroundFal(
1204
1209
  { fetchImpl: fetch, resolveKey: (ref) => resolveApiKey(ctx, ref), cfg },
@@ -1236,6 +1241,9 @@ export function apply(ctx, config) {
1236
1241
  format: 'png',
1237
1242
  attachment,
1238
1243
  })
1244
+ } catch (err) {
1245
+ throw new Error(sanitizeErrorAndLogs(err.message || err))
1246
+ }
1239
1247
  },
1240
1248
  }),
1241
1249
  )
@@ -1266,8 +1274,9 @@ export function apply(ctx, config) {
1266
1274
  },
1267
1275
  },
1268
1276
  async execute(args, exec) {
1269
- const source = await resolveSource(ctx, exec, args.image)
1270
- if (!source || !source.bytes) throw new Error('Source image not found: ' + args.image)
1277
+ try {
1278
+ const source = await resolveSource(ctx, exec, args.image)
1279
+ if (!source || !source.bytes) throw new Error('Source image not found: ' + args.image)
1271
1280
  const cfg = live()
1272
1281
  const res = await upscaleImageFal(
1273
1282
  { fetchImpl: fetch, resolveKey: (ref) => resolveApiKey(ctx, ref), cfg },
@@ -1305,6 +1314,9 @@ export function apply(ctx, config) {
1305
1314
  height: res.height || attachment.height,
1306
1315
  attachment,
1307
1316
  })
1317
+ } catch (err) {
1318
+ throw new Error(sanitizeErrorAndLogs(err.message || err))
1319
+ }
1308
1320
  },
1309
1321
  }),
1310
1322
  )
@@ -1378,14 +1390,17 @@ export function apply(ctx, config) {
1378
1390
  },
1379
1391
  },
1380
1392
  async execute(args, exec) {
1381
- const refs = Array.isArray(args.images) ? args.images : [args.images].filter(Boolean)
1393
+ try {
1394
+ const cfg = live()
1395
+ trackAndAssertLoopGuard(exec?.agent?.session?.id || 'default', { limit: cfg.loopGuardLimit })
1396
+ assertBudgetAvailable(0.05, cfg.dailyBudgetUsd)
1397
+ const refs = Array.isArray(args.images) ? args.images : [args.images].filter(Boolean)
1382
1398
  const sources = []
1383
1399
  for (const r of refs) {
1384
1400
  const s = await resolveSource(ctx, exec, r)
1385
1401
  if (s && s.bytes) sources.push(s)
1386
1402
  }
1387
1403
  if (sources.length === 0) throw new Error('No valid images found to blend')
1388
- const cfg = live()
1389
1404
  const res = await blendImagesFal(
1390
1405
  { fetchImpl: fetch, resolveKey: (ref) => resolveApiKey(ctx, ref), cfg },
1391
1406
  { images: sources, weights: args.weights, prompt: args.prompt, signal: exec.signal }
@@ -1421,6 +1436,9 @@ export function apply(ctx, config) {
1421
1436
  height: res.height || attachment.height,
1422
1437
  attachment,
1423
1438
  })
1439
+ } catch (err) {
1440
+ throw new Error(sanitizeErrorAndLogs(err.message || err))
1441
+ }
1424
1442
  },
1425
1443
  }),
1426
1444
  )
@@ -1542,7 +1560,16 @@ export function apply(ctx, config) {
1542
1560
  },
1543
1561
  },
1544
1562
  async execute(args, exec) {
1545
- const source = await resolveConversationImage(ctx, exec, args.image)
1563
+ try {
1564
+ trackAndAssertLoopGuard(exec?.agent?.session?.id || 'default', { limit: cfg.loopGuardLimit })
1565
+ const estimatedCostEdit = calculateGenerationCost({
1566
+ provider: cfg.provider || 'fal',
1567
+ model: cfg.model,
1568
+ size: cfg.defaultSize || 'square_hd',
1569
+ count: 1,
1570
+ })
1571
+ assertBudgetAvailable(estimatedCostEdit, cfg.dailyBudgetUsd)
1572
+ const source = await resolveConversationImage(ctx, exec, args.image)
1546
1573
  const mask = args.mask ? await resolveSource(ctx, exec, args.mask) : undefined
1547
1574
  const vision = await analyzeImageWithVision(ctx, exec, source)
1548
1575
 
@@ -1603,6 +1630,9 @@ export function apply(ctx, config) {
1603
1630
  result.visionAnalysis = vision.summary
1604
1631
  }
1605
1632
  return toLosslessJson(result)
1633
+ } catch (err) {
1634
+ throw new Error(sanitizeErrorAndLogs(err.message || err))
1635
+ }
1606
1636
  },
1607
1637
  }),
1608
1638
  )
@@ -1662,7 +1692,17 @@ export function apply(ctx, config) {
1662
1692
  },
1663
1693
  },
1664
1694
  async execute(args, exec) {
1665
- const source = await resolveConversationImage(ctx, exec, args.image)
1695
+ try {
1696
+ trackAndAssertLoopGuard(exec?.agent?.session?.id || 'default', { limit: cfg.loopGuardLimit })
1697
+ const count = normalizeCount(args.count || 1)
1698
+ const estimatedCostVary = calculateGenerationCost({
1699
+ provider: cfg.provider || 'fal',
1700
+ model: cfg.model,
1701
+ size: cfg.defaultSize || 'square_hd',
1702
+ count,
1703
+ })
1704
+ assertBudgetAvailable(estimatedCostVary, cfg.dailyBudgetUsd)
1705
+ const source = await resolveConversationImage(ctx, exec, args.image)
1666
1706
  const vision = await analyzeImageWithVision(ctx, exec, source)
1667
1707
 
1668
1708
  const provider = cfg.provider || 'fal'
@@ -1671,8 +1711,6 @@ export function apply(ctx, config) {
1671
1711
  resolveKey: (ref) => resolveApiKey(ctx, ref),
1672
1712
  cfg,
1673
1713
  }
1674
-
1675
- const count = normalizeCount(args.count || 1)
1676
1714
  const variationStrength = Math.max(0.05, Math.min(0.95, args.variation_strength ?? 0.35))
1677
1715
  const baseSeed = Math.floor(Math.random() * 100000)
1678
1716
  const format = cfg.defaultFormat || 'png'
@@ -1727,6 +1765,9 @@ export function apply(ctx, config) {
1727
1765
  ...first,
1728
1766
  variations: results.map((r) => ({ path: r.path, attachmentId: r.attachment?.attachmentId, seed: r.seed })),
1729
1767
  })
1768
+ } catch (err) {
1769
+ throw new Error(sanitizeErrorAndLogs(err.message || err))
1770
+ }
1730
1771
  },
1731
1772
  }),
1732
1773
  )
package/lib/providers.js CHANGED
@@ -749,7 +749,7 @@ export function makeProviders(deps, job) {
749
749
  // Seedream (ByteDance): OpenAI-совместимый API картинок.
750
750
  async function seedream(seedArg = seed, promptArg = prompt) {
751
751
  const key = await resolveKey(cfg.seedreamKeyEnv)
752
- const base = 'https://api.bytedanceapi.com/v1'
752
+ const base = (cfg.seedreamBaseURL || 'https://api.bytedanceapi.com/v1').replace(/\/+$/, '')
753
753
  const res = await fetchImpl(`${base}/images/generations`, {
754
754
  method: 'POST',
755
755
  headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${key}` },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-image-gen",
3
- "version": "0.10.13",
3
+ "version": "0.10.14",
4
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).",
5
5
  "keywords": [
6
6
  "deepseek-harness",