Releases: GooDAnDReaDY/dsh-image-gen
Release list
dsh-fal-image-gen 0.7.0
Two providers that need no key at all: codex draws with gpt-image-2 and grok with grok-imagine, both through a subscription you are already logged into.
Nothing about keys, logins or token refreshing lives in this plugin. The subscriptions plugin owns the account and lends a finished picture through an in-process service — the token never crosses, and there is still exactly one owner of the refresh. Without that plugin the two providers decline with a sentence saying so, and the rest of the plugin is unaffected.
The named sizes stay the tool's language and map onto the subscription's own sizes; Grok's aspect ratios follow from those. subscriptionQuality passes low, medium or high when the subscription accepts one.
dsh plugin --profile web add @goodandready/dsh-fal-image-gen
dsh plugin --profile web add @goodandready/dsh-subscriptionsdsh-fal-image-gen 0.6.1
Settings now work when the Web UI is opened at a LAN address rather than localhost.
The harness turns its settings service off on any page that is not loopback: the settings document is never read, every namespace reports unavailable, and saving silently does nothing. That is a decision made in the browser — the server serves settings over the network perfectly well.
@goodandready/dsh-lanmode stands the same machinery up over the same calls. This release makes the card use it when it is installed, and the core service otherwise — which stays correct on a loopback page.
dsh plugin --profile web add @goodandready/dsh-lanmodeNothing else changed.
dsh-fal-image-gen 0.6.0
The settings card moves out of Settings → Plugins → Plugin configuration and into its own section in the settings sidebar, next to Vision, Voice, Speech and Key Rotation.
Why
On some deployments that core tab renders empty — the plugins themselves load fine, there is no error banner, and a cache-bypassing reload does not help. The tab is drawn by the core and a plugin cannot reach into it. A plugin's own section is drawn by the plugin, so it does not depend on that tab at all.
The move also retires a compatibility workaround: the registration had to carry both id and key, because the slot changed shape between core versions. settings.section takes id on all of them.
Two details that came with it
- the card started collapsed — sensible among many cards in a tab, but on a page of its own that reads as a blank page, so it now opens straight into the form;
- when the namespace was not published yet the card returned nothing at all, leaving an unexplained empty section. It now says what is going on in one line.
Nothing about generation itself changed: the same providers, the same tool, the same settings.
Install
dsh plugin --profile web add @goodandready/dsh-fal-image-gendsh-fal-image-gen 0.5.1
The plugin's card was sometimes missing from Settings → Plugins → Plugin configuration entirely, and stayed missing until the page was reloaded.
Why
The browser keeps one mirror of the Host settings document, and every settings surface — this card and the core ones alike — derives from it. It refreshes on exactly two signals, a document commit and a (re)connect. A namespace registering is neither: settings.register adds the registration to the registry and never emits settings/document-updated, which only a value change or a commit does.
The Host, meanwhile, answers HTTP well before registration finishes — on one harness the port was announced 1.4 seconds after start. A page that reads settings.describe inside that window gets a view without the namespaces that have not registered yet, and then never re-reads it. Nothing in the tab can recover: the card is not mounted there, so it cannot fix itself the way a mounted component could.
What changed
The client half asks the mirror to re-read while its namespace is absent from it — once a second, at most fifteen times. The mirror is shared, so one re-read brings back every other card too, including the core ones. In the healthy case this costs nothing measurable: the first check sees the namespace and no timer is ever started.
Verified on a staging harness. With the namespace present the check is a no-op and the card renders as before. With registration disabled in the installed host copy, the retry ran for twenty seconds with zero page errors, the core cards stayed intact, and the card was correctly absent — the Host really does not have that namespace, and the plugin does not pretend otherwise.
The real fix belongs upstream: either open the port after registration finishes, or invalidate the mirror when a namespace registers.
Install
dsh plugin --profile web add @goodandready/dsh-fal-image-gendsh-fal-image-gen 0.5.0
The plugin was FAL from end to end. It is becoming the one image generation plugin, where FAL is a provider rather than the whole design.
Providers
A provider now turns a prompt into image bytes and nothing else. Everything after that — the attachment, the durable copy in the session workspace, the same-origin URL that outlives the provider's own link, the tool card — is shared and written once.
provider |
What it is | Protocol |
|---|---|---|
fal (default) |
the FAL queue, exactly as before | submit, poll, download |
custom |
any OpenAI-compatible API | one POST {customBaseURL}/images/generations |
- id: dsh-fal-image-gen
config:
provider: custom
customBaseURL: https://api.openai.com/v1
customModel: gpt-image-1
customKeyEnv: OPENAI_API_KEYAll four fields are editable in the settings card. An empty customKeyEnv means no authorization header at all — a real case for a local gateway, not a misconfiguration.
Sizes stay the tool's language
The named sizes do not change when the provider does, so a prompt keeps its meaning. FAL takes them as they are; for an OpenAI-compatible API they are translated (landscape_4_3 → 1024x768). An API picky about sizes gets customSize, which is sent verbatim instead.
response_format is deliberately not sent: newer OpenAI models reject it, and the answer is read either way — base64 inline, or a link that is downloaded.
Removed: a settings field that lied
The card offered "Max images per call" (numImagesMax), but no such key existed in the host schema and generate_image has no num_images parameter — it always asks for one image. Turning the knob changed nothing.
Also
- default
outputDirmoves fromgenerated/faltogenerated/images, since the folder is no longer FAL's; deployments that set it explicitly are unaffected; - 12 unit tests, the first this plugin has had.
Renaming to @goodandready/dsh-image-gen waits until the provider set settles.
Install
dsh plugin --profile web add @goodandready/dsh-fal-image-gendsh-fal-image-gen 0.4.1
Compatibility fix for dsh 0.1.0-rc.8.
On rc8 the whole client half of the plugin failed to apply:
keyed slot "settings.plugin.item" requires options.key
and both cards went with it — the settings section and the generate_image result card, so a generated picture arrived as a JSON dump again.
The slot changed shape between core versions: a list slot needing options.id up to rc7, a keyed slot needing options.key from rc8, where the tab asks the Host for the configurable namespaces and renders one card per namespace. Each check only looks at its own field, so the registration now carries both and one build works on either version.
Verified on a staging harness running rc8 with the full plugin set: reproducible before the change, gone after — zero failed to apply entries, container healthy.
Install
dsh plugin --profile web add @goodandready/dsh-fal-image-gendsh-fal-image-gen 0.4.0
Two delivery modes. The picture appears in the conversation either way; what changes is what the chat model receives.
link (new default) |
image |
|
|---|---|---|
| The model receives | text and a link | the image itself |
| Shown in the chat | yes, the card renders it from the link | yes |
| Works with a text-only chat model | yes, on its own | no — needs dsh-vision-bridge or a vision-capable model |
| The model can reason about the picture | no | yes |
link is the default because it works in every deployment. Pick image when the conversation should be able to discuss what was drawn — "make the cat bluer" needs a model that can actually see it.
The tool description no longer claims the model can see the picture when it only got a link; without that line a model happily invents what it never saw. The link points at the plugin's own route rather than fal.media, which expires.
Also fixes settings, which never worked for this plugin. The host never registered its settings namespace and had no settings service injected, so the card bound to a namespace nobody declared, stayed unready and rendered nothing. The config is now read per call, so an edit applies to the next generation instead of after a restart.
Install
dsh plugin --profile web add @goodandready/dsh-fal-image-gendsh-fal-image-gen 0.3.0
Изображение теперь показывается прямо в чате.
- Своя карточка результата. Карточки инструментов в dsh не рисуют image-блоки — это умеют только сообщения пользователя и ассистента, поэтому сгенерированная картинка приходила как путь плюс JSON-дамп вложения. Плагин регистрирует keyed-запись
tool.call.toolviewдляgenerate_imageи отдаёт байты своим роутомGET /dsh-fal-image-gen/image. num_imagesубран. FAL генерировал и считал деньги за все картинки, а сохранялась и показывалась только первая.- Относительный
outputDirтеперь считается от рабочей папки сессии (exec.agent.session.header.cwd), а не от каталога, из которого запущен харнесс. - Scoped-имя сведено в трёх местах (
package.json, bundle patch, id загрузчика клиента) — без этого браузерная половина не попадает в граф при установке из npm.
Проверено на живом профиле: картинка сгенерирована и показана в карточке, файл записан в папку сессии, роут отдаёт ровно те же байты (200, image/png, 512×512) и отбивает некорректный id (400).
Установка
dsh plugin --profile web add @goodandready/dsh-fal-image-gen