Files
majordomo/docs/adr/0018-imagegen-editor.md
T
steve 434d721b99
CI / Tidy (pull_request) Successful in 10m9s
CI / Build & Test (pull_request) Successful in 11m16s
Adversarial Review (Gadfly) / review (pull_request) Successful in 14m51s
feat: audio surfaces (TTS + transcription), imagegen.Editor, llamaswap health probe
- New leaf package `audio` (ADR-0017): SpeechModel/SpeechProvider and
  TranscriptionModel/TranscriptionProvider with imagegen conventions
  (zero value = backend default, functional options + Apply, bytes
  in/out, never URLs). Root re-exports added.
- imagegen.Editor (ADR-0018): optional image-to-image interface —
  EditRequest carries the generation knobs plus Init image and
  denoising Strength; separate interface so existing Models keep
  compiling.
- provider/llamaswap implements all of it: POST /v1/audio/speech (JSON,
  raw-audio response, MIME from Content-Type with format fallback),
  POST /v1/audio/transcriptions (multipart, response_format=json),
  ListVoices (GET /v1/audio/voices?model=, tolerant of string-list and
  object-list shapes), POST /sdapi/v1/img2img (txt2img wire +
  init_images/denoising_strength, shared image decode), and Health(ctx)
  (GET /health) — a cheap liveness probe for often-offline hosts.
- Hermetic httptest coverage for every new wire shape and validation
  path; README sections + support-matrix footnote updated in the same
  commit (also corrects the stale /v1/images/generations claim — the
  image path has been SDAPI since the seed fix).

First consumer: mort's llamaswap media tool cluster (status / image /
TTS / STT agent tools against the netherstorm host).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AXQxVhXBw8PwFAtsVrXSmj
2026-07-11 23:24:14 -04:00

1.7 KiB

ADR-0018: imagegen.Editor — image-to-image as a separate optional interface

Status: Accepted — 2026-07-11

Context

ADR-0016 shipped text-to-image and explicitly deferred img2img. mort's new llama-swap media tools need "edit this image under this prompt" (image-to-image with a denoising strength). Two shape questions: does Edit belong on imagegen.Model, and which llama-swap endpoint carries it — OpenAI-style /v1/images/edits (multipart) or A1111-style /sdapi/v1/img2img (JSON)?

Decision

  • Editor is a separate, optional interface (Edit(ctx, EditRequest, ...EditOption) (*Result, error)), not a new method on Model. Existing Model implementations keep compiling; callers type-assert (m.(imagegen.Editor)) or require the capability explicitly.
  • EditRequest = the generation knobs (prompt, N, size, steps, cfg, negative prompt, sampler, seed) plus Init Image (required) and Strength *float64 (denoising strength in [0,1]; nil = backend default). Same option/Apply conventions; result type is the shared Result.
  • llama-swap implements it via /sdapi/v1/img2img, not /v1/images/edits: the same sd-server build that ignores seed on the OpenAI images route (the reason txt2img went SDAPI in ADR-0016's implementation) applies; the JSON shape is txt2img's plus init_images: ["<b64>"] + denoising_strength, so it reuses doJSON verbatim, where the OpenAI route is multipart.

Consequences

  • Backends that can't edit simply don't implement Editor; no stub methods.
  • The init image travels base64-inline in JSON (~33% overhead) — acceptable at chat-image sizes; a future backend needing multipart can still satisfy the same interface.